diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..6fa875f9 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,439 @@ +name: release + +# Release pipeline, hardened (rc.5): +# validate -> tests -> build (read-only) -> publish (contents: write) +# +# Gates, in order: +# 1. validate: the effective tag (input or pushed ref) must match the +# whitelist regex (upstream style 1.1.01 or legacy v-prefixed), the tag +# must check out, and the tag must match src/version.h VERSION_STRING +# (the single source of truth for the version). +# 2. tests: both Python regression suites must pass on the tag's commit. +# A release can never be published without the tests being green on +# the exact bits being shipped. +# 3. build: compiles the shipping configurations on the pinned +# windows-2022 (v143) image, builds both installers, packages the +# zips and records SHA-256 for every asset as job outputs (not just +# as a file inside the artifact). +# 4. publish: re-downloads the artifact, RE-VERIFIES every SHA-256 +# against the build job's outputs (artifact transport integrity), +# refuses to overwrite an existing release (the old --clobber path +# is deliberately gone), generates the notes from Changes.txt at +# the tag and publishes the release with the checksums file. +# +# Every user-controllable value (inputs.tag, github.ref_name) reaches a +# shell only through an environment variable and only after the +# whitelist regex check; no ${{ }} interpolation happens inside any +# run: block. +on: + push: + tags: + - 'v*' + - '[0-9]*' + workflow_dispatch: + inputs: + tag: + description: 'Tag to release (e.g. 1.1.01 or v1.1.0-rc.7). Required for manual runs; tag pushes use the pushed tag.' + required: false + default: '' + +permissions: + contents: read + +jobs: + validate: + runs-on: ubuntu-latest + outputs: + tag: ${{ steps.resolve.outputs.tag }} + version: ${{ steps.resolve.outputs.version }} + phase: ${{ steps.resolve.outputs.phase }} + commit: ${{ steps.commit.outputs.commit }} + steps: + - name: Resolve and validate the tag + id: resolve + env: + INPUT_TAG: ${{ inputs.tag }} + REF_NAME: ${{ github.ref_name }} + run: | + tag="${INPUT_TAG}" + if [ -z "$tag" ]; then + tag="${REF_NAME}" + fi + if [ -z "$tag" ]; then + echo "::error::no tag: push a version tag or provide the tag input for manual runs" + exit 1 + fi + # upstream style tags carry no v prefix (1.1.01); our legacy tags do + # (v1.1.0-rc.7). both are accepted, the tag is used exactly as pushed. + # 3 or 4 numeric segments, optional -beta.N / -rc.N phase. + if ! printf '%s' "$tag" | grep -Eq '^v?[0-9]+\.[0-9]+(\.[0-9]+){1,2}(-(beta|rc)\.[0-9]+)?$'; then + echo "::error::tag '$tag' does not match the release tag whitelist" + exit 1 + fi + version="${tag#v}" + if printf '%s' "$version" | grep -Eq -- '-rc\.'; then + phase=' (RC)' + elif printf '%s' "$version" | grep -Eq -- '-beta\.'; then + phase=' (BETA)' + else + phase='' + fi + { + echo "tag=$tag" + echo "version=$version" + echo "phase=$phase" + } >> "$GITHUB_OUTPUT" + echo "tag=$tag version=$version phase=$phase" + + - name: Checkout tag + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ steps.resolve.outputs.tag }} + fetch-depth: 1 + + - name: Verify the checked out commit is the tag + id: commit + env: + TAG: ${{ steps.resolve.outputs.tag }} + run: | + # fail closed: if the tag ref cannot be resolved here the + # check must abort, not silently pass against itself + tagged="$(git rev-parse "refs/tags/${TAG}^{commit}")" || { + echo "::error::cannot resolve refs/tags/${TAG} after checkout" + exit 1 + } + head="$(git rev-parse HEAD)" + if [ "$head" != "$tagged" ]; then + echo "::error::HEAD $head does not match tag commit $tagged" + exit 1 + fi + echo "commit=$head" >> "$GITHUB_OUTPUT" + echo "commit=$head" + + - name: Verify the tag matches src/version.h + env: + TAG: ${{ steps.resolve.outputs.tag }} + run: | + python3 - "$TAG" <<'EOF' + import re, sys + tag = sys.argv[1] + src = open('src/version.h', encoding='utf-8-sig').read() + # the release identity is VERSION_STRING (what the tag, the + # installer names and the version resource display); the numeric + # quad is the internal build identity and is not part of the tag. + m = re.search(r'#define\s+VERSION_STRING\s+"([^"]*)"', src) + if not m: + sys.exit('::error::src/version.h does not define VERSION_STRING') + expected = m.group(1) + if tag.lstrip('v') != expected: + sys.exit('::error::tag %s does not match src/version.h VERSION_STRING (expected %s). Bump src/version.h to match the tag.' % (tag, expected)) + print('tag matches src/version.h VERSION_STRING: %s' % expected) + EOF + + tests: + needs: validate + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ needs.validate.outputs.tag }} + fetch-depth: 1 + + - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: '3.12' + + - name: Zoom math regression tests + run: python3 tests/zoom_math_test.py + + - name: Menu structure, dark mode wiring and version consistency tests + run: python3 tests/menu_structure_test.py + + - name: Second-rework simulation tests (the 1.1.07 check) + run: python3 tests/simulation_test.py + + build: + needs: [validate, tests] + runs-on: windows-2022 + permissions: + contents: read + outputs: + artifact: ${{ steps.meta.outputs.artifact }} + sha256_x64_setup: ${{ steps.checksums.outputs.sha256_x64_setup }} + sha256_x86_setup: ${{ steps.checksums.outputs.sha256_x86_setup }} + sha256_x64_zip: ${{ steps.checksums.outputs.sha256_x64_zip }} + sha256_x86_zip: ${{ steps.checksums.outputs.sha256_x86_zip }} + env: + VERSION: ${{ needs.validate.outputs.version }} + steps: + - name: Checkout tag + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ needs.validate.outputs.tag }} + fetch-depth: 1 + + - name: Verify the checked out commit is the tag + env: + EXPECTED_COMMIT: ${{ needs.validate.outputs.commit }} + run: | + $head = git rev-parse HEAD + if ($head -ne $env:EXPECTED_COMMIT) { + throw "HEAD $head does not match the validated tag commit $env:EXPECTED_COMMIT" + } + Write-Host "building commit $head" + + - uses: microsoft/setup-msbuild@30375c66a4eea26614e0d39710365f22f8b0af57 # v3 + + - name: Build x64 (Release) + shell: cmd + run: msbuild vs2019\voidImageViewer.vcxproj /p:Configuration=Release /p:Platform=x64 /p:PlatformToolset=v143 "/p:OutDir=%GITHUB_WORKSPACE%\build\x64\\" "/p:IntDir=%GITHUB_WORKSPACE%\build\obj\x64\\" /m /nologo /v:m + + - name: Build x86 (Release) + shell: cmd + run: msbuild vs2019\voidImageViewer.vcxproj /p:Configuration=Release /p:Platform=Win32 /p:PlatformToolset=v143 "/p:OutDir=%GITHUB_WORKSPACE%\build\x86\\" "/p:IntDir=%GITHUB_WORKSPACE%\build\obj\x86\\" /m /nologo /v:m + + - name: Verify build output + shell: pwsh + run: | + $errors = @() + foreach ($p in @('build\x64\voidImageViewer.exe', 'build\x86\voidImageViewer.exe')) { + if (!(Test-Path $p)) { + $errors += "missing build output: $p" + continue + } + Write-Host "== $p ==" + (Get-Item $p).VersionInfo | Format-List FileVersion, ProductVersion, FileDescription | Out-Host + if ((Get-Item $p).VersionInfo.FileVersion -notmatch '\d+') { + $errors += "no version info in $p" + } + if ((Get-Item $p).VersionInfo.FileVersion -notlike "*$env:VERSION*") { + $errors += "binary FileVersion does not contain $env:VERSION (the tag and src/version.h must match the built binary)" + } + } + if ($errors.Count -gt 0) { throw ($errors -join '; ') } + + # the release binary itself passes the real machine smoke test + # before anything is packaged or published: the anomaly sweep runs + # against the freshly compiled x64 exe (see tests.yml for the + # push-time twin of this step). + - name: Real machine smoke test (the anomaly sweep) + shell: powershell + run: powershell -ExecutionPolicy Bypass -File tests\smoke_test.ps1 -ExePath "build\x64\voidImageViewer.exe" -SamplesDir "tests\samples" + + - name: Build installers (NSIS) + shell: pwsh + run: | + # locate makensis: the pinned windows-2022 image ships NSIS; + # the choco fallback is pinned to a known version for + # reproducibility (the 2025/2026 images do not ship NSIS at + # all and install it from the network every run). + $makensis = Get-Command makensis.exe -ErrorAction SilentlyContinue + if (-not $makensis) { + if (Test-Path 'C:\Program Files (x86)\NSIS\makensis.exe') { + $makensis = 'C:\Program Files (x86)\NSIS\makensis.exe' + } else { + Write-Host 'installing nsis 3.12.0 via choco...' + choco install nsis -y --no-progress --version=3.12.0 + $makensis = 'C:\Program Files (x86)\NSIS\makensis.exe' + } + } + Write-Host "makensis: $makensis" + + # validate the encodings required by the bilingual installer files + & powershell -ExecutionPolicy Bypass -File nsis\ensure_encodings.ps1 + + # the unified bilingual installer: the language is selected inside the setup. + & $makensis "-DVIV_EXE_DIR=$env:GITHUB_WORKSPACE\build\x64" '-Dx64' nsis\installer.nsi + if ($LASTEXITCODE -ne 0) { throw 'x64 installer build failed' } + + & $makensis "-DVIV_EXE_DIR=$env:GITHUB_WORKSPACE\build\x86" nsis\installer.nsi + if ($LASTEXITCODE -ne 0) { throw 'x86 installer build failed' } + + # makensis writes the output relative to the script directory (nsis\) + $errors = @() + foreach ($f in @('nsis\voidImageViewer-*-x64-Setup.exe', 'nsis\voidImageViewer-*-x86-Setup.exe')) { + if (!(Get-ChildItem $f -ErrorAction SilentlyContinue)) { $errors += "missing installer: $f" } + } + if ($errors.Count -gt 0) { throw ($errors -join '; ') } + Get-ChildItem nsis\*Setup.exe | Out-Host + + - name: Package + id: meta + shell: pwsh + run: | + $version = $env:VERSION + $x64zip = "voidImageViewer-$version-x64.zip" + $x86zip = "voidImageViewer-$version-x86.zip" + Compress-Archive -Path 'build\x64\voidImageViewer.exe', 'LICENSE' -DestinationPath $x64zip + Compress-Archive -Path 'build\x86\voidImageViewer.exe', 'LICENSE' -DestinationPath $x86zip + if (!(Test-Path $x64zip) -or !(Test-Path $x86zip)) { throw 'packaging failed' } + # rename the installers to include the release version (built into nsis\) + Move-Item "nsis\voidImageViewer-*-x64-Setup.exe" "voidImageViewer-$version-x64-Setup.exe" -Force + Move-Item "nsis\voidImageViewer-*-x86-Setup.exe" "voidImageViewer-$version-x86-Setup.exe" -Force + if (!(Test-Path "voidImageViewer-$version-x64-Setup.exe")) { throw 'x64 setup missing' } + if (!(Test-Path "voidImageViewer-$version-x86-Setup.exe")) { throw 'x86 setup missing' } + "artifact=voidImageViewer-$version" | Add-Content -Path $env:GITHUB_OUTPUT + Get-ChildItem *.zip, *Setup.exe | Out-Host + + - name: Compute SHA-256 checksums + id: checksums + shell: pwsh + run: | + $version = $env:VERSION + $assets = @( + @{ out = 'sha256_x64_setup'; file = "voidImageViewer-$version-x64-Setup.exe" }, + @{ out = 'sha256_x86_setup'; file = "voidImageViewer-$version-x86-Setup.exe" }, + @{ out = 'sha256_x64_zip'; file = "voidImageViewer-$version-x64.zip" }, + @{ out = 'sha256_x86_zip'; file = "voidImageViewer-$version-x86.zip" } + ) + $lines = @() + foreach ($a in $assets) { + $h = (Get-FileHash -Algorithm SHA256 $a.file).Hash.ToLower() + $lines += "$h $($a.file)" + "$($a.out)=$h" | Add-Content -Path $env:GITHUB_OUTPUT + Write-Host "$($a.file): $h" + } + $lines | Out-File -FilePath sha256.txt -Encoding ascii + Get-Content sha256.txt + + - name: Upload build artifact (hand-off to publish) + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: voidImageViewer-${{ needs.validate.outputs.version }} + path: | + voidImageViewer-*-x64-Setup.exe + voidImageViewer-*-x86-Setup.exe + voidImageViewer-*-x64.zip + voidImageViewer-*-x86.zip + sha256.txt + if-no-files-found: error + + publish: + needs: [validate, build] + runs-on: ubuntu-latest + permissions: + contents: write + env: + TAG: ${{ needs.validate.outputs.tag }} + VERSION: ${{ needs.validate.outputs.version }} + PHASE: ${{ needs.validate.outputs.phase }} + COMMIT: ${{ needs.validate.outputs.commit }} + ARTIFACT: ${{ needs.build.outputs.artifact }} + SHA256_X64_SETUP: ${{ needs.build.outputs.sha256_x64_setup }} + SHA256_X86_SETUP: ${{ needs.build.outputs.sha256_x86_setup }} + SHA256_X64_ZIP: ${{ needs.build.outputs.sha256_x64_zip }} + SHA256_X86_ZIP: ${{ needs.build.outputs.sha256_x86_zip }} + GH_TOKEN: ${{ github.token }} + steps: + - name: Checkout tag (for Changes.txt) + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ needs.validate.outputs.tag }} + fetch-depth: 1 + + - name: Download build artifact + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: voidImageViewer-${{ needs.validate.outputs.version }} + path: dist + + - name: Re-verify artifact SHA-256 against the build job outputs + run: | + cd dist + check() { + local expected="$1" file="$2" + if [ ! -f "$file" ]; then echo "::error::missing artifact file $file"; exit 1; fi + local actual + actual="$(sha256sum "$file" | cut -d' ' -f1)" + if [ "$actual" != "$expected" ]; then + echo "::error::SHA-256 mismatch for $file: build=$expected downloaded=$actual (artifact transport integrity failure)" + exit 1 + fi + echo "ok $file $actual" + } + check "$SHA256_X64_SETUP" "voidImageViewer-$VERSION-x64-Setup.exe" + check "$SHA256_X86_SETUP" "voidImageViewer-$VERSION-x86-Setup.exe" + check "$SHA256_X64_ZIP" "voidImageViewer-$VERSION-x64.zip" + check "$SHA256_X86_ZIP" "voidImageViewer-$VERSION-x86.zip" + sha256sum -c sha256.txt + + - name: Generate release notes from Changes.txt + run: | + python3 - <<'EOF' + import os, textwrap + tag = os.environ['VERSION'] + phase = os.environ['PHASE'] + with open('Changes.txt', encoding='utf-8-sig', errors='replace') as f: + lines = f.read().splitlines() + # headings look like "Release candidate: Version 1.1.0-rc.4 (title)" + marks = [i for i, l in enumerate(lines) if ': Version ' in l] + marks.append(len(lines)) + body = None + for a, b in zip(marks, marks[1:]): + head = lines[a] + ver = head.split(': Version ', 1)[1].split(' ', 1)[0].split('(', 1)[0].strip() + if ver == tag: + body = [head] + [l.lstrip('\t') for l in lines[a + 1:b]] + body = '\n'.join(body).rstrip() + break + if body is None: + raise SystemExit('::error::no Changes.txt section for version %s' % tag) + # the banner follows the phase: pre-releases say so, the stable + # line presents itself as what it is. + if phase: + banner = "> **Pre-release**: this is an experimental fork of voidtools/voidImageViewer adding touch optimizations, on-screen zoom controls and a bilingual installer with a UI language switcher. Feedback is welcome in the issue tracker." + else: + banner = "> A stable fork of voidtools/voidImageViewer: touch optimizations, on-screen zoom controls, a dark UI, and a bilingual installer with a UI language switcher. Feedback is welcome in the issue tracker." + notes = textwrap.dedent("""\ + # voidImageViewer {v} - Touch, Zoom & Languages{p} + + {banner} + + ## What's new + + {body} + + ## Downloads + + | File | Platform | + |---|---| + | voidImageViewer-{v}-x64-Setup.exe | 64-bit installer (English + 简体中文) | + | voidImageViewer-{v}-x86-Setup.exe | 32-bit installer (English + 简体中文) | + | voidImageViewer-{v}-x64.zip | 64-bit portable zip | + | voidImageViewer-{v}-x86.zip | 32-bit portable zip | + + SHA-256 checksums for every download are published as the `sha256.txt` release asset. + + Requires Windows 7 or later. Gestures require touch hardware. + + See `Changes.txt` in the repository for the full history. Based on upstream voidtools/voidImageViewer 1.0.0.15 (MIT license). + """).format(v=tag, p=phase, banner=banner, body=body) + with open('release-notes.md', 'w', encoding='utf-8') as f: + f.write(notes) + print(notes) + EOF + + - name: Refuse to overwrite an existing release + run: | + if gh release view "$TAG" > /dev/null 2>&1; then + echo "::error::release $TAG already exists. The overwrite (--clobber) path was removed deliberately: delete the release manually if you truly want to re-publish." + exit 1 + fi + echo "no existing release for $TAG, proceeding" + + - name: Create release + run: | + cd dist + title="voidImageViewer $VERSION - Touch, Zoom & Languages$PHASE" + args=(--target "$COMMIT" --title "$title" --notes-file "$GITHUB_WORKSPACE/release-notes.md") + case "$VERSION" in + *-rc.*|*-beta.*) args+=(--prerelease) ;; + esac + gh release create "$TAG" \ + "voidImageViewer-$VERSION-x64-Setup.exe" \ + "voidImageViewer-$VERSION-x86-Setup.exe" \ + "voidImageViewer-$VERSION-x64.zip" \ + "voidImageViewer-$VERSION-x86.zip" \ + sha256.txt \ + "${args[@]}" + gh release view "$TAG" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 00000000..dd362bd6 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,99 @@ +name: tests + +# Continuous verification of the zoom math, menu structure, dark mode wiring +# and localization alignment invariants. Runs on every push (branches and +# tags) and every pull request. +# +# The daily schedule (04:00 UTC = 12:00 Asia/Shanghai) intentionally runs +# ONLY the Windows compile matrix: the Python suites are fully covered by +# push/PR/tag events, while compiling every day on pinned runner images is +# the drift detector for hosted-image toolchain changes (the images gain +# and lose preinstalled software over time, e.g. the VS2026 images ship +# without NSIS and without the v143 toolset). +on: + push: + branches: ['**'] + tags: ['v*', '[0-9]*'] + pull_request: + branches: ['**'] + schedule: + - cron: '0 4 * * *' + workflow_dispatch: + +jobs: + tests: + if: github.event_name != 'schedule' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: '3.12' + + - name: Zoom math regression tests + run: python3 tests/zoom_math_test.py + + - name: Menu structure, dark mode wiring and version consistency tests + run: python3 tests/menu_structure_test.py + + - name: Second-rework simulation tests (the 1.1.07 check) + run: python3 tests/simulation_test.py + + # Compile both shipping configurations on every push (since rc.2), pull + # request, tag and daily schedule so a build break is caught before + # tagging a release. + # + # Runner matrix: windows-latest is in the middle of GitHub's gradual + # migration to the Windows Server 2025 + VS2026 (v145) image, and the + # 2025 image has no v143 toolset (MSB8020). Pin the shipping build to + # windows-2022 (VS2022, v143) and pair it with windows-2025 (VS2026, + # v145 via the vs2026 project) so the migration can not break this + # repository's CI by surprise: the v145 leg doubles as the forward + # compatibility / image drift detector. + compile: + strategy: + fail-fast: false + matrix: + include: + - name: windows-2022 v143 + runner: windows-2022 + project: vs2019 + toolset: v143 + - name: windows-2025 v145 + runner: windows-2025 + project: vs2026 + toolset: v145 + runs-on: ${{ matrix.runner }} + name: compile (${{ matrix.name }}) + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - uses: microsoft/setup-msbuild@30375c66a4eea26614e0d39710365f22f8b0af57 # v3 + + - name: Build x64 (Release) + shell: cmd + run: msbuild ${{ matrix.project }}\voidImageViewer.vcxproj /p:Configuration=Release /p:Platform=x64 /p:PlatformToolset=${{ matrix.toolset }} "/p:OutDir=%GITHUB_WORKSPACE%\build\x64\\" "/p:IntDir=%GITHUB_WORKSPACE%\build\obj\x64\\" /m /nologo /v:m + + - name: Build x86 (Release) + shell: cmd + run: msbuild ${{ matrix.project }}\voidImageViewer.vcxproj /p:Configuration=Release /p:Platform=Win32 /p:PlatformToolset=${{ matrix.toolset }} "/p:OutDir=%GITHUB_WORKSPACE%\build\x86\\" "/p:IntDir=%GITHUB_WORKSPACE%\build\obj\x86\\" /m /nologo /v:m + + - name: Verify build output + shell: pwsh + run: | + foreach ($p in @('build\x64\voidImageViewer.exe', 'build\x86\voidImageViewer.exe')) { + if (!(Test-Path $p)) { throw "missing build output: $p" } + Write-Host "== $p ==" (Get-Item $p).Length bytes + } + + # the real machine smoke test from the 1.0.02 audit round never ran + # automatically: every push now opens the full anomaly sample set + # through the freshly compiled x64 exe on the windows-2022 runner + # (a hosted windows runner is a real windows machine - gui launch, + # exit codes and close all work). the samples generate inline when + # the directory is missing (pure stdlib python, no extra deps). + - name: Real machine smoke test (the anomaly sweep) + if: matrix.runner == 'windows-2022' + shell: powershell + run: powershell -ExecutionPolicy Bypass -File tests\smoke_test.ps1 -ExePath "build\x64\voidImageViewer.exe" -SamplesDir "tests\samples" diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..cbdc2d6f --- /dev/null +++ b/.gitignore @@ -0,0 +1,47 @@ +# local build/verification artifacts (not needed for MSVC builds) +shim/ +build/ +*.o +*.obj +*.exe +*.pdb +*.iobj +*.ipdb + +# zig build scratch (the object tree, logs and the generated manifest copy) +build-zig/obj/ +build-zig/err.log +build-zig/viv.exe.manifest + +# Visual Studio binary resource editor state (res/voidImageViewer.aps etc) +*.aps + +# Visual Studio per-user state +*.user +*.suo +*.ncb +*.opt +*.plg +*.sdf +*.opensdf + +# tarball pax header metadata directories (extracted junk, never source) +PaxHeaders.X/ + +# OS junk +Thumbs.db +.DS_Store + +# python bytecode (the local test suites) +__pycache__/ +*.pyc + +# downloaded release assets kept for local forensics only +tool-results/r20/ +tests/samples/ + +# local round patch scripts (byte-level prepend helpers, one-shot per round) +tools/r*_*.py + +# anomaly sample self-check output (generated by make_anomaly_samples.py --self-check) +--self-check/ diff --git a/Changes.txt b/Changes.txt index 62d6cdba..c42de5fe 100644 --- a/Changes.txt +++ b/Changes.txt @@ -1,120 +1,1378 @@ -Monday, 12 January 2026: Version 1.0.0.15 - fixed an issue with scrolling large images. - improved position offset when using numpad keys. +Stable: Version 1.1.12 (the remake stable) +*the promotion round carries no code: every fix it rides already + shipped as 1.1.12-rc.17 and passed the full gate on real windows + (the three suites, both compile legs, the anomaly sweep smoke test, + and the release build itself). the stable mark is the verdict on + the whole rc arc, not a new behavior. +*the arc in one breath: the gui remake (the theme token system, the + owner drawn menus, the remade settings window and message boxes, + the client side top bar, the self drawn zoom row), the structure + split (the 2,208 line window procedure became 42 per-message + handlers across the domain modules, the gesture cluster moved + home), the crash the remake planted and the ci smoke sweep caught + (the status panes route by the control id first), the platform + guardrails (the official manifest guid, the unicows clean, the + wm_dpichanged lparam guard), the field arcs (the non-win11 + fallbacks, the zoom pane editor, the recent-list intent policy, + the text proportions at 4k 225%, the capture hint bridge, the + menu process check), and the external review absorption (the + itemid carrier, the token strip, the settings dpi correction, + the resize escape hatch, the startup dpi sync). +*the discipline that earned the mark: seventeen release candidates, + each landed changelog first, each pinned by its own guard section + (the three suites carry a section per round back to the fork), + each version-guarded, each green on the ci legs before its tag - + the anomaly sweep smoke test opens real images on a real windows + runner for every tag, so no candidate could ship unproven. -Tuesday, 16 December 2025: Version 1.0.0.14 - fixed an issue with webp using the wrong background color. - fixed an issue with tracking the center of the image when resizing. - fixed an issue with rendering images larger than 65536x65536. - fixed an issue with screen saver not being prevented in slide show mode or when there is an animation. - improved rendering performance. - improved zooming of small images when going fullscreen. - move window action will now scroll if zoomed. - re-enabled WEBP_MSC_SSE41 - added title_bar_format ini setting. - added System.Photo.Orientation support. - added - command line switch support. Escape with "" or include a . in your switch. +Pre-release: Version 1.1.12-rc.17 (the review absorption round) +*an external carpet review (v2, two independent cross-validation + passes) read the rc.16 tree line by line; this round absorbs its + confirmed findings and records its refutations. the refutations + matter as much as the fixes: the gesture leak it asked to + self-check is not there (the unhandled paths - gid_begin, + gid_end, the default, the failed decode - all return 0 and the + caller forwards every one of them to defwindowproc, which owns + the info handle; only the handled paths close it themselves; + setgestureconfig's cbsize is the single-struct size the api + wants), and the strip height audit found every view geometry in + the tree riding the one _viv_get_view_top() helper - no + hand-written offsets anywhere. +*the status pane index now reads the official carrier: comctl + fills drawitemstruct.itemid with the drawing pane's index; the + code read itemdata instead - the lparam our own sb_settextw + happens to store there, which equals the index only on the + paths we sent ourselves. a draw arriving any other way fell out + of the range check and returned silently unhandled, leaving the + bare light comctl face - the exact shape of the rc.11 bottom + white bar. the draw reads itemid first (itemdata stays the + compatibility fallback), and an unresolvable pane paints the + strip face instead of painting nothing: a failure shows as a + quiet pane, not a light slab. +*the crash-guard comment told the wrong story: it called the + status bar's ctltype == odt_menu "a historical quirk" - the + words of a stable system behavior. comctl leaves the field + uninitialized on that path (the value is garbage that happens + to look like the menu type), and the comment now says so: a + future maintainer trusting "quirk" could simplify the + control-id routing away and re-detonate the 0x1 dereference + the branch order exists to prevent. the logic did not move. +*the status strip joins the token system: the erase, the pane + fill, the pane text, the size grip fill and dots, and the zoom + editor's field colors all rode hardcoded rgb values or the + dialogs face while the menu bar and the toolbar above them + ride the chrome token - the strip was the one surface a theme + or accent flip could not re-skin. all the sites route through + viv_theme_color / viv_theme_brush now; the dark strip face + moves from the dialogs tone to the chrome tone, so the three + strips read as one chrome. +*the settings window owed its dpi correction: the outer frame + was measured at the viewer's dpi, the window was created with + cw_usedefault, and the layout then ran at the window's own dpi + - a window landing on a different-scaled monitor showed a + frame one size and content another (the probe the author left + recorded the mismatch and never fixed it). the show path now + re-measures the frame at the window's own dpi and sizes it + into place before the first layout - the same correction the + wm_dpichanged branch already applies after a move. +*the settings window can grow: it was a fixed 660x628 dip panel + with no thick frame and no wheel handling - any page whose + content outgrows the design (long locale text, future rows) + would clip its footer out of reach with no escape. the left, + right and bottom edges now report the sizing hit codes (the + system runs its own resize loop on the borderless popup, no + native frame drawn), the minimum track size is the design + size, and the existing wm_size relayout stretches the page. + the title row keeps the drag; the close button keeps its + margin clear of the edge band. +*the startup dpi sync: the init path read the dpi from GetDC(0) + - the primary monitor - and only wm_dpichanged ever refreshed + the globals; a launch restoring the window onto another + monitor would build every strip at the primary's scale, + because a create-time dpichanged is not something the system + documents. one explicit os_window_update_dpi runs after the + main window exists and before the first strip is built from + the globals. +*recorded, deferred on purpose (the review's own advice): the + ~1400 lines of retired options dialog stay frozen in place + until the settings window regains list browsing (the old pages + are the only scrollable command list left), the per-window dpi + refactor (every surface still shares the process globals, each + new surface adding a private bypass) and the resource.h id + splits stay on the debt list, and the dpi probes stay - they + compile to nothing in release and earn their keep the next + time the field reports a dpi oddity. -Sunday, 10 August 2025: Version 1.0.0.13 - fixed an issue with losing the image center on resize - fixed back/forward mouse buttons not working from toolbars - fixed an issue with loading the wrong next image when it was preloaded and changed externally - improved rendering performance - added left click action: move window - added auto size window GUI option +Pre-release: Version 1.1.12-rc.16 (the open intent round) +*the follow-up on the recent-list fix: the guard asked the right + question at the wrong place. "is this the file already on screen" + was answered for every open - including the opens where the user + had just said so: a click on a recent entry, a re-open through + the dialog, a re-drop of the same file. the honest trade of the + last round (clicking the recent entry of the displayed file no + longer re-shuffled it to the top) was that cost, and it is + refunded here. +*the intent is now declared where it is knowable instead of + guessed where it is not: the open-by-name carries a recent-list + policy from its caller. the three user commands (the open dialog, + the drag-drop, the recent click) declare a user open and feed the + recent list unconditionally - the standard mru contract, a + re-open of the displayed file re-tops it. the one path that + cannot know its own intent - the single-instance forward of a + second launch, the re-entry the rotate verb's refresh and the + rotate-then-recheck double-click both ride - declares itself + forwarded and keeps the one honest question: a same-file forward + is a reload, not a recent open, and does not reorder the list. + a forwarded new file still enters the list as a brand-new open, + and the startup command line is vacuously fine (no file is on + screen yet, so the first open still enters the list). -Friday, 25 July 2025: Version 1.0.0.12 - fixed a gdi leak when freeing mipmaps - fixed a gdi leak when refreshing - fixed an issue with loading the wrong next image after changing the sort - added natural sort +Pre-release: Version 1.1.12-rc.15 (the field report round) +*the field report: the recent list, the text proportions, the + shortcut capture hint, and one cross-process hardening. +*"rotating an image lands it wrongly in the recent files list": + the rotate itself never touches the recent list (the audit traced + every writer; the shell verb runs the system's lossless rotation, + the in-memory bitmaps follow). what reorders the list is a silent + re-open: any path that hands the viewer the file already on + screen (the single-instance forward, a re-drop, a re-click, a + re-open of the same file) fed the recent list as if it were a + brand new open - the file jumped to the top with no visible open + anywhere. the push site now asks one question: is this the file + already on screen? a reload is not a recent open. the honest + trade: clicking the recent entry of the file already displayed + no longer re-shuffles it to the top. +*the recent list also kept dead entries: deleting a file left it + in the list until some later click failed, and renaming left the + old name forever (the new one never entered). both operations + maintain their own entry now: the delete drops it, the rename + swaps it in place (the position is kept, nothing jumps). +*"the text proportions look wrong at 4k 225%": the settings window + was the one surface that did not ride the system font size - its + rows carried a 13 dip font while the menu bar, the toolbar, the + message boxes and the classic dialogs all sit on the system font + (12 at 96 dpi). the gap is a fixed ratio: invisible at 96 dpi + (one pixel) and visible at 216 dpi (two to three pixels on every + glyph, the field's own measurements). the settings rows move to + 12 dip and the descriptions to 11 - the sizes coincide with the + message font basis at every dpi, and the dropdowns stop changing + size between the closed value and the open list. +*the status bar never got a font of its own: it ran on whatever + the common control defaulted to, which happens to scale but does + not match the strip's basis. the bar now carries the menu font + (the same one the toolbar and the menu bar ride) and re-pins it + when the dpi changes; the zoom pane editor inherits it through + the same wm_getfont it always used. +*"weird garbled text in the options shortcuts": the capture hint + line under the add / edit / remove buttons ("edit keyboard + shortcut: ") was built by copying the localization string + with the wide-string copier. the localization returns utf-8; + each byte pair became one character of mojibake. the copy is + utf-8 now, and a guard scans the whole tree for the pattern so + no other site can grow it. +*the win7+ hardening: the menu theming finds the system menu + window by class name (#32768) - a name shared by every menu in + every process on the desktop. the find can return another + process's menu; the viewer would theme that one and leave its + own popup plain. both find sites now check the owning process + before touching the class. -Sunday, 20 July 2025: Version 1.0.0.11 - fixed an issue with using the wrong association registry key - fixed a crash when interrupting the loading of a multi-frame image - fixed an issue with displaying images after rotating - fixed an issue with remembering some view settings - fixed an issue with losing the view after toogling fullscreen - inverted increase/descrease slideshow rate - improved preloading next/previous image - added cache last image +Pre-release: Version 1.1.12-rc.14 (the zoom pane editor round) +*the field report on the status bar zoom pane: one click, no box. +*"the zoom percent in the corner needs two clicks to open, and the + click shows a select box": the pane is the click target, but the + click never reached it. the pane's own subclass ate every left + button down on it (the status bar drag anchor inherited from + upstream: hold and drag moves the window) and handed it to the + move loop, which swallowed the button up too - the open command + rides the up, so the box only opened by luck (a click on an + inactive window's orphan up). the anchor is retired: the pane is + pure input now, the drag lives on the toolbar, the menu gaps and + the title bar. +*"the select box": the box itself was a 1998 dialog - a centered + modal frame with a sunken number field, native buttons and a + select-all blue block, never touched by the remade chrome. the + editor is in place now: the pane itself becomes a borderless + number field in the strip's own font and colors (the status bar + answers ctlcolor for it), enter commits, escape cancels, focus + lost commits, typing replaces the selected digits. the dialog + template, its two controls and its two localization strings are + gone; the entry function keeps its name so the click site is + untouched. the system selection color stays (the edit control + offers no custom one) - it lives on four digits for the seconds + the editor is open. +*the empty or zero input keeps the old dialog's contract: ignored. +*the audit round: a canvas click now takes the keyboard home - the + editor held the focus while it lived, so a click on the image left + the arrow and page keys routed into the number field (a dead + navigation zone until enter or escape); the click's focus move is + itself what commits an open editor. +*the 1600% clamp and the view-center anchor carry over unchanged. -Tuesday, 17 June 2025: Version 1.0.0.10 - improved webp memory usage +Pre-release: Version 1.1.12-rc.13 (the non-win11 field round) +*the field report on a windows 10 machine, three roots, fixed. +*"the play button shows pause on an idle photo": the toolbar read the + animation preference bit as the playing state; that bit defaults to 1 + and every image switch resets it to 1, so the pause face sat on every + static image. the face now gates the clock on the frame count (the + ontop rule's own gate), and the five clock-changing paths (the pause + toggle, the frame step and prev, the frame home and end jumps) notify + the toolbar and recompute the on-top window. +*"zoom needs two clicks to work": two roots in the button stepping. + the snap to the nearest multiple of ten could move against the click + direction (a fresh 31% best fit zoomed in to 30 on the first click - + invisible, the visible step only came on the second), and a zoom out + from the best fit hit a dead pos==0 gate written before the below-fit + extension. the snap is direction strict now (out lands on the multiple + strictly below, in on the one strictly above), the floor gate reads the + true ladder floor, and a sparse-zone fallback steps one position when + a ten-point target sits between two ladder positions. +*"it looks bad on non-win11": the remade surfaces leaned on win11-only + dwm attributes with no fallback. the settings window is a borderless + popup that got no shadow at all on windows 10/7 (a bare floating + panel); its dropdowns opened as native string menus with the system + blue highlight and the native checkmark next to the accent pill + sidebar; the light hover token sat ~3 points off the strip and was + invisible; the light settings sidebar equaled the content face + exactly; and the light toolbar carried a private gray between the menu + and button faces. the round: the settings class registers the drop + shadow style off win11, the settings dropdowns ride the owner drawn + menu rows (the same painter, radio dots, one pool per open, the shared + popup theming), the light tokens recalibrate (hover contrast, the nav + layer, the menu-tone strip), and the message box buttons take the + settings window's pill radius. +*the dwm chrome calls double as the platform probe now (the attribute + 33 result latches the answer, os_is_win11 reads it) so every fallback + decision is one honest check instead of a silent no-op. the zoom pill + no longer re-centers its row under an active press. -Thursday, 22 May 2025: Version 1.0.0.9 - added webp support - added animated webp support - added mipmap support for faster resizing - added preload option - added maximized options - added option to copy image - added option to copy filename - added new code signing certificate: voidtools PTY LTD - improved animation timings +Pre-release: Version 1.1.12-rc.12 (the platform guardrails round) +*the import audit's three platform-level roots, fixed and pinned: the + manifest's windows 8.1 supportedOS GUID was a hand-corrupted value + (the first block matched the official guid and the rest did not), so + a windows 8.1 host never matched the 8.1 entry and kept the 8.0 view; + the manifest now carries the official + {1f676c76-80e1-4239-95bb-83d0f6d0da78}, verified against the + microsoft application-manifests documentation. +*unicows is dead weight for a win7+ target: the win32 link lines of + both project files carried UnicoWS.lib straight from the original + upstream import - a windows 9x compatibility stub the modern sdks are + phasing out, and the link dies with lnk1104 the moment an sdk drops + it. nothing in the tree imports an mslu symbol (the x64 configurations + never carried the lib and always linked), so the dependency is deleted + from the vs2019 and vs2026 win32 configurations. the ci legs still + link today (the hosted sdks still ship the stub), so this is the + forward-compatibility clean, not a regression repair. +*wm_dpichanged dereferenced its lparam unconditionally: the system + supplies the suggested rect, but a synthetic message or a compatibility + layer may not, and a null lparam crashed inside the resize. the resize + is now optional - the dpi refresh and re-layout that ride the same + handler still run, only the suggested-rect SetWindowPos is guarded. +*three regression guards pin the round (the official guid present with + the corrupted one absent, the null guard in the dpi handler, no + unicows in either project file), and the version moves to build 54. -Wednesday, 11 October 2017: Version 1.0.0.8b - added ctrl mousewheel action - fixed an issue when only one image was in the playlist - fixed a leak when loading an image - fixed a crash when there was only one shuffled image - improved randomize seeding - fixed a leak when loading an image while already loading an image - -Wednesday, 20 September 2017: Version 1.0.0.7b - added randomized everything search option - added 1:1 scroll option - added rotate options - fixed a bug when navigating to the next image from the first image +Pre-release: Version 1.1.12-rc.11 (the carpet repair round) +*the user's gui remake (rc.8-rc.10) went through a seven-subagent + adversarial carpet review; this round repairs what the review found. + the two headline breaks: the menu bar roots measured empty (the rc.9 + owner draw flip stored no label on the popup rows and the bar kept + reading miim_string - every root collapsed to a blank sliver and the + alt mnemonics died with them; the bar now re-derives the labels from + the live rows) and the status date pane rendered a lone "0" (a wide + format string through the narrow printf parser; the stamp now builds + with the localized getdateformat/gettimeformat pair). +*the viewport geometry caught up with the top strips: the toolbar moved + under the menu bar in rc.8 but the image math still reserved its band + above the status bar - a 40dip dead strip at the bottom and the image + top hidden behind the strips. one view-top helper (menubar + toolbar) + now rides every size computation, paint blit, mouse anchor and scroll + clip, and the zoom pill lands at the viewport bottom instead of + floating one strip high. +*the system theme flip never flushed the token brushes (the half-skinned + ui the field kept catching): the apply path refreshes the cache, heals + the #32768 class brush, and a classic palette change (wm_syscolorchange) + repaints too. +*the toolbar: the play slot resolves from the live state (slideshow + pauses, an animated image toggles the animation clock, idle starts the + windowed slideshow - the fullscreen jump is gone), the faces ride the + theme tokens (the light hover is the quiet 3dlight, not the selection + blue; the private palette duplicate is deleted), the strip background + drag moves the window again (the rebar rule), and the leave tracking + re-arms after a captured press. +*the themed message boxes: owned by the parent (no taskbar button, no + raising the disabled owner), the close button maps to cancel semantics + (an ok box closes as ok), four leaked brushes and a leaked font pair + per box are gone, wm_quit propagates, a second box brings the first to + the front instead of corrupting it, the light box gets a light caption, + the focus ring actually draws (the hpen-as-hbrush no-op), the secondary + button keeps a visible border, the height clamps to the work area, and + the dpi follows the box across monitors. +*the settings window shortcut editor: an unchanged edit confirmed with + enter keeps the binding (it used to delete it), the "currently used by" + row is live during a capture, and modifier combos are capturable again + (ctrl+return - the app's own default - was un-rebindable). +*win 7 closes the dpi ladder: the manifest declares the legacy + dpiaware tag next to the 2016 per-monitor-v2 section (the pre-1607 + loaders ignore the 2016 namespace - without the legacy tag 7 and 8.0 + ran the app dpi-unaware, bitmap-stretched), and the runtime chain ends + with the classic setprocessdpiaware tier. the rc.10 "win 7 keeps the + classic system aware behavior" claim was wrong - unaware, not aware. +*the popup menus: the recent-files header is owner drawn like its + siblings (the type flag landed in fstate, which only takes mfs_ + values, and the row painted in the system look), radio groups draw + the dot, grayed rows never fire from the keyboard, the idle pump + treats the getmessage error return as an error, the owner draw delete + notification is acknowledged, and a slideshow-timer mru rebuild + defers while a popup displays the old rows. +*the pill percent reads the app-wide number (render over native, the + same value the status bar shows - the ladder scale read "100%" at + best fit on a photo the ui called 23%), the failed glyph build never + caches, the double-brace splice leftovers are unwound (the dispatch + is 49 handlers now: wm_deleteitem and wm_syscolorchange joined), and + the pixel probe tooltip correction: it has been dead code since + before rc.7 (the callers were already commented upstream) - the rc.9 + "rides the tokens" line was written into that dead code and is hereby + corrected rather than revived. +*the crash the ci anomaly sweep caught: the comctl status bar sends its + owner-drawn pane draws with ctltype == odt_menu (a historical quirk), + so the menu branch the remake put first cast the pane index - the + itemdata - into a menu row pointer and dereferenced address 0x1 on + every slow-decoded image (the preload pane draws while the load thread + still runs; a fast gif/bmp decode never shows the pane, which is why + the crash looked png-specific). the panes route by the control id + first again, the menu rows after - the baseline's proven + discriminator. stack-captured under cdb on a diagnostic branch (the + fault resolved to the fixed offset 0x486dc in the release map). +*verified: the full tree compiles (zig cc, 98 units, bit-comparable to + the user's build), the three suites pass with 38 new carpet-repair + guards, the link scan stays clean at 111/111, and every fix is pinned. -Thursday, 14 September 2017: Version 1.0.0.6b - added /x /y /width /height /minimal /compact /shuffle /everything command line options. - added jump to list - added everything search - added shuffle - fixed /dc command line option - fixed a bug when opening void image viewer and getting a random filename - -Thursday, 31 August 2017: Version 1.0.0.5b - fixed a bug with move to/copy to - fixed a bug with save as filters +Pre-release: Version 1.1.12-rc.10 (the dpi correctness round) +*fixed the high dpi font bug for real: the per monitor v2 declaration + never shipped in the binary the way it was read - the vs linker merged + the manifest (good), but the zig builds had no manifest at all and the + os_init runtime safety net sat before its own GetProcAddress block, so + the pointers were still null when it ran and it silently never fired. + an unaware process gets bitmap-stretched by the system at high dpi: + every font blurry and oversized. the claim now runs after the api + probes, gains a process wide tier (win10 1703+ SetProcessDpiAwareness +Context) above the per thread tier (1607+) and the win 8.1 shcore + fallback (win 7 keeps the classic system aware behavior), and the zig + build drops a viv.exe.manifest next to the exe for loader level + coverage - three independent layers, all no-ops where unsupported. +*the message box scale follows its parent window's monitor now, not + the stale global logical dpi (mixed-dpi monitor pairs). +*the wndproc domain carried 17 splice-accident double-brace wrappers + with dead DefWindowProc tails; they are unwound (the case exits pin + drops 60 -> 43), the wndproc file is back under the line cap. +*verified under wine: the pre-fix binary renders the settings window + bitmap-stretched to ~2x at 150% scaling; the fixed binary renders it + 1:1 physical and the window self-scales to exactly 1.5x (660x628 -> + 990x942) with the fonts riding the same per-window dip pipeline. +Pre-release: Version 1.1.12-rc.9 (the gui remake round 2 - everything gets the theme) +*the whole ui now draws from one palette: the new viv_theme domain holds +17 semantic tokens x dark/light x five accents (azure, teal, violet, +amber, rose). every surface - the chrome strips, the menus, the dialogs, +the settings window, the zoom pill, the tooltips - resolves its colors +through it, so a theme or accent flip re-skins the app with zero +per surface edits. the accent picks up an ini key (accent_color) and a +swatch row in the settings window, applied live. +*the popup menus are owner drawn now. every visible row carries a tiny +draw record and the painters re-derive the label at draw time from the +command table, the localization table and the live key bindings - a +language or shortcut change can never show a stale row. the rows paint +the theme face, the accent check marks, right aligned shortcuts and +hairline separators; the popup layer gets the #32768 class brush and the +win11 rounded corners plus themed border through the dwm. the unicode +mnemonic scan (wm_menuchar) keeps alt+letter working on the drawn rows. +*the message boxes are the theme panel now: viv_msgbox draws the vector +icon, the wrapped text and the accent primary button, with a real modal +pump (tab/enter/esc). the five messageBox call sites moved over; the +fatal paths in debug/mem keep the native box on purpose. +*the classic dialogs join the theme for real: the dark dialog skin +reads the same tokens (the old hardcoded 202020 palette is gone), and +every dialog frame gets the win11 rounded corners plus the caption +color from the dwm. the old tabbed options dialog route now opens the +remade settings window. +*the zoom pill and the pixel probe tooltip ride the tokens too; the +menubar tokens replace its private brush cache. +*build: zig cc builds the whole tree (build-zig/build.sh, 98 translation +units), msvc-only seh is guarded, and the theme transcribes itself into +the page simulator (scripts/extract-theme.mjs) so the mockup can never +drift from the binary again. +Pre-release: Version 1.1.12-rc.8 (the gui remake round) + *the main window chrome is remade around one palette and three self + drawn strips. the comctl toolbar, its image list, the rebar host and + the pinned button widths are gone: the new viv_toolbar domain paints + a full width command strip (icon plus label buttons - open, previous, + next, slideshow, 1:1, best fit, zoom out, zoom in, rotate and image + info - grouped with hairline separators) with capture based press + tracking, hover faces, disabled states and the overflow rule that + hides whole separator bound groups from the right. the menubar gains + the remake geometry (the strip floors at 28 dip), labels measure with + their hidden accelerators stripped, a pressed root wears its own face, + the popups take tpm_rightbutton so the press drag across items is the + classic one, and a popup follows the mouse across the roots again + (the move onto another root cancels the loop and the same call + reopens there; the idle pump rides wm_enteridle on the owner). + *the zoom pill is one bottom centered row in both modes now: previous, + play/pause, next, a hairline separator, zoom out, the zoom percent and + zoom in - the percent cell renders the ladder value in the menu font + and polls 150ms so wheel and pinch zoom stay fresh; the windowed two + button corner pill is gone. the status bar grew the remake row: the + message pane shows the playlist position and the filename when + nothing else is talking, the pixel rgb pane uses the localized rgb + format, and a date pane pins the local last-modified stamp at the + right edge (the parts cap moved to 8). + *the options dialog is retired from the command path: the new + viv_settings domain opens a frameless-feel settings window (dwm dark + caption, rounded corners) with a three page navigation rail - general, + view, controls - custom drawn dropdowns, toggles, the association + checkbox grid and ok/cancel. the window snapshots the affected config + on open, applies live (language, theme, associations, startup run + key), restores on cancel and saves on ok; every option the old three + pages carried is present. + *the dark palette moves to the remake tokens: chrome faces 0x202024 / + 0x1b1b1e, strokes 0x3a3a40, text 0xe8e8ea over 0x9a9aa0, hover + 0x2e2e33, press 0x38383e. the light ui keeps the system colors. -Saturday, 19 August 2017: Version 1.0.0.4b - added background color selection - added close - added status bar - added keyboard and mouse customization - added print - added play gifs at least once option - added set as desktop background - added prevent sleep when playing or animating - added custom slideshow rate - added animation menu - added copy to / move to menu - added automatic window sizes - added multiple instances / single instance - improved portability - fixed an issue with holding a handle to the current directory - -Saturday, 18 Feburary 2017: Version 0.2.0.3b - added Multiple instances support - added multiple file drag drop support - added command line options /slideshow /fullscreen /window /rate and /? - added Edit and Preview file menu items - -Saturday, 17 August 2016: Version 0.0.0.1b - added animation controls - added mouse back/forward - added min/mag filter modes - added file associations - added open folders support - added Open Location - added properties option - added middle mouse move - added IStream support - added navigation - added hide cursor on fullscreen - improved slideshow mode - improved 1:1 mode - fixed an issue with transparent gifs - fixed an issue when deleting an image and displaying the next image +Pre-release: Version 1.1.12-rc.7 (the zoom pill rework round) + *the zoom pill is a single self drawn window now: the old control + nested six owner drawn BUTTON children inside a WS_EX_LAYERED tray + child, so the layered redraw, the button roundrect edges, the hover + and the fade fought each other and the capsules lost their stadium + shape next to the remade top bar. zoomui.c now paints the tray and + every capsule itself in one WM_PAINT pass - full semicircle ends at + every dpi, one hit test over the button rects, capture based press + tracking with a no-fire-on-drag-away guarantee, and a WM_NCHITTEST + that returns HTTRANSPARENT outside the capsules so a fading pill + never eats clicks on the image behind. + *the windowed pill stays two buttons (zoom out / zoom in) in the + bottom right, the fullscreen bar stays six buttons centered at the + bottom with the idle fade; both modes now share one painter and one + tooltip (rect based, re-targeted on dpi and mode changes), the + keyboard path is real (tab / arrows move the hot capsule, space and + enter fire it), and the disabled state dims the glyphs through + DrawState instead of disappearing. + +Pre-release: Version 1.1.12-rc.6 (the top bar remake round) + *the top bar is remade as a fully self drawn strip: the frame menu is + gone for good - the window is created without one, the bar is a client + side child window (the new viv_menubar domain) that paints every pixel + itself, and the popups are the same HMENU tree opened with + TrackPopupMenuEx. five rounds of field reports lived on the seam where + the system measured and painted the bar and the app patched around it + (the white right strip, the pad capture drifting 5.5x wide, the flip + races); with one painter there is nothing left to race. + *the menu item spacing is identical in both themes: the field + screenshots measured a 17px gap between the labels in the light ui + and a 94px gap in the dark ui - the owner draw measure padded every + label with a "captured system pad" that was really slot-minus-text + compounded through the two measurement systems. the remake uses one + fixed air (4px at 96dpi, rescaled) for both themes, which also + reproduces the light system layout within a pixel. + *the keyboard entry points survive the remake: alt + mnemonic opens + the matching root menu (wm_syschar), f10 opens the first one, the + alt-key underline policy (hidden until alt is held) is kept, and the + popup state refresh that lived in wm_initmenu runs from both + wm_initmenu and the new wm_initmenupopup route. + *the status bar no longer shows the light slab under the dark ui: the + strip erases with the dark face (the comctl status class paints its + own background from the light palette even under the dark theme + class), every pane is registered as owner drawn from the first update + so the pane fills always own the strip (the empty-bar case never drew + anything and showed the bare light face), and the dark pass repaints + the sunken top edge and the size grip with the chrome palette so the + bottom band reads as one dark chrome. + *the toolbar button spacing is pinned: the comctl auto size adapts + each button to its own icon width, so the visual gaps drifted between + the pairs (the zoom pair sat 12px tighter than the prev/next pair) and + the theme re-metrics drifted them again. one uniform button width and + one separator width (tb_setbuttoninfo per index, re-pinned after the + theme flip and the dpi change) keep the spacing identical in both + themes. + *the owner draw menu machinery is deleted with the seam it lived on: + the root item tagging, the draw and measure routes, the pad capture, + the non client tail fill, the theme toggle and the re-measure walk + (502 lines of viv_chrome.c); the menu font cache survives - the remake + measures its labels with it. the splice manifest is the 13 domain + list now (viv_menubar joined), the props register the pair once, and + the dispatch carries 43 handlers (wm_syschar, wm_syskeydown and + wm_initmenupopup joined; wm_measureitem and wm_ncpaint left with their + subjects). + +Pre-release: Version 1.1.12-rc.5 (the structure round) + *the three structure debts the rc series carried are paid. + *the touch gesture cluster is home in the view domain: viv_chrome.c + carried the gesture engine (_viv_on_gesture), the touch click probe + and the double click handler since the one-shot split - chrome is + window dressing, gestures are zoom and pan input; the five engine + statics moved with the functions, chrome no longer references the + cluster at all. + *the window procedure is a domain module: _viv_proc was a 2,208-line + switch; the case bodies are now 42 static per-message handlers in + viv_wndproc.c (the 44 case labels - 41 WM_ messages, two internal + _VIV_WM_ messages and the raw tablet query - collapse to 42 handlers + because two label pairs share a body). the dispatch itself is 95 + lines. every case body moved byte-identical; only the 35 case-exit + break statements became explicit DefWindowProc returns (34 direct + exits plus the touch-double-tap one that sat inside an if-block - + break binds to the nearest loop or switch, and an if-block catches + nothing; the ci compile caught it as a lone c2043), and the two + symbols the handlers share with the core (the background brush, the + command line processor) are externed through viv_state.h (113 -> 114 + externs). the core is 2,431 lines now. + *the splice guard grew the file manifest: the test suite reads viv.c + spliced with every src/viv_*.c (a glob), so a new domain module + changed the measured total silently - the growth window was pinned + against an invisible list. the manifest is pinned now (the core, the + twelve domain modules, the state layer), so adding or renaming a + module without registering it fails the suite. + +Pre-release: Version 1.1.12-rc.4 (the theme race self-heal round) + *the white band is back with two new triggers - opening the options + dialog and switching the theme - and it is a mixed chrome, not a stale + repaint: the system side repaints the frame and the comctl classes in + light asynchronously (the app mode policy flush, the theme broadcast + sweep) while the app level dark answer never flipped, so every re-apply + was gated on was_dark != is_dark and never ran. the delayed recheck + timer and the wm_themechanged handler now re-apply the chrome + unconditionally (the sweep is idempotent), the options combo schedules + the assert after its app mode flush, and the options dialog re-runs its + own full dark pass on a one shot timer so a creation moment that read + an unsettled state heals itself - the caption, the control classes and + all. + *the options navigation tree kept the light explorer class label gray + on the dark face (a themed tree ignores the text color message, and it + read as low contrast): the dark dialog children walk now pins the tree + face and label colors per pass - the same values the initdialog + applies - and hands them back to the system on the light flip. + *the main window erases with the dark chrome face in the dark ui: a + paint that bypasses the handlers must not flash the light class brush + the class still carries (the 1.1.03 lesson, closed for the erase path + too). + *the rc.3 entry core line count corrected: 4,718 as measured (the 4,715 + there was the pre-729c7d7 read; the typedef asserts grew the core by + three lines after that measurement). + +Pre-release: Version 1.1.12-rc.3 (the architecture split round) + *the viv.c monolith is split: 21,129 lines become a 4,718-line core (the + window procedure, startup/shutdown, the command line, the shared state + definitions) plus eleven domain modules - viv_recent, viv_playlist, + viv_load, viv_anim, viv_render, viv_chrome, viv_dark, viv_dialogs, + viv_view, viv_install, viv_menu - and a viv_state.h shared-context + layer, every module under 3,000 lines. pure physical move: function + bodies are byte-identical, the only text edits are the static prefixes + dropped on the 163 cross-module exports and the 113 shared-state + externs (52 single-domain variables moved with their consumers and + keep static; 13 core-private variables are untouched). + *performance and size are unchanged by construction: the projects + already compile with /gl whole-program optimization, so cross-module + inlining survives the split, and exported symbols never enter the + release binary. + *the guard suites read viv.c spliced with every domain module (plus + viv_state.h for the macro guards), so the existing 140+ shape guards + cover the moved code with only optional-static recalibrations; new r70 + guards pin the residual under 5,000 lines, every domain under 3,000, + the pure-move window (spliced total 21,130 -> 21,7xx lines, only + declarations) and the props registration of every new compile unit. + *the spec and the plan carry the r70 one-shot recalibration (the user + released the per-slice pacing; the merged domains, the minimal export + surface and the gate order are documented in the r70 addendum). + *the split's compile hardening (five ci catches between the landing + and this rc): three core states the domains reference left their + static prefixes in the core (the status pane text store, the cursor + visibility flag, the options page id table) and the command table + extern printed after the type that consumes it; the five table-count + macros were sizeof measurements on unsized externs - msvc c resolves + those to zero, so the key-list struct sized its arrays to zero and + the animation, slideshow, options-page and association loops would + all have silently stopped in the domain modules - the macros carry + literals now (154 commands, 21 animation rates, 17 slideshow presets, + 3 options pages, 11 association extensions), each pinned to its real + table by a negative-subscript typedef assert; and a bare-cr line join + the generator fumbled swallowed the light window theme declaration + into a comment in os.h. every class is guarded in the suite. + *the installer association page grows the emf and wmf checkboxes (both + languages, second column): the metafile pair joined the association + table in 1.1.12 but the setup page never offered them, so a setup + install silently skipped the two. the exe-side install switches were + already generic over the extension table (/emf /noemf /wmf /nowmf). + *housekeeping: the vendored libwebp drops the non-windows build + systems, fuzzers and docs (62 files this repository never built), + and Changes.txt keeps its crlf discipline back (an r69 regression + caught by the simulation suite). + +Pre-release: Version 1.1.12-rc.2 (the white band fix round) + + the architecture split decision (r69, documents only): viv.c has + grown to 21,129 lines / 536 functions / 159 file-scope statics with + the window procedure alone at 2,208 lines, and every field fix of + the rc line landed inside that one translation unit. the split now + has a written spec and a written plan (docs/architecture/): the + dialectic (split vs keep, by domain vs by layer, accessors vs a + shared state header, the upstream-shape cost), the decision (a + viv_state.h extern layer first, then eleven domain slices in + measured-closure order, pure physical moves only - no function + body may be rewritten, renamed or reordered), and the guard + strategy (the three suites will read viv.c plus every viv_*.c + spliced in dictionary order so the existing 140+ shape guards + keep covering the moved code without edits). the round itself + changes no C code and ships no binary: the menu-structure suite + gains the r69 guards pinning the documents, the discipline, the + monolith line baseline and the not-yet-existing state layer, so + the split can only shrink the file from here. + + the field report on rc.1: a white band survives the theme flip on + the upper chrome, until a manual resize or refresh brings the dark + face back. the judgment round traced the strip to a chain of gaps, + all on the flip path (the user's 30 second probe - the band dies on + a resize - matched the menu bar candidate, the code evidence + confirmed it and a second strip below it): + - the menu bar strip (the band right of the last top level item): + the flip ends with an immediate repaint sweep over the children + that never carried rdw_frame, and the official semantics keep the + non client area out of a frameless sweep: no wm_ncpaint, so the + dark gap fill that lives in that message never runs, the system + light strip stays until a manual frame change (the one-shot retry + inside the fill only helps when the paint already reached the + bar). the sweep now carries rdw_frame. + - the menu bar item widths: the dark ui measures the top level + items itself (the label at the menu font plus a pad), the light + ui hands them to the system - two measurement systems, so every + flip relayouts the bar (chinese labels accumulate the per item + drift). the pad was a literal 8 at 96 dpi; it is now probed from + the system's own layout (the rect the system gave a top level + item while it was still system drawn, minus its label extent), + cached with the dpi it was captured at and rescaled to the + window dpi, so both themes measure with the system air. + - the toolbar strip (the band right of the buttons): the theme flip + re-metrics the comctl toolbar (the immersive flag, the rebuilt + image list) but never relayouted the strip windows - the dpi + change and the language switch both run the layout. the flip + now runs the same sweep after the image list rebuild. + - the toolbar width: get_wide returned the content span (the union + of the item rects), which loses the first item's left inset twice + against the window the toolbar needs - the rightmost button + could hide (hideclippedbuttons) and the strip behind it widened. + tb_getmaxsize is the official query for the window the toolbar + needs (the total size of all the visible buttons and separators, + wm_user + 83); the content scan stays as the runtime fallback for + the pre 5.80 comctl sets. + - the class brushes: the register wrapper ignored the brush and the + cursor it was given and registered every class with the light + window brush (white) - the rebar caller's own argument was never + in effect, and the zoomui class asked for no brush and got white + anyway. the wrapper honors its parameters now; the rebar passes + no brush (the strip face is painted by theme in the erase and + the paint handlers, a bypassing erase no longer flashes white), + and the main, fullscreen and zoomui classes get what their + callers always wrote (the main and fullscreen windows erase + themselves, so nothing changes there). + the version moves to 1.1.12-rc.2 build 44: the candidate goes back + to the field - the rc.1 acceptance list carries over and the white + band becomes the first check (win11, 150 percent scaling, chinese + ui: flip dark and light five times without touching the window). + +Pre-release: Version 1.1.12-rc.1 (the about line release candidate) + + the first release candidate of the 1.1.12 line: two rounds since + the 1.1.11 stable, both on the about dialog, both hard codes - + the one the 1.1.11 font round put on record, the one the field + made visible once the fonts went per-dpi. + - the about title: the larger face kept the literal 32-pixel + height of the 96 dpi design point (150% drew two thirds of + the intended proportion, 200% half of it). the title now + derives from the live dialog font at the dialog's own dpi - + family, weight and the 8/3 ratio of the message font - and + is rebuilt at every open, so a dpi change between two opens + no longer draws the stale face (b41, the about title hard + code fix round). + - the about band: the dark-mode band chrome (the two separator + lines and the button strip face) moved from the runtime + wm_paint passes into the dialog resource template: the 1-du + line controls and the 24-du strip ride the template grid at + every dpi, the colors travel the control color replies with + the 1.1.11 palettes, and the dialog face answers through the + wm_ctlcolordlg pipeline (b42, the about band template round). + the version moves to 1.1.12-rc.1 build 43: the tag and the + pre-release stay user-gated, the candidate goes through one + full field acceptance (the dark band alignment at every dpi + scale, the light zero-regression, the theme flip refresh) + before the stable line. + +Stable: Version 1.1.12 (the about band template round) + + the dark mode field report on the about dialog: the band chrome (the + two separator lines and the button strip face) was painted at runtime + by a wm_paint case - three fillrect passes whose band edges were + pixel literals (48 and 46 at the 96 dpi design point, scaled by the + system dpi fraction), while the dialog template positions the + buttons in dialog units: two coordinate systems that only met at 96 + dpi. at any other scale (and after the b41 round made the dialog + font per-dpi) the lines drifted off the button strip and the band + boundaries crossed the controls - the rendering the report called + temporary drawing that never reached the resource template. + the fix moves the band chrome into the resource template: + - the geometry: two 1-du line controls (idc_aboutline1, + idc_aboutline2) and one 24-du strip control (idc_aboutband) + declared before the buttons in the idd_about template, so they + sit under them in the z order. the template grid owns the band + layout now: the lines ride the button strip at every dpi, in both + themes, and the dialog font rounds apply to the band as to every + other template control. + - the colors: the wm_paint case is gone. the control color replies + carry the same palettes the passes used (the dark 0x45/0x70 + separator lines and the 0x25 strip face, the light 0xec lines and + the white strip), the banner keeps its 1.1.11 face (the black band + with the white title in the light ui, the shared dark canvas in + the dark), and the dialog face itself answers through the + WM_CTLCOLORDLG pipeline - the official dialog background path, + so the light ui erases white and the dark erases the canvas + color through one contract. + - the about color replies run before the shared dark dialog handler + (its flat 0x20 static reply would flatten the line and strip + faces); every other control keeps the shared pair untouched. + the version moves to 1.1.12 build 42: one dialog, one round, the + tag and the release stay user-gated. +Stable: Version 1.1.12 (the about title hard code fix round) + + the first round after the rollback is one hard code, the one the 1.1.11 + font round itself put on record ("the about title derives its larger + face from it"): the derivation only ever covered the family. the + height stayed the literal 32: + - lf.lfheight = 32 was a 96 dpi design point. the message font scales + with the dialog window dpi (-18 at 150%, -24 at 200%) while the + title stayed 32 pixels on every screen: the 8/3 proportion the + font round promised collapsed to 2/3 at 150% and to 1/2 at 200% - + the title read relatively smaller on every high dpi display. + - the font site was the only one left on the unsuffixed forms: + getobject, logfont and createfontindirect borrow the wide pipeline + from the project-level unicode define, while every other font + site spells the w forms - the wide face name path hung on a + setting outside the code. + - the handle was created once and cached for the process lifetime: + a dpi change between two about opens (a monitor reconfiguration, + a system scale move) kept drawing the stale face. + the fix follows the font round's own derivation rule to the end: + - the title derives from the live dialog font: wm_getfont on the + title control (the shared dialog proc applied the message font at + this dialog window own dpi before this case runs) -> getobjectw + into a logfontw -> the height scaled by 8/3 (the message font is + -12 at 96 dpi and -12 * 8 / 3 = -32: the design point the + literal encoded, now as a ratio that travels with the dpi) -> + createfontindirectw. the family, the weight and the scale all + arrive with the font the dialog actually draws: one type system, + every dpi, both themes. + - the face is rebuilt at every open. the previous handle dies + inside the same message after the control took the new face (a + paint can never interleave the synchronous wm_setfont), and a + creation failure keeps the previous face drawing instead of + handing the control a null font. + the version moves to 1.1.12 build 41: the first round after the + 1.1.12-rc series was deleted from the remote, the number restarts + clean, and the tag and the release stay user-gated. +Stable: Version 1.1.11 (the font unification round) + + the font round unifies the ui type system. the audit locked the + contradiction first: the 1.1.09 unification hard coded every dialog + template to segoe ui 9pt, but segoe ui carries no cjk glyphs - on a + chinese system every dialog label rendered through the gdi per + character font linking fallback with the latin line metrics, while + the menu bar (lfMenuFont) and the status bar (lfStatusFont) draw the + system locale face, microsoft yahei ui. two type systems in one + window: the line heights, the baselines and the glyph density of the + dialog text never matched the menu and status text: + - every dialog takes the system message font now. the shared dialog + proc runs the apply from wm_initdialog, before each dialog's own + case: the dialog window itself and every child control receive + wm_setfont with the message font at the dialog window own dpi + (getdpiforwindow when the os provides it, the tracked dpi + otherwise). segoe ui on an english system, the locale native ui + face on a chinese one - the same family the menu bar and the + status bar draw. one type system, both themes. + - the template face keeps its job: the dlu grid. the dialog manager + sizes the control rectangles from the template font at creation + and the layout stays; only the rendering font follows the message + font (the upstream shipped ms shell dlg 8pt, whose font mapping + picked the locale face - the hard coded segoe ui lost that locale + awareness; the message font restores it without the 8pt skeleton). + - the order matters and the tests pin it: the shared proc runs + before each dialog's own initialization, so the dark flip captures + the native combo field heights against the final font, the about + title derives its larger face from it and the localized labels + render with it. + - the font belongs to the dialog that draws it (the review fix: + the shared cache deleted the handle under the open dialogs - the + options container and its pages coexist and jumpto is a create + dialog too, so a settings broadcast arriving while a dialog stood + open killed the face its controls still held, and the next paint + fell to the default system face): every dialog creates its own + message font at its own dpi, a monitor crossing replaces the face + inside the same message (wm_dpichanged - the old handle dies only + after every child took the new face), the release lands at the + dialog ncdestroy after its children are gone, and the next dialog + reads the fresh metrics at its own open. + - the known limits, on record: a dialog that stands open through a + system font change keeps its face until it reopens (the windows + dialogs behave the same way), and the vertical budget keeps the + segoe skeleton - a locale face a couple of pixels taller than the + latin metrics paints inside the row spacing, the ltext rows sit + two pixels tight (the simulation models the budget with the + tolerance stated, not assumed away). + the version moves to 1.1.11 build 40. + +Stable: Version 1.1.10 (field fix round 6: the dialog return value) + the sixth field round repairs the 1.1.09 dark options fix itself. a + source audit of the custom draw path caught the headline bug: a dialog + procedure cannot return a notify result directly - the dialog manager + keeps the message result in the window data, so the plain + cdrf_skipdefault return handed every button a zero (= cdrf_dodefault) + instead. the skip never reached a single control on any machine: + - the custom draw result travels through dwlp_msgresult now, the way + the nm_customdraw documentation prescribes for dialog procedures: + setwindowlongptr on the dialog, then a true return. two places + changed: the shared dark proc's notify case and the notify function + it calls. + - the glyph travels with the fix: a working skip takes the whole + native painting (the official wording: the control will not draw + any portion of the item), so the checkbox and radio faces draw + complete now - the dark dialog background, the theme part glyph in + the control's own checked, mixed, disabled and hot state (bm_getcheck + plus the custom draw item state through the cbs_*/rbs_* map), the + light label and the focus frame drawn exactly once (two xor frames + cancelled each other before - the keyboard walk lost its dot in the + dark). + - the button theme opens once per dialog and closes on destroy and on + the theme change broadcast (an open and a close pair per + notification was pure uxtheme bookkeeping on every paint). + - the touch probe mask drops the pen digitizer bit: nid_integrated_pen + is 0x04 and nid_external_touch is 0x02, so the old mask missed the + external-only touch screens and passed the pen-only digitizers. + - the ci runs the real machine smoke test now: every push and every + tag build opens the full anomaly sample set through the freshly + compiled exe on the windows runner (the test existed since the + 1.0.02 audit round but never ran automatically). + - readme honesty pass: the dark options wording matches the shipped + mechanism, the emf/wmf bullet notes the metafiles rasterize through + gdi+ (display-level support, not a native loader), and the pan && + scan removal lands in the readme story (it was recorded in the + 1.1.0-beta.6 changes entry only - the removal was deliberate: the + feature stretched x and y independently and fought the aspect ratio + lock). + the version moves to 1.1.10 build 39. + +Stable: Version 1.1.09 (field fix round 5) + the fifth field round lands the dark options text reports. this + entry replaces the withdrawn first 1.1.09 build (build 37): that + build flipped the checkboxes and the radios to owner draw on every + machine, the owner draw bit occupies the button type field, so the + flip replaced BS_AUTOCHECKBOX itself - the automatic check state + machine went with it, clicks stopped toggling, BM_GETCHECK read + zero and every options checkbox froze in the dark ui: + - the checkbox and radio labels paint through the custom draw path + now: the themed button paints its own label color (the + WM_CTLCOLORSTATIC text never reaches it - the field report read + black labels at 0.78:1 on the dark face, the microsoft q&a + documents the behavior), so the shared dialog dark proc takes the + button NM_CUSTOMDRAW notifications and repaints the label only - + light text, the control font, the focus frame - returning skip + default, which on a button replaces the label drawing while the + system theme keeps painting the glyph with its checked, hot and + disabled states. no style bit changes: the check state machine, the + radio grouping and every saved-settings read keep working in both + themes. the dead owner draw flip is gone entirely (it also sat + latent on the pre 1903 fallback since the last round). + - the fonts read different between the light and the dark ui: the + owner drawn controls drew with whatever font the draw dc carried, + and the eleven dialog templates mixed two MS Shell Dlg charsets + plus the obsolete DS_FIXEDSYS flag (the pages and the containers + measured their dialog units with different fonts). every template + now declares the same statement - Segoe UI 9pt, one weight, one + charset - so the pages and the containers share one unit grid and + the drawn text selects the control font explicitly before it draws + (the pick and the restore ride every owner draw path). + - the about dialog carried the last light strip in the dark ui: the + bottom band painted the system button colors unconditionally. the + band follows the theme now (the dark chrome strip with its divider + lines) and the light ui takes the fixed win11 command bar palette + (the white face, the subtle line) instead of the system-dependent + button colors. + - the geometry checks move to the pixel grid: the dialog units + follow the dialog font, so a font change rescales every template + 15-23 percent while the DLU numbers stay put - the new simulation + walks every control of every template on the Segoe UI 9pt base + units and proves the fit (containment, the eleven association + checkboxes, the label-plus-glyph widths). + - the option inventory stays pinned: the test baseline carries + every control id of the eleven dialogs (89 ids) and the rewrite + loses none of them. +Stable: Version 1.1.08 (field fix round 4) + the fourth field round lands the reports from the 1.1.07 test: + - the light dialogs painted dark controls: the dark theme classes + were applied whatever the app theme, so the light options page + showed black comboboxes and black select-all buttons. the classes, + the immersive flag and the owner draw flips now follow the app + theme together, and the flip back to light restores the explorer + class and the light title bar (an open dialog no longer keeps the + dark chrome from an earlier flip either). + - the dark combos grew a chin: the owner draw flip rebuilt the + closed field height from the font metrics, which drifts a few + pixels at some dpis - the field then grows or shrinks against its + label row. the flip now captures the native field height first and + keeps it exactly, so the dark combo is pixel identical to the light + one (the measure fallback reads the captured height back). + - the dark push buttons owner draw on every build: the native dark + button carries a light bottom edge (the chin under the buttons) and + a hard rectangle that fights the rest of the dark chrome. the flat + face matches the combo fields exactly; the bitmap color swatches + keep their own painting in every state. + - changing the backdrop or the canvas color with no image open + showed a load failure at the bottom left: the refresh reloads the + current file, and with none the empty name only fails. the refresh + now keeps the blank state - no reload, no error, the stale flags + reset - so the bare program accepts any color change quietly. + - the mat confusion: the backdrop is what shows under the + transparent pixels of an image with alpha, not the canvas around + the image. the menu is renamed to the transparency backdrop and a + new view menu item (windowed background color...) puts the canvas + color one click away from it. the zoom range note: the below-fit + ladder from the 1.1.06 field round reaches about fit/16 - the 3 + percent floor and the 1600 percent cap are the two ends of that + symmetric range. + - the theme change broadcast schedules the one shot dark re-check + as well (the visual style flip can race the registry the same way + the immersive color set broadcast does). + the version moves to 1.1.08 build 36. + +Stable: Version 1.1.07 (the second-rework simulation round) + the second rework check runs as a simulation: the new suite + (tests/simulation_test.py) extracts the constants, the formulas + and the control flow from the shipped source and re-executes the + behavior itself - a renamed symbol or a reordered source keeps a + string guard honest only by luck, so every field report is replayed + against the extracted logic: + - the mat color battery walks light, dark, cutoff-boundary and + saturated colors through the extracted 601 mapper: the light mats + land at or under the chrome face with the hue intact, the dark ones + pass through, and the white fast path is bit-exact with the scaled + formula. both user states from the report (the empty canvas and the + open-image backdrop) prove they route through the one shared mapper, + and the follow mat proves it picks the color of the mode the window + actually paints. + - the mru model replays a five-open burst (zero ini writes land + mid-burst on the ui thread, exactly one deferred write after the + settle, and the exit fold absorbs a still-pending write), fifteen + opens against the ten-entry cap (newest first, the oldest evicted), + the case-variant reopen (the move keeps the stored casing and a + top-row variant stays put), a twenty-row hand-edited ini (the load + walk stops at the cap and the clamp repairs the count), and the + surgical popup swap (no SetMenu, one row touched, the swapped-out + popup destroyed). + - the menu walk locates the command-table loop body span and proves + the mru insertion sits after the loop closes: the round-42 bug would + emit one recent row per command, and the simulation emits one. + - the zoom ladder walks the extracted 278-step shrink range: the + 200% fill lock is gone, the floor lands about one sixteenth of the + fit and mirrors the 16x native cap, every negative position reads a + positive table entry (never out of bounds), a runaway position + clamps to the floor and the deepest render keeps its one pixel. + - the blank state replays a missing-file open, a close and a later + failure: the status reports are fresh, never stale and never sticky. + - the options geometry parses the resource script and proves all + eleven association checkboxes sit inside the 242-tall page, the page + fits the 264-tall tab and the buttons keep the five-unit margin. + - the theme flip replays the registry race: the broadcast that + outruns the personalize write applies nothing at t=0, the 400ms + re-check lands the flip, and every flip invalidates the whole + window unconditionally. + - the release identity: the version quad moves to 1.1.7.35 and the + tag, the installer, the about dialog and the readme all carry + 1.1.07. the ci runs the simulation suite beside the two existing + suites on every push and on every tag. +Stable: Version 1.1.06 (field fix round 3) + the field report read "the background mat color is dead, with an + image open and without one": a customized windowed background color + always won, so a light mat kept glaring out of the dark chrome in + both states while the default white had long mapped to the dark + canvas. the mat rule is shared now: in the dark ui any light color + (601 luminance at or above 48) keeps its hue but lands at or under + the dark chrome face, the default white stays bit-exact with the + palette canvas, and an already dark color passes through unchanged; + the light ui always shows the exact configured color. the custom + backdrop color follows the same rule (a light backdrop under + transparent pixels used to glare the same way), and the follow + backdrop now matches the mat the window actually paints - the + fullscreen canvas shows the fullscreen color under the image instead + of the windowed one (a two-tone split around fullscreen pictures). + changing the windowed color from the options dialog re-tints the + windows 11 caption, repaints the canvas and reloads the image, so a + follow-mode transparency picks the new mat up immediately (the ok + button used to invalidate the canvas only, which left the caption + tint and the under-image backdrop stale until the next theme flip). + dark dialogs: the options pages (and every dark dialog) owner draw + their comboboxes on every windows build now - the darkmode explorer + style carries no combobox parts, so the language, dark-mode, + blit-mode and action fields stayed light inside the dark pages on + 1903+ machines. the comboboxes take the darkmode common-dialog + theme class for the dark frames and arrows where it exists, and the + field and list rows paint through the dialog dark handler on every + build. + docs: the readme told the 1.0.04 story while the shipped version was + 1.1.06 - the what's new section carries the 1.1 line (emf and wmf, + recent files, the backdrop menu, the dark dialog completion, the + below-fit zoom ladder and the field fixes), the format list carries + emf and wmf, and new sections document the canvas/backdrop/dark + rules and the recent-files behavior. the test suite pins build 34 + and gains the round-44 guards (the mat mapper math, the backdrop + rules, the fullscreen-aware follow, the options ok chain, the + combobox owner-draw ungating and the cfd theme wiring). + +Stable: Version 1.1.06 (field fix round 2) + open speed: every single-file open wrote the whole settings file and + rebuilt the entire menu bar on the ui thread before the image load was + dispatched - the visible stutter when opening files (worst with + real-time antivirus scanning the temp ini). the recent-files save is + debounced now: a two second timer coalesces a burst of opens into one + write, and the exit / logoff saves fold a still-pending write in. the + menu update swaps just the recent-files popup inside the live file menu + instead of destroying and recreating the whole bar (the full-rebuild + path is deleted outright), so the dark bar owner-draw state survives + without a re-apply and the non-client area is not repainted mid-open. + recent files count limit: the list is capped at ten entries on every + path - a compile-time check locks the command-id block to the array + bound, the ini load clamps the count, the push trims with a while loop, + and the popup builder clamps its own loop bound, so the list can never + emit command ids past the reserved block or overflow the menu. + options dialog: the emf and wmf association checkboxes pushed the + association list past the general page template bottom (the last rows + were clipped). the page grows to fit all eleven checkboxes and the + group box, and the options container, tree, tabs and buttons move down + with it so the layout relationships survive. + +Stable: Version 1.1.06 (field fix round) + the field report on the 1.1.06 build: the recent-files submenu was + inserted once per command-table entry instead of once per rebuild, so + the file menu grew dozens of duplicate rows (the block moved outside + the walk, and the test suite now simulates the brace depth so the + placement can never regress silently). + status honesty: closing the image kept the "failed to load" and "file + not found" messages on the status bar with no image open - the blank + state clears both flags now. + theme stability: every dark-mode flip repaints the whole window (a + partial invalidation left a light strip beside the toolbar and a + white canvas until a manual resize), and the immersive color set + broadcast gets a delayed re-check so a registry value that settles + after the message still lands. + chrome symmetry: the light toolbar strip follows the light menu face + with flat separator lines instead of the gray button face with the 3d + etch, so both themes read as one chrome band above the canvas. + options dialog: the page-title tab header and the sliver under every + page stayed light in the dark ui (the comctl tab paints its whole face + itself and the custom draw only reached the items) - the subclass + paints the entire control dark now. + zoom range: the ladder extends below the best fit (about one + sixteenth of it, mirroring the 16x native cap above) so a touch + pinch can zoom out to a thumbnail view; the fill-window upscale no + longer locks small images at a 200% minimum. the allow-shrinking + option keeps its meaning: with shrinking off the best fit stays the + floor. + +Stable: Version 1.1.06 (modern ux round) + third audit round: the fork now answers every low-cost item from + the upstream wish list it can carry. emf and wmf files open + everywhere (the gdi+ draw path rasterizes metafiles with no new + decoder, the association table, the open dialog filter, the + everything search default and the command line switches all grow + the two extensions), the status bar picks b / kb / mb / gb units + instead of rounding every file to kilobytes, the file menu gains + a persistent recent-files submenu, and the edit command gets a + default shortcut and menu hint again. + audit consistency: the webp frame-delay allocation multiplies + through the safe size helpers (the one bare multiply left in the + newest code), and 32-bit builds cap animated webp canvases at 25 + megapixels (the decode canvas, the anim decoder frame and the + display bitmap are roughly 12 bytes per pixel inside a 2 gb + address space). + ux hardening: the wallpaper change asks before it touches the + desktop (the menu comment has wanted this dialog since the first + release and the ctrl+d default key returns with it), up and down + navigate when no slideshow is running, the single o key for + options becomes ctrl+comma so a stray letter no longer pops a + modal dialog, and everything-add moves to ctrl+alt+e so the + editor can take ctrl+shift+e. + +Stable: Version 1.1.05 (second review fix round) + second review: the thirteen findings from the first audit round were + re-verified line by line against the sources and msdn. two were + withdrawn (the mem debug tail magic sits fully inside the allocation + and the two-step getregiondata is the documented pattern), the + small-pool alignment note was downgraded to a comment fix, and the + confirmed set ships here. + drag and drop: every wm_dropfiles now ends in dragfinish - the shell + file list leaked on every drop. the clipboard file-list paste reuses + the same handler without finishing the clipboards own hdrop (which + would corrupt clipboard memory). + memory safety: a null free crashed inside heapsize before the invalid + free guard could run; the glyph cache eviction copied overlapping + arrays with memcpy; the clipboard dib paste now applies the same + pixel budget as the file loaders and no longer truncates the copy + size to int (os_copy_memory and os_move_memory take size_t lengths). + registry: the add/remove programs entry is written to the 64-bit view + and removed with regdeletekeyexw (regdeletekeyw cannot reach the + alternate view; the nsis probe already used setregview 64), with the + legacy wow6432node copy swept on uninstall. + webp animations: each frame now carries its own duration from a + container scan - the old loop handed every frame the gap to the + previous one and the last frames duration never existed. + touch: the digitizer probe asks for a touch screen (not just any ready + digitizer), gid_begin and gid_end reach defwindowproc as msdn requires, + and the press-and-hold and flick system gestures are disabled for the + window. + robustness: the ini reader refuses files over 16 mb, a failed utf-8 + config conversion no longer reads an unterminated buffer, bad + localization ids clamp to a fallback instead of an out-of-bounds read + in release builds, and the safe_size wchar multiply comment no longer + says addition. + +Stable: Version 1.1.04 (tag hygiene round) + tag hygiene: the public tag list consolidates to the release ladder + 1.1.02, 1.1.03, 1.1.04 - the dashboard round markers and the + 1.0.03/1.0.04 pair leave the tag namespace after this release + ships (the round history stays reachable through the backup ref + and the archive snapshots, and the 1.0.x release pages keep + their assets), so the tags view reads as one clean version + staircase with this release on top instead of a dashboard + marker sitting above the releases. + shipping code: unchanged from 1.1.03 apart from the version + identity - the magnifier pill, the capsule zoom bar, the 32bpp + toolbar icons and the dark menu strip from the pill round ship + again as they are. + version order: the ladder stays strictly increasing, no + duplicates: it now reads 1.1.02, 1.1.03, 1.1.04. + +Stable: Version 1.1.03 (magnifier pill round) + pill icons: the zoom magnifier glyphs are redrawn. the zoom in/out + strokes declared three point polylines over two element arrays, so the + renderer walked one element past each array and drew a stray tail line + to whatever coordinate pair lived in the adjacent memory (the crooked + cross and handle in the field screenshots), the hand written 21 point + ring wobbled between radii 12.65 and 13.6 which read as a lumpy lens at + the pill sizes, and the cross strokes collapsed into capped smudges at + the small toolbar sizes. the ring is now a true gdi+ ellipse primitive + (drawn through gdipdrawellipse, not a sampled polyline), the counts + match the arrays, the handle starts exactly on the 45 degree ring + point, and the cross grew one grid unit longer and one wider. + pill shape: the zoom buttons and their tray are true stadium capsules + now (roundrect with half height end radii) with breathing room between + the buttons - the old zero gap layout packed both square borders back + to back in the middle (a double line) and the blocky pair sat next to + the flat toolbar like a patch from another toolkit. the glyph padding + follows the button height so all four sides stay even at every dpi. + toolbar icons: the toolbar image list keeps the 32bpp alpha channel + (ilc_color32) - the old 24 bit list with a mask binarized the + antialiased glyph edges and washed the toolbar icons into a pale gray + while the zoom pill drew the same glyphs from the raw icons at full + contrast (the two-tone toolbar the field screenshots caught). + dark strip: the rebar strip behind the centered toolbar now carries + the dark chrome face - the rebar window was registered with the light + window class brush, so the slabs on both sides of the toolbar stayed + white in dark mode (the big white rectangle the field screenshots + caught in the menu bar row). + version order: the release series returns to the 1.1 line as the + leading one, so the tag ladder reads 1.0.03, 1.0.04, 1.1.02, 1.1.03 - + strictly increasing, no duplicates, nothing deleted. + +Stable: Version 1.0.04 (pointer width budget) + load performance: the pixel budget ceiling is now pointer width + dependent. 32-bit builds keep the 100 mp guard (a 100 mp rgba + frame is already 400 mb against a 2 gb address space) while + 64-bit builds (x64 and arm64) raise the ceiling to 400 mp, so + real panoramic stitches and large flatbed scans load normally + instead of failing like a corrupt file - the reported 1.0.03 + regression where big-but-honest images stopped opening. + budget diagnostics: both loaders now print the refusal reason + (the claimed megapixels and the ceiling) through the debug + channel, so a user wondering why a file fails can turn the debug + banner on and read it - silent refusals are over. + test kit: the anomaly sample set grows to 38 samples - 35 now + doubles as the x64 acceptance boundary (110 mp loads on x64, + still refused on 32-bit) and 38 pins the x64 refusal point + (625 mp lying header). the guard suite pins both branches of + the ceiling split and the diagnostic on both loaders. +Stable: Version 1.0.03 (version display unification) + version identity: every user visible version now shows the release + identity - the tag string. the about dialog showed 1.0.2.25, the + add/remove programs entry showed 1.0.2 and the installer version + keys showed 1.0.02.x64 while the tag said 1.0.02 - the about line, + the uninstall DisplayVersion, the debug banner and the two nsis + version keys now derive straight from VERSION_STRING, and the test + suite guards all five display points against regression. + +Stable: Version 1.0.02 (third audit round closed) + pixel budget: both decoders (gdi+ and webp, animation and + still) now refuse a canvas over 100 mp before any allocation + happens - a 428 kb hostile header asking for a 20000 x 20000 + decode used to reach the allocator and die with a fatal + dialog; it now fails like any unloadable file. + uninstaller identity: closing the old instance no longer trusts + the window class name alone - the process image name is + verified as voidImageViewer.exe before any close or terminate + is sent, so a foreign program reusing the class name is left + alone. + third audit delivery: a generated anomaly sample set (37 + samples across truncation, lying headers, zero delay, frame + floods, broken chunk order, trailing garbage and over budget + canvases) plus a windows smoke test script, so a passing + suite can be followed by a real machine run. + +Stable: Version 1.0.01 (the fork restarts its version line at a clean 1.0.01) + version line: the public version sequence restarts here. the retired + 1.1.x line (three stables, seven release candidates, thirteen betas) + is gone from the tags and the releases; this file now keeps one entry + per development stage instead of one entry per round - the full + per-commit story lives in the git log. no code change ships with the + reset: the binaries are the twice-audited tree with the version + resource moved to the new line. + + the fork, by stage: + - foundation betas: the touch and zoom core (pinch, pan, two finger + and double tap, the floating zoom bar, one percent zoom steps), the + bilingual installer, the ui language switcher, save as, dark mode + detection, the single instance fix. + - engineering release candidates: the modern chrome and the release + engineering - PerMonitorV2 dpi, win11 rounded corners, the vector + toolbar glyphs, the fullscreen overlay fade, pinned ci runners, the + four stage release pipeline, the single source version.h, the pinch + floor and the 1600 percent zoom ceiling. + - dark completion: the complete dark ui - dialogs, status bar, + toolbar, zoom bar, the owner drawn menu bar (for the builds that + never darken a win32 menu bar), the options tabs, the pre 1903 + control fallbacks, live re-theming, crisp glyphs. + - audit hardening: two full codebase user audits - the gdi+ frame + delay and frame dimension guards, safe size wiring at every + allocation arithmetic, the dark brush and shuffle array releases, + the save as extension reservation, both performance counter seed + halves. + +Monday, 12 January 2026: Version 1.0.0.15 + fixed an issue with scrolling large images. + improved position offset when using numpad keys. + +Tuesday, 16 December 2025: Version 1.0.0.14 + fixed an issue with webp using the wrong background color. + fixed an issue with tracking the center of the image when resizing. + fixed an issue with rendering images larger than 65536x65536. + fixed an issue with screen saver not being prevented in slide show mode or when there is an animation. + improved rendering performance. + improved zooming of small images when going fullscreen. + move window action will now scroll if zoomed. + re-enabled WEBP_MSC_SSE41 + added title_bar_format ini setting. + added System.Photo.Orientation support. + added - command line switch support. Escape with "" or include a . in your switch. + +Sunday, 10 August 2025: Version 1.0.0.13 + fixed an issue with losing the image center on resize + fixed back/forward mouse buttons not working from toolbars + fixed an issue with loading the wrong next image when it was preloaded and changed externally + improved rendering performance + added left click action: move window + added auto size window GUI option + +Friday, 25 July 2025: Version 1.0.0.12 + fixed a gdi leak when freeing mipmaps + fixed a gdi leak when refreshing + fixed an issue with loading the wrong next image after changing the sort + added natural sort + +Sunday, 20 July 2025: Version 1.0.0.11 + fixed an issue with using the wrong association registry key + fixed a crash when interrupting the loading of a multi-frame image + fixed an issue with displaying images after rotating + fixed an issue with remembering some view settings + fixed an issue with losing the view after toogling fullscreen + inverted increase/descrease slideshow rate + improved preloading next/previous image + added cache last image + +Tuesday, 17 June 2025: Version 1.0.0.10 + improved webp memory usage + +Thursday, 22 May 2025: Version 1.0.0.9 + added webp support + added animated webp support + added mipmap support for faster resizing + added preload option + added maximized options + added option to copy image + added option to copy filename + added new code signing certificate: voidtools PTY LTD + improved animation timings + +Wednesday, 11 October 2017: Version 1.0.0.8b + added ctrl mousewheel action + fixed an issue when only one image was in the playlist + fixed a leak when loading an image + fixed a crash when there was only one shuffled image + improved randomize seeding + fixed a leak when loading an image while already loading an image + +Wednesday, 20 September 2017: Version 1.0.0.7b + added randomized everything search option + added 1:1 scroll option + added rotate options + fixed a bug when navigating to the next image from the first image + +Thursday, 14 September 2017: Version 1.0.0.6b + added /x /y /width /height /minimal /compact /shuffle /everything command line options. + added jump to list + added everything search + added shuffle + fixed /dc command line option + fixed a bug when opening void image viewer and getting a random filename + +Thursday, 31 August 2017: Version 1.0.0.5b + fixed a bug with move to/copy to + fixed a bug with save as filters + +Saturday, 19 August 2017: Version 1.0.0.4b + added background color selection + added close + added status bar + added keyboard and mouse customization + added print + added play gifs at least once option + added set as desktop background + added prevent sleep when playing or animating + added custom slideshow rate + added animation menu + added copy to / move to menu + added automatic window sizes + added multiple instances / single instance + improved portability + fixed an issue with holding a handle to the current directory + +Saturday, 18 Feburary 2017: Version 0.2.0.3b + added Multiple instances support + added multiple file drag drop support + added command line options /slideshow /fullscreen /window /rate and /? + added Edit and Preview file menu items + +Saturday, 17 August 2016: Version 0.0.0.1b + added animation controls + added mouse back/forward + added min/mag filter modes + added file associations + added open folders support + added Open Location + added properties option + added middle mouse move + added IStream support + added navigation + added hide cursor on fullscreen + improved slideshow mode + improved 1:1 mode + fixed an issue with transparent gifs + fixed an issue when deleting an image and displaying the next image diff --git a/README.md b/README.md index 1d27215e..e18fce99 100644 --- a/README.md +++ b/README.md @@ -1,50 +1,159 @@ -# void Image Viewer -A lightweight image viewer for Windows with animated GIF/WEBP support. -Opens and displays BMP, GIF, ICO, PNG, JPG, TIF and WEBP images as fast as possible. -Animate GIF/WEBP files as accurately as possible. +# void Image Viewer (Touch + Languages) -[Download](#download)
-[See also](#See-also)
-


+[![stable](https://img.shields.io/badge/status-stable-brightgreen.svg)](https://github.com/purrfecto114-lgtm/voidImageViewer_PLUS/releases) +[![release](https://img.shields.io/github/v/release/purrfecto114-lgtm/voidImageViewer_PLUS.svg?display_name=tag)](https://github.com/purrfecto114-lgtm/voidImageViewer_PLUS/releases) +[![license](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) +> A stable fork of [voidtools/voidImageViewer](https://github.com/voidtools/voidImageViewer) with **touch optimizations**, **on-screen zoom controls**, a **complete dark UI**, and a **bilingual installer + UI language switcher**. Issues welcome in the [issue tracker](https://github.com/purrfecto114-lgtm/voidImageViewer_PLUS/issues). +A lightweight Windows image viewer (BMP, GIF, ICO, PNG, JPG, TIF, WEBP, EMF, WMF — animated GIF/WEBP included) that opens and displays images as fast as possible. + +[Download](#download) · [What's new](#whats-new) · [Touch & zoom](#touch--zoom-controls) · [Canvas & backdrop](#canvas-backdrop--dark-mode) · [Recent files](#recent-files) · [Languages](#languages) · [Build](#build-from-source) Download -------- -https://github.com/voidtools/voidImageViewer/releases +Stable binaries (setup + zip, x86/x64, SHA-256 checksums): + +https://github.com/purrfecto114-lgtm/voidImageViewer_PLUS/releases -https://www.voidtools.com/forum/viewtopic.php?t=5623 -


+What's new +-------- +**1.1.12 — the remake arc: the full GUI remake, the platform guardrails, the field fixes and the review absorption (the current stable):** +- **The stable promotion carries no code** — every fix already shipped as 1.1.12-rc.17 and passed the full gate on real Windows (the three suites, both compile legs, the anomaly-sweep smoke test, the release build itself). The stable mark is the verdict on the whole rc arc, not a new behavior. +- **The arc in one breath** — the GUI remake (the theme token system, the owner-drawn menus, the remade settings window and message boxes, the client-side top bar, the self-drawn zoom row), the structure split (the 2,208-line window procedure became 42 per-message handlers across the domain modules), the crash the remake planted and the smoke sweep caught (the status panes route by the control id first), the platform guardrails (the official manifest GUID, the UnicoWS clean, the WM_DPICHANGED lParam guard), the field arcs (the non-Win11 fallbacks, the zoom pane editor, the recent-list intent policy, the text proportions at 4K 225%, the capture-hint bridge, the menu process check), and the external review absorption (the itemID carrier, the token strip, the settings DPI correction, the resize escape hatch, the startup DPI sync). +- **The discipline that earned the mark** — seventeen release candidates, each landed changelog-first, each pinned by its own guard section, each version-guarded, each green on the CI legs before its tag; the anomaly sweep opens real images on a real Windows runner for every tag. +- Full narrative: `Changes.txt`. -void Image Viewer main window: +**1.1.12-rc.17 — the review absorption round (the previous release candidate):** -![Void Image Viewer Image View](https://www.voidtools.com/voidImageViewer.Image.View10.gif) -


+- **The external carpet review (v2) absorbed** — its confirmed findings fixed, its refutations recorded. The gesture "leak" it asked to self-check is not there (every unhandled WM_GESTURE path forwards to DefWindowProc, which owns the info handle), and the strip-height audit found every view geometry in the tree riding the one `_viv_get_view_top()` helper. +- **The status pane index rides the official carrier** — the draw read `itemData` (the lParam our own SB_SETTEXTW happens to store there); it now reads `itemID` (the field comctl officially fills with the pane index), itemData stays the fallback — and an unresolvable pane paints the strip face instead of returning silently unhandled, closing the rc.11 bottom-white-bar failure mode for good. +- **The status strip joins the token system** — the erase, the pane fill and text, the size grip fill and dots, and the zoom editor field all rode hardcoded RGB values while the menubar and toolbar ride the chrome token. Every site routes through the theme tokens now, so a theme or accent flip re-skins the strip too, and the three strips read as one chrome. +- **The settings window DPI correction + the escape hatch** — the outer frame is re-measured at the window's own DPI after the create (the same correction WM_DPICHANGED applies after a move; the probe recorded the mismatch but never fixed it), and the window can now be enlarged from the left/right/bottom edges (minimum track size = the design size) so a page whose content outgrows the fixed panel can never trap its footer out of reach. +- **The startup DPI sync** — GetDC(0) reads the primary monitor; one explicit `os_window_update_dpi` after the main window exists, before the first strip is built from the globals, so a launch restored onto another monitor builds every strip at the right scale. +- **Deferred on purpose (the review's own advice)** — the retired options dialog stays frozen until the settings window regains list browsing; the per-window DPI refactor and the resource.h ID splits stay on the debt list. +- Full narrative: `Changes.txt`. + +**1.1.12-rc.16 — the open intent round (the previous release candidate):** + +- **The recent-list trade refunded** — the last round's guard asked "is this the file already on screen" for *every* open, which cost the standard MRU behavior: clicking the recent entry of the displayed file stopped re-topping it. The intent is now declared where it is knowable instead of guessed where it is not: the open dialog, the drag-drop and the recent click feed the recent list unconditionally (re-opening the displayed file re-tops it, like every other Windows MRU). Only the one path that cannot know its own intent — the single-instance forward of a second launch, the re-entry the rotate verb's refresh and the rotate-then-recheck double-click ride — keeps the same-file question: a same-file forward is a reload, not a recent open. A forwarded new file still enters the list. +- Full narrative: `Changes.txt`. + +**1.1.12-rc.15 — the field report round (the previous release candidate):** + +- **Rotating an image landed it wrongly in the recent files list** — the rotate itself never touches the list; what reordered it was a silent re-open (any path handing the viewer the file already on screen fed the list as a brand-new open). The push site now asks one question: is this the file already on screen? A reload is not a recent open. Deleting and renaming also maintain their own entry now — the delete drops it, the rename swaps it in place. +- **The text proportions at 4K 225%** — the settings window was the one surface riding its own font size (13 dip rows) while the menu bar, toolbar, message boxes and dialogs all sit on the system font — an invisible 1px gap at 96 dpi that becomes 2-3px on every glyph at 216 dpi. The settings rows move to 12 dip, the descriptions to 11, and the status bar now carries the menu font explicitly (re-pinned on DPI change). +- **The garbled line under the shortcuts buttons** — the capture hint ("edit keyboard shortcut: ...") copied the localization string through the wide-string copier while localization returns UTF-8, so every byte pair became a mojibake character. The copy goes through the UTF-8 bridge now, and a tree-wide guard keeps the pattern from coming back. +- **Menu theming hardened** — the system menu window is found by a class name shared by every menu in every process; the find now checks the owning process before theming, so the viewer never paints a stranger's menu and leaves its own plain. +- Full narrative: `Changes.txt`. + +**1.1.12-rc.14 — the zoom pane editor round (the previous release candidate):** + +- **The corner zoom percent needed two clicks, and showed a "select box"** — the click never reached the pane: the pane doubled as the window-drag anchor (inherited from upstream), its subclass ate the button down and the move loop ate the up, so the open command only fired from an inactive window's orphan up. The pane is pure input now — the drag lives on the toolbar, the menu gaps and the title bar. +- **The editor is in place, not in a 1998 box** — the pane itself becomes a borderless number field in the strip's own font and colors; enter commits, escape cancels, focus lost commits, typing replaces the selected digits. The centered dialog (sunken field, native buttons, select-all blue block) is retired along with its template and strings. The system selection color stays — the edit control offers no custom one, and it lives on four digits for the seconds the editor is open. +- Full narrative: `Changes.txt`. + +**1.1.12-rc.13 — the non-win11 field round (the previous release candidate):** + +- **The play button showed “pause” on an idle photo** — the toolbar read the animation preference bit as the playing state (it defaults to on and every image switch resets it); the face now gates on the frame count, and every clock-changing path notifies the toolbar and recomputes the on-top window. +- **“Zoom needs two clicks to work”** — the first zoom-in from a fresh best fit snapped the wrong way (31% → 30, invisible) and a zoom-out from best fit hit a dead gate written before the below-fit ladder. Stepping is direction-strict now, the floor gate reads the true ladder floor, and a sparse-zone fallback guarantees a move. +- **The non-Win11 look** — the settings window gets a real drop shadow on Windows 10/7, its dropdowns ride the same owner-drawn rows as the menus (no more system-blue lists next to the accent pills), the light hover/nav/strip tokens recalibrate for real contrast and layering, and the message box buttons take the pill radius. The DWM chrome calls double as the platform probe, so every fallback is one honest check. +- Full narrative: `Changes.txt`. + +**1.1.12-rc.12 — the platform guardrails round (the previous release candidate):** + +- **The Windows 8.1 manifest GUID was corrupted** — the supportedOS id for 8.1 was a hand-mangled value, so Windows 8.1 hosts never matched their own entry; the manifest now carries the official GUID (verified against the Microsoft application-manifests documentation). +- **The dead UnicoWS dependency is gone** — the Win32 link lines carried `UnicoWS.lib` (the Windows 9x unicode layer) straight from the original upstream import; nothing in the code imports an MSLU symbol and the x64 builds never carried it. Modern SDKs are phasing the stub out, so its removal is the forward-compatibility clean — the CI legs still link today. +- **`WM_DPICHANGED` no longer dereferences a null rect** — the system always supplies the suggested rectangle, but synthetic messages and compatibility layers may not; the resize is now optional while the DPI refresh still runs. +- Full narrative: `Changes.txt`. +**1.1.12-rc.11 — the carpet repair round (the previous release candidate):** + +- **The remake's two headline breaks are fixed** — the menu bar roots measured empty since the rc.9 owner-draw flip (the labels now re-derive from the live rows, Alt mnemonics with them), and the status date pane rendered a lone "0" (a wide format through the narrow parser; the stamp now uses the localized system formatters). +- **The image viewport caught up with the top strips** — the toolbar moved under the menu bar in rc.8 but the image math still reserved its band above the status bar: a 40dip dead strip and the image top hidden behind the chrome. One view-top origin now rides every size, blit, mouse anchor and the zoom pill. +- **The theme flip flushes the token cache** — the half-skinned UI after a system theme change is gone; the toolbar rides the same tokens as the menus (light hover is the quiet 3D-light, no more selection blue); the message boxes are owned, leak-free and close-correct; the shortcut editor keeps a no-op confirm a no-op; **Win 7 closes the DPI ladder** (legacy `dpiAware` + runtime `SetProcessDPIAware` — it was DPI-*unaware*, not system-aware); the pill percent matches the status bar; the play button stops forcing fullscreen. +- Full narrative: `Changes.txt`. + +**1.1.12-rc.10 — the dpi correctness round (the previous release candidate):** +- **The high-dpi font bug is fixed at the root** — the per-monitor-v2 declaration never reached the binary the way it was read: the zig builds shipped no manifest at all, and the `os_init` runtime safety net sat *before* its own `GetProcAddress` block, so the pointers were still null when it ran and it silently never fired. A dpi-unaware process gets bitmap-stretched by the system at high dpi — every font blurry and oversized. The claim now runs after the api probes and stacks three independent, all-guarded layers: a process-wide claim (Win10 1703+ `SetProcessDpiAwarenessContext`), a per-thread claim (1607+), and the Win 8.1 `shcore` fallback (Win 7 keeps the classic system-aware behavior); the zig build also drops a `viv.exe.manifest` next to the exe for loader-level coverage. +- **The message box scales from its parent's monitor** (not the stale global logical dpi) — correct on mixed-dpi monitor pairs. +- **17 splice-accident double-brace wrappers with dead `DefWindowProc` tails unwound** in the wndproc domain. +- Verified under wine: the pre-fix binary renders the settings window bitmap-stretched to ~2x at 150% scaling; the fixed binary renders 1:1 physical and self-scales to exactly 1.5x (660×628 → 990×942) with the fonts riding the same per-window dip pipeline. -void Image Viewer General Options: +**1.1.12-rc.9 — the gui remake round 2: one palette for everything:** -![Void Image Viewer Options General](https://www.voidtools.com/voidImageViewer.Options.General10.png) -


+- **One theme system for the whole ui** — the new `viv_theme` domain holds 17 semantic tokens × dark/light × five accents (azure, teal, violet, amber, rose). The chrome strips, the menus, the dialogs, the settings window, the zoom pill and the tooltips all resolve their colors through it, so a theme or accent flip re-skins the app with zero per surface edits. The accent ships with an ini key (`accent_color`) and a live swatch row in the settings window. +- **The popup menus are app drawn** — every visible row carries a draw record and the painters re-derive the label at draw time (command table + localization + live key bindings), so a language or shortcut change never shows a stale row. Accent check marks, right aligned shortcuts, hairline separators; the popup layer gets the win11 rounded corners and a themed border through the dwm; `WM_MENUCHAR` keeps alt+letter working. No undocumented uxtheme ordinal in the menu path anymore. +- **Themed message boxes** — `viv_msgbox` draws the vector icon, the wrapped text and the accent primary button with a real modal pump (tab/enter/esc); the five `MessageBox` call sites moved over (the fatal paths in debug/mem keep the native box on purpose). +- **The classic dialogs join the theme** — the dark dialog skin reads the same tokens (the old hardcoded palette is gone) and every dialog frame gets the win11 rounded corners plus the caption color from the dwm. The old tabbed options route opens the remade settings window. +- **A build the mockup cannot drift from** — `scripts/extract-theme.mjs` transcribes `src/viv_theme.c` into the page simulator, and zig cc builds the whole tree (`build-zig/build.sh`, 98 translation units, about 465 KB x64 with `-Os`). +**1.1.12-rc.7 — the zoom pill rework:** +- **The zoom pill is one self-drawn window** — no nested owner-drawn buttons fighting the layered tray: `zoomui.c` paints the tray and every capsule in a single `WM_PAINT` pass (true stadium caps at every DPI), hit tests the button rects itself, tracks presses with capture (no command when the drag leaves the button), and passes clicks through everything outside the capsules so a fading pill never blocks the image. -void Image Viewer View Options: +Recent versions, one line each — full per-round detail in [Changes.txt](Changes.txt): -![Void Image Viewer Options View](https://www.voidtools.com/voidImageViewer.Options.View10.png) -


+- **1.1.12-rc.6** — the top bar remake: the menu bar is a fully self-drawn child window (`viv_menubar`), the status bar owns its dark face, the toolbar button spacing is pinned uniform in both themes. +- **1.1.12-rc.5** — the structure round: the gesture cluster home in the view domain, the 2,208-line window procedure split into 42 per-message handlers in the new `viv_wndproc.c`, the splice guard's file manifest pinned. +- **1.1.12-rc.4** — the white band after opening Options or switching the theme fixed at the root (the dark re-apply lost its flip gate; the sweep is now unconditional and idempotent); the Options navigation tree reads in the dark UI. +- **1.1.12-rc.3** — the monolith is gone: `viv.c` (21,129 lines) is now a 4,718-line core plus eleven domain modules and a `viv_state.h` shared-context layer — a pure physical move (function bodies byte-identical; `/GL` whole-program optimization keeps cross-module inlining, performance unchanged); the setup offers the EMF/WMF associations; the vendored libwebp pruned of non-Windows build systems, fuzzers and docs (62 files — `COPYING`/`PATENTS`/`AUTHORS` kept). +- **1.1.12-rc.2** — the About dialog's band and title move into the resource template (correct at every DPI and in both themes); the post-theme-flip white band fixed (the frame repaint joined the sweep, the toolbar strip relayouts with the system metrics). +- **1.1.11** — one type system for the whole UI (the system message font per dialog at its own window DPI — CJK-safe, no more fallback-font mismatch); EMF/WMF in every association surface (metafiles rasterize via GDI+ — display-level support); recent files, transparency backdrop, complete dark dialogs. +Touch & zoom controls +-------- + +| Gesture / control | Action | +| --- | --- | +| Two finger pinch | Zoom in / out (anchored at finger center) | +| Two finger drag | Pan / scroll image (with inertia) | +| Two finger tap | Reset zoom | +| Double tap (touch) | Toggle 1:1 / best fit | +| Toolbar zoom buttons | Zoom in / out | +| Floating zoom bar | Windowed: zoom pill. Fullscreen: prev / play / pause / next / zoom (bottom center, idle fade) | + +Gestures need Windows 7+ with touch hardware. Single-finger input stays mouse-compatible, so configured click actions are unaffected. Toggle the floating controls via **View → Zoom Controls**. A pinch keeps shrinking below the windowed fit, down to about fit/16 (mirroring the 16× zoom cap) — `Allow shrinking` in Options keeps its meaning. + +Canvas, backdrop & dark mode +-------- + +- **Windowed / fullscreen background color** — Options → View, or the View menu picker; the mat around the image and the empty-window canvas. +- **Backdrop under transparency** — View → Transparency backdrop: follow the window background color, black, white, custom color, or checkerboard. Alpha images (PNG/GIF/WEBP) composite over it at load time. This is *not* the canvas around the image — that color is the windowed background above. +- **Dark UI rule** — the light UI always shows your exact colors. In the dark UI a light mat keeps its hue but drops into the dark range (the default white maps to the dark palette canvas), and the same rule applies to the custom backdrop, so nothing glares out of the dark chrome. The Win11 caption tint follows the mat. +- **The dark UI is complete** — dialogs, options pages, the menu bar and the navigation tree all follow the theme (owner-drawn where the theme API falls short on older builds); light dialogs stay light. +- Dark mode itself: Options → General → Dark mode — light, dark, or follow Windows. Theme flips repaint the whole window and re-assert the dark chrome unconditionally (a delayed re-check heals any system-side light repaint), and the open dialogs re-theme live. + +Recent files +-------- +File → Recent keeps the last ten opened paths (deduplicated case-insensitively; missing files drop out on the next open; Clear empties the list). The list is capped at ten on every path and writes are debounced off the open path. + +Languages +-------- +English and 简体中文 ship built-in. +- The setup picks the language on its first page. +- **Options → General → Language** switches Auto / English / 简体中文 on the fly (no restart). +- Stored as `language=auto|english|chinese` in `voidImageViewer.ini`; unattended installs may pass `/language english|chinese|auto`. -void Image Viewer Controls Options: +Build from source +-------- +Plain C + Win32 API, Visual Studio: -![Void Image Viewer Image Controls](https://www.voidtools.com/voidImageViewer.Options.Controls10.png) -


+1. Open `vs2019/voidImageViewer.sln` (VS2022+, v143 toolset) or `vs2026/voidImageViewer.sln` (v145 toolset). Both share one file list (`voidImageViewer.files.props`). VS2019 works with `/p:PlatformToolset=v142` (not CI-covered). +2. Build the `voidImageViewer` project (x64 or Win32). +3. Optional setup: NSIS 3 via `nsis\build_installer.ps1` (auto-detects the VS version; sources compile with `/utf-8`). +The zig cross build needs no Visual Studio: `sh build-zig/build.sh` (98 translation units, about 465 KB x64 with `-Os`). The vs linker embeds `res/voidImageViewer.Manifest` (per-monitor v2); the zig build keeps no embedded manifest, so it writes `viv.exe.manifest` next to the exe and the runtime claim in `os_init` covers even a stripped copy — keep the two files together, or build through vs when you need a single-file binary. +The source layout: one core (`src/viv.c` — the window procedure, startup, the command line, the state definitions) plus eleven domain modules (`src/viv_.c/.h`) and the shared-context header (`src/viv_state.h`); see `docs/architecture/viv-split-spec.md`. + +GitHub Actions compiles every push (pinned `windows-2022`/v143 + `windows-2025`/v145 legs); tag pushes run the tests, verify SHA-256 end to end and publish the release assets. + +![Void Image Viewer Image View](https://www.voidtools.com/voidImageViewer.Image.View10.gif) See also -------- -https://www.voidtools.com/forum/viewtopic.php?t=5623 +Upstream project: https://github.com/voidtools/voidImageViewer diff --git a/build-zig/build-selfshot.sh b/build-zig/build-selfshot.sh new file mode 100644 index 00000000..fa22a4a0 --- /dev/null +++ b/build-zig/build-selfshot.sh @@ -0,0 +1,40 @@ +#!/bin/sh +# zig cc cross build with the self screenshot harness enabled (test builds +# only - the production build must use build.sh). usage: sh build-zig/build-selfshot.sh +set -e +cd "$(dirname "$0")/.." + +ZIG="${ZIG:-python3 -m ziglang}" +FLAGS="-target x86_64-windows-gnu -O1 -DNDEBUG -DVERSION_X64 -DUNICODE -D_UNICODE -DVIVP_SELF_SHOT -Wno-macro-redefined" +OBJDIR="build-zig/obj-self" + +mkdir -p "$OBJDIR" + +fail=0 +while read -r f; do + [ -n "$f" ] || continue + case "$f" in + libwebp/*) inc="-Ilibwebp" ;; + *) inc="-Ilibwebp" ;; + esac + o="$OBJDIR/$(printf '%s' "$f" | tr '/' '_' | sed 's/\.c$/.o/')" + $ZIG cc $FLAGS $inc -c "$f" -o "$o" 2>> "$OBJDIR/errors.log" || fail=1 +done < build-zig/files.txt + +# the harness itself. +o="$OBJDIR/src_viv_selfshot.o" +$ZIG cc $FLAGS -Ilibwebp -c src/viv_selfshot.c -o "$o" 2>> "$OBJDIR/errors.log" || fail=1 + +if [ "$fail" -ne 0 ]; then + echo "COMPILE FAILED - see $OBJDIR/errors.log" + grep -m 12 "error:" "$OBJDIR/errors.log" || true + exit 1 +fi + +$ZIG cc $FLAGS $OBJDIR/*.o -o build-zig/viv_self.exe -mwindows \ + -lcomctl32 -lcomdlg32 -lshlwapi -lshell32 -lgdi32 -luser32 \ + -ladvapi32 -lole32 -loleaut32 -luuid -lwinmm -ldwmapi -lversion + +cp res/voidImageViewer.Manifest build-zig/viv_self.exe.manifest +ls -l build-zig/viv_self.exe +echo "BUILD OK" diff --git a/build-zig/build.sh b/build-zig/build.sh new file mode 100644 index 00000000..04d2cd11 --- /dev/null +++ b/build-zig/build.sh @@ -0,0 +1,48 @@ +#!/bin/sh +# zig cc cross build: compiles every translation unit listed in files.txt +# then links a 64 bit windows executable. usage: sh build-zig/build.sh +# requires: python3 with the ziglang wheel (pip install ziglang). +set -e +cd "$(dirname "$0")/.." + +ZIG="${ZIG:-python3 -m ziglang}" +FLAGS="-target x86_64-windows-gnu -Os -DNDEBUG -DVERSION_X64 -DUNICODE -D_UNICODE -Wno-macro-redefined" +OBJDIR="build-zig/obj" + +mkdir -p "$OBJDIR" + +# compile in small batches: each zig cc process is a full clang front end. +fail=0 +batch=0 +while read -r f; do + [ -n "$f" ] || continue + # libwebp includes repo relative headers ("src/dec/..."), the app code + # is self rooted ("viv.h") - give each tree only its own include root so + # the two string.h headers can never shadow each other. + case "$f" in + libwebp/*) inc="-Ilibwebp" ;; + *) inc="-Ilibwebp" ;; + esac + o="$OBJDIR/$(printf '%s' "$f" | tr '/' '_' | sed 's/\.c$/.o/')" + $ZIG cc $FLAGS $inc -c "$f" -o "$o" 2>> "$OBJDIR/errors.log" || fail=1 + batch=$((batch+1)) + if [ $batch -ge 8 ]; then + wait 2>/dev/null || true + batch=0 + fi +done < build-zig/files.txt +wait 2>/dev/null || true + +if [ "$fail" -ne 0 ]; then + echo "COMPILE FAILED - see $OBJDIR/errors.log" + grep -m 12 "error:" "$OBJDIR/errors.log" || true + exit 1 +fi + +$ZIG cc $FLAGS $OBJDIR/*.o -o build-zig/viv.exe -mwindows \ + -lcomctl32 -lcomdlg32 -lshlwapi -lshell32 -lgdi32 -luser32 \ + -ladvapi32 -lole32 -loleaut32 -luuid -lwinmm -ldwmapi -lversion + +cp res/voidImageViewer.Manifest build-zig/viv.exe.manifest +ls -l build-zig/viv.exe +echo "BUILD OK" diff --git a/build-zig/dpiprobe.c b/build-zig/dpiprobe.c new file mode 100644 index 00000000..e51cf9b2 --- /dev/null +++ b/build-zig/dpiprobe.c @@ -0,0 +1,54 @@ +// dpi probe test tool: asks every dpi api what it reports under wine. +#include +#include + +typedef UINT (WINAPI *fn_GetDpiForWindow)(HWND); +typedef HANDLE (WINAPI *fn_SetThreadDpiAwarenessContext)(HANDLE); + +int main(void) +{ + HDC dc; + fn_GetDpiForWindow pGet; + fn_SetThreadDpiAwarenessContext pSet; + HMODULE user32; + + dc = GetDC(0); + printf("GetDeviceCaps LOGPIXELSX=%d Y=%d\n", GetDeviceCaps(dc,LOGPIXELSX), GetDeviceCaps(dc,LOGPIXELSY)); + printf("GetDeviceCaps HORZSIZE=%dmm VERTSIZE=%dmm\n", GetDeviceCaps(dc,HORZSIZE), GetDeviceCaps(dc,VERTSIZE)); + ReleaseDC(0,dc); + + user32 = GetModuleHandleA("user32.dll"); + pGet = (fn_GetDpiForWindow)(void *)GetProcAddress(user32,"GetDpiForWindow"); + pSet = (fn_SetThreadDpiAwarenessContext)(void *)GetProcAddress(user32,"SetThreadDpiAwarenessContext"); + + if (pGet) + { + printf("GetDpiForWindow(desktop)=%u (unaware context)\n", pGet(GetDesktopWindow())); + } + else + { + printf("GetDpiForWindow: MISSING\n"); + } + + if (pSet) + { + pSet((HANDLE)-4); + printf("claimed PerMonitorV2\n"); + if (pGet) + { + printf("GetDpiForWindow(desktop)=%u (PMv2 context)\n", pGet(GetDesktopWindow())); + } + } + else + { + printf("SetThreadDpiAwarenessContext: MISSING\n"); + } + + { + char env[64]; + DWORD n = GetEnvironmentVariableA("VIVP_TEST",env,sizeof(env)); + printf("VIVP_TEST=%.*s\n", n>63?63:(int)n, env); + } + fflush(stdout); + return 0; +} diff --git a/build-zig/files.txt b/build-zig/files.txt new file mode 100644 index 00000000..3159490d --- /dev/null +++ b/build-zig/files.txt @@ -0,0 +1,98 @@ +libwebp/src/dec/alpha_dec.c +libwebp/src/dec/buffer_dec.c +libwebp/src/dec/frame_dec.c +libwebp/src/dec/idec_dec.c +libwebp/src/dec/io_dec.c +libwebp/src/dec/quant_dec.c +libwebp/src/dec/tree_dec.c +libwebp/src/dec/vp8l_dec.c +libwebp/src/dec/vp8_dec.c +libwebp/src/dec/webp_dec.c +libwebp/src/demux/anim_decode.c +libwebp/src/demux/demux.c +libwebp/src/dsp/alpha_processing.c +libwebp/src/dsp/alpha_processing_mips_dsp_r2.c +libwebp/src/dsp/alpha_processing_neon.c +libwebp/src/dsp/alpha_processing_sse2.c +libwebp/src/dsp/alpha_processing_sse41.c +libwebp/src/dsp/cpu.c +libwebp/src/dsp/dec.c +libwebp/src/dsp/dec_clip_tables.c +libwebp/src/dsp/dec_mips32.c +libwebp/src/dsp/dec_mips_dsp_r2.c +libwebp/src/dsp/dec_msa.c +libwebp/src/dsp/dec_neon.c +libwebp/src/dsp/dec_sse2.c +libwebp/src/dsp/dec_sse41.c +libwebp/src/dsp/filters.c +libwebp/src/dsp/filters_mips_dsp_r2.c +libwebp/src/dsp/filters_msa.c +libwebp/src/dsp/filters_neon.c +libwebp/src/dsp/filters_sse2.c +libwebp/src/dsp/lossless.c +libwebp/src/dsp/lossless_avx2.c +libwebp/src/dsp/lossless_mips_dsp_r2.c +libwebp/src/dsp/lossless_msa.c +libwebp/src/dsp/lossless_neon.c +libwebp/src/dsp/lossless_sse2.c +libwebp/src/dsp/lossless_sse41.c +libwebp/src/dsp/rescaler.c +libwebp/src/dsp/rescaler_mips32.c +libwebp/src/dsp/rescaler_mips_dsp_r2.c +libwebp/src/dsp/rescaler_msa.c +libwebp/src/dsp/rescaler_neon.c +libwebp/src/dsp/rescaler_sse2.c +libwebp/src/dsp/upsampling.c +libwebp/src/dsp/upsampling_mips_dsp_r2.c +libwebp/src/dsp/upsampling_msa.c +libwebp/src/dsp/upsampling_neon.c +libwebp/src/dsp/upsampling_sse2.c +libwebp/src/dsp/upsampling_sse41.c +libwebp/src/dsp/yuv.c +libwebp/src/dsp/yuv_mips32.c +libwebp/src/dsp/yuv_mips_dsp_r2.c +libwebp/src/dsp/yuv_neon.c +libwebp/src/dsp/yuv_sse2.c +libwebp/src/dsp/yuv_sse41.c +libwebp/src/utils/bit_reader_utils.c +libwebp/src/utils/color_cache_utils.c +libwebp/src/utils/filters_utils.c +libwebp/src/utils/huffman_utils.c +libwebp/src/utils/palette.c +libwebp/src/utils/quant_levels_dec_utils.c +libwebp/src/utils/random_utils.c +libwebp/src/utils/rescaler_utils.c +libwebp/src/utils/thread_utils.c +libwebp/src/utils/utils.c +src/config.c +src/debug.c +src/glyphs.c +src/ini.c +src/mem.c +src/localization.c +src/os.c +src/safe_size.c +src/small_pool.c +src/string.c +src/utf8.c +src/viv.c +src/viv_anim.c +src/viv_chrome.c +src/viv_dark.c +src/viv_dialogs.c +src/viv_install.c +src/viv_load.c +src/viv_menu.c +src/viv_menubar.c +src/viv_playlist.c +src/viv_recent.c +src/viv_render.c +src/viv_settings.c +src/viv_theme.c +src/viv_msgbox.c +src/viv_toolbar.c +src/viv_view.c +src/viv_wndproc.c +src/wchar.c +src/webp.c +src/zoomui.c diff --git a/docs/architecture/viv-split-plan.md b/docs/architecture/viv-split-plan.md new file mode 100644 index 00000000..f45f9feb --- /dev/null +++ b/docs/architecture/viv-split-plan.md @@ -0,0 +1,99 @@ +# viv.c 架构拆分实现计划 + +> **面向 AI 代理的工作者:** 必需子技能:使用 subagent-driven-development(推荐)或 +> executing-plans 逐任务实现此计划。步骤使用复选框(`- [ ]`)语法来跟踪进度。 + +**目标:** 把 21,129 行的 `src/viv.c` 按功能域拆为 `viv_.c/.h` 模块(12 片),残余收敛至 <5,000 行,全程纯物理移动零行为变化。 + +**架构:** 片 0 先建 `viv_state.h`(159 个 extern 共享状态声明)铺平跨域引用;随后按封闭性升序逐域移动函数到新编译单元;守卫测试改为拼接读取(viv.c + 全部 viv_*.c),现有守卫零修改自动覆盖。 + +**技术栈:** C(Win32 GDI)· MSBuild v143/v145(经共享 `voidImageViewer.files.props` 声明编译单元)· Python 三套件守卫。 + +**规格:** `docs/architecture/viv-split-spec.md`(论证依据——执行者两份都读)。 + +## 全局约束 + +- 纯移动纪律:只允许剪切/粘贴/新声明/props 加行/Changes.txt;禁止函数体重写、重命名、重排序。 +- 每片一轮,diff 预算 ~10 文件 / ~400 行(viv.c 削减与新增移动行成对,不双计)。 +- 每片门禁:G1 三套件全绿 → G2 CI 双工具链 0 error 0 warning → G3 push 快进 → G4 每 2–3 片用户实机。 +- 模块命名 `viv_.c/.h`,目录 `src/`,编译单元单点登记于 `voidImageViewer.files.props`。 +- 新 .h 只声明该域导出函数(供 viv.c 与其他域 include);域内函数保持 static。 +- 回滚:单片单 commit,`git revert` 即回。 + +--- + +## 任务 A · 片 0:状态层 `viv_state.h`(R70 执行) + +文件:新增 `src/viv_state.h`;修改 `src/viv.c`(159 个 static → 去 static)、`voidImageViewer.files.props`(无新 .c,不动)、`Changes.txt`、`tests/menu_structure_test.py`(守卫)。 + +- [ ] A1. 守卫先行(红):menu_structure_test.py 新增 `t_split_architecture_round69()` —— 已随本计划文档先行落地(规格/计划文档存在 + 拼接助手存在 + 片序锁定);再新增 `t_state_layer_round70()`:断言 `src/viv_state.h` 存在且包含分组 extern 声明、viv.c 中 `^static.*_viv_` 文件级计数 = 0(存量 159 → 0),先跑出 FAIL。 +- [ ] A2. 生成 `viv_state.h`:脚本从 viv.c 提取 159 个文件级 static 变量声明 → extern 化(保留原注释/初始化剥离)→ 按功能域分组(chrome/图像/视图/播放列表/加载/杂项)+ 文件头注释(用途、纪律、"过渡态"声明引用 spec §2.3)。 +- [ ] A3. viv.c:159 个定义行去 `static` 关键字(位置/行文不动);`#include "viv_state.h"` 加在 `#include "viv.h"` 之后。 +- [ ] A4. G1 三套件复跑全绿;G2 本地括号平衡 + 提交,push 触发 CI 双工具链(v143 + v145 均 0 error 0 warning 才算过)。 +- [ ] A5. Changes.txt 新节(片 0:状态层,移动清单 = 159 声明)。 +- [ ] A6. Commit(`the viv state layer round: the split begins, 159 shared statics declared in one header`)→ push 快进。 + +## 任务 B · 片 1:`viv_recent.c`(R71 执行) + +文件:新增 `src/viv_recent.c`、`src/viv_recent.h`;修改 `src/viv.c`、`voidImageViewer.files.props`、`tests/*_test.py`(拼接助手)、`Changes.txt`。 + +- [ ] B1. 守卫先行(红):新增 `t_split_recent_round71()`:断言 `src/viv_recent.c` 存在、包含 7 个 `_viv_recent_*` 函数定义、viv.c 不再包含其函数体(按函数名 + 特征行计数);三套件 read 助手改拼接模式(`viv.c + viv_*.c` 字典序)——助手改动本身加守卫(拼接后总文本长度守恒 ±ε)。 +- [ ] B2. 剪切 7 个函数(`_viv_recent_file_push/remove/clear`、`_viv_create_recent_menu`、`_viv_recent_save_fold` 等测量清单)+ 3 个共享 static 走 `viv_state.h`(已在片 0 extern 化,零额外工作)。 +- [ ] B3. 新建 `viv_recent.c`(文件头 license 短注 + include viv.h/viv_state.h + 7 函数原样粘贴 + 域内函数补 static)与 `viv_recent.h`(7 个导出原型)。 +- [ ] B4. viv.c:删除 7 函数体与对应前置声明;加 `#include "viv_recent.h"`;props 加 ``。 +- [ ] B5. G1 全绿(拼接守卫自动覆盖)→ G2 CI 双工具链 → Changes.txt(片 1:recent 域,移动清单)→ commit + push。 + +## 任务 C · 片 2–终片(R72+ 逐轮) + +按 spec §4 片序表执行(everything → playlist → render → anim → fullscreen → dark_ui/dialogs → load → chrome → view → 残余整理),每片复用任务 B 模板:守卫先行(红)→ 纯移动 → 拼接守卫(绿)→ CI → Changes.txt → commit/push。 +片 7(对话框域)与片 9(chrome 域)开始前重测域边界(届时 viv.c 已收缩,封闭性数据会变化,重跑 spec §1 的测量脚本更新片序理由)。 + +## 完成定义(DoD) + +- [ ] viv.c < 5,000 行;全部 `viv_*.c` 各 < 3,000 行(对齐 os.c 体量上限惯例)。 +- [ ] 三套件守卫在拼接模式下全绿且守卫总数只增不减。 +- [ ] CI 双工具链在拆分后首个 release tag 上全绿(发版由用户指令触发)。 +- [ ] 用户实机验收(拆分潮合并验收:功能冒烟 + 白条/About 回归项)。 +- [ ] spec §2.3 的"过渡态"记录在案:extern 状态清单移交后续逐域私有化轮(T15 候选,不属本计划)。 + +--- + +## R70 校准增补(2026-09-11):一次性全量拆分 + +> 用户指令松绑了本计划"每片一轮"的节奏约束:"拆分没必要局限在现有的 +> 限制中,先审视大方向"。校准结论:把任务 A–C 的全部 12 片压缩为 +> 一轮(R70)一次性落地,风险控制从"节奏"转移到"机械验证"。 + +**大方向重审(与原计划的差异):** + +1. **一次性 vs 分片**:原计划 12 轮的目的是控制单轮 diff 风险;一次性 + 拆分把风险交给机械保证——生成器只做物理移动(函数体逐字节搬运, + 唯一允许的文本变更 = 剥离导出符号的 `static` 前缀),另有字节守恒、 + 括号平衡、引用解析、单一编译单元定义四道本地验证 + CI 双工具链编译。 +2. **域合并与新增**(对 spec §4 片序表的落地修正):fullscreen 并入 + chrome;dialog_dark 基础设施独立为 dark;everything 并入 playlist; + **新增 install**(安装/关联/注册表/快捷方式——spec 把它们留在残余, + 实测 975 行成体系,抽出后残余才能 <5,000)与 **menu**(命令表/键 + 表/菜单构造,688 行)。 +3. **最小导出面**(对 spec §2.3 片 0 的收紧):不再把 159 个 static 全 + 部 extern 化——只 extern 被跨域引用的(110 个);被单一域独占的 + 52 个变量连同定义一起搬进该域并保留 static;核心独占的 13 个不动。 + 导出函数同理:283 个函数中 163 个导出,其余保持 static。 +4. **性能与体积保证**:工程早已开启 `/GL`(WholeProgramOptimization, + 链接期全程序优化)——跨编译单元内联由链接器恢复,拆分零性能损失; + 导出符号不进入发行版二进制(符号只在 PDB),exe 体积不变。CI 构建 + 产物与上一 tag 对账。 +5. **拼接模式升级**:三套件 read("src/viv.c") 返回 viv.c + 全部 + viv_*.c(字典序);menu/simulation 再拼上 viv_state.h(宏与共享 + 类型守卫需要对状态层解析)。纯移动守恒窗口:拼接总量 21,130 → + 21,7xx 行(只增声明)。 +6. **门禁前移**:提交①(纯拆分)推送后先等 CI 双工具链编译绿,才做 + 提交②(rc.3 版本位 + 安装程序 EMF/WMF + 文档 + 清理);tag 在②的 + CI 绿之后才打——release 流水线五资产自动产出。 + +**落地实测(R70 生成器输出)**:viv.c 21,130 → 4,742 行(残余 = +WndProc 2,207 + init/kill/exit/main + 命令行 + 状态定义 + 110 个 +extern 定义);11 个域模块全部 <3,000 行(chrome 2,911 / view 2,923 +为最大);viv_state.h 391 行(14 类型 + 13 宏区 + 110 extern + 5 核心 +导出原型)。原计划任务 A/B/C 的 DoD 全部达成(残余 <5,000 ✓、域 +<3,000 ✓、守卫拼接绿 ✓、CI 在 rc.3 tag 上验证 ✓)。 diff --git a/docs/architecture/viv-split-spec.md b/docs/architecture/viv-split-spec.md new file mode 100644 index 00000000..bf330334 --- /dev/null +++ b/docs/architecture/viv-split-spec.md @@ -0,0 +1,125 @@ +# viv.c 拆分规格(架构级设计文档) + +> 生成:R69(2026-09-10)· 方法论:superpowers-zh brainstorming(架构级路径) +> + writing-plans(配套计划:`viv-split-plan.md`) +> 状态:用户已授权自主分配("辩证讨论自主分配,进行架构拆分和优化"); +> 每片执行仍走 experience.md 四道门 + 用户验收门。 + +## 1. 问题陈述(测量数据) + +| 指标 | 数值 | 对照 | +|---|---|---| +| viv.c 行数 | 21,129 | 全 src 其余模块总和 ~5,000(os.c 2,602 为次大) | +| 函数数 | 536 static 函数 | — | +| 文件级 static 变量 | 159 个(几乎全部 `_viv_` 前缀共享状态) | — | +| 最大函数 | `_viv_proc`(WndProc)2,208 行 · 41 个 WM_ case | 次大 `_viv_command_with_is_key_repeat` 989 行 | +| R63–R67 修 bug 位置 | 全部落在 viv.c | 坐标漂移 / 字体 / 白条 | + +功能域分布(关键词聚类,测量值): + +| 域 | 函数 | 行数 | 封闭性 | +|---|---|---|---| +| 窗口/chrome(proc/全屏/rebar/工具栏/菜单/状态栏) | 146 | 9,213 | 差(`_viv_hwnd` 共享 238 次) | +| 缩放/平移/导航/命令 | 70 | 2,824 | 中 | +| 对话框(options/jumpto/about + 暗色基础设施) | 50 | 1,599+950 | 良 | +| 图像加载/解码(线程/webp/定向) | 34 | 1,132 | 中 | +| 进程/init/kill/命令行 | 26 | 884 | 良 | +| 主题/暗色/字体 | 9 | 324 | 良 | +| 最近文件/设置持久化 | 18 | 269 | **最优**(共享仅 3 个) | +| 其余(文件系统/渲染像素/播放列表/Everything/编辑) | — | ~4,400 | 分域后良 | + +## 2. 辩证讨论 + +### 2.1 拆还是不拆 + +**反方(维持单文件)**: +- 教训 1/5 的直接推论——fluent 重写(27 文件 +3,347)引发回滚;拆 21k 行 = 更大的结构变更; +- 上游 voidtools 就是单文件风格,拆分增加未来 merge 上游的成本; +- C 编译器对单编译单元的静态检查最严(跨文件调用必须走头文件声明,反而丢失隐式一致性); +- 每轮 bug 修复(R63–R67)虽都在 viv.c,但都修完了——现状"能工作"。 + +**正方(拆)**: +- 教训的实质是"单轮变更量失控",不是"文件应该大"——fluent 是**重写行为**,本方案是**纯物理移动**(函数体逐字节不变),风险模型完全不同; +- fork 与上游已深度分叉(b41/b42/rc.1/rc.2 + 回滚史),"保持上游形状"的收益已趋零——上游 merge 本就不现实; +- 守卫测试按 `viv.count(...)` 形态匹配巨型文件,域越混守卫越写不准(R64/R67 守卫演进已在挣扎); +- 21k 行里任何导航/评审/冲突面都在放大后续每一轮的边际成本。 + +**裁决:拆**,但以"纯移动 + 状态层先行 + 域封闭性升序"把 fluent 式风险(行为重写)从物理上排除。 + +### 2.2 按什么维度拆 + +- **方案 A(按技术层级:ui/render/core)**:违反 writing-plans 的"按职责拆分,而非按技术层级"——把高内聚职责链(如 webp 动画的加载+定时器+渲染)撕碎到三层。否决。 +- **方案 B(按功能域)**:每域一起变更、一起被守卫锁定、与仓库既有模块模式(config.c/os.c/string.c 职责单一、各配 .h)一致。**采纳**。 +- **方案 C(最小拆分:只抽三巨头)**:WndProc 分发/加载线程/options 对话框。治标——viv.c 仍 ~16k 行。作为 B 的阶段产物吸收(三巨头分别落在终片/加载片/对话框片)。 + +### 2.3 共享状态怎么办(本设计的核心) + +测量事实:159 个文件级 static 被全域共享;`_viv_hwnd` 被六个候选域引用 220–238 次; +playlist 域的 6 个 static 全部被域外直接访问——**viv.c 不是"函数太长",是"共享上下文 + 域逻辑绞合"**。 + +- **方案 A(访问器封装)**:每个搬走的 static 配 getter/setter。边界最干净,但每片引入新代码(访问器)+ 调用点改名,diff 面扩散到消费端——违背纯移动纪律,风险回归 fluent 模式。否决(域成熟后可再逐个收回,见 §4 终态)。 +- **方案 B(extern 状态层)**:159 个 static 集中为 `viv_state.h` 的 extern 声明(定义仍在 viv.c),各新域 include。C 消息驱动架构(GDI/Win32)状态天然共享,extern 是该生态的惯例(os.c 的 `os_GdiplusToken` 同模式);每片 diff = 纯移动 + 一行 include;编译器对 extern 的类型检查完整保留。**采纳为过渡态**。 + +### 2.4 守卫兼容(拆分的隐藏成本) + +menu_structure_test.py 有 125 处 `viv.c` 引用、zoom_math 16 处、simulation 2 处。 +拆分后这些守卫若逐条改读新文件 = 巨型测试 diff 且每片重复付费。 + +**策略:read 拼接**——三套件的读取助手改为"viv.c + 所有 `src/viv_*.c` 按字典序拼接"。 +纯移动保证总文本不变 → 现有 125+16+2 处守卫**零修改自动继续全绿**, +新域文件自动纳入守卫视野。每片的测试 diff 恒为一行(首次引入拼接助手时)。 + +### 2.5 命名与目录 + +- 新模块命名 `viv_.c/.h`(`viv_recent.c`、`viv_playlist.c`……):与既有通用模块(os/string/mem——无 viv 前缀)区分"应用域模块"层级,且杜绝与上游未来文件名冲突; +- 目录留在 `src/`(不建子目录——vs2019/vs2026/nsis 全部按 `src\*.c` 扁平约定,props 单点加行即可双工程生效,已验证两工程均 import `voidImageViewer.files.props`)。 + +## 3. 决策摘要 + +1. **片 0 = 状态层先行**:新建 `src/viv_state.h`(159 个 extern 声明,分组注释),viv.c 定义保持不动仅去 static。编译器全量验证、零行为变化。此片独立成轮,因为它本身 ~200 行 diff。 +2. **域片按封闭性升序**(测量驱动,见 §4 片序表):状态共享越少越先拆,每片积累"域文件已存在"的势能,最后拆高耦合域时消费端已就位。 +3. **纯移动纪律**:每片只允许 ①剪切函数 ②粘贴到新 .c ③新 .h 声明导出面 ④props 加编译单元 ⑤守卫拼接自动覆盖 ⑥Changes.txt 记录移动清单。**禁止**任何函数体重写/重命名/重排序。 +4. **viv.c 终态**:残余 = `_viv_proc` 分发 + init/kill + 命令分发 + 状态定义,目标 <5,000 行(后续再评估是否拆 WndProc)。 +5. **每片门禁**:G1 三套件(拼接后自动绿)+ G2 编译零警告(CI 双工具链 windows-2022 v143 + windows-2025 v145)+ G3 push 触发 CI + G4 用户实机冒烟(拆分轮合并验收节奏:每 2–3 片一次实机,纯移动风险递减)。 +6. **回滚**:每片一个 commit,出问题 `git revert` 单片;任何时点上一 release tag 恒可回滚(流程 4)。 + +## 4. 片序表(自主分配结果) + +| 片 | 目标模块 | 预计规模 | 理由(测量依据) | +|---|---|---|---| +| 0 | `viv_state.h` 状态层 | ~200 行声明 | extern 化全量状态,为一切域片铺路 | +| 1 | `viv_recent.c`(最近文件/MRU) | ~230 行 · 7 函数 | 封闭性最优(共享 static 仅 3) | +| 2 | `viv_everything.c`(Everything 搜索) | ~290 行 · 5 函数 | 次优封闭(3 共享) | +| 3 | `viv_playlist.c`(播放列表) | ~425 行 · 12 函数 | 状态进状态层后即纯移动 | +| 4 | `viv_render.c`(StretchBlt/像素/mipmap/定向) | ~680 行 · 6 函数 | 像素数学为主,测量后共享多为读 | +| 5 | `viv_anim.c`(webp 帧/动画) | ~400 行+关联 | 消费加载域,先行独立 | +| 6 | `viv_fullscreen.c` | ~285 行 · 2 函数 | 外部调用面仅 1 函数 | +| 7 | `viv_dark_ui.c` + `viv_dialogs.c`(暗色基础设施 + 对话框族) | ~2,500 行 | 对话框自成体系(R64/R67 已证明) | +| 8 | `viv_load.c`(加载线程/解码) | ~1,500 行 | 依赖 anim/render,就位后移动 | +| 9 | `viv_chrome.c`(rebar/工具栏/菜单/状态栏) | ~2,500 行 | R67 白条修复域,独立性强 | +| 10 | `viv_view.c`(缩放/平移/手势/导航/命令) | ~2,800 行 | 最杂,依赖全域就位 | +| 终 | viv.c 残余整理 + `viv.h` 瘦身 | 收敛至 <5,000 行 | 状态定义 + WndProc + init/kill | + +每片 = 一轮(经验:diff 预算 ~10 文件/400 行内天然满足:2 新文件 + viv.c 削减 + props + Changes.txt + 守卫)。 + +## 5. 风险登记 + +| 风险 | 缓解 | +|---|---| +| extern 化引入隐式跨单元耦合 | 过渡态设计(§4 终态后逐域收回私有化);守卫拼接恒全量扫描 | +| 纯移动中遗漏前置声明 | 编译器硬门(G2/CI 双工具链 0 error 0 warning) | +| 守卫拼接顺序敏感 | 拼接按字典序 + 纯移动保证文本不变;拼接助手本身加守卫(round69) | +| CI image 漂移(MSB8020 类) | 已 pin windows-2022 + windows-2025 双腿(tests.yml 现状) | +| 用户验收节奏被拆分潮淹没 | 拆分轮合并验收:每 2–3 片一次实机;rc 转正决策不受拆分影响(用户指令触发) | + +--- + +## R70 落地记录(补充 §4) + +片序表按计划方向落地,但按用户"先审视大方向"的松绑指令改为一次性 +执行:fullscreen 并入 chrome、dialog_dark 独立为 dark、everything 并入 +playlist,新增 install 与 menu 两域(spec 原把它们留在残余,实测成体 +系)。§2.3 的过渡态按"最小导出面"收紧(110/159 extern 化,52 个单域 +变量随域搬家并保留 static)。§2.4 拼接策略升级为含 viv_state.h 的完 +整拼接。性能与体积由既有 /GL 全程序优化兜底,详见 +viv-split-plan.md 的《R70 校准增补》。 diff --git a/docs/gui-remake-2-spec.md b/docs/gui-remake-2-spec.md new file mode 100644 index 00000000..b9e7ae40 --- /dev/null +++ b/docs/gui-remake-2-spec.md @@ -0,0 +1,63 @@ +# gui-remake-2 轮 · 子代理实施规格 + +基线:rc.8 内容(gui-remake 分支)。设计目标:用户 ChatGPT 参考图 = 全暗色现代外壳 +(标题栏/菜单条/工具栏/状态栏/居中胶囊/现代设置窗),本轮补齐所有剩余原生亮色表面。 + +## 共享纪律(所有代理) +- C89(声明在块首)、tab 缩进、CRLF 行尾(例外:localization_en_us.h / localization_zh_cn.h 是 LF)。 +- 所有颜色走 src/viv_theme.h 的 token(viv_theme_color(token)),禁止新增硬编码 RGB。 +- 不改其他代理的文件。改动文件必须逐个自查编译: + `python3 -m ziglang cc -target x86_64-windows-gnu -Os -DNDEBUG -DVERSION_X64 -Ilibwebp -Wno-macro-redefined -c src/.c -o /tmp/.o` +- 完成后在**自己的 worktree** 提交(git -c user.email=z@local -c user.name=z commit), + 并向 /home/z/my-project/worklog.md 追加一节(--- 开头,Task ID / Agent / Task / Work Log / Stage Summary)。 + +## 3-a 弹出菜单全自绘(worktree /home/z/wt-3a) +可改:src/viv_menu.c、viv_menu.h、viv_menubar.c、viv_menubar.h、viv_recent.c、viv_wndproc.c +1. 弹窗菜单(TrackPopupMenuEx 弹层)owner-draw: + - 可见项构建时(viv_menu.c _viv_create_menu / viv_recent.c recent 菜单)加 MF_OWNERDRAW, + itemData 传 static 指针结构 {command_index, recent 文本指针或 0}; + **文字在绘制时重推导**(localization_get_string(_viv_commands[i].localization_id) + + "\t"+_viv_get_key_text,key 变更后无需重建即正确)。viv.c 的表内 MF_OWNERDRAW=隐藏 + 的既有语义不得破坏(跳过项依旧跳过)。 + - viv_wndproc.c 主窗 dispatch 已有 WM_DRAWITEM 入口(_viv_on_wm_drawitem)——扩展它; + 新增 WM_MEASUREITEM / WM_DELETEITEM 处理(挂同一 dispatch 风格)。 + - 测量:宽=文本(含 \t 快捷键)+左右 padding(各 12dip)+勾选槽(20dip);高=字体高+10dip; + 分隔项=高 9dip(线画中);popup 头不画快捷键列,画右箭头。 + - 绘制:整项填 VIV_TK_FACE;hover=VIV_TK_HOVER、按下=VIV_TK_DOWN(ODS_SELECTED/ + ODS_SCROLLBARBAR?用 itemState);灰=VIV_TK_TEXTOFF;主文本左对齐(DT_LEFT| + SINGLELINE|VCENTER),'\t' 后快捷键 DT_RIGHT 用 VIV_TK_TEXT2; + 勾选(ODS_CHECKED)/单选(ODS_RADIOCHECK)画强调色矢量勾/圆点(20dip 槽内居中); + 子菜单箭头=实心三角 VIV_TK_TEXT2。助记符下划线始终绘制(DrawTextW 前缀处理)。 + - 菜单层背景:WM_INITMENUPOPUP(已有入口)里对 FindWindowW(L"#32768",0) + SetClassLongPtrW(GCLP_HBRBACKGROUND,(LONG_PTR)viv_theme_brush(VIV_TK_FACE)); + 同处尝试 DwmSetWindowAttribute(menu_hwnd,33/34,圆角/边框色 VIV_TK_LINE) + (动态加载 dwmapi 或复用 os.c 现有导出;静默失败)。 +2. 菜单条 token 化:viv_menubar.c 全部 {#202020,#454545,#E8E8E8,#9A9A9A} 与 GetSysColor 项 → + VIV_TK_CHROME / VIV_TK_HOVER / VIV_TK_TEXT / VIV_TK_TEXT2(亮色语义由 token 亮侧映射)。 +3. 不许删 os.c 的 SetPreferredAppMode 机制(仍服务 MessageBox/comdlg)。 +4. 测试:python3 tests/menu_structure_test.py —— 你域内 pin 必须绿(菜单结构/ID/顺序未变)。 + +## 3-b 对话框套件 + viv_msgbox(主线程自己做,本文件仅存档) +可改:viv_dialogs.c/h、viv_msgbox.c/h(新)、viv_view.c、viv_playlist.c、viv_load.c/h +要点:7 个 DialogBox 模板对话框重制为主题化模态面板(WS_POPUP|WS_DLGFRAME + +os_dark_titlebar + DWM caption 色=VIV_TK_CHROME;居中 owner;自泵模态循环; +IsDialogMessage tab/enter/esc);_viv_options() → _viv_settings_show(); +viv_msgbox(parent,caption,text,type) 支持 MB_OK/OKCANCEL/YESNO + 图标 i/!/X/?; +替换 5 个调用点(viv_load 642/737、viv_dialogs 1999、viv_view 2039、viv_playlist 902); +debug.c/mem.c 原生保留。功能逐 proc 保留(edit_key 按键捕获、set_zoom 钳制、rename 校验等)。 + +## 3-c 设置窗对齐设计图(worktree /home/z/wt-3c) +只改:src/viv_settings.c(必要时 +h、+三表同步) +1. _viv_settings_color() 全部 14 个 case → viv_theme_color 薄映射(删硬编码 RGB)。 +2. 新增「强调色」行(LOCALIZATION_ID_ACCENT_COLOR 已预分配):5 圆 swatch + (viv_theme_accent_swatch(0..4)),选中=2px 强调环+白勾;点击 viv_theme_set_accent(i) + + 刷新主窗/自身(InvalidateRect(_viv_hwnd));取消恢复初值,确定沿用 config_save_settings。 +3. 主题下拉=现有 DARK_MODE_AUTO/LIGHT/DARK 文案;切换后 _viv_apply_dark_mode(1) + (viv_chrome.h 声明;不可见则 extern)。 +4. 视觉对齐:标题行齿轮+「设置」+X;侧栏选中=强调色圆角块;底部 取消/确定(主按钮强调色); + DPI 缩放沿用文件内 dip 体系。 +5. 三页与旧 IDD_OPTIONS 选项对照,缺项补齐或如实报告。 + +## 主线程收尾(合并后) +zoomui/tooltip/HUD token 化 → 全量编译 + 测试 → 模拟器转录(theme→TS 自动提取)→ +agent-browser 视觉比对 → wine 实物截图(若可用)→ README/Changes/docs 更新 → 打包 zip。 diff --git a/libwebp/AUTHORS b/libwebp/AUTHORS index 8359b20d..6fe9552c 100644 --- a/libwebp/AUTHORS +++ b/libwebp/AUTHORS @@ -2,23 +2,31 @@ Contributors: - Aidan O'Loan (aidanol at gmail dot com) - Alan Browning (browning at google dot com) - Alexandru Ardelean (ardeleanalex at gmail dot com) +- Anuraag Agrawal (anuraaga at gmail dot com) +- Arthur Eubanks (aeubanks at google dot com) - Brian Ledger (brianpl at google dot com) - Charles Munger (clm at google dot com) - Cheng Yi (cyi at google dot com) - Christian Duvivier (cduvivier at google dot com) - Christopher Degawa (ccom at randomderp dot com) - Clement Courbet (courbet at google dot com) +- devtools-clrobot at google dot com (devtools-clrobot@google dot com) - Djordje Pesut (djordje dot pesut at imgtec dot com) +- Frank (1433351828 at qq dot com) - Frank Barchard (fbarchard at google dot com) +- Henner Zeller (hzeller at google dot com) - Hui Su (huisu at google dot com) - H. Vetinari (h dot vetinari at gmx dot com) - Ilya Kurdyukov (jpegqs at gmail dot com) - Ingvar Stepanyan (rreverser at google dot com) +- Istvan Stefan (Istvan dot Stefan at arm dot com) - James Zern (jzern at google dot com) - Jan Engelhardt (jengelh at medozas dot de) - Jehan (jehan at girinstud dot io) - Jeremy Maitin-Shepard (jbms at google dot com) - Johann Koenig (johann dot koenig at duck dot com) +- Jonathan Grant (jgrantinfotech at gmail dot com) +- Jonliu1993 (13720414433 at 163 dot com) - Jovan Zelincevic (jovan dot zelincevic at imgtec dot com) - Jyrki Alakuijala (jyrki at google dot com) - Konstantin Ivlev (tomskside at gmail dot com) @@ -28,13 +36,16 @@ Contributors: - Marcin Kowalczyk (qrczak at google dot com) - Martin Olsson (mnemo at minimum dot se) - Maryla Ustarroz-Calonge (maryla at google dot com) +- Masahiro Hanada (hanada at atmark-techno dot com) - Mikołaj Zalewski (mikolajz at google dot com) - Mislav Bradac (mislavm at google dot com) +- natewood (natewood at fb dot com) - Nico Weber (thakis at chromium dot org) - Noel Chromium (noel at chromium dot org) - Nozomi Isozaki (nontan at pixiv dot co dot jp) - Oliver Wolff (oliver dot wolff at qt dot io) - Owen Rodley (orodley at google dot com) +- Ozkan Sezer (sezeroz at gmail dot com) - Parag Salasakar (img dot mips1 at gmail dot com) - Pascal Massimino (pascal dot massimino at gmail dot com) - Paweł Hajdan, Jr (phajdan dot jr at chromium dot org) @@ -55,6 +66,7 @@ Contributors: - Vincent Rabaud (vrabaud at google dot com) - Vlad Tsyrklevich (vtsyrklevich at chromium dot org) - Wan-Teh Chang (wtc at google dot com) +- wrv (wrv at utexas dot edu) - Yang Zhang (yang dot zhang at arm dot com) - Yannis Guyon (yguyon at google dot com) - Zhi An Ng (zhin at chromium dot org) diff --git a/libwebp/Android.mk b/libwebp/Android.mk deleted file mode 100644 index f1e9ad80..00000000 --- a/libwebp/Android.mk +++ /dev/null @@ -1,295 +0,0 @@ -# Ignore this file during non-NDK builds. -ifdef NDK_ROOT -LOCAL_PATH := $(call my-dir) - -WEBP_CFLAGS := -Wall -DANDROID -DHAVE_MALLOC_H -DHAVE_PTHREAD -DWEBP_USE_THREAD -WEBP_CFLAGS += -fvisibility=hidden - -ifeq ($(APP_OPTIM),release) - WEBP_CFLAGS += -finline-functions -ffast-math \ - -ffunction-sections -fdata-sections - ifeq ($(findstring clang,$(NDK_TOOLCHAIN_VERSION)),) - WEBP_CFLAGS += -frename-registers -s - endif -endif - -# mips32 fails to build with clang from r14b -# https://bugs.chromium.org/p/webp/issues/detail?id=343 -ifeq ($(findstring clang,$(NDK_TOOLCHAIN_VERSION)),clang) - ifeq ($(TARGET_ARCH),mips) - clang_version := $(shell $(TARGET_CC) --version) - ifneq ($(findstring clang version 3,$(clang_version)),) - WEBP_CFLAGS += -no-integrated-as - endif - endif -endif - -ifneq ($(findstring armeabi-v7a, $(TARGET_ARCH_ABI)),) - # Setting LOCAL_ARM_NEON will enable -mfpu=neon which may cause illegal - # instructions to be generated for armv7a code. Instead target the neon code - # specifically. - NEON := c.neon - USE_CPUFEATURES := yes - WEBP_CFLAGS += -DHAVE_CPU_FEATURES_H -else - NEON := c -endif - -sharpyuv_srcs := \ - sharpyuv/sharpyuv.c \ - sharpyuv/sharpyuv_cpu.c \ - sharpyuv/sharpyuv_csp.c \ - sharpyuv/sharpyuv_dsp.c \ - sharpyuv/sharpyuv_gamma.c \ - sharpyuv/sharpyuv_neon.$(NEON) \ - sharpyuv/sharpyuv_sse2.c \ - -dec_srcs := \ - src/dec/alpha_dec.c \ - src/dec/buffer_dec.c \ - src/dec/frame_dec.c \ - src/dec/idec_dec.c \ - src/dec/io_dec.c \ - src/dec/quant_dec.c \ - src/dec/tree_dec.c \ - src/dec/vp8_dec.c \ - src/dec/vp8l_dec.c \ - src/dec/webp_dec.c \ - -demux_srcs := \ - src/demux/anim_decode.c \ - src/demux/demux.c \ - -dsp_dec_srcs := \ - src/dsp/alpha_processing.c \ - src/dsp/alpha_processing_mips_dsp_r2.c \ - src/dsp/alpha_processing_neon.$(NEON) \ - src/dsp/alpha_processing_sse2.c \ - src/dsp/alpha_processing_sse41.c \ - src/dsp/cpu.c \ - src/dsp/dec.c \ - src/dsp/dec_clip_tables.c \ - src/dsp/dec_mips32.c \ - src/dsp/dec_mips_dsp_r2.c \ - src/dsp/dec_msa.c \ - src/dsp/dec_neon.$(NEON) \ - src/dsp/dec_sse2.c \ - src/dsp/dec_sse41.c \ - src/dsp/filters.c \ - src/dsp/filters_mips_dsp_r2.c \ - src/dsp/filters_msa.c \ - src/dsp/filters_neon.$(NEON) \ - src/dsp/filters_sse2.c \ - src/dsp/lossless.c \ - src/dsp/lossless_mips_dsp_r2.c \ - src/dsp/lossless_msa.c \ - src/dsp/lossless_neon.$(NEON) \ - src/dsp/lossless_sse2.c \ - src/dsp/lossless_sse41.c \ - src/dsp/rescaler.c \ - src/dsp/rescaler_mips32.c \ - src/dsp/rescaler_mips_dsp_r2.c \ - src/dsp/rescaler_msa.c \ - src/dsp/rescaler_neon.$(NEON) \ - src/dsp/rescaler_sse2.c \ - src/dsp/upsampling.c \ - src/dsp/upsampling_mips_dsp_r2.c \ - src/dsp/upsampling_msa.c \ - src/dsp/upsampling_neon.$(NEON) \ - src/dsp/upsampling_sse2.c \ - src/dsp/upsampling_sse41.c \ - src/dsp/yuv.c \ - src/dsp/yuv_mips32.c \ - src/dsp/yuv_mips_dsp_r2.c \ - src/dsp/yuv_neon.$(NEON) \ - src/dsp/yuv_sse2.c \ - src/dsp/yuv_sse41.c \ - -dsp_enc_srcs := \ - src/dsp/cost.c \ - src/dsp/cost_mips32.c \ - src/dsp/cost_mips_dsp_r2.c \ - src/dsp/cost_neon.$(NEON) \ - src/dsp/cost_sse2.c \ - src/dsp/enc.c \ - src/dsp/enc_mips32.c \ - src/dsp/enc_mips_dsp_r2.c \ - src/dsp/enc_msa.c \ - src/dsp/enc_neon.$(NEON) \ - src/dsp/enc_sse2.c \ - src/dsp/enc_sse41.c \ - src/dsp/lossless_enc.c \ - src/dsp/lossless_enc_mips32.c \ - src/dsp/lossless_enc_mips_dsp_r2.c \ - src/dsp/lossless_enc_msa.c \ - src/dsp/lossless_enc_neon.$(NEON) \ - src/dsp/lossless_enc_sse2.c \ - src/dsp/lossless_enc_sse41.c \ - src/dsp/ssim.c \ - src/dsp/ssim_sse2.c \ - -enc_srcs := \ - src/enc/alpha_enc.c \ - src/enc/analysis_enc.c \ - src/enc/backward_references_cost_enc.c \ - src/enc/backward_references_enc.c \ - src/enc/config_enc.c \ - src/enc/cost_enc.c \ - src/enc/filter_enc.c \ - src/enc/frame_enc.c \ - src/enc/histogram_enc.c \ - src/enc/iterator_enc.c \ - src/enc/near_lossless_enc.c \ - src/enc/picture_enc.c \ - src/enc/picture_csp_enc.c \ - src/enc/picture_psnr_enc.c \ - src/enc/picture_rescale_enc.c \ - src/enc/picture_tools_enc.c \ - src/enc/predictor_enc.c \ - src/enc/quant_enc.c \ - src/enc/syntax_enc.c \ - src/enc/token_enc.c \ - src/enc/tree_enc.c \ - src/enc/vp8l_enc.c \ - src/enc/webp_enc.c \ - -mux_srcs := \ - src/mux/anim_encode.c \ - src/mux/muxedit.c \ - src/mux/muxinternal.c \ - src/mux/muxread.c \ - -utils_dec_srcs := \ - src/utils/bit_reader_utils.c \ - src/utils/color_cache_utils.c \ - src/utils/filters_utils.c \ - src/utils/huffman_utils.c \ - src/utils/palette.c \ - src/utils/quant_levels_dec_utils.c \ - src/utils/random_utils.c \ - src/utils/rescaler_utils.c \ - src/utils/thread_utils.c \ - src/utils/utils.c \ - -utils_enc_srcs := \ - src/utils/bit_writer_utils.c \ - src/utils/huffman_encode_utils.c \ - src/utils/quant_levels_utils.c \ - -################################################################################ -# libwebpdecoder - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - $(dec_srcs) \ - $(dsp_dec_srcs) \ - $(utils_dec_srcs) \ - -LOCAL_CFLAGS := $(WEBP_CFLAGS) -LOCAL_EXPORT_C_INCLUDES += $(LOCAL_PATH)/src - -# prefer arm over thumb mode for performance gains -LOCAL_ARM_MODE := arm - -ifeq ($(USE_CPUFEATURES),yes) - LOCAL_STATIC_LIBRARIES := cpufeatures -endif - -LOCAL_MODULE := webpdecoder_static - -include $(BUILD_STATIC_LIBRARY) - -ifeq ($(ENABLE_SHARED),1) -include $(CLEAR_VARS) - -LOCAL_WHOLE_STATIC_LIBRARIES := webpdecoder_static - -LOCAL_MODULE := webpdecoder - -include $(BUILD_SHARED_LIBRARY) -endif # ENABLE_SHARED=1 - -################################################################################ -# libwebp - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - $(sharpyuv_srcs) \ - $(dsp_enc_srcs) \ - $(enc_srcs) \ - $(utils_enc_srcs) \ - -LOCAL_CFLAGS := $(WEBP_CFLAGS) -LOCAL_EXPORT_C_INCLUDES += $(LOCAL_PATH)/src $(LOCAL_PATH) - -# prefer arm over thumb mode for performance gains -LOCAL_ARM_MODE := arm - -LOCAL_WHOLE_STATIC_LIBRARIES := webpdecoder_static - -LOCAL_MODULE := webp - -ifeq ($(ENABLE_SHARED),1) - include $(BUILD_SHARED_LIBRARY) -else - include $(BUILD_STATIC_LIBRARY) -endif - -################################################################################ -# libwebpdemux - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := $(demux_srcs) - -LOCAL_CFLAGS := $(WEBP_CFLAGS) -LOCAL_EXPORT_C_INCLUDES += $(LOCAL_PATH)/src - -# prefer arm over thumb mode for performance gains -LOCAL_ARM_MODE := arm - -LOCAL_MODULE := webpdemux - -ifeq ($(ENABLE_SHARED),1) - LOCAL_SHARED_LIBRARIES := webp - include $(BUILD_SHARED_LIBRARY) -else - LOCAL_STATIC_LIBRARIES := webp - include $(BUILD_STATIC_LIBRARY) -endif - -################################################################################ -# libwebpmux - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := $(mux_srcs) - -LOCAL_CFLAGS := $(WEBP_CFLAGS) -LOCAL_EXPORT_C_INCLUDES += $(LOCAL_PATH)/src - -# prefer arm over thumb mode for performance gains -LOCAL_ARM_MODE := arm - -LOCAL_MODULE := webpmux - -ifeq ($(ENABLE_SHARED),1) - LOCAL_SHARED_LIBRARIES := webp - include $(BUILD_SHARED_LIBRARY) -else - LOCAL_STATIC_LIBRARIES := webp - include $(BUILD_STATIC_LIBRARY) -endif - -################################################################################ - -WEBP_SRC_PATH := $(LOCAL_PATH) -include $(WEBP_SRC_PATH)/imageio/Android.mk -include $(WEBP_SRC_PATH)/examples/Android.mk - -ifeq ($(USE_CPUFEATURES),yes) - $(call import-module,android/cpufeatures) -endif -endif # NDK_ROOT diff --git a/libwebp/CMakeLists.txt b/libwebp/CMakeLists.txt deleted file mode 100644 index 6979f6f9..00000000 --- a/libwebp/CMakeLists.txt +++ /dev/null @@ -1,827 +0,0 @@ -# Copyright (c) 2020 Google LLC. -# -# Use of this source code is governed by a BSD-style license -# that can be found in the LICENSE file in the root of the source -# tree. An additional intellectual property rights grant can be found -# in the file PATENTS. All contributing project authors may -# be found in the AUTHORS file in the root of the source tree. - -if(APPLE) - cmake_minimum_required(VERSION 3.17) -else() - cmake_minimum_required(VERSION 3.7) -endif() - -if(POLICY CMP0072) - cmake_policy(SET CMP0072 NEW) -endif() - -project(WebP C) - -# Options for coder / decoder executables. -if(BUILD_SHARED_LIBS) - set(WEBP_LINK_STATIC_DEFAULT OFF) -else() - set(WEBP_LINK_STATIC_DEFAULT ON) -endif() -option(WEBP_LINK_STATIC - "Link using static libraries. If OFF, use dynamic libraries." - ${WEBP_LINK_STATIC_DEFAULT}) -if(NOT EMSCRIPTEN) - # Disable SIMD on Emscripten by default, as it's a new unstable Wasm feature. - # Users can still explicitly opt-in to make a SIMD-enabled build. - set(WEBP_ENABLE_SIMD_DEFAULT ON) -endif() -option(WEBP_ENABLE_SIMD "Enable any SIMD optimization." - ${WEBP_ENABLE_SIMD_DEFAULT}) -option(WEBP_BUILD_ANIM_UTILS "Build animation utilities." ON) -option(WEBP_BUILD_CWEBP "Build the cwebp command line tool." ON) -option(WEBP_BUILD_DWEBP "Build the dwebp command line tool." ON) -option(WEBP_BUILD_GIF2WEBP "Build the gif2webp conversion tool." ON) -option(WEBP_BUILD_IMG2WEBP "Build the img2webp animation tool." ON) -option(WEBP_BUILD_VWEBP "Build the vwebp viewer tool." ON) -option(WEBP_BUILD_WEBPINFO "Build the webpinfo command line tool." ON) -option(WEBP_BUILD_LIBWEBPMUX "Build the libwebpmux library." ON) -option(WEBP_BUILD_WEBPMUX "Build the webpmux command line tool." ON) -option(WEBP_BUILD_EXTRAS "Build extras." ON) -option(WEBP_BUILD_WEBP_JS "Emscripten build of webp.js." OFF) -option(WEBP_USE_THREAD "Enable threading support" ON) -option(WEBP_NEAR_LOSSLESS "Enable near-lossless encoding" ON) -option(WEBP_ENABLE_SWAP_16BIT_CSP "Enable byte swap for 16 bit colorspaces." - OFF) -set(WEBP_BITTRACE "0" CACHE STRING "Bit trace mode (0=none, 1=bit, 2=bytes)") -set_property(CACHE WEBP_BITTRACE PROPERTY STRINGS 0 1 2) -option(WEBP_ENABLE_WUNUSED_RESULT "Add [[nodiscard]] to some functions. \ - CMake must be at least 3.21 to force C23" OFF) - -if(WEBP_LINK_STATIC) - if(WIN32) - set(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES}) - else() - set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES}) - endif() - set(CMAKE_POSITION_INDEPENDENT_CODE ON) - # vwebp does not compile on Ubuntu with static libraries so disabling it for - # now. - set(WEBP_BUILD_VWEBP OFF) -endif() - -# Option needed for handling Unicode file names on Windows. -if(WIN32) - option(WEBP_UNICODE "Build Unicode executables." ON) -endif() - -if(WEBP_BUILD_WEBP_JS) - set(WEBP_BUILD_ANIM_UTILS OFF) - set(WEBP_BUILD_CWEBP OFF) - set(WEBP_BUILD_DWEBP OFF) - set(WEBP_BUILD_GIF2WEBP OFF) - set(WEBP_BUILD_IMG2WEBP OFF) - set(WEBP_BUILD_VWEBP OFF) - set(WEBP_BUILD_WEBPINFO OFF) - set(WEBP_BUILD_WEBPMUX OFF) - set(WEBP_BUILD_EXTRAS OFF) - set(WEBP_USE_THREAD OFF) - - if(WEBP_ENABLE_SIMD) - message(NOTICE - "wasm2js does not support SIMD, disabling webp.js generation.") - endif() -endif() - -set(SHARPYUV_DEP_LIBRARIES) -set(SHARPYUV_DEP_INCLUDE_DIRS) -set(WEBP_DEP_LIBRARIES) -set(WEBP_DEP_INCLUDE_DIRS) - -if(NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE "Release" - CACHE STRING "Build type: Release, Debug, MinSizeRel or RelWithDebInfo" - FORCE) -endif() - -# Include dependencies. -if(WEBP_BUILD_ANIM_UTILS - OR WEBP_BUILD_CWEBP - OR WEBP_BUILD_DWEBP - OR WEBP_BUILD_EXTRAS - OR WEBP_BUILD_GIF2WEBP - OR WEBP_BUILD_IMG2WEBP) - set(WEBP_FIND_IMG_LIBS TRUE) -else() - set(WEBP_FIND_IMG_LIBS FALSE) -endif() -include(cmake/deps.cmake) -include(GNUInstallDirs) - -if(BUILD_SHARED_LIBS AND NOT DEFINED CMAKE_INSTALL_RPATH) - # Set the rpath to match autoconf/libtool behavior. Note this must be set - # before target creation. - set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}") -endif() - -# ############################################################################## -# Options. -if(WEBP_ENABLE_SWAP_16BIT_CSP) - add_definitions(-DWEBP_SWAP_16BIT_CSP=1) -endif() - -if(NOT WEBP_BITTRACE STREQUAL "0") - add_definitions(-DBITTRACE=${WEBP_BITTRACE}) -endif() - -if(WEBP_UNICODE) - # Windows recommends setting both UNICODE and _UNICODE. - add_definitions(-DUNICODE -D_UNICODE) -endif() - -if(WIN32 AND BUILD_SHARED_LIBS) - add_definitions(-DWEBP_DLL) -endif() - -# pkg-config variables used by *.pc.in. -set(prefix ${CMAKE_INSTALL_PREFIX}) -set(exec_prefix "\${prefix}") -if(IS_ABSOLUTE "${CMAKE_INSTALL_LIBDIR}") - set(libdir "${CMAKE_INSTALL_LIBDIR}") -else() - set(libdir "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}") -endif() -if(IS_ABSOLUTE "${CMAKE_INSTALL_INCLUDEDIR}") - set(includedir "${CMAKE_INSTALL_INCLUDEDIR}") -else() - set(includedir "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}") -endif() -set(PTHREAD_LIBS ${CMAKE_THREAD_LIBS_INIT}) -set(INSTALLED_LIBRARIES) - -if(MSVC) - # match the naming convention used by nmake - set(webp_libname_prefix "lib") - set(CMAKE_SHARED_LIBRARY_PREFIX "${webp_libname_prefix}") - set(CMAKE_IMPORT_LIBRARY_PREFIX "${webp_libname_prefix}") - set(CMAKE_STATIC_LIBRARY_PREFIX "${webp_libname_prefix}") -endif() - -if(NOT WIN32) - set(CMAKE_C_VISIBILITY_PRESET hidden) -endif() - -if(WEBP_ENABLE_WUNUSED_RESULT) - if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.21.0) - set(CMAKE_C_STANDARD 23) - else() - unset(CMAKE_C_STANDARD) - add_compile_options($<$:-std=gnu2x>) - endif() - add_compile_options(-Wunused-result) - add_definitions(-DWEBP_ENABLE_NODISCARD=1) -endif() - -# ############################################################################## -# Android only. -if(ANDROID) - include_directories(${ANDROID_NDK}/sources/android/cpufeatures) - add_library(cpufeatures-webp STATIC - ${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c) - list(APPEND INSTALLED_LIBRARIES cpufeatures-webp) - target_link_libraries(cpufeatures-webp dl) - set(SHARPYUV_DEP_LIBRARIES ${SHARPYUV_DEP_LIBRARIES} cpufeatures-webp) - set(WEBP_DEP_LIBRARIES ${WEBP_DEP_LIBRARIES} cpufeatures-webp) - set(cpufeatures_include_dir ${ANDROID_NDK}/sources/android/cpufeatures) - set(SHARPYUV_DEP_INCLUDE_DIRS ${SHARPYUV_DEP_INCLUDE_DIRS} - ${cpufeatures_include_dir}) - set(WEBP_DEP_INCLUDE_DIRS ${WEBP_DEP_INCLUDE_DIRS} ${cpufeatures_include_dir}) - add_definitions(-DHAVE_CPU_FEATURES_H=1) - set(HAVE_CPU_FEATURES_H 1) -else() - set(HAVE_CPU_FEATURES_H 0) -endif() - -function(configure_pkg_config FILE) - configure_file("${CMAKE_CURRENT_SOURCE_DIR}/${FILE}.in" - "${CMAKE_CURRENT_BINARY_DIR}/${FILE}" @ONLY) - - if(HAVE_MATH_LIBRARY) - # MSVC doesn't have libm - file(READ ${CMAKE_CURRENT_BINARY_DIR}/${FILE} data) - string(REPLACE "-lm" "" data ${data}) - file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/${FILE} ${data}) - endif() - - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${FILE}" - DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) -endfunction() - -# ############################################################################## -# WebP source files. Read the Makefile.am to get the source files. - -# We expect the Makefiles to define the sources as defined in the first regex. -# E.g.: libimagedec_la_SOURCES = image_dec.c image_dec.h -function(parse_Makefile_am FOLDER VAR SRC_REGEX) - file(READ ${FOLDER}/Makefile.am MAKEFILE_AM) - string(REGEX MATCHALL "${SRC_REGEX}_SOURCES[ ]*\\+?=[ ]+[0-9a-z\\._ ]*" - FILES_PER_LINE ${MAKEFILE_AM}) - set(SRCS ${${VAR}}) - foreach(FILES ${FILES_PER_LINE}) - string(FIND ${FILES} "=" OFFSET) - math(EXPR OFFSET "${OFFSET} + 2") - string(SUBSTRING ${FILES} ${OFFSET} -1 FILES) - if(FILES) - string(REGEX MATCHALL "[0-9a-z\\._]+" FILES ${FILES}) - foreach(FILE ${FILES}) - list(APPEND SRCS ${FOLDER}/${FILE}) - endforeach() - endif() - endforeach() - set(${VAR} ${SRCS} PARENT_SCOPE) -endfunction() - -set(WEBP_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src) -parse_makefile_am(${WEBP_SRC_DIR}/dec "WEBP_DEC_SRCS" "") -parse_makefile_am(${WEBP_SRC_DIR}/demux "WEBP_DEMUX_SRCS" "") -parse_makefile_am(${WEBP_SRC_DIR}/dsp "WEBP_DSP_COMMON_SRCS" "COMMON") -parse_makefile_am(${WEBP_SRC_DIR}/dsp "WEBP_DSP_ENC_SRCS" "ENC") -parse_makefile_am(${WEBP_SRC_DIR}/dsp "WEBP_DSP_ENC_SRCS" "dsp_[^ ]*") -parse_makefile_am(${WEBP_SRC_DIR}/dsp "WEBP_DSP_DEC_SRCS" "decode_[^ ]*") -parse_makefile_am(${WEBP_SRC_DIR}/enc "WEBP_ENC_SRCS" "") -parse_makefile_am(${WEBP_SRC_DIR}/utils "WEBP_UTILS_COMMON_SRCS" "COMMON") -parse_makefile_am(${WEBP_SRC_DIR}/utils "WEBP_UTILS_ENC_SRCS" "ENC") -parse_makefile_am(${WEBP_SRC_DIR}/utils "WEBP_UTILS_DEC_SRCS" "decode_[^ ]*") - -# Remove the files specific to SIMD we don't use. -foreach(FILE ${WEBP_SIMD_FILES_NOT_TO_INCLUDE}) - list(REMOVE_ITEM WEBP_DSP_ENC_SRCS ${FILE}) - list(REMOVE_ITEM WEBP_DSP_DEC_SRCS ${FILE}) -endforeach() - -# Generate the config.h file. -configure_file(${CMAKE_CURRENT_LIST_DIR}/cmake/config.h.in - ${CMAKE_CURRENT_BINARY_DIR}/src/webp/config.h @ONLY) -add_definitions(-DHAVE_CONFIG_H) - -# Set the version numbers. -macro(set_version FILE TARGET_NAME NAME_IN_MAKEFILE) - file(READ ${CMAKE_CURRENT_SOURCE_DIR}/${FILE} SOURCE_FILE) - string(REGEX MATCH - "${NAME_IN_MAKEFILE}_la_LDFLAGS[^\n]* -version-info [0-9:]+" TMP - ${SOURCE_FILE}) - string(REGEX MATCH "[0-9:]+" TMP ${TMP}) - string(REGEX REPLACE ":" " " LT_VERSION ${TMP}) - - # See the libtool docs for more information: - # https://www.gnu.org/software/libtool/manual/libtool.html#Updating-version-info - # - # c=, a=, r= - # - # libtool generates a .so file as .so.[c-a].a.r, while -version-info c:r:a is - # passed to libtool. - # - # We set FULL = [c-a].a.r and MAJOR = [c-a]. - separate_arguments(LT_VERSION) - list(GET LT_VERSION 0 LT_CURRENT) - list(GET LT_VERSION 1 LT_REVISION) - list(GET LT_VERSION 2 LT_AGE) - math(EXPR LT_CURRENT_MINUS_AGE "${LT_CURRENT} - ${LT_AGE}") - - set_target_properties( - ${TARGET_NAME} - PROPERTIES VERSION ${LT_CURRENT_MINUS_AGE}.${LT_AGE}.${LT_REVISION} - SOVERSION ${LT_CURRENT_MINUS_AGE}) - if(APPLE) - # For compatibility, set MACHO_COMPATIBILITY_VERSION and - # MACHO_CURRENT_VERSION to match libtool. These properties were introduced - # in 3.17: - # https://cmake.org/cmake/help/latest/prop_tgt/MACHO_COMPATIBILITY_VERSION.html - math(EXPR LIBWEBP_MACHO_COMPATIBILITY_VERSION "${LT_CURRENT} + 1") - set_target_properties( - ${TARGET_NAME} - PROPERTIES MACHO_COMPATIBILITY_VERSION - ${LIBWEBP_MACHO_COMPATIBILITY_VERSION} - MACHO_CURRENT_VERSION - ${LIBWEBP_MACHO_COMPATIBILITY_VERSION}.${LT_REVISION}) - endif() -endmacro() - -# ############################################################################## -# Build the webpdecoder library. - -# Creates a source file with an unused stub function in $CMAKE_BINARY_DIR and -# adds it to the specified target. Currently used only with Xcode. -# -# See also: -# https://cmake.org/cmake/help/v3.18/command/add_library.html#object-libraries -# "Some native build systems (such as Xcode) may not like targets that have only -# object files, so consider adding at least one real source file to any target -# that references $." -function(libwebp_add_stub_file TARGET) - set(stub_source_dir "${CMAKE_BINARY_DIR}") - set(stub_source_file "${stub_source_dir}/libwebp_${TARGET}_stub.c") - set(stub_source_code - "// Generated file. DO NOT EDIT!\n" - "// C source file created for target ${TARGET}.\n" - "void libwebp_${TARGET}_stub_function(void)\;\n" - "void libwebp_${TARGET}_stub_function(void) {}\n") - file(WRITE "${stub_source_file}" ${stub_source_code}) - - target_sources(${TARGET} PRIVATE ${stub_source_file}) -endfunction() - -parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/sharpyuv "WEBP_SHARPYUV_SRCS" "") -add_library(sharpyuv ${WEBP_SHARPYUV_SRCS}) -target_link_libraries(sharpyuv ${SHARPYUV_DEP_LIBRARIES}) -set_version(sharpyuv/Makefile.am sharpyuv sharpyuv) -target_include_directories( - sharpyuv PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/src) -set_target_properties( - sharpyuv - PROPERTIES PUBLIC_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/sharpyuv/sharpyuv.h;\ -${CMAKE_CURRENT_SOURCE_DIR}/sharpyuv/sharpyuv_csp.h") -configure_pkg_config("sharpyuv/libsharpyuv.pc") -install( - TARGETS sharpyuv - EXPORT ${PROJECT_NAME}Targets - PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/webp/sharpyuv - INCLUDES - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} - ${CMAKE_INSTALL_INCLUDEDIR}/webp - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) - -if(MSVC) - # avoid security warnings for e.g., fopen() used in the examples. - add_definitions(-D_CRT_SECURE_NO_WARNINGS) -else() - add_compile_options(-Wall) -endif() -include_directories(${WEBP_DEP_INCLUDE_DIRS}) -add_library(webpdecode OBJECT ${WEBP_DEC_SRCS}) -target_include_directories(webpdecode PRIVATE ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}) -add_library(webpdspdecode OBJECT ${WEBP_DSP_COMMON_SRCS} ${WEBP_DSP_DEC_SRCS}) -target_include_directories(webpdspdecode PRIVATE ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}) -add_library(webputilsdecode OBJECT ${WEBP_UTILS_COMMON_SRCS} - ${WEBP_UTILS_DEC_SRCS}) -target_include_directories(webputilsdecode PRIVATE ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}) -add_library( - webpdecoder $ $ - $) -if(XCODE) - libwebp_add_stub_file(webpdecoder) -endif() -target_link_libraries(webpdecoder ${WEBP_DEP_LIBRARIES}) -target_include_directories( - webpdecoder PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} - INTERFACE $ - $) -set_target_properties( - webpdecoder - PROPERTIES PUBLIC_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/src/webp/decode.h;\ -${CMAKE_CURRENT_SOURCE_DIR}/src/webp/types.h") - -configure_pkg_config("src/libwebpdecoder.pc") - -# Build the webp library. -add_library(webpencode OBJECT ${WEBP_ENC_SRCS}) -target_include_directories( - webpencode PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/src) -add_library(webpdsp OBJECT ${WEBP_DSP_COMMON_SRCS} ${WEBP_DSP_DEC_SRCS} - ${WEBP_DSP_ENC_SRCS}) -target_include_directories(webpdsp PRIVATE ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}) -add_library(webputils OBJECT ${WEBP_UTILS_COMMON_SRCS} ${WEBP_UTILS_DEC_SRCS} - ${WEBP_UTILS_ENC_SRCS}) -target_include_directories(webputils PRIVATE ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}) -add_library(webp $ $ - $ $) -target_link_libraries(webp sharpyuv) -if(XCODE) - libwebp_add_stub_file(webp) -endif() -target_link_libraries(webp ${WEBP_DEP_LIBRARIES}) -target_include_directories( - webp PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} - PUBLIC $ - $) -set_target_properties( - webp - PROPERTIES PUBLIC_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/src/webp/decode.h;\ -${CMAKE_CURRENT_SOURCE_DIR}/src/webp/encode.h;\ -${CMAKE_CURRENT_SOURCE_DIR}/src/webp/types.h") - -# Make sure the OBJECT libraries are built with position independent code (it is -# not ON by default). -set_target_properties(webpdecode webpdspdecode webputilsdecode webpencode - webpdsp webputils PROPERTIES POSITION_INDEPENDENT_CODE ON) -configure_pkg_config("src/libwebp.pc") - -# Build the webp demux library. -add_library(webpdemux ${WEBP_DEMUX_SRCS}) -target_link_libraries(webpdemux webp) -target_include_directories( - webpdemux PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} - PUBLIC $) -set_target_properties( - webpdemux - PROPERTIES - PUBLIC_HEADER - "${CMAKE_CURRENT_SOURCE_DIR}/src/webp/decode.h;\ -${CMAKE_CURRENT_SOURCE_DIR}/src/webp/demux.h;\ -${CMAKE_CURRENT_SOURCE_DIR}/src/webp/mux_types.h;\ -${CMAKE_CURRENT_SOURCE_DIR}/src/webp/types.h") - -configure_pkg_config("src/demux/libwebpdemux.pc") - -set_version(src/Makefile.am webp webp) -set_version(src/Makefile.am webpdecoder webpdecoder) -set_version(src/demux/Makefile.am webpdemux webpdemux) -file(READ ${CMAKE_CURRENT_SOURCE_DIR}/configure.ac CONFIGURE_FILE) -string(REGEX MATCH "AC_INIT\\([^\n]*\\[[0-9\\.]+\\]" TMP ${CONFIGURE_FILE}) -string(REGEX MATCH "[0-9\\.]+" PROJECT_VERSION ${TMP}) - -# Define the libraries to install. -list(APPEND INSTALLED_LIBRARIES webpdecoder webp webpdemux) - -# Deal with SIMD. Change the compile flags for SIMD files we use. -list(LENGTH WEBP_SIMD_FILES_TO_INCLUDE WEBP_SIMD_FILES_TO_INCLUDE_LENGTH) -math(EXPR WEBP_SIMD_FILES_TO_INCLUDE_RANGE - "${WEBP_SIMD_FILES_TO_INCLUDE_LENGTH}-1") - -foreach(I_FILE RANGE ${WEBP_SIMD_FILES_TO_INCLUDE_RANGE}) - list(GET WEBP_SIMD_FILES_TO_INCLUDE ${I_FILE} FILE) - list(GET WEBP_SIMD_FLAGS_TO_INCLUDE ${I_FILE} SIMD_COMPILE_FLAG) - set_source_files_properties(${FILE} PROPERTIES COMPILE_FLAGS - ${SIMD_COMPILE_FLAG}) -endforeach() - -if(NOT WEBP_BUILD_LIBWEBPMUX) - set(WEBP_BUILD_GIF2WEBP OFF) - set(WEBP_BUILD_IMG2WEBP OFF) - set(WEBP_BUILD_WEBPMUX OFF) -endif() - -if(WEBP_BUILD_GIF2WEBP AND NOT GIF_FOUND) - set(WEBP_BUILD_GIF2WEBP OFF) -endif() - -if(WEBP_BUILD_ANIM_UTILS AND NOT GIF_FOUND) - set(WEBP_BUILD_ANIM_UTILS OFF) -endif() - -# Build the executables if asked for. -if(WEBP_BUILD_ANIM_UTILS - OR WEBP_BUILD_CWEBP - OR WEBP_BUILD_DWEBP - OR WEBP_BUILD_GIF2WEBP - OR WEBP_BUILD_IMG2WEBP - OR WEBP_BUILD_VWEBP - OR WEBP_BUILD_WEBPMUX - OR WEBP_BUILD_WEBPINFO) - # Example utility library. - parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "EXAMPLEUTIL_SRCS" - "example_util_[^ ]*") - list(APPEND EXAMPLEUTIL_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/examples/stopwatch.h) - add_library(exampleutil STATIC ${EXAMPLEUTIL_SRCS}) - target_include_directories( - exampleutil PUBLIC $) - - parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/imageio "IMAGEIOUTILS_SRCS" - "imageio_util_[^ ]*") - add_library(imageioutil STATIC ${IMAGEIOUTILS_SRCS}) - target_link_libraries(imageioutil webp) - target_link_libraries(exampleutil imageioutil) - - # Image-decoding utility library. - parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/imageio "IMAGEDEC_SRCS" - "imagedec_[^ ]*") - add_library(imagedec STATIC ${IMAGEDEC_SRCS}) - target_link_libraries(imagedec imageioutil webpdemux webp - ${WEBP_DEP_IMG_LIBRARIES}) - - # Image-encoding utility library. - parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/imageio "IMAGEENC_SRCS" - "imageenc_[^ ]*") - add_library(imageenc STATIC ${IMAGEENC_SRCS}) - target_link_libraries(imageenc imageioutil webp) - - set_property( - TARGET exampleutil imageioutil imagedec imageenc - PROPERTY INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}/src - ${CMAKE_CURRENT_BINARY_DIR}/src) -endif() - -if(WEBP_BUILD_DWEBP) - # dwebp - parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "DWEBP_SRCS" "dwebp") - add_executable(dwebp ${DWEBP_SRCS}) - target_link_libraries(dwebp exampleutil imagedec imageenc) - target_include_directories(dwebp PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src) - install(TARGETS dwebp RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) -endif() - -if(WEBP_BUILD_CWEBP) - # cwebp - parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "CWEBP_SRCS" "cwebp") - add_executable(cwebp ${CWEBP_SRCS}) - target_link_libraries(cwebp exampleutil imagedec webp) - target_include_directories(cwebp PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src - ${CMAKE_CURRENT_SOURCE_DIR}) - install(TARGETS cwebp RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) -endif() - -if(WEBP_BUILD_LIBWEBPMUX) - parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/src/mux "WEBP_MUX_SRCS" "") - add_library(libwebpmux ${WEBP_MUX_SRCS}) - target_link_libraries(libwebpmux webp) - target_include_directories(libwebpmux PRIVATE ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}) - set_version(src/mux/Makefile.am libwebpmux webpmux) - set_target_properties( - libwebpmux - PROPERTIES PUBLIC_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/src/webp/mux.h;\ -${CMAKE_CURRENT_SOURCE_DIR}/src/webp/mux_types.h;\ -${CMAKE_CURRENT_SOURCE_DIR}/src/webp/types.h;") - set_target_properties(libwebpmux PROPERTIES OUTPUT_NAME webpmux) - list(APPEND INSTALLED_LIBRARIES libwebpmux) - configure_pkg_config("src/mux/libwebpmux.pc") -endif() - -if(WEBP_BUILD_GIF2WEBP) - # gif2webp - include_directories(${WEBP_DEP_GIF_INCLUDE_DIRS}) - parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "GIF2WEBP_SRCS" - "gif2webp") - add_executable(gif2webp ${GIF2WEBP_SRCS}) - target_link_libraries(gif2webp exampleutil imageioutil webp libwebpmux - ${WEBP_DEP_GIF_LIBRARIES}) - target_include_directories(gif2webp PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src) - install(TARGETS gif2webp RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) -endif() - -if(WEBP_BUILD_IMG2WEBP) - # img2webp - include_directories(${WEBP_DEP_IMG_INCLUDE_DIRS}) - parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "IMG2WEBP_SRCS" - "img2webp") - add_executable(img2webp ${IMG2WEBP_SRCS}) - target_link_libraries(img2webp exampleutil imagedec imageioutil webp - libwebpmux) - target_include_directories(img2webp PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src - ${CMAKE_CURRENT_SOURCE_DIR}) - install(TARGETS img2webp RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) -endif() - -if(WEBP_BUILD_VWEBP) - # vwebp - find_package(GLUT) - if(GLUT_FOUND) - include_directories(${WEBP_DEP_IMG_INCLUDE_DIRS}) - parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "VWEBP_SRCS" "vwebp") - add_executable(vwebp ${VWEBP_SRCS}) - target_link_libraries( - vwebp - ${OPENGL_LIBRARIES} - exampleutil - GLUT::GLUT - imageioutil - webp - webpdemux) - target_include_directories( - vwebp PRIVATE ${GLUT_INCLUDE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/src - ${OPENGL_INCLUDE_DIR}) - install(TARGETS vwebp RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) - if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") - check_c_compiler_flag("-Wno-deprecated-declarations" HAS_NO_DEPRECATED) - if(HAS_NO_DEPRECATED) - target_compile_options(vwebp PRIVATE "-Wno-deprecated-declarations") - endif() - endif() - endif() -endif() - -if(WEBP_BUILD_WEBPINFO) - # webpinfo - include_directories(${WEBP_DEP_IMG_INCLUDE_DIRS}) - parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "WEBPINFO_SRCS" - "webpinfo") - add_executable(webpinfo ${WEBPINFO_SRCS}) - target_link_libraries(webpinfo exampleutil imageioutil) - target_include_directories(webpinfo PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src - ${CMAKE_CURRENT_SOURCE_DIR}/src) - install(TARGETS webpinfo RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) -endif() - -if(WEBP_BUILD_WEBPMUX) - # webpmux - parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "WEBPMUX_SRCS" - "webpmux") - add_executable(webpmux ${WEBPMUX_SRCS}) - target_link_libraries(webpmux exampleutil imageioutil libwebpmux webp) - target_include_directories(webpmux PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src) - install(TARGETS webpmux RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) -endif() - -if(WEBP_BUILD_EXTRAS) - set(EXTRAS_MAKEFILE "${CMAKE_CURRENT_SOURCE_DIR}/extras") - parse_makefile_am(${EXTRAS_MAKEFILE} "WEBP_EXTRAS_SRCS" "libwebpextras_la") - parse_makefile_am(${EXTRAS_MAKEFILE} "GET_DISTO_SRCS" "get_disto") - parse_makefile_am(${EXTRAS_MAKEFILE} "WEBP_QUALITY_SRCS" "webp_quality") - parse_makefile_am(${EXTRAS_MAKEFILE} "VWEBP_SDL_SRCS" "vwebp_sdl") - - # libextras - add_library(extras STATIC ${WEBP_EXTRAS_SRCS}) - target_include_directories( - extras PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/src) - - # get_disto - add_executable(get_disto ${GET_DISTO_SRCS}) - target_link_libraries(get_disto imagedec) - target_include_directories(get_disto PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_BINARY_DIR}/src) - - # webp_quality - add_executable(webp_quality ${WEBP_QUALITY_SRCS}) - target_link_libraries(webp_quality exampleutil imagedec extras) - target_include_directories(webp_quality PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_BINARY_DIR}) - - # vwebp_sdl - find_package(SDL2 QUIET) - if(WEBP_BUILD_VWEBP AND SDL2_FOUND) - add_executable(vwebp_sdl ${VWEBP_SDL_SRCS}) - target_link_libraries(vwebp_sdl ${SDL2_LIBRARIES} imageioutil webp) - target_include_directories( - vwebp_sdl PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_CURRENT_BINARY_DIR}/src ${SDL2_INCLUDE_DIRS}) - set(WEBP_HAVE_SDL 1) - target_compile_definitions(vwebp_sdl PUBLIC WEBP_HAVE_SDL) - endif() -endif() - -if(WEBP_BUILD_WEBP_JS) - # The default stack size changed from 5MB to 64KB in 3.1.27. See - # https://crbug.com/webp/614. - if(EMSCRIPTEN_VERSION VERSION_GREATER_EQUAL "3.1.27") - # TOTAL_STACK size was renamed to STACK_SIZE in 3.1.27. The old name was - # kept for compatibility, but prefer the new one in case it is removed in - # the future. - set(emscripten_stack_size "-sSTACK_SIZE=5MB") - else() - set(emscripten_stack_size "-sTOTAL_STACK=5MB") - endif() - # Set SDL2 flags so that ports are downloaded by emscripten. - set(EMSCRIPTEN_SDL2_FLAGS "-sUSE_SDL=2 -sUSE_SDL_IMAGE=2") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EMSCRIPTEN_SDL2_FLAGS}") - # wasm2js does not support SIMD. - if(NOT WEBP_ENABLE_SIMD) - # JavaScript version - find_package(SDL2 QUIET) - add_executable(webp_js ${CMAKE_CURRENT_SOURCE_DIR}/extras/webp_to_sdl.c) - target_link_libraries(webp_js webpdecoder SDL2) - target_include_directories(webp_js PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) - set(WEBP_HAVE_SDL 1) - set_target_properties( - webp_js - PROPERTIES - LINK_FLAGS - "-sWASM=0 ${emscripten_stack_size} \ - -sEXPORTED_FUNCTIONS=_WebPToSDL -sINVOKE_RUN=0 \ - -sEXPORTED_RUNTIME_METHODS=cwrap ${EMSCRIPTEN_SDL2_FLAGS} \ - -sALLOW_MEMORY_GROWTH") - set_target_properties(webp_js PROPERTIES OUTPUT_NAME webp) - target_compile_definitions(webp_js PUBLIC EMSCRIPTEN WEBP_HAVE_SDL) - endif() - - # WASM version - add_executable(webp_wasm ${CMAKE_CURRENT_SOURCE_DIR}/extras/webp_to_sdl.c) - target_link_libraries(webp_wasm webpdecoder SDL2) - target_include_directories(webp_wasm PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) - set_target_properties( - webp_wasm - PROPERTIES - LINK_FLAGS - "-sWASM=1 ${emscripten_stack_size} \ - -sEXPORTED_FUNCTIONS=_WebPToSDL -sINVOKE_RUN=0 \ - -sEXPORTED_RUNTIME_METHODS=cwrap ${EMSCRIPTEN_SDL2_FLAGS} \ - -sALLOW_MEMORY_GROWTH") - target_compile_definitions(webp_wasm PUBLIC EMSCRIPTEN WEBP_HAVE_SDL) - - target_compile_definitions(webpdspdecode PUBLIC EMSCRIPTEN) -endif() - -if(WEBP_BUILD_ANIM_UTILS) - # anim_diff - include_directories(${WEBP_DEP_IMG_INCLUDE_DIRS} ${WEBP_DEP_GIF_INCLUDE_DIRS}) - parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "ANIM_DIFF_SRCS" - "anim_diff") - add_executable(anim_diff ${ANIM_DIFF_SRCS}) - target_link_libraries( - anim_diff - exampleutil - imagedec - imageenc - imageioutil - webp - webpdemux - ${WEBP_DEP_GIF_LIBRARIES}) - target_include_directories(anim_diff PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src) - - # anim_dump - include_directories(${WEBP_DEP_IMG_INCLUDE_DIRS} ${WEBP_DEP_GIF_INCLUDE_DIRS}) - parse_makefile_am(${CMAKE_CURRENT_SOURCE_DIR}/examples "ANIM_DUMP_SRCS" - "anim_dump") - add_executable(anim_dump ${ANIM_DUMP_SRCS}) - target_link_libraries( - anim_dump - exampleutil - imagedec - imageenc - imageioutil - webp - webpdemux - ${WEBP_DEP_GIF_LIBRARIES}) - target_include_directories(anim_dump PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src) -endif() - -# Install the different headers and libraries. -install( - TARGETS ${INSTALLED_LIBRARIES} - EXPORT ${PROJECT_NAME}Targets - PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/webp - INCLUDES - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) -set(ConfigPackageLocation ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/cmake/) -install(EXPORT ${PROJECT_NAME}Targets NAMESPACE ${PROJECT_NAME}:: - DESTINATION ${ConfigPackageLocation}) - -# Create the CMake version file. -include(CMakePackageConfigHelpers) -write_basic_package_version_file( - "${CMAKE_CURRENT_BINARY_DIR}/WebPConfigVersion.cmake" - VERSION ${PACKAGE_VERSION} COMPATIBILITY AnyNewerVersion) - -# Create the Config file. -include(CMakePackageConfigHelpers) -# Fix libwebpmux reference. The target name libwebpmux is used for compatibility -# purposes, but the library mentioned in WebPConfig.cmake should be the -# unprefixed version. Note string(...) can be replaced with list(TRANSFORM ...) -# if cmake_minimum_required is >= 3.12. -string(REGEX REPLACE "libwebpmux" "webpmux" INSTALLED_LIBRARIES - "${INSTALLED_LIBRARIES}") - -if(MSVC) - # For compatibility with nmake, MSVC builds use a custom prefix (lib) that - # needs to be included in the library name. - string(REGEX REPLACE "[A-Za-z0-9_]+" "${CMAKE_STATIC_LIBRARY_PREFIX}\\0" - INSTALLED_LIBRARIES "${INSTALLED_LIBRARIES}") -endif() - -configure_package_config_file( - ${CMAKE_CURRENT_SOURCE_DIR}/cmake/WebPConfig.cmake.in - ${CMAKE_CURRENT_BINARY_DIR}/WebPConfig.cmake - INSTALL_DESTINATION ${ConfigPackageLocation} - PATH_VARS CMAKE_INSTALL_INCLUDEDIR) - -# Install the generated CMake files. -install(FILES "${CMAKE_CURRENT_BINARY_DIR}/WebPConfigVersion.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/WebPConfig.cmake" - DESTINATION ${ConfigPackageLocation}) - -# Install the man pages. -set(MAN_PAGES - cwebp.1 - dwebp.1 - gif2webp.1 - img2webp.1 - vwebp.1 - webpmux.1 - webpinfo.1) -set(EXEC_BUILDS - "CWEBP" - "DWEBP" - "GIF2WEBP" - "IMG2WEBP" - "VWEBP" - "WEBPMUX" - "WEBPINFO") -list(LENGTH MAN_PAGES MAN_PAGES_LENGTH) -math(EXPR MAN_PAGES_RANGE "${MAN_PAGES_LENGTH} - 1") - -foreach(I_MAN RANGE ${MAN_PAGES_RANGE}) - list(GET EXEC_BUILDS ${I_MAN} EXEC_BUILD) - if(WEBP_BUILD_${EXEC_BUILD}) - list(GET MAN_PAGES ${I_MAN} MAN_PAGE) - install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/man/${MAN_PAGE} - DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 COMPONENT doc) - endif() -endforeach() diff --git a/libwebp/CONTRIBUTING.md b/libwebp/CONTRIBUTING.md deleted file mode 100644 index 9540f34f..00000000 --- a/libwebp/CONTRIBUTING.md +++ /dev/null @@ -1,78 +0,0 @@ -# How to Contribute - -We'd love to accept your patches and contributions to this project. There are -just a few small guidelines you need to follow. - -## Contributor License Agreement - -Contributions to this project must be accompanied by a Contributor License -Agreement. You (or your employer) retain the copyright to your contribution; -this simply gives us permission to use and redistribute your contributions as -part of the project. Head over to to see -your current agreements on file or to sign a new one. - -You generally only need to submit a CLA once, so if you've already submitted one -(even if it was for a different project), you probably don't need to do it -again. - -## Code reviews - -All submissions, including submissions by project members, require review. We -use a [Gerrit](https://www.gerritcodereview.com) instance hosted at -https://chromium-review.googlesource.com for this purpose. - -## Sending patches - -The basic git workflow for modifying libwebp code and sending for review is: - -1. Get the latest version of the repository locally: - - ```sh - git clone https://chromium.googlesource.com/webm/libwebp && cd libwebp - ``` - -2. Copy the commit-msg script into ./git/hooks (this will add an ID to all of - your commits): - - ```sh - curl -Lo .git/hooks/commit-msg https://chromium-review.googlesource.com/tools/hooks/commit-msg && chmod u+x .git/hooks/commit-msg - ``` - -3. Modify the local copy of libwebp. Make sure the code - [builds successfully](https://chromium.googlesource.com/webm/libwebp/+/HEAD/doc/building.md#cmake). - -4. Choose a short and representative commit message: - - ```sh - git commit -a -m "Set commit message here" - ``` - -5. Send the patch for review: - - ```sh - git push https://chromium-review.googlesource.com/webm/libwebp HEAD:refs/for/main - ``` - - Go to https://chromium-review.googlesource.com to view your patch and - request a review from the maintainers. - -See the -[WebM Project page](https://www.webmproject.org/code/contribute/submitting-patches/) -for additional details. - -## Code Style - -The C code style is based on the -[Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html) and -`clang-format --style=Google`, though this project doesn't use the tool to -enforce the formatting. - -CMake files are formatted with -[cmake-format](https://cmake-format.readthedocs.io/en/latest/). `cmake-format --i` can be used to format individual files, it will use the settings from -`.cmake-format.py`. - -## Community Guidelines - -This project follows -[Google's Open Source Community Guidelines](https://opensource.google.com/conduct/). diff --git a/libwebp/ChangeLog b/libwebp/ChangeLog deleted file mode 100644 index 33ec4863..00000000 --- a/libwebp/ChangeLog +++ /dev/null @@ -1,4626 +0,0 @@ -1ace578c update NEWS -63234c42 bump version to 1.3.2 -2af26267 Fix OOB write in BuildHuffmanTable. -fd7bb21c update ChangeLog (tag: v1.3.1-rc2, tag: v1.3.1) -e1adea50 update NEWS -43393320 enc/*: normalize WebPEncodingSetError() calls -287fdefe enc/*: add missing WebPEncodingSetError() calls -c3bd7cff EncodeAlphaInternal: add missing error check -d49cfbb3 vp8l_enc,WriteImage: add missing error check -2e5a9ec3 muxread,MuxImageParse: add missing error checks -ebb6f949 cmake,emscripten: explicitly set stack size -59a2b1f9 WebPDecodeYUV: check u/v/stride/uv_stride ptrs -8e965ccb Call png_get_channels() to see if image has alpha -7f0a3419 update ChangeLog (tag: v1.3.1-rc1) -bab7efbe update NEWS -7138bf8f bump version to 1.3.1 -435b4ded update AUTHORS -47351229 update .mailmap -ff6c7f4e CONTRIBUTING.md: add C style / cmake-format notes -dd530437 add .cmake-format.py -adbe2cb1 cmake,cosmetics: apply cmake-format -15b36508 doc/webp-container-spec: rm future codec comment -c369c4bf doc/webp-lossless-bitstream-spec: improve link text -1de35f47 doc/webp-container-spec: don't use 'currently' -bb06a16e doc/webp-container-spec: prefer present tense -9f38b71e doc/webp-lossless-bitstream-spec: prefer present tense -7acb6b82 doc/webp-container-spec: avoid i.e. & e.g. -4967e7cd doc/webp-lossless-bitstream-spec: avoid i.e. & e.g. -e3366659 Merge "Do not find_package image libraries if not needed." into main -428588ef clarify single leaf node trees and use of canonical prefix coding -709ec152 Do not find_package image libraries if not needed. -8dd80ef8 fuzz_utils.h: lower kFuzzPxLimit w/ASan -8f187b9f Clean message calls in CMake -cba30078 WebPConfig.cmake.in: use calculated include path -6cf9a76a Merge "webp-lossless-bitstream-spec: remove use of 'dynamics'" into main -740943b2 Merge "Specialize and optimize ITransform_SSE2 using do_two" into main -2d547e24 Compare kFuzzPxLimit to max_num_operations -ac42dde1 Specialize and optimize ITransform_SSE2 using do_two -17e0ef1d webp-lossless-bitstream-spec: remove use of 'dynamics' -ed274371 neon.h,cosmetics: clear a couple lint warnings -3fb82947 cpu.h,cosmetics: segment defines -0c496a4f cpu.h: add WEBP_AARCH64 -8151f388 move VP8GetCPUInfo declaration to cpu.c -916548c2 Make kFuzzPxLimit sanitizer dependent -4070b271 advanced_api_fuzzer: reduce scaling limit -761f49c3 Merge "webp-lossless-bitstream-spec: add missing bits to ABNF" into main -84d04c48 webp-lossless-bitstream-spec: add missing bits to ABNF -0696e1a7 advanced_api_fuzzer: reduce scaling limit -93d88aa2 Merge "deps.cmake: remove unneeded header checks" into main -118e0035 deps.cmake: remove unneeded header checks -4c3d7018 webp-lossless-bitstream-spec: condense normal-prefix-code -a6a09b32 webp-lossless-bitstream-spec: fix 2 code typos -50ac4f7c Merge "cpu.h: enable NEON w/_M_ARM64EC" into main -4b7d7b4f Add contribution instructions -0afbd97b cpu.h: enable NEON w/_M_ARM64EC -349f4353 Merge changes Ibd89e56b,Ic57e7f84,I89096614 into main -8f7513b7 upsampling_neon.c: fix WEBP_SWAP_16BIT_CSP check -cbf624b5 advanced_api_fuzzer: reduce scaling limit -89edfdd1 Skip slow scaling in libwebp advanced_api_fuzzer -859f19f7 Reduce libwebp advanced_api_fuzzer threshold -a4f04835 Merge changes Ic389aaa2,I329ccd79 into main -1275fac8 Makefile.vc: fix img2webp link w/dynamic cfg -2fe27bb9 img2webp: normalize help output -24bed3d9 cwebp: reflow -near_lossless help text -0825faa4 img2webp: add -sharp_yuv/-near_lossless -d64e6d7d Merge "PaletteSortModifiedZeng: fix leak on error" into main -0e12a22d Merge "EncodeAlphaInternal: clear result->bw on error" into main -0edbb6ea PaletteSortModifiedZeng: fix leak on error -41ffe04e Merge "Update yapf style from "chromium" to "yapf"" into main -2d9d9265 Update yapf style from "chromium" to "yapf" -a486d800 EncodeAlphaInternal: clear result->bw on error -1347a32d Skip big scaled advanced_api_fuzzer -52b6f067 Fix scaling limit in advanced_api_fuzzer.c -73618428 Limit scaling in libwebp advanced_api_fuzzer.c -b54d21a0 Merge "CMakeLists.txt: allow CMAKE_INSTALL_RPATH to be set empty" into main -31c28db5 libwebp{,demux,mux}.pc.in: Requires -> Requires.private -d9a505ff CMakeLists.txt: allow CMAKE_INSTALL_RPATH to be set empty -bdf33d03 Merge tag 'v1.3.0' -b5577769 update ChangeLog (tag: v1.3.0-rc1, tag: v1.3.0) -0ba77244 update NEWS -e763eb1e bump version to 1.3.0 -2a8686fc update AUTHORS -106a57c1 Merge "*/Android.mk: add a check for NDK_ROOT" into main -c5e841c4 Merge "extras: WebpToSDL -> WebPToSDL" into main -dbc30715 Merge "xcframeworkbuild.sh: bump MACOSX_CATALYST_MIN_VERSION" into main -6fc1a9f9 */Android.mk: add a check for NDK_ROOT -d3e151fc doc/api.md,webp_js/README.md: Webp -> WebP -ed92a626 extras: WebpToSDL -> WebPToSDL -6eb0189b xcframeworkbuild.sh: bump MACOSX_CATALYST_MIN_VERSION -1d58575b CMake: align .pc variables with autoconf -e5fe2cfc webp-lossless-bitstream-spec,cosmetics: reflow paragraphs -0ceeeab9 webp-lossless-bitstream-spec: add amendment note -607611cd Merge "webp-container-spec: normalize section title case" into main -f853685e lossless: SUBTRACT_GREEN -> SUBTRACT_GREEN_TRANSFORM -786497e4 webp-lossless-bitstream-spec: fix inv color txfm description -c6ac672d webp-lossless-bitstream-spec: fix num_code_lengths check -b5700efb webp-lossless-bitstream-spec,cosmetics: grammar/capitalization -d8ed8c11 webp-container-spec: normalize section title case -52ec0b8f Merge changes Ie975dbb5,Ifc8c93af,I6ca7c5d6,I2e8d66f5,I152477b8 into main -5097ef62 webp-container-spec,cosmetics: grammar/capitalization -e3ba2b1f webp-lossless-bitstream-spec,cosmetics: reflow abstract -1e8e3ded webp-lossless-bitstream-spec: reword abstract re alpha -017cb6fa webp-container-spec,cosmetics: normalize range syntax -f6a4684b webp-lossless-bitstream-spec,cosmetics: normalize range syntax -54ebd5a3 webp-lossless-bitstream-spec: limit dist map lut to 69 cols -44741f9c webp-lossless-bitstream-spec: fix dist mapping example -fad0ece7 pnmdec.c: use snprintf instead of sprintf -3f73e8f7 sharpyuv: add SharpYuvGetVersion() -ce2f2d66 SharpYuvConvert: fix a race on SharpYuvGetCPUInfo -a458e308 sharpyuv_dsp.h: restore sharpyuv_cpu.h include -9ba800a7 Merge changes Id72fbf3b,Ic59d23a2 into main -979c0ebb sharpyuv: add SharpYuvGetCPUInfo -8bab09a4 Merge "*.pc.in: rename lib_prefix to webp_libname_prefix" into main -769387c5 cpu.c,cosmetics: fix a typo -a02978c2 sharpyuv/Makefile.am+cmake: add missing -lm -28aedcb9 *.pc.in: rename lib_prefix to webp_libname_prefix -c42e6d5a configure.ac: export an empty lib_prefix variable -dfc843aa Merge "*.pc.in: add lib prefix to lib names w/MSVC" into main -2498209b *.pc.in: add lib prefix to lib names w/MSVC -ac252b61 Merge "analysis_enc.c: fix a dead store warning" into main -56944762 analysis_enc.c: fix a dead store warning -d34f9b99 Merge "webp-lossless-bitstream-spec: convert BNF to ABNF" into main -dc05b4db Merge changes I96bc063c,I45880467,If9e18e5a,I6ee938e4,I0a410b28, ... into main -83270c7f webp-container-spec: add prose for rendering process -73b19b64 webp-container-spec: note reserved fields MUST be ignored -57101d3f webp-lossless-bitstream-spec: improve 'small' color table stmt -dfd32e45 webp-container-spec: remove redundant sentence -8a6185dd doc/webp-*: fix some punctuation, grammar -72776530 webp-lossless-bitstream-spec: convert BNF to ABNF -d992bb08 cmake: rename cpufeatures target to cpufeatures-webp -3ed2b275 webp-container-spec: clarify background color note -951c292d webp-container-spec: come too late -> out of order -902dd787 webp-container-spec: prefer hex literals -a8f6b5ee webp-container-spec: change SHOULD to MUST w/ANIM chunk -1dc59435 webp-container-spec: add unknown fields MUST be ignored -280a810f webp-container-spec: make padding byte=0 a MUST -41f0bf68 webp-container-spec: update note on trailing data -6bdd36db webp-container-spec: clarify Chunk Size is in bytes -87e36c48 Merge "webp_js/README.md,cosmetics: reflow some lines" into main -5b01f321 Merge "Update Windows makefile to build libsharpyuv library." into main -19b1a71c webp_js/README.md,cosmetics: reflow some lines -780db756 Update Windows makefile to build libsharpyuv library. -e407d4b3 CMakeLists.txt: replace GLUT_glut_LIBRARY w/GLUT::GLUT -abf73d62 Merge "WebPConfig.cmake.in: add find_dependency(Threads)" into main -25807fb4 Merge "cmake: restore compatibility with cmake < 3.12" into main -5dbc4bfa WebPConfig.cmake.in: add find_dependency(Threads) -b2a175dd Merge "Update wasm instructions." into main -cb90f76b Update wasm instructions. -02d15258 cmake: restore compatibility with cmake < 3.12 -5ba046e2 CMake: add_definitions -> add_compile_options -e68765af dsp,neon: use vaddv in a few more places -e8f83de2 Set libsharpyuv include dir to 'webp' subdirectory. -15a91ab1 cmake,cosmetics: apply cmake-format -0dd49d1a CMakeLists.txt: set @ONLY in configure_file() calls -62b1bfe8 Merge changes I2877e7bb,I777cad70,I15af7d1a,I686e6740,If10538a9, ... into main -95c8fe5f Merge changes Iecea3603,I9dc228ab into main -e7c805cf picture_csp_enc.c: remove SafeInitSharpYuv -6af8845a sharpyuv: prefer webp/types.h -639619ce cmake: fix dll exports -782ed48c sharpyuv,SharpYuvInit: add mutex protection when available -cad0d5ad sharyuv_{neon,sse2}.c: merge WEBP_USE_* sections -ef70ee06 add a few missing includes for NULL -f0f9eda4 sharpyuv.h: remove -9b902cba Merge "picture_csp_enc.c,CheckNonOpaque: rm unneeded local" into main -9c1d457c cmake/cpu.cmake: remove unused variable -9ac25bcb CMakeLists.txt,win32: match naming convention used by nmake -76c353ba picture_csp_enc.c,CheckNonOpaque: rm unneeded local -5000de54 Merge "cwebp: fix WebPPictureHasTransparency call" into main -e1729309 Merge "WebPPictureHasTransparency: add missing pointer check" into main -00ff988a vp8l_enc,AddSingleSubGreen: clear int sanitizer warnings -e2fecc22 dsp/lossless_enc.c: clear int sanitizer warnings -129cf9e9 dsp/lossless.c: clear int sanitizer warnings -ad7d1753 dsp/lossless_enc.c: clear int sanitizer warnings -5037220e VP8LSubtractGreenFromBlueAndRed_C: clear int sanitizer warnings -2ee786c7 upsampling_sse2.c: clear int sanitizer warnings -4cc157d4 ParseOptionalChunks: clear int sanitizer warning -892cf033 BuildHuffmanTable: clear int sanitizer warning -3a9a4d45 VP8GetSigned: clear int sanitizer warnings -704a3d0a dsp/lossless.c: quiet int sanitizer warnings -1a6c109c WebPPictureHasTransparency: add missing pointer check -c626e7d5 cwebp: fix WebPPictureHasTransparency call -866e349c Merge tag 'v1.2.4' -c170df38 Merge "Create libsharpyuv.a in makefile.unix." into main -9d7ff74a Create libsharpyuv.a in makefile.unix. -0d1f1254 update ChangeLog (tag: v1.2.4) -fcbc2d78 Merge "doc/*.txt: restrict code to 69 columns" into main -4ad0e189 Merge "webp-container-spec.txt: normalize fourcc spelling" into main -980d2488 update NEWS -9fde8127 bump version to 1.2.4 -7a0a9935 doc/*.txt: restrict code to 69 columns -c040a615 webp-container-spec.txt: normalize fourcc spelling -aff1c546 dsp,x86: normalize types w/_mm_cvtsi128_si32 calls -ab540ae0 dsp,x86: normalize types w/_mm_cvtsi32_si128 calls -8980362e dsp,x86: normalize types w/_mm_set* calls (2) -e626925c lossless: fix crunch mode w/WEBP_REDUCE_SIZE -83539239 dsp,x86: normalize types w/_mm_set* calls -8a4576ce webp-container-spec.txt: replace & with & -db870881 Merge "webp-container-spec.txt: make reserved 0 values a MUST" into main -01d7d378 webp-lossless-bitstream-spec: number all sections -337cf69f webp-lossless-bitstream-spec: mv Nomenclature after Intro -79be856e Merge changes I7111d1f7,I872cd62c into main -5b87983a webp-container-spec.txt: make reserved 0 values a MUST -bd939123 Merge changes I7a25b1a6,I51b2c2a0,I87d0cbcf,I6ec60af6,I0a3fe9dc into main -04764b56 libwebp.pc: add libsharpyuv to requires -7deee810 libsharpyuv: add pkg-config file -1a64a7e6 webp-container-spec.txt: clarify some SHOULDs -bec2c88a webp-container-spec.txt: move ChunkHeader to terminology -c9359332 webp-container-spec.txt: clarify 'VP8 '/'XMP ' fourccs -70fe3063 webp-container-spec.txt: rightsize table entries -ddbf3f3f webp-container-spec.txt: update 'key words' text -c151e95b utils.h,WEBP_ALIGN: make bitmask unsigned -748e92bb add WebPInt32ToMem -3fe15b67 Merge "Build libsharpyuv as a full installable library." into main -4f402f34 add WebPMemToInt32 -a3b68c19 Build libsharpyuv as a full installable library. -b4994eaa CMake: set rpath for shared objects -94cd7117 Merge "CMake: fix dylib versioning" into main -e91451b6 Fix the lossless specs a bit more. -231bdfb7 CMake: fix dylib versioning -bfad7ab5 CMakeLists.txt: correct libwebpmux name in WebPConfig.cmake -c2e3fd30 Revert "cmake: fix webpmux lib name for cmake linking" -7366f7f3 Merge "lossless: fix crunch mode w/WEBP_REDUCE_SIZE" into main -84163d9d lossless: fix crunch mode w/WEBP_REDUCE_SIZE -d01c1eb3 webp-lossless-bitstream-spec,cosmetics: normalize capitalization -8813ca8e Merge tag 'v1.2.3' -3c4a0fbf update ChangeLog (tag: v1.2.3) -56a480e8 dsp/cpu.h: add missing extern "C" -62b45bdd update ChangeLog (tag: v1.2.3-rc1) -8764ec7a Merge changes Idb037953,Id582e395 into 1.2.3 -bcb872c3 vwebp: fix file name display in windows unicode build -67c44ac5 webpmux: fix -frame option in windows unicode build -8278825a makefile.unix: add sharpyuv objects to clean target -14a49e01 update NEWS -34b1dc33 bump version to 1.2.3 -0b397fda update AUTHORS -c16488ac update .mailmap -5a2d929c Merge "unicode.h: set console mode before using wprintf" into main -169f867f unicode.h: set console mode before using wprintf -a94b855c Merge "libsharpyuv: add version defines" into main -f83bdb52 libsharpyuv: add version defines -bef0d797 unicode_gif.h: fix -Wdeclaration-after-statement -404c1622 Rename Huffman coding to prefix coding in the bitstream spec -8895f8a3 Merge "run_static_analysis.sh: fix scan-build archive path" into main -92a673d2 Merge "Add -fvisibility=hidden flag in CMakeLists." into main -67c1d722 Merge "add WEBP_MSAN" into main -1124ff66 Add -fvisibility=hidden flag in CMakeLists. -e15b3560 add WEBP_MSAN -ec9e782a sharpyuv: remove minimum image size from sharpyuv library -7bd07f3b run_static_analysis.sh: fix scan-build archive path -5ecee06f Merge "sharpyuv: increase precision of gamma<->linear conversion" into main -f81dd7d6 Merge changes I3d17d529,I53026880,I1bd61639,I6bd4b25d,Icfec8fba into main -2d607ee6 sharpyuv: increase precision of gamma<->linear conversion -266cbbc5 sharpyuv: add 32bit version of SharpYuvFilterRow. -9fc12274 CMake: add src to webpinfo includes -7d18f40a CMake: add WEBP_BUILD_WEBPINFO to list of checks for exampleutil -11309aa5 CMake: add WEBP_BUILD_WEBPMUX to list of checks for exampleutil -4bc762f7 CMake: link imageioutil to exampleutil after defined -0d1b9bc4 WEBP_DEP_LIBRARIES: use Threads::Threads -20ef48f0 Merge "sharpyuv: add support for 10/12/16 bit rgb and 10/12 bit yuv." into main -93c54371 sharpyuv: add support for 10/12/16 bit rgb and 10/12 bit yuv. -53cf2b49 normalize WebPValidatePicture declaration w/definition -d3006f4b sharpyuv: slightly improve precision -ea967098 Merge changes Ia01bd397,Ibf3771af into main -11bc8410 Merge changes I2d317c4b,I9e77f6db into main -30453ea4 Add an internal WebPValidatePicture. -6c43219a Some renamings for consistency. -4f59fa73 update .mailmap -e74f8a62 webp-lossless-bitstream-spec,cosmetics: normalize range syntax -5a709ec0 webp-lossless-bitstream-spec,cosmetics: fix code typo -a2093acc webp-lossless-bitstream-spec: add amendment note -86c66930 webp-lossless-bitstream-spec: fix BNF -232f22da webp-lossless-bitstream-spec: fix 'simple code' snippet -44dd765d webp-lossless-bitstream-spec: fix ColorTransform impl -7a7e33e9 webp-lossless-bitstream-spec: fix TR-pixel right border note -86f94ee0 Update lossless spec with Huffman codes. -a3927cc8 sharpyuv.c,cosmetics: fix indent -6c45cef7 Make sure the stride has a minimum value in the importer. -0c8b0e67 sharpyuv: cleanup/cosmetic changes -dc3841e0 {histogram,predictor}_enc: quiet int -> float warnings -a19a25bb Replace doubles by floats in lossless misc cost estimations. -42888f6c Add an option to enable static builds. -7efcf3cc Merge "Fix typo in color constants: Marix -> Matrix" into main -8f4b5c62 Fix typo in color constants: Marix -> Matrix -90084d84 Merge "demux,IsValidExtendedFormat: remove unused variable" into main -ed643f61 Merge changes I452d2485,Ic6d75475 into main -8fa053d1 Rename SharpYUV to SharpYuv for consistency. -99a87562 SharpYuvComputeConversionMatrix: quiet int->float warnings -deb426be Makefile.vc: add sharpyuv_csp.obj to SHARPYUV_OBJS -779597d4 demux,IsValidExtendedFormat: remove unused variable -40e8aa57 Merge "libsharpyuv: add colorspace utilities" into main -01a05de1 libsharpyuv: add colorspace utilities -2de4b05a Merge changes Id9890a60,I376d81e6,I1c958838 into main -b8bca81f Merge "configure.ac: use LT_INIT if available" into main -e8e77b9c Merge changes I479bc487,I39864691,I5d486c2c,I186d13be into main -7e7d5d50 Merge ".gitignore: add Android Studio & VS code dirs" into main -10c50848 normalize label indent -89f774e6 mux{edit,internal}: fix leaks on error -2d3293ad ExUtilInitCommandLineArguments: fix leak on error -ec34fd70 anim_util: fix leaks on error -e4717287 gif2webp: fix segfault on OOM -e3cfafaf GetBackwardReferences: fail on alloc error -a828a59b BackwardReferencesHashChainDistanceOnly: fix segfault on OOM -fe153fae VP8LEncodeStream: fix segfault on OOM -919acc0e .gitignore: add Android Studio & VS code dirs -efa0731b configure.ac: use LT_INIT if available -0957fd69 tiffdec: add grayscale support -e685feef Merge "Make libsharpyuv self-contained by removing dependency on cpu.c" into main -841960b6 Make libsharpyuv self-contained by removing dependency on cpu.c -617cf036 image_dec: add WebPGetEnabledInputFileFormats() -7a68afaa Let SharpArgbToYuv caller pass in an RGB>YUV conversion matrix. -34bb332c man/cwebp.1: add note about crop/resize order -f0e9351c webp-lossless-bitstream-spec,cosmetics: fix some typos -5ccbd6ed vp8l_dec.c,cosmetics: fix a few typos -c3d0c2d7 fix ios build scripts after sharpyuv dep added -d0d2292e Merge "Make libwebp depend on libsharpyuv." into main -03d12190 alpha_processing_neon.c: fix 0x01... typo -d55d447c Make libwebp depend on libsharpyuv. -e4cbcdd2 Fix lossless encoding for MIPS. -924e7ca6 alpha_processing_neon.c: fix Dispatch/ExtractAlpha_NEON -0fa0ea54 Makefile.vc: use /MANIFEST:EMBED -29cc95ce Basic version of libsharpyuv in libwebp, in C. -a30f2190 examples/webpmux.c: fix a couple of typos -66b3ce23 Fix bad overflow check in ReadTIFF() -54e61a38 Markdownify libwebp docs and reorganize them. -b4533deb CMakeLists.txt,cosmetics: break long line -b9d2f9cd quant_enc.c: use WEBP_RESTRICT qualifier -ec178f2c Add progress hook granularity in lossless -26139c73 Rename MAX_COST to MAX_BIT_COST in histogram_enc.c -13b82816 cmake: fix webpmux lib name for cmake linking -88b6a396 webp-container-spec.txt,cosmetics: normalize formatting -6f496540 Merge tag 'v1.2.2' -4074acf8 dsp.h: bump msvc arm64 version requirement to 16.6 -b0a86089 update ChangeLog (tag: v1.2.2) -6db8248c libwebp: Fix VP8EncTokenLoop() progress -827a307f BMP enc: fix the transparency case -db25f1b4 libwebp: Fix VP8EncTokenLoop() progress -286e7fce libwebp: do not destroy jpeg codec twice on error -6e8a4126 libwebp: do not destroy jpeg codec twice on error -faf21968 Merge "BMP enc: fix the transparency case" into main -480cd51d BMP enc: fix the transparency case -9195ea05 update ChangeLog (tag: v1.2.2-rc2) -4acae017 update NEWS -883f0633 man/img2webp.1: update date -567e1f44 Reword img2webp synopsis command line -1b0c15db man/img2webp.1: update date -17bade38 Merge "Reword img2webp synopsis command line" into main -a80954a1 Reword img2webp synopsis command line -f084244d anim_decode: fix alpha blending with big-endian -b217b4ff webpinfo: fix fourcc comparison w/big-endian -ec497b75 Merge "anim_decode: fix alpha blending with big-endian" into main -e4886716 anim_decode: fix alpha blending with big-endian -e3cb052c webpinfo: fix fourcc comparison w/big-endian -a510fedb patch-check: detect duplicated files -f035d2e4 update ChangeLog (tag: v1.2.2-rc1) -7031946a update NEWS -973390b6 bump version to 1.2.2 -abd6664f update AUTHORS -5b7e7930 Merge "add missing USE_{MSA,NEON} checks in headers" into main -02ca04c3 add missing USE_{MSA,NEON} checks in headers -e94716e2 xcframeworkbuild.sh: place headers in a subdir -c846efd8 patch-check: commit subject length check -b6f756e8 update http links -8f5cb4c1 update rfc links -8ea81561 change VP8LPredictorFunc signature to avoid reading 'left' -6b1d18c3 webpmux: fix the -bgcolor description -3368d876 Merge "webpmux: add "-set bgcolor A,R,G,B"" into main -f213abf6 webpinfo: print the number of warnings -50c97c30 webpmux: add "-set bgcolor A,R,G,B" -2c206aaf Remove CMakeLists.txt check in compile.sh -96e3dfef Merge "infra/common.sh: add shard_should_run()" into main -0e0f74b7 infra/common.sh: add shard_should_run() -35b7436a Jenkins scripts port: update shell function comments -21d24b4c webp-container-spec.txt: remove 'experimental' markers -cdcf8902 Merge "Port Jenkins script: compile" into main -dc683cde Jenkins scripts port: static analysis -0858494e Port Jenkins script: compile -c2cf6a93 Jenkins scripts port: android compilation -df0e808f presubmit: Add pylint-2.7 and .pylintrc -676c57db patch-check: shfmt -7bb7f747 patch-check: Add shellcheck -abcd1797 Reformat docstrings and imports -edaf0895 Port Jenkins scripts: compile js -b9622063 Set CheckPatchFormatted flags to fail on diffs -e23cd548 dsp.h: enable NEON w/VS2019+ ARM64 targets -3875c7de CMakeLists.txt: set minimum version to 3.7 -1a8f0d45 Have a hard-coded value for memset in TrellisQuantizeBlock. -93480160 Speed up TrellisQuantizeBlock -45eaacc9 Convert deprecated uint32 to uint32_t. -42592af8 webp,cmake: Remove unnecessary include dirs -e298e05f Add patch-check steps in PRESUBMIT.py -29148919 Merge tag 'v1.2.1' -9ce5843d update ChangeLog (tag: v1.2.1) -d9191588 fuzzer/*: normalize src/ includes -c5bc3624 fuzzer/*: normalize src/ includes -53b6f762 fix indent -d2caaba4 fix indent -731246ba update ChangeLog (tag: v1.2.1-rc2) -d250f01d dsp/*: use WEBP_HAVE_* to determine Init availability -1fe31625 dsp/*: use WEBP_HAVE_* to determine Init availability -3a4d3ecd update NEWS -b2bc8093 bump version to 1.2.1 -e542fc7a update AUTHORS -e0241154 Merge "libwebp/CMake: Add to webp incl" into main -edea6444 libwebp/CMake: Add to webp incl -ece18e55 dsp.h: respect --disable-sse2/sse4.1/neon -a89a3230 wicdec: support alpha from WebP WIC decoder -26f4aa01 Merge "alpha_processing: fix visual studio warnings" into main -8f594663 alpha_processing: fix visual studio warnings -46d844e6 Merge "cpu.cmake: fix compiler flag detection w/3.17.0+" into main -298d26ea Merge changes I593adf92,If20675e7,Ifac68eac into main -a1e5dae0 alpha_processing*: use WEBP_RESTRICT qualifier -327ef24f cpu.cmake: fix compiler flag detection w/3.17.0+ -f70819de configure: enable libwebpmux by default -dc7e2b42 configure: add informational notices when disabling binaries -9df23ddd configure: move lib flag checks before binaries -a2e18f10 Merge "WebPConfig.config.in: correct WEBP_INCLUDE_DIRS" into main -e1a8d4f3 Merge "bit_reader_inl_utils: uniformly apply WEBP_RESTRICT" into main -4de35f43 rescaler.c: fix alignment -0f13eec7 bit_reader_inl_utils: uniformly apply WEBP_RESTRICT -277d3074 Fix size_t overflow in WebPRescalerInit -97adbba5 WebPConfig.config.in: correct WEBP_INCLUDE_DIRS -b60d4603 advanced_api_fuzzer: add extreme config value coverage -72fe52f6 anim_encode.c,cosmetics: normalize indent -116d235c anim_encode: Fix encoded_frames_[] overflow -6f445b3e CMake: set CMP0072 to NEW -b1cf887f define WEBP_RESTRICT for MSVC -3e265136 Add WEBP_RESTRICT & use it in VP8BitReader -f6d29247 vp8l_dec::ProcessRows: fix int overflow in multiply -de3b4ba8 CMake: add WEBP_BUILD_LIBWEBPMUX -7f09d3d1 CMakeLists.txt: rm libwebpmux dep from anim_{diff,dump} -4edea4a6 Init{RGB,YUV}Rescaler: fix a few more int overflows -c9e26bdb rescaler_utils: set max valid scaled w/h to INT_MAX/2 -28d488e6 utils.h: add SizeOverflow() -695bdaa2 Export/EmitRescaledRowsRGBA: fix pointer offset int overflow -685d073e Init{RGB,YUV}Rescaler: fix int overflows in multiplication -d38bd0dd WebPFlipBuffer: fix integer overflow -109ff0f1 utils: allow MALLOC_LIMIT to indicate a max -a2fce867 WebPRescalerImportRowExpand_C: promote some vals before multiply -776983d4 AllocateBuffer: fix int multiplication overflow check -315abbd6 Merge "Revert "Do not use a palette for one color images."" -eae815d0 Merge changes Ica3bbf75,I82f82954 -afbca5a1 Require Emscripten 2.0.18 -3320416b CMakeLists,emscripten: use EXPORTED_RUNTIME_METHODS -29145ed6 Update README instructions for using Emscripten -1f579139 cosmetics: remove use of 'sanity' / 'master' -29b6129c WebPAnimEncoderNewInternal: remove some unnecessary inits -b60869a1 Revert "Do not use a palette for one color images." -6fb4cddc demux: move padded size calc post unpadded validation -05b72d42 vp8l_enc.c: normalize index types -b6513fba Do not use a palette for one color images. -98bbe35b Fix multi-threading with palettes. -b1674240 Add modified Zeng's method to palette sorting. -88c90c45 add CONTRIBUTING.md -6a9916d7 WebPRescalerInit: add missing int64_t promotion -b6cf52d5 WebPIoInitFromOptions: treat use_scaling as a bool -3b12b7f4 WebPIoInitFromOptions: treat use_cropping as a bool -595fa13f add WebPCheckCropDimensions() -8fdaecb0 Disable cross-color when palette is used. -8933bac2 WebPIoInitFromOptions: respect incoming bypass_filtering val -7d416ff0 webpdec,cosmetics: match error text to function call -ec6cfeb5 Fix typo on WebPPictureAlloc() in README -7e58a1a2 *.cmake: add license header -5651a6b2 cmake: fix .so versioning -25ae67b3 xcframeworkbuild.sh: add arm64 simulator target -5d4ee4c3 cosmetics: remove use of the term 'dummy' -01b38ee1 faster CollectColorXXXTransforms_SSE41 -652aa344 Merge "Use BitCtz for FastSLog2Slow_C" -0320e1e3 add the missing default BitsCtz() code -8886f620 Use BitCtz for FastSLog2Slow_C -fae41617 faster CombinedShannonEntropy_SSE2 -5bd2704e Introduce the BitCtz() function. -fee64287 Merge "wicdec,icc: treat unsupported op as non-fatal" -33ddb894 lossless_sse{2,41}: remove some unneeded includes -b27ea852 wicdec,icc: treat unsupported op as non-fatal -b78494a9 Merge "Fix undefined signed shift." -e79974cd Fix undefined signed shift. -a8853394 SSE4.1 versions of BGRA to RGB/BGR color-space conversions -a09a6472 SSE4.1 version of TransformColorInverse -401da22b Merge "pngdec: check version before using png_get_chunk_malloc_max" -26907822 pngdec: check version before using png_get_chunk_malloc_max -06c1e72e Code cleanup -8f0d41aa Merge changes Id135bbf4,I99e59797 -373eb170 gif2webp: don't store loop-count if there's only 1 frame -759b9d5a cmake: add WEBP_USE_THREAD option -926ce921 cmake: don't install binaries from extras/ -9c367bc6 WebPAnimDecoderNewInternal: validate bitstream before alloc -47f64f6e filters_sse2: import Chromium change -cc3577e9 fuzzer/*: use src/ based include paths -004d77ff Merge tag 'v1.2.0' -fedac6cc update ChangeLog (tag: v1.2.0-rc3, tag: v1.2.0) -170a8712 Fix check_c_source_compiles with pthread. -ceddb5fc Fix check_c_source_compiles with pthread. -85995719 disable CombinedShannonEntropy_SSE2 on x86 -289757fe TiffDec: enforce stricter mem/dimension limit on tiles -8af7436f Merge "{ios,xcframework}build.sh: make min version(s) more visible" into 1.2.0 -e56c3c5b pngdec: raise memory limit if needed -8696147d pngdec: raise memory limit if needed -13b8e9fe {ios,xcframework}build.sh: make min version(s) more visible -a9225410 animdecoder_fuzzer: fix memory leak -d6c2285d update gradle to 6.1.1 -8df77fb1 animdecoder_fuzzer: fix memory leak -52ce6333 update NEWS -28c49820 bump version to 1.2.0 -7363dff2 webp/encode.h: restore WEBP_ENCODER_ABI_VERSION to v1.1.0 -826aafa5 update AUTHORS -63258823 animdecoder_fuzzer: validate canvas size -9eb26381 CMake: remove duplicate "include(GNUInstallDirs)" -2e7bed79 WebPPicture: clarify the ownership of user-owned data. -cccf5e33 webpmux: add an '-set loop ' option -c9a3f6a1 Merge changes Ie29f9867,I289c54c4 -319f56f1 iosbuild.sh: sync some aspects of xcframeworkbuild.sh -e8e8db98 add xcframeworkbuild.sh -ae545534 dsp.h: allow config.h to override MSVC SIMD autodetection -fef789f3 Merge "cmake: fix per-file assembly flags" -fc14fc03 Have C encoding predictors use decoding predictors. -7656f0b3 README,cosmetics: fix a couple typos -d2e245ea cmake: disable webp.js if WEBP_ENABLE_SIMD=1 -96099a79 cmake: fix per-file assembly flags -5abb5582 Merge "cmake: fix compilation w/Xcode generator" -8484a120 cmake: fix compilation w/Xcode generator -d7bf01c9 Merge changes Ifcae0f38,Iee2d7401 -36c81ff6 WASM-SIMD: port 2 patches from rreverser@'s tree -988b02ab Merge "Couple of fixes to allow SIMD on Emscripten" -26faf770 wicdec: fail with animated images -ab2d08a8 [cd]webp: document lack of animated webp support -52273943 Couple of fixes to allow SIMD on Emscripten -8870ba7f Fix skia bug #10952 -4b3c6953 Detect if StoreFrame read more than anmf_payload_size bytes -17fd4ba8 webp/decode.h,cosmetics: normalize 'flip' comment -411d3677 remove some unreachable break statements -3700ffd7 WebPPictureHasTransparency: remove unreachable return -83604bf3 {animencoder,enc_dec}_fuzzer: convert some abort()s to returns -eb44119c Merge changes I8ae09473,I678c8b1e -9f6055fc fuzz_utils.h: rename max() to Max() -695788e7 fuzz_utils.h: make functions WEBP_INLINE -906c1fcd make ImgIoUtilReadFile use WebPMalloc instead of malloc -8cb7e536 rename demux_api_fuzzer.c -> mux_demux_api_fuzzer.c -443db47d add animdecoder_fuzzer.cc -36a6eea3 Merge "import fuzzers from oss-fuzz/chromium" -ec5f12c1 Makefile.vc: remove deprecated /Gm option -64425a08 picture_tools_enc: fix windows build warning -bd94090a import fuzzers from oss-fuzz/chromium -cf847cba use WEBP_DSP_INIT_FUNC for Init{GammaTables*,GetCoeffs} -55a080e5 Add WebPReplaceTransparentPixels() in dsp -84739717 GetBackgroundColorGIF: promote to uint32_t before << 24 -def64e92 cwebp: Fix -print_psnr for near_lossless -cf2f88b3 Add palette and spatial for q >= 75 and -m 5 -f0110bae Add no-color cache configuration to the cruncher -749a8b99 Better estimate of the cache cost. -4f9f00cc Use spatial predictors on top of palette no matter what. -7658c686 Add spatial prediction on top of palette in cruncher. -133ff0e3 webp_js: force WASM=0 option explicitly -e3c259a2 Fix integer overflow in EmitFancyRGB. -b3ff0bde man/{gif2,img2}webp,webpmux: normalize some wording -f9b30586 fix ABI breakage introduced by 6a0ff358 -1d58dcfc README.webp_js: update note about emscripten version -44070266 README.webp_js: s/fastcomp/upstream/ -2565fa8f README.webp_js: update cmake command -47309ef5 webp: WEBP_OFFSET_PTR() -687ab00e DC{4,8,16}_NEON: replace vmovl w/vaddl -1b92fe75 DC16_NEON,aarch64: use vaddlv -53f3d8cf dec_neon,DC8_NEON: use vaddlv instead of movl+vaddv -27d08240 Fix integer overflow in WebPAnimDecoderGetNext() -69776e38 Merge "remove call to MBAnalyzeBestIntra4Mode for method >= 5" -a99078c1 remove call to MBAnalyzeBestIntra4Mode for method >= 5 -22e404cc CMakeLists.txt: fix set(CACHE) argument order -71690b52 fix MSVC warning -6a0ff358 Enc: add a qmin / qmax range for quality factor -0fa56f30 Merge tag 'v1.1.0' -6cf504d0 PNM decoding: handle max_value != 255 -d7844e97 update ChangeLog (tag: v1.1.0-rc2, tag: v1.1.0) -7f006436 Makefile.vc: fix webp_quality.exe link -cf047e83 Makefile.vc: fix webp_quality.exe link -c074c653 update NEWS -30f09551 bump version to 1.1.0 -a76694a1 update AUTHORS -6e3ef7b3 extras: fix WEBP_SWAP_16BIT_CSP check -47178dbd extras: add WebPUnmultiplyARGB() convenience function -22cbae33 idec_dec: fix 0 offset of NULL pointer -290dd0b4 muxread: fix 0 offset of NULL pointer -0df474ac Merge "lossless_(enc_|)sse2: avoid offsetting a NULL pointer" -c6b75a19 lossless_(enc_|)sse2: avoid offsetting a NULL pointer -295e5e38 fix UBSAN warning -e2575e05 DC8_NEON,aarch64: use vaddv -b0e09e34 dec_neon: Fix build failure under some toolchains -cf0e903c dsp/lossless: Fix non gcc ARM builds -bb7bc40b Remove ubsan errors. -78881b76 CMake: fix GLUT library link -9f750f7a cmake: fix BUILD_SHARED_LIBS build on mac -17850e74 libwebp: Remove char-subscripts warning in pnmdec.c -2fa2552d Merge "Expose WebPMalloc() in addition to WebPFree()" -a4df4aae Expose WebPMalloc() in addition to WebPFree() -853ea3d8 imageio/tiff: Return error before allocating bad tile size -af650c0b Fix a Wxor-used-as-pow false positive -601ef17c libwebp.py: update to swig 3.0.12 -0e48d889 bugfix: last alpha rows were incorrectly decoded -24d2ccb4 webp: Fix imageio ReadPNM() TUPLTYPE -fab8f9cf cosmetics: normalize '*' association -94138e0e update .gitignore -0fe1a89d update ChangeLog (tag: v1.0.3-rc1, tag: v1.0.3) -2ad0916d update NEWS -1287362b bump version to 1.0.3 -7b968cc2 update AUTHORS -9d6988f4 Fix the oscillating prediction problem at low quality -312f74d0 makefile.unix: allow *_LIBS to be overridden w/EXTRA_LIBS -92dbf237 filters_sse2,cosmetics: shorten some long lines -a277d197 filters_sse2.c: quiet integer sanitizer warnings -804540f1 Fix cpufeatures in CMake. -bf00c15b Add CMake option for bittrace. -a788b498 filters_sse2.c: quiet integer sanitizer warnings -e6a92c5e filters.c: quiet integer sanitizer warnings -ec1cc40a lossless.c: remove U32 -> S8 conversion warnings -1106478f remove conversion U32 -> S8 warnings -812a6b49 lossless_enc: fix some conversion warning -4627c1c9 lossless_enc,TransformColorBlue: quiet uint32_t conv warning -c84673a6 lossless_enc_sse{2,41}: quiet signed conv warnings -776a7757 dec_sse2: quiet signed conv warnings -bd39c063 Merge "thread_utils: release mutex before signaling" -0550576f Merge "(alpha_processing,enc}_sse2: quiet signed conv warnings" -6682f2c4 thread_utils: release mutex before signaling -e78dea75 (alpha_processing,enc}_sse2: quiet signed conv warnings -9acf18ba iosbuild.sh: add WebP{Demux,Mux}.framework -b9be7e65 vwebp: remove the -fit option (and make it default) -1394a2bb Merge "README.webp_js: update Emscripten.cmake note" -dd3e7f8a README.webp_js: update Emscripten.cmake note -32cf8801 predictor_enc,GetBestGreenRedToBlue: quiet implicit conv warnings -e1c8acb5 Merge "vwebp: add a -fit option" -cbd23dd5 vwebp: add a -fit option -2e672351 bit_writer_utils,Flush: quiet implicit conversion warnings -1326988d swig: update libwebp_python_wrap.c -0e7f8548 update generated swig files -17ed1438 Merge "PutLE{16,24}: quiet implicit conversion warnings" -24686538 PutLE{16,24}: quiet implicit conversion warnings -153bb3a0 fix some clang-7 warnings: -ab2dc893 Rescaler: fix rounding error -aa65f89a HistogramCombineStochastic: fix free of uninit value -af0bac64 Merge "encode.h: mention 'exact' default in WebPEncodeLossless*" -6d2e11ec encode.h: mention 'exact' default in WebPEncodeLossless* -8c3f04fe AndroidCPUInfo: reorder terms in conditional -fcfd9c71 BitTrace: if BITTRACE is > 0, record and print syntax bits used -067031ea Speedups for unused Huffman groups. -01ac46ba libwebp: Display "libjpeg error:" in imageio/jpegdec -d9a662e1 WebPRescalerGetScaledDimensions: round scaled dimension up -62eb3f08 libwebp: Fix missing '{' in README -e05f785a Merge "unicode,INIT_WARGV: add missing cast" -63c9a69f tag the VP8LHashPix() function for potential uint roll-over -2b7214ab unicode,INIT_WARGV: add missing cast -bf424b46 tag the GetPixPairHash64() function for potential uint roll-over -7d05d6ca Have the color cache computation be u32-bit only. -6bcf8769 Remove BINARYEN_METHOD in wasm settings. -2b98df90 update ChangeLog (tag: v1.0.2-rc1, tag: v1.0.2) -61e372b7 update NEWS -7ae658a0 bump version to 1.0.2 -51c4907d update AUTHORS -666bd6c6 man/cwebp.1: refine near-lossless text -561cdce5 Clarify the doc about GetFeatures. -aec2cf02 near_lossless: fix fuzzing-detected integer overflow -928a75de webp: Fix VP8LBitWriterClone() bug -5173d4ee neon IsFlat -5b081219 IsFlat: inline when possible -381b7b54 IsFlat: use int for thresh -6ed15ea1 fix unprobable leak in webp_sdl.c -22bbb24e Merge "IsFlat: return int" -8b3fb238 Merge tag 'v1.0.1' -f435de95 IsFlat: return int -41521aed utils.h: only define WEBP_NEED_LOG_TABLE_8BIT when needed -9f4d4a3f neon: GetResidualCost -0fd7514b neon: SetResidualCoeffs -f95a996c Simpler histogram clustering. -e85d3313 update ChangeLog (tag: v1.0.1-rc2, tag: v1.0.1) -fa8210e4 Fix pair update in stochastic entropy merging. -fd198f73 add codereview.settings -825389ac README.mux: add a reference to the AnimDecoder API -3be698c3 CMake: fix webp_js compilation -485ff86f Fix pair update in stochastic entropy merging. -4cd0582d CMake: fix webp_js compilation -4cbb4caf update NEWS -f5a5918d bump version to 1.0.1 -d61385db Speed-up: Make sure we only initialize histograms when needed. -6752904b Speed-up: Make sure we only initialize histograms when needed. -0c570316 update AUTHORS -301a2dda img2webp: add help note about arguments from a file -f0abab92 Speedups for empty histograms. -f2dfd925 Split HistogramAdd to only have the high level logic in C. -06b7bc7d Fix compilation on windows and clang-cl+ninja. -b6284d82 img2webp: add help note about arguments from a file -decf6f6b Speedups for empty histograms. -dea3e899 Split HistogramAdd to only have the high level logic in C. -632798ae Merge "Fix compilation on windows and clang-cl+ninja." -dc1a9518 Merge "libwebp: Unicode command tools on Windows" -9cf9841b libwebp: Unicode command tools on Windows -98179495 remove some minor TODOs -a376e7b9 Fix compilation on windows and clang-cl+ninja. -cbf82cc0 Remove AVX2 files. -5030e902 Merge "TIFF decoder: remove unused KINV definition" -ac543311 Remove a few more useless #defines -123d3306 TIFF decoder: remove unused KINV definition -ef1094b0 Merge "- install pkg-config files during the CMake build" -b911fbc9 libwebp: Remove duplicate GIFDisplayError in anim_util -eee00b66 - install pkg-config files during the CMake build -ac3ec8c9 Merge "Clean-up the common sources in dsp." -3e13da7b Clean-up the common sources in dsp. -5c395f1d libwebp: cmake-format all -e7a69729 libwebp: Add extras targets in CMakeLists.txt -e52485d6 libwebp: Rename macros in webpmux.c -92dc0f09 clean-up MakeInputImageCopy() -39952de2 VP8IteratorImport: add missing 'const' -382af7a2 clean-up WebPBlendAlpha -14d020f6 libwebp: Use ExUtilGet*() in anim_diff -0d92ff25 libwebp: remove useless variable in gif2webp -556cb1b4 Merge "CMake: Set WEBP_BUILD_GIF2WEBP to off" -da26ee49 CMake: Set WEBP_BUILD_GIF2WEBP to off -b2a867c0 cwebp: Don't premultiply during -resize if -exact -637141bc pngdec: fix build w/libpng < 1.4.x -bc5092b1 pngdec: set memory functions -50d8345a Fix CMake math library. -6aa3e8aa Fix math library on Visual Studio. -d71df4e2 Fix math library finding in CMake. -de08d727 cosmetics: normalize include guard comment -009562b4 vwebp: Fix bug when Dispose then NoBlend frames -423f2579 Fix up CMake to create targets. -907208f9 Wait for all threads to be done in DecodeRemaining. -4649b3c4 vwebp: Add background color display option -78ad57a3 Fix bad glClearColor parameters -da96d8d9 Allow for a non-initialized alpha decompressor in DoRemap. -2563db47 fix rescaling rounding inaccuracy -211f37ee fix endian problems in pattern copy -5f0f5c07 Make sure partition #0 is read before VP8 data in IDecode. -de98732b fix GetColorf() bug -4338cd36 misc fixes in libwebpmux -e00af13e fix signatures after a9ceda7ff1 -a9ceda7f Speed-up chunk list operations. -2281bbf6 Merge "Better handling of bogus Huffman codes." -39cb9aad Better handling of bogus Huffman codes. -89cc9d37 Merge "fix read-overflow while parsing VP8X chunk" -95fd6507 fix read-overflow while parsing VP8X chunk -9e729fe1 Fix VP8IoTeardownHook being called twice on worker sync failure -29fb8562 Merge "muxread,anmf: fail on multiple image chunks" -eb82ce76 muxread,anmf: fail on multiple image chunks -1344a2e9 fix alpha-filtering crash when image width is larger than radius -be738c6d muxread,ChunkVerifyAndAssign: validate chunk_size -2c70ad76 muxread,CreateInternal: fix riff size checks -569001f1 Fix for thread race heap-use-after-free -c56a02d9 Android.mk: use LOCAL_EXPORT_C_INCLUDES w/public libs -15795596 CMakeLists.txt,cosmetics: normalize if() formatting -1a44c233 Merge "cmake: add support for webpmux" -e9569ad7 Merge "configure,*am,cosmetics: s/WANT_/BUILD_/" -35c7de6f cmake: add support for webpmux -0f25e61c WebpToSDL(): fix the return value in case of error -5d8985de configure,*am,cosmetics: s/WANT_/BUILD_/ -895fd28f Merge "man/Makefile.am: add img2webp.1" -5cf3e2af man/Makefile.am: add img2webp.1 -2a9de5b9 Add build rules for anim_diff & anim_dump utils. -71ed73cf fix invalid check for buffer size -af0e4fbb gif2webp: fix transcode of loop count=65535 -dce5d764 Limit memory allocation when reading invalid Huffman codes. -f9df0081 Merge "cmake: quiet glut deprecation warnings on OS X" -dc39b16f webpmux.1: correct grammar -c7aa1264 cwebp.c: fix a missing \n -53aa51e9 Merge tag 'v1.0.0' -698b8844 update ChangeLog (tag: v1.0.0) -8d510751 webp-container-spec: correct frame duration=0 note -e6b2164e vwebp: Copy Chrome's behavior w/frame duration == 0 -094b3b28 cmake: quiet glut deprecation warnings on OS X -71c39a06 webp-container-spec: correct frame duration=0 note -fd3d5756 vwebp: Copy Chrome's behavior w/frame duration == 0 -b0c966fb Build vwebp from CMake. -d20b7707 update ChangeLog (tag: v1.0.0-rc3) -0d5fad46 add WEBP_DSP_INIT / WEBP_DSP_INIT_FUNC -d77bf512 add WEBP_DSP_INIT / WEBP_DSP_INIT_FUNC -c1cb86af fix 16b overflow in SSE2 -e577feb7 makefile.unix: add DEBUG flag for compiling w/ debug-symbol -99be34b3 cwebp,get_disto: fix bpp output -e122e511 cwebp,get_disto: fix bpp output -f5565ca8 cmake: Make sure we use near-lossless by default. -d898dc14 fix bug in WebPImport565: alpha value was not set -1c8f358d Fix CMake with WASM. -a0215fb7 webp_js: fix webp_js demo html -882784b0 update ChangeLog (tag: v1.0.0-rc2) -2f930e08 Revert "Use proper targets for CMake." -8165e8fb Use proper targets for CMake. -3f157dd5 Remove some very hard TODOs. -abb47760 Merge "Use proper targets for CMake." -cd758a17 {de,}mux/Makefile.am: add missing headers -e155dda0 Use proper targets for CMake. -b892b8ba makefile.unix,dist: use ascii for text output -64a57d05 add -version option to anim_dump,anim_diff and img2webp -994be82d Merge "Remove some very hard TODOs." -4033e1d7 Remove some very hard TODOs. -fc1b8e3a webp_js: fix webp_js demo html -15aa48d9 update ChangeLog (tag: v1.0.0-rc1) -e607dabc update AUTHORS -38410c08 [CFI] Remove function pointer casts -978eec25 [CFI] Remove function pointer casts -c57b2736 bump version to 1.0.0 -cba28853 update NEWS -c909d531 Merge "remove some deprecation warning on MacOSX" -217443c7 remove some deprecation warning on MacOSX -b672bdfa configure: quiet glut deprecation warnings on OS X -daa9fcaf configure: use sdl-config if available -dd174cae Merge "imagedec: support metadata reading for WebP image decoding" -641cedcc imagedec: support metadata reading for WebP image decoding -065b2ce1 anim_diff: add a couple missing newlines in Help() -c4cc1147 Merge "gif2webp: force low duration frames to 100ms" -09333097 gif2webp: force low duration frames to 100ms -e03f0ec3 sharp_yuv: use 14b fixed-point precision for gamma -b2db361c image_enc,WebPWritePNG: move locals after setjmp -74e82ec6 Merge "WebPPictureDistortion: fix big-endian results order" -645d04ca Merge "cwebp,get_disto: report bpp" -120f58c3 Merge "lossless*sse2: improve non-const 16-bit vector creation" -a7fe9412 WebPPictureDistortion: fix big-endian results order -e26fe066 cwebp,get_disto: report bpp -9df64e28 Merge changes Id5b4a1a4,Ia20ce844 -8043504f lossless*sse2: improve non-const 16-bit vector creation -1e3dfc48 Import: extract condition from loop -3b07d327 Import,RGBA: fix for BigEndian import -551948e4 Remove unused argument in VP8LBitsEntropy. -3005237a ReadWebP: fix for big-endian -499c395a Merge "anim_diff: expose the -max_diff option" -f69dcd69 Merge "remove WEBP_EXPERIMENTAL_FEATURES" -07d884d5 anim_diff: expose the -max_diff option -f4dd9256 remove WEBP_EXPERIMENTAL_FEATURES -94a8377b extract the command-line parsing helpers to example_util -fc09e6e2 PNM decoder: prevent unsupported depth=2 PAM case. -6de58603 MIPS64: Fix defined-but-not-used errors with WEBP_REDUCE_CSP -cbde5728 gif2webp: add support for reading from stdin -cf1c5054 Add an SSE4 version of some lossless color transforms. -45a8b5eb Fix lint error with man page. -cff38e8f Merge "PNG decoder: handle gAMA chunk" -59cb1a48 Merge "enable dc error-diffusion always" -78318b30 PNG decoder: handle gAMA chunk -664c21dd Merge "remove some TODOs" -815652de enable dc error-diffusion always -aec45cec remove some TODOs -5715dfce fix block-count[] increment in case of large image -c2d04f3e enable DC error-diffusion always for multi-pass -96bf07c5 use DC error diffusion for U/V at low-quality -1c59020b fix missing sse41 targets in makefile.unix -7a8e814b cosmetics: s/color_space/colorspace/ -05f6fe24 upsampling: rm asserts w/REDUCE_CSP+OMIT_C_CODE -b4cf5597 Merge "Upsampling SSE2/SSE4 speedup." -ccbeb32c Makefile.vc: add missing sse41 files -55403a9a Upsampling SSE2/SSE4 speedup. -807b53c4 Implement the upsampling/yuv functions in SSE41 -84101a81 Fix wasm WebP compilation -8bebd2a3 fix warning on MSVC -a7f93fe3 webpmux: allow reading argument from a file -b69f18a7 gif2webp.1: fix -loop_compatibility layout -72d530c0 Merge "fix lossless decoding w/WEBP_REDUCE_SIZE" -296c7dc4 fix lossless decoding w/WEBP_REDUCE_SIZE -0d5d029c Merge "ImgIoUtilReadFile: fix file leak upon error" -ae568ce7 ImgIoUtilReadFile: fix file leak upon error -796b5a8a Merge tag 'v0.6.1' -6b7a95fd update ChangeLog (tag: v0.6.1) -f66955de WEBP_REDUCE_CSP: restrict colorspace support -1af0df76 Merge "WEBP_REDUCE_CSP: restrict colorspace support" -6de20df0 WEBP_REDUCE_CSP: restrict colorspace support -a289d8e7 update ChangeLog (tag: v0.6.1-rc2) -c10a493c vwebp: disable double buffering on windows & mac -0d4466c2 webp_to_sdl.c: fix file mode -1b27bf8b WEBP_REDUCE_SIZE: disable all rescaler code -126be109 webpinfo: add -version option -0df22b9e WEBP_REDUCE_SIZE: disable all rescaler code -9add62b5 bump version to 0.6.1 -d3e26144 update NEWS -2edda639 README: add webpinfo section -9ca568ef Merge "right-size some tables" -31f1995c Merge "SSE2 implementation of HasAlphaXXX" -a80c46bd SSE2 implementation of HasAlphaXXX -083507f2 right-size some tables -2e5785b2 anim_utils.c: remove warning when !defined(WEBP_HAVE_GIF) -b299c47e add WEBP_REDUCE_SIZE -f593d71a enc: disable pic->stats/extra_info w/WEBP_DISABLE_STATS -541179a9 Merge "predictor_enc: fix build w/--disable-near-lossless" -5755a7ec predictor_enc: fix build w/--disable-near-lossless -eab5bab7 add WEBP_DISABLE_STATS -8052c585 remove some petty TODOs from vwebp. -c245343d move LOAD8x4 and STORE8x2 closer to their use location -b9e734fd dec,cosmetics: normalize function naming style -c188d546 dec: harmonize function suffixes -28c5ac81 dec_sse41: harmonize function suffixes -e65b72a3 Merge "introduce WebPHasAlpha8b and WebPHasAlpha32b" -b94cee98 dec_sse2: remove HE8uv_SSE2 -44a0ee3f introduce WebPHasAlpha8b and WebPHasAlpha32b -aebf59ac Merge "WebPPictureAllocARGB: align argb allocation" -c184665e WebPPictureAllocARGB: align argb allocation -3daf7509 WebPParseHeaders: remove obsolete animation TODO -80285d97 cmake: avoid security warnings under msvc -650eac55 cmake: don't set -Wall with MSVC -c462cd00 Remove useless code. -01a98217 Merge "remove WebPWorkerImpl declaration from the header" -3c49fc47 Merge "thread_utils: fix potentially bad call to Execute" -fde2782e thread_utils: fix potentially bad call to Execute -2a270c1d remove WebPWorkerImpl declaration from the header -f1f437cc remove mention of 'lossy-only parameters' from the doc -3879074d Merge "WebPMemToUint32: remove ptr cast to int" -04b029d2 WebPMemToUint32: remove ptr cast to int -b7971d0e dsp: avoid defining _C functions w/NEON builds -6ba98764 webpdec: correct alloc size check w/use_argb -5cfb3b0f normalize include guards -f433205e Merge changes Ia17c7dfc,I75423abb,Ia2f716b4,I161caa14,I4210081a, ... -8d033b14 {dec,enc}_neon: harmonize function suffixes x2 -0295e981 upsampling_neon: harmonize function suffixes -d572c4e5 yuv_neon: harmonize function suffixes -ab9c2500 rescaler_neon: harmonize function suffixes -93e0ce27 lossless_neon: harmonize function suffixes -22fbc50e lossless_enc_neon: harmonize function suffixes -447875b4 filters_neon,cosmetics: fix indent -e51bdd43 remove unused VP8TokenToStats() function -785da7ea enc_neon: harmonize function suffixes -bc1a251f dec_neon: harmonize function suffixes -61e535f1 dsp/lossless: workaround gcc-4.8 bug on arm -68b2eab7 cwebp: fix alpha reporting w/lossless & metadata -30042faa WebPDemuxGetI: add doc details around WebPFormatFeature -0a17f471 Merge "WIP: list includes as descendants of the project dir" -a4399721 WIP: list includes as descendants of the project dir -08275708 Merge "Make sure we reach the full range for alpha blending." -d361a6a7 yuv_sse2: harmonize function suffixes -6921aa6f upsampling_sse2: harmonize function suffixes -08c67d3e ssim_sse2: harmonize function suffixes -582a1b57 rescaler_sse2: harmonize function suffixes -2c1b18ba lossless_sse2: harmonize function suffixes -0ac46e81 lossless_enc_sse2: harmonize function suffixes -bc634d57 enc_sse2: harmonize function suffixes -bcb7347c dec_sse2: harmonize function suffixes -e14ad93c Make sure we reach the full range for alpha blending. -7038ca8d demux,StoreFrame: restore hdr size check to min req -fb3daad6 cpu: fix ssse3 check -be590e06 Merge "Fix CMake redefinition for HAVE_CPU_FEATURES_H" -35f736e1 Fix CMake redefinition for HAVE_CPU_FEATURES_H -a5216efc Fix integer overflow warning. -a9c8916b decode.h,WebPIDecGetRGB: clarify output ptr validity -3c74c645 gif2webp: handle 1-frame case properly + fix anim_diff -c7f295d3 Merge "gif2webp: introduce -loop_compatibility option" -b4e04677 gif2webp: introduce -loop_compatibility option -f78da3de add LOCAL_CLANG_PREREQ and avoid WORK_AROUND_GCC w/3.8+ -01c426f1 define WEBP_USE_INTRINSICS w/gcc-4.9+ -8635973d use sdl-config (if available) to determine the link flags -e9459382 use CPPFLAGS before CFLAGS -4a9d788e Merge "Android.mk,mips: fix clang build with r15" -4fbdc9fb Android.mk,mips: fix clang build with r15 -a80fcc4a ifdef code not used by Chrome/Android. -3993af12 Fix signed integer overflows. -f66f94ef anim_dump: small tool to dump frames from animated WebP -6eba857b Merge "rationalize the Makefile.am" -c5e34fba function definition cleanup -3822762a rationalize the Makefile.am -501ef6e4 configure style fix: animdiff -> anim_diff -f8bdc268 Merge "protect against NULL dump_folder[] value in ReadAnimatedImage()" -23bfc652 protect against NULL dump_folder[] value in ReadAnimatedImage() -8dc3d71b cosmetics,ReadAnimatedWebP: correct function comment -5bd40066 Merge changes I66a64a0a,I4d2e520f -7945575c cosmetics,webpinfo: remove an else after a return -8729fa11 cosmetics,cwebp: remove an else after a return -f324b7f9 cosmetics: normalize fn proto & decl param names -869eb369 CMake cleanups. -289e62a3 Remove declaration of unimplemented VP8ApplyNearLosslessPredict -20a94186 pnmdec,PAM: validate depth before calculating bytes_per_px -34130afe anim_encode: fix integer overflow -42c79aa6 Merge "Encoder: harmonize function suffixes" -b09307dc Encoder: harmonize function suffixes -bed0456d Merge "SSIM: harmonize the function suffix" -54f6a3cf lossless_sse2.c: fix some missed suffix changes -088f1dcc SSIM: harmonize the function suffix -86fc4dd9 webpdec: use ImgIoUtilCheckSizeArgumentsOverflow -08ea9ecd imageio: add ability restrict max image size -6f9daa4a jpegdec,ReadError: fix leaks on error -a0f72a4f VP8LTransformColorFunc: drop an non-respected 'const' from the signature. -8c934902 Merge "Lossess dec: harmonize the function suffixes" -622242aa Lossess dec: harmonize the function suffixes -1411f027 Lossless Enc: harmonize the function suffixes -24ad2e3c add const to two variables -46efe062 Merge "Allow the lossless cruncher to work for alpha." -8c3f9a47 Speed-up LZ77. -1aef4c71 Allow the lossless cruncher to work for alpha. -b8821dbd Improve the box LZ77 speed. -7beed280 add missing ()s to macro parameters -6473d20b Merge "fix Android standalone toolchain build" -dcefed95 Merge "build.gradle: fix arm64 build" -0c83a8bc Merge "yuv: harmonize suffix naming" -c6d1db4b fix Android standalone toolchain build -663a6d9d unify the ALTERNATE_CODE flag usage -73ea9f27 yuv: harmonize suffix naming -c71b68ac build.gradle: fix arm64 build -c4568b47 Rescaler: harmonize the suffix naming -6cb13b05 Merge "alpha_processing: harmonize the naming suffixes to be _C()" -83a3e69a Merge "simplify WEBP_EXTERN macro" -7295fde2 Merge "filters: harmonize the suffixes naming to _SSE2(), _C(), etc." -8e42ba4c simplify WEBP_EXTERN macro -331ab34b cost*.c: harmonize the suffix namings -b161f670 filters: harmonize the suffixes naming to _SSE2(), _C(), etc. -dec5e4d3 alpha_processing: harmonize the naming suffixes to be _C() -6878d427 fix memory leak in SDL_Init() -461ae555 Merge "configure: fix warnings in sdl check" -62486a22 configure: test for -Wundef -92982609 dsp.h: fix -Wundef w/__mips_dsp_rev -0265cede configure: fix warnings in sdl check -88c73d8a backward_references_enc.h: fix WINDOW_SIZE_BITS check -4ea49f6b rescaler_sse2.c: fix WEBP_RESCALER_FIX -> _RFIX typo -1b526638 Clean-up some CMake -87f57a4b Merge "cmake: fix gif lib detection when cross compiling" -b34a9db1 cosmetics,dec_sse2: remove some redundant comments -471c5755 cmake: fix gif lib detection when cross compiling -c793417a cmake: disable gif2webp if gif lib isn't found -dcbc1c88 cmake: split gif detection from IMG deps -66ad84f0 Merge "muxread: remove unreachable code" -50ec3ab7 muxread: remove unreachable code -7d67a164 Lossy encoding: smoothen transparent areas to improve compression -e50650c7 Merge "fix signature for DISABLE_TOKEN_BUFFER compilation" -671d2567 fix signature for DISABLE_TOKEN_BUFFER compilation -d6755580 cpu.cmake: use unique flag to test simd disable flags -28914528 Merge "Remove the argb* files." -8acb4942 Remove the argb* files. -3b62347b README: correct cmake invocation note -7ca0df13 Have the SSE2 version of PackARGB use common code. -7b250459 Merge "Re-use the transformed image when trying several LZ77 in lossless." -e132072f Re-use the transformed image when trying several LZ77 in lossless. -5d7a50ef Get code to compile in C++. -7b012987 configure: test for -Wparentheses-equality -f0569adb Fix man pages for multi-threading. -f1d5a397 multithread cruncher: only copy stats when picture->stats != NULL -f8c2ac15 Multi-thread the lossless cruncher. -a88c6522 Merge "Integrate a new LZ77 looking for matches in the neighborhood of a pixel only." -8f6df1d0 Unroll Predictors 10, 11 and 12. -355c3d1b Integrate a new LZ77 looking for matches in the neighborhood of a pixel only. -a1779a01 Refactor LZ77 handling in preparation for a new method. -67de68b5 Android.mk/build.gradle: fix mips build with clang from r14b -f209a548 Use the plane code and not the distance when computing statistics. -b903b80c Split cost-based backward references in its own file. -498cad34 Cosmetic changes in backward reference. -e4eb4587 lossless, VP8LTransformColor_C: make sure no overflow happens with colors. -af6deaff webpinfo: handle alpha flag mismatch -7caef29b Fix typo that creeped in. -39e19f92 Merge "near lossless: fix unsigned int overflow warnings." -9bbc0891 near lossless: fix unsigned int overflow warnings. -e1118d62 Merge "cosmetics,FindClosestDiscretized: use uint in mask creation" -186bc9b7 Merge "webpinfo: tolerate ALPH+VP8L" -b5887297 cosmetics,FindClosestDiscretized: use uint in mask creation -f1784aee near_lossless,FindClosestDiscretized: use unsigned ops -0d20abb3 webpinfo: tolerate ALPH+VP8L -972104b3 webpmux: tolerate false positive Alpha flag -dd7e83cc tiffdec,ReadTIFF: ensure data_size is < tsize_t max -d988eb7b tiffdec,MyRead: quiet -Wshorten-64-to-32 warning -dabda707 webpinfo: add support to parse Alpha bitstream -4c117643 webpinfo: correct background color output, BGRA->ARGB -defc98d7 Doc: clarify the role of quality in WebPConfig. -d78ff780 Merge "Fix code to compile with C++." -c8f14093 Fix code to compile with C++. -497dc6a7 pnmdec: sanitize invalid header output -d78e5867 Merge "configure: test for -Wconstant-conversion" -481e91eb Merge "pnmdec,PAM: set bytes_per_px based on depth when missing" -93b12753 configure: test for -Wconstant-conversion -645f0c53 pnmdec,PAM: set bytes_per_px based on depth when missing -e9154605 Merge "vwebp: activate GLUT double-buffering" -818d795b vwebp: activate GLUT double-buffering -d63e6f4b Add a man page for webpinfo -4d708435 Merge "NEON: implement ConvertRGB24ToY/BGR24/ARGB/RGBA32ToUV/ARGBToUV" -faf42213 NEON: implement ConvertRGB24ToY/BGR24/ARGB/RGBA32ToUV/ARGBToUV -b4d576fa Install man pages with CMake. -cbc1b921 webpinfo: add features to parse bitstream header -e644c556 Fix bad bit writer initialization. -b62cdad2 Merge "Implement a cruncher for lossless at method 6." -da3e4dfb use the exact constant for the gamma transfer function -a9c701e0 Merge "tiffdec: fix EXTRASAMPLES check" -adab8ce0 Implement a cruncher for lossless at method 6. -1b92b237 Merge "Fix VP8ApplyNearLossless to respect const and stride." -1923ff02 tiffdec: fix EXTRASAMPLES check -97cce5ba tiffdec: only request EXTRASAMPLES w/> 3 samples/px -0dcd85b6 Fix VP8ApplyNearLossless to respect const and stride. -f7682189 yuv: rationalize the C/SSE2 function naming -52245424 NEON implementation of some Sharp-YUV420 functions -690efd82 Avoid several backward reference copies. -4bb1f607 src/dec/vp8_dec.h, cosmetics: fix comments -285748be cmake: build/install webpinfo -78fd199c backward_references_enc.c: clear -Wshadow warnings -ae836410 WebPLog2FloorC: clear -Wshadow warning -d0b7404e Merge "WASM support" -134e314f WASM support -c08adb6f Merge "VP8LEnc: remove use of BitsLog2Ceiling()" -28c37ebd VP8LEnc: remove use of BitsLog2Ceiling() -2cb58ab2 webpinfo: output format as a human readable string -bb175a93 Merge "rename some symbols clashing with MSVC headers" -39eda658 Remove a duplicated pixel hash implementation. -36b8274d rename some symbols clashing with MSVC headers -274daf54 Add webpinfo tool. -ec5036e4 add explicit reference to /usr/local/{lib,inc} -18f0dfac Merge "fix TIFF encoder regarding rgbA/RGBA" -4e2b0b50 Merge "webpdec.h: fix a doc typo" -e2eeabff Merge "Install binaries, libraries and headers in CMake." -836607e6 webpdec.h: fix a doc typo -9273e441 fix TIFF encoder regarding rgbA/RGBA -17e3c11f Add limited PAM decoding support -5f624871 Install binaries, libraries and headers in CMake. -976adac1 Merge "lossless incremental decoding: fix missing eos_ test" -f8fad4fa lossless incremental decoding: fix missing eos_ test -27415d41 Merge "vwebp_sdl: fix the makefile.unix" -49566182 Merge "ImgIoUtilWriteFile(): use ImgIoUtilSetBinaryMode" -6f75a51b Analyze the transform entropy on the whole image. -a5e4e3af Use palette only if we can in entropy analysis. -75a9c3c4 Improve compression by better entropy analysis. -39cf6f4f vwebp_sdl: fix the makefile.unix -699b0416 ImgIoUtilWriteFile(): use ImgIoUtilSetBinaryMode -7d985bd1 Fix small entropy analysis bug. -6e7caf06 Optimize the color cache size. -833c9219 More efficient stochastic histogram merge. -5183326b Refactor the greedy histogram merge. -99f6f462 Merge "histogram_enc.c,MyRand: s/ul/u/ for unsigned constants" -80a22186 ssim.c: remove dead include -a128dfff histogram_enc.c,MyRand: s/ul/u/ for unsigned constants -693bf74e move the SSIM calculation code in ssim.c / ssim_sse2.c -10d791ca Merge "Fix the random generator in HistogramCombineStochastic." -fa63a966 Fix the random generator in HistogramCombineStochastic. -16be192f VP8LSetBitPos: remove the eos_ setting -027151ca don't erase the surface before blitting. -4105d565 disable WEBP_USE_XXX optimisations when EMSCRIPTEN is defined -9ee32a75 Merge "WebP-JS: emscripten-based Javascript decoder" -ca9f7b7d WebP-JS: emscripten-based Javascript decoder -868aa690 Perform greedy histogram merge in a unified way. -5b393f2d Merge "fix path typo for vwebp_sdl in Makefile.vc" -e0012bea CMake: only use libwebpdecoder for building dwebp -84c2a7b0 fix path typo for vwebp_sdl in Makefile.vc -1b0e4abf Merge "Add a flag to disable SIMD optimizations." -32263250 Add a flag to disable SIMD optimizations. -b494fdec optimize the ARGB->ARGB Import to use memcpy -f1536039 Merge "ReadWebP: decode directly into a pre-allocated buffer" -e69ed291 ReadWebP: decode directly into a pre-allocated buffer -57d8de8a Merge "vwebp_sdl: simple viewer based on SDL" -5cfd4ebc LZ77 interval speedups. Faster, smaller, simpler. -1e7ad88b PNM header decoder: add some basic numerical validation -17c7890c Merge "Add a decoder only library for WebP in CMake." -be733786 Merge "Add clang build fix for MSA" -03cda0e4 Add a decoder only library for WebP in CMake. -aa893914 Add clang build fix for MSA -31a92e97 Merge "imageio: add limited PNM support for reading" -dcf9d82a imageio: add limited PNM support for reading -6524fcd6 vwebp_sdl: simple viewer based on SDL -6cf24a24 get_disto: fix reference file read -43d472aa Merge tag 'v0.6.0' -50d1a848 update ChangeLog (tag: v0.6.0, origin/0.6.0) -20a7fea0 extras/Makefile.am: fix libwebpextras.la reference -415f3ffe update ChangeLog (tag: v0.6.0-rc3) -3c6d1224 update NEWS -ee4a4141 update AUTHORS -32ed856f Fix "all|no frames are keyframes" settings. -1c3190b6 Merge "Fix "all|no frames are keyframes" settings." -f4dc56fd disable GradientUnfilter_NEON -4f3e3bbd disable GradientUnfilter_NEON -2dc0bdca Fix "all|no frames are keyframes" settings. -0d8e0588 img2webp: treat -loop as a no-op w/single images -b0450139 ReadImage(): restore size reporting -0ad3b4ef update ChangeLog (tag: v0.6.0-rc2) -6451709e img2webp,get_disto: fix image decode w/WIC builds -92504d21 get_disto: make ReadPicture() return a bool -c3e4b3a9 update NEWS -3363eb6d man/img2webp.1: fix formatting warning -4d1312f2 update NEWS -36c42ea4 bump version to 0.6.0 -bb498a51 update AUTHORS -84cef16f Makefile.vc: fix CFG=debug-dynamic build -919f9e2f Merge "add .rc files for windows dll versioning" -f1ae8af4 Merge ".gitignore: add img2webp" -4689ce16 cwebp: add a -sharp_yuv option for 'sharp' RGB->YUV conversion -79bf46f1 rename the pretentious SmartYUV into SharpYUV -eb1dc89a silently expose use_delta_palette in the WebPConfig API -c85b0dde .gitignore: add img2webp -43d3f01a add .rc files for windows dll versioning -668e1dd4 src/{dec,enc,utils}: give filenames a unique suffix -0e6b7f33 Merge "iosbuild.sh: only add required headers to framework" -29ed6f9a iosbuild.sh: only add required headers to framework -71c53f1a NEON: speed-up strong filtering -73f567ea Merge "get_disto: remove redundant reader check" -9e14276f Merge "makefiles: prune get_disto & webp_quality deps" -99965bac Merge "Makefile.vc: add get_disto.exe, webp_quality.exe" -d4912238 get_disto: remove redundant reader check -ea482409 makefiles: prune get_disto & webp_quality deps -2ede5a19 Makefile.vc: add get_disto.exe, webp_quality.exe -a345068a ARM: speed up bitreader by avoiding tables -1dc82a6b Merge "introduce a generic GetCoeffs() function pointer" -8074b89e introduce a generic GetCoeffs() function pointer -749a45a5 Merge "NEON: implement alpha-filters (horizontal/vertical/gradient)" -74c053b5 Merge "NEON: fix overflow in SSE NxN calculation" -0a3aeff7 Merge "dsp: WebPExtractGreen function for alpha decompression" -1de931c6 NEON: implement alpha-filters (horizontal/vertical/gradient) -9b3aca40 NEON: fix overflow in SSE NxN calculation -1c07a3c6 dsp: WebPExtractGreen function for alpha decompression -9ed5e3e5 use pointers for WebPRescaler's in WebPDecParams -db013a8d Merge "ARM: don't use USE_GENERIC_TREE" -fcd4784d use a 8b table for C-version for clz() -fbb5c473 ARM: don't use USE_GENERIC_TREE -8fda5612 Merge "add a kSlowSSSE3 feature for CPUInfo" -86bbd245 add a kSlowSSSE3 feature for CPUInfo -7c2779e9 Get code to fully compile in C++. -250c3586 Merge "When compiling as C++, avoid narrowing warnings." -c0648ac2 When compiling as C++, avoid narrowing warnings. -0d55f60c 40% faster ApplyAlphaMultiply_SSE2 -49d0280d NEON: implement several alpha-processing functions -48b1e85f SSE2: 15% faster alpha-processing functions -e3b8abbc fix warning from static analysis. -28fe054e SSE2: 30% faster ApplyAlphaMultiply() -f44acd25 Merge "Properly compute the optimal color cache size." -527844fe Properly compute the optimal color cache size. -be0ef639 fix a comment typo -8874b162 Fix a non-deterministic color cache size computation. -d712e20d Do not allow a color cache size bigger than the number of colors. -ecff04f6 re-introduce some comments in Huffman Cost. -259e9828 replace 'ptr + y * stride' by 'ptr += stride' -00b08c88 Merge "NEON: 5% faster conversion to RGB565 and RGBA4444" -0e7f4447 Merge "NEON: faster fancy upsampling" -b016cb91 NEON: faster fancy upsampling -1cb63801 Call the C function to finish off lossless SSE loops only when necessary. -875fafc1 Implement BundleColorMap in SSE2. -3674d49e Merge "remove Clang warnings with unused arch arguments." -f04eb376 Merge tag 'v0.5.2' -341d711c NEON: 5% faster conversion to RGB565 and RGBA4444 -abb54827 remove Clang warnings with unused arch arguments. -ece9684f update ChangeLog (tag: v0.5.2-rc2, tag: v0.5.2, origin/0.5.2) -aa7744ca anim_util: quiet implicit conv warnings in 32-bit -d9120271 jpegdec: correct ContextFill signature -24eb3940 Remove some errors when compiling the code as C++. -a4a8e5f3 vwebp: clear canvas during resize w/o animation -67c25ad5 vwebp: clear canvas during resize w/o animation -a4bbe4b3 fix indentation -31ca2a80 tiffdec: restore libtiff 3.9.x compatibility -b2f77b57 update NEWS -5ab6d9de AnimEncoder: avoid freeing uninitialized memory pointer. -f29bf582 WebPAnimEncoder: If 'minimize_size' and 'allow_mixed' on, try lossy + lossless. -3ebe1c00 AnimEncoder: avoid freeing uninitialized memory pointer. -df780e0e fix a potential overflow with MALLOC_LIMIT -58fc5078 Merge "PredictorSub: implement fully-SSE2 version" -9cc42167 PredictorSub: implement fully-SSE2 version -0aa1f35c remove dependency of imageio/ to stopwatch.h -cb9ec84b Merge "remove the dependency to stop_watch.[ch] in imageio" -dc0c01fb Merge "anim_util: quiet implicit conv warnings in 32-bit" -827d3c50 Merge "fix a potential overflow with MALLOC_LIMIT" -1e2e25b0 anim_util: quiet implicit conv warnings in 32-bit -218460cd bump version to 0.5.2 -de7d654d update AUTHORS & .mailmap -273367c1 Merge "dsp/lossless.c,cosmetics: fix indent" -76bbcf2e fix a potential overflow with MALLOC_LIMIT -8ac1abfe Merge "jpegdec: correct ContextFill signature" -cb215aed remove the dependency to stop_watch.[ch] in imageio -2423017a dsp/lossless.c,cosmetics: fix indent -74a12b10 iosbuild.sh: add WebPDecoder.framework + encoder -a9cc7621 Merge "iosbuild.sh: add WebPDecoder.framework + encoder" -fbba5bc2 optimize predictor #1 in plain-C For some reason, gcc has hard time inlining this one... -9ae0b3f6 Merge "SSE2: slightly (~2%) faster Predictor #1" -c1f97bd7 SSE2: slightly (~2%) faster Predictor #1 -ea664b89 SSE2: 10% faster Predictor #11 -be7dcc08 AnimEncoder: Correctly skip a frame when sub-rectangle is empty. -40885830 Fix assertions in WebPRescalerExportRow() -1d5046d1 iosbuild.sh: add WebPDecoder.framework + encoder -cec72014 jpegdec: correct ContextFill signature -8f38c72e fix a typo in WebPPictureYUVAToARGB's doc -33ca93f9 systematically call WebPDemuxReleaseIterator() on dec->prev_iter_ -76e19073 doc: use two's complement explicitly for uint8->int8 conversion -f91ba963 Anim_encoder: correctly handle enc->prev_candidate_undecided_ -25d74e65 WebPPictureDistortion(): free() -> WebPSafeFree() -03f1c008 mux/Makefile.am: add missing -lm -58410cd6 fix bug in RefineUsingDistortion() -e168af8c fix filtering auto-adjustment -ed9dec41 fix doc and code snippet for WebPINewDecoder() doc -3c49178f prevent 32b overflow for very large canvas_width / height -9595f290 fix anim_util.c compilation when HAVE_GIF is not defined. -7ec9552c Make gif transparent color to be transparent black -b3fb8bb6 slightly faster Predictor #11 in NEON -9871335f Add a CMake option for WEBP_SWAP_16BIT_CSP. -0ae32226 Fix missing cpu-features for Android. -ab4c8056 cpu.cmake: improve webp_check_compiler_flag output -eec5fa3a Provide support for CMake on Android studio 2.2. -004d5690 Split the main CMake file. -4fe5d588 Android.mk: use -fvisibility=hidden -bd63a31a vwebp: ensure setenv() is available in stdlib.h -363a5681 vwebp: handle window resizing properly -a0d2753f lower WEBP_MAX_ALLOCABLE_MEMORY default -31fe11a5 fix infinite loop in case of PARTITION0 overflow -532215dd Change the rule of picking UV mode in MBAnalyzeBestUVMode() -9c75dbd3 cwebp.1: improve some grammar -af2e05cb vwebp: Clear previous frame when a key triggers a redraw -26ffa296 Add descriptions of default configuration in help info. -7416280d Fix an unsigned integer overflow error in enc/cost.h -13cf1d2e Do token recording and counting in a single loop -eb9a4b97 Reset segment id if we decide not to update segment map -42ebe3b7 configure: fix NEON flag detection under gcc 6 -76ebbfff NEON: implement predictor #13 -95b12a08 Merge "Revert Average3 and Average4" -54ab2e75 Revert Average3 and Average4 -fe12330c 3-5% faster Predictor #5, #6, #7 and #10 for NEON -fbfb3bef ~2% faster predictor #10 for NEON -d4b7d801 lossless_sse2: use the local functions -a5e3b225 Lossless decoder SSE2 improvements. -58a1f124 ~2% faster predictor #12 in NEON. -906c3b63 Merge "Implement lossless transforms in NEON." -d23abe4e Implement lossless transforms in NEON. -2e6cb6f3 Give more flexibility to the predictor generating macro. -28e0bb70 Merge "Fix race condition in multi-threading initialization." -64704530 Fix race condition in multi-threading initialization. -bded7848 img2webp: fix default -lossless value and use pic.argb=1 -0e61a513 Merge "img2webp: convert a sequence of images to an animated webp" -1cc79e92 AnimEncoder: Correctly skip a frame when sub-rectangle is empty. -03f40955 img2webp: convert a sequence of images to an animated webp -ea72cd60 add missing 'extern' keyword for predictor dcl -67879e6d SSE implementation of decoding predictors. -34aee990 Merge "vwebp: make 'd' key toggle the debugging of fragments" -a41296ae Fix potentially uninitialized value. -c85adb33 vwebp: make 'd' key toggle the debugging of fragments -4239a148 Make the lossless predictors work on a batch of pixels. -bc18ebad fix extra 'const's in signatures -71e2f5ca Remove memcpy in lossless decoding. -7474d46e Do not use a register array in SSE. -67748b41 Improve latency of FTransform2. -16951b19 Merge "Provide an SSE implementation of ConvertBGRAToRGB" -6540cd0e Provide an SSE implementation of ConvertBGRAToRGB -de568abf Android.mk: use -fvisibility=hidden -3c2a61b0 remove some unneeded casts -9ac063c3 add dsp functions for SmartYUV -22efabdd Merge "smart_yuv: switch to planar instead of packed r/g/b processing" -1d6e7bf3 smart_yuv: switch to planar instead of packed r/g/b processing -0a3838ca fix bug in RefineUsingDistortion() -c0699515 webpmux -duration: set default 'end' value equal to 'start' -83cbfa09 Import: use relative pointer offsets -a1ade40e PreprocessARGB: use relative pointer offsets -fd4d090f ConvertWRGBToYUV: use relative pointer offsets -9daad459 ImportYUVAFromRGBA: use relative pointer offsets -f90c60d1 Merge "add a "-duration duration,start,end" option to webpmux" -3f182d36 add a "-duration duration,start,end" option to webpmux -342e15f0 Import: use relative pointer offsets -1147ab4e PreprocessARGB: use relative pointer offsets -e4cd4daf fix filtering auto-adjustment -e7152856 fix doc and code snippet for WebPINewDecoder() doc -de9fa507 ConvertWRGBToYUV: use relative pointer offsets -deb1b831 ImportYUVAFromRGBA: use relative pointer offsets -c284780f imageio_util: add ImgIoUtilCheckSizeArgumentsOverflow -e375080d gifdec,Remap: avoid out of bounds colormap read -c222a053 additional fix for stride type as size_t -bb233617 fix potential overflow when width * height * 4 >= (1<<32) -883d41fb gif2webp: fix crash with NULL extension data -cac9a36a gifdec,Remap: avoid out of bounds colormap read -4595e01f Revert "gifdec,Remap: avoid out of bounds colormap read" -fb52d443 gifdec: make some constants unsigned -f048d38d gifdec,Remap: avoid out of bounds colormap read -31b1e343 fix SSIM metric ... by ignoring too-dark area -2f51b614 introduce WebPPlaneDistortion to compute plane distortion -0104d730 configure: fix NEON flag detection under gcc 6 -265abbe9 Merge "additional fix for stride type as size_t" -f7601aa6 Merge "Introduce a generic WebPGetImageReader(type) function" -ce873320 Introduce a generic WebPGetImageReader(type) function -2a2773ea imageio/*dec,Read*: add input parameter checks -9f5c8eca additional fix for stride type as size_t -4eb5df28 remove unused stride fields from VP8Iterator -11bc423a MIN_LENGTH cleanups. -273d035a Merge "fix a typo in WebPPictureYUVAToARGB's doc" -4db82a17 Merge "fix potential overflow when width * height * 4 >= (1<<32)" -e2affacc fix potential overflow when width * height * 4 >= (1<<32) -dc789ada fix a typo in WebPPictureYUVAToARGB's doc -539f5a68 Fix non-included header in config.c. -aaf2a6a6 systematically call WebPDemuxReleaseIterator() on dec->prev_iter_ -20ef9915 Merge "imageio_util: add ImgIoUtilCheckSizeArgumentsOverflow" -bc86b7a8 imageio_util: add ImgIoUtilCheckSizeArgumentsOverflow -806f6279 gif2webp: fix crash with NULL extension data -68ae5b67 Add libwebp/src/mux/animi.h -28ce3043 Remove some errors when compiling the code as C++. -b34abcb8 Favor keeping the areas locally similar in spatial prediction mode selection -ba843a92 fix some SSIM calculations -51b71fd2 Merge "vwebp: ensure setenv() is available in stdlib.h" -fb01743a get_disto: fix the r/g/b order for luma calculation -bfab8947 vwebp: ensure setenv() is available in stdlib.h -9310d192 vwebp: handle window resizing properly -f79450ca Speedup ApplyMap. -cfdda7c6 Merge "prevent 32b overflow for very large canvas_width / height" -e36396ba Merge "get_disto: new option to compute SSIM map and convert to gray" -18a9a0ab Add an API to import a color-mapped image. -30d43706 Speed-up Combined entropy for palettized histograms. -36aa087b get_disto: new option to compute SSIM map and convert to gray -86a84b35 2x faster SSE2 implementation of SSIMGet -b8384b53 lower WEBP_MAX_ALLOCABLE_MEMORY default -1c364400 prevent 32b overflow for very large canvas_width / height -eee0cce1 Merge "Small LZ77 speedups." -5f1caf29 Small LZ77 speedups. -1effde7b fix anim_util.c compilation when HAVE_GIF is not defined. -a2fe9bf4 Speedup TrellisQuantizeBlock(). -573cce27 smartYUV improvements -21e7537a fix infinite loop in case of PARTITION0 overflow -053a1565 Merge "Change the rule of picking UV mode in MBAnalyzeBestUVMode()" -1377ac2e Change the rule of picking UV mode in MBAnalyzeBestUVMode() -7c1fb7d0 fix uint32_t initialization (0. -> 0) -bfff0bf3 speed-up SSIM calculation -64577de8 De-VP8L-ize GetEntropUnrefinedHelper. -a7be7328 Merge "refactor the PSNR / SSIM calculation code" -50c3d7da refactor the PSNR / SSIM calculation code -d6228aed indentation fix after I7055d3ee3bd7ed5e78e94ae82cb858fa7db3ddc0 -dd538b19 Remove unused declaration. -6cc48b17 Move some lossless logic out of dsp. -78363e9e Merge "Remove a redundant call to InitLeft() in VP8IteratorReset()" -ffd01929 Refactor VP8IteratorNext(). -c4f6d9c9 Remove a redundant call to InitLeft() in VP8IteratorReset() -c27d8210 Merge "smartYUV: simplify main loop" -07795296 smartYUV: simplify main loop -c9b45863 Split off common lossless dsp inline functions. -490ae5b1 smartYUV: improve initial state for faster convergence -894232be smartYUV: fix and simplify the over-zealous stop criterion -8de08483 Remove unused code in webpi.h -41cab7fe imageio/Android.mk: correct imagedec dependencies -82c91c70 Merge "libimageenc.a: extract image-saving code from dwebp" -af1ad3e2 libimageenc.a: extract image-saving code from dwebp -dd7309e3 Merge "doc: use two's complement explicitly for uint8->int8 conversion" -6105777e Merge "add gif2webp to CMake" -13ae011e doc: use two's complement explicitly for uint8->int8 conversion -4bda0cfb add gif2webp to CMake -6029c7fe Merge "remove mention of fragment, frgm, FRGM, etc." -545c147f remove mention of fragment, frgm, FRGM, etc. -5b46f7fc cwebp.1: improve some grammar -9e478f80 dec/vp8l.c: add assertions in EmitRescaledRowsRGBA/YUVA -43bd8958 Make gif transparent color to be transparent black -0887fc2d Merge "get_disto: add a '-o file' option to save a diff map" -0de48e18 get_disto: add a '-o file' option to save a diff map -0a57ad0d cosmetics: WebPSafeAlloc -> WebPSafeMalloc -0a4699bc Merge "WebPPictureDistortion(): free() -> WebPSafeFree()" -29fedbf5 Anim_encoder: correctly handle enc->prev_candidate_undecided_ -32dead4e WebPPictureDistortion(): free() -> WebPSafeFree() -85cd5d06 Smarter LZ77 for uniform regions. -6585075f Change PixelsAreSimilar() to handle black pixels correctly. -c0a27fd2 vwebp: Clear previous frame when a key triggers a redraw -57a5e3b6 webp_quality should return '0' in case of success. -7f1b897b Faster stochastic histogram merging. -48c810b8 Merge "remove WEBP_FORCE_ALIGNED and use memcpy() instead." -3884972e remove WEBP_FORCE_ALIGNED and use memcpy() instead. -485cac1a switch libimagedec.a and libimageio_util.a to avoid undefined symbol -005e15b1 Merge "{extras,mux}/Makefile.am: add missing -lm" -6ab496ed fix some 'unsigned integer overflow' warnings in ubsan -8a4ebc6a Revert "fix 'unsigned integer overflow' warnings in ubsan" -9d4f209f Merge changes I25711dd5,I43188fab -e44f5248 fix 'unsigned integer overflow' warnings in ubsan -27b5d991 Fix assertions in WebPRescalerExportRow() -74f6f9e7 Add descriptions of default configuration in help info. -aaf2530c {extras,mux}/Makefile.am: add missing -lm -1269dc7c Refactor VP8LColorCacheContains() -40872fb2 dec_neon,NeedsHev: micro optimization -7b54e26b Add a CMake option for WEBP_SWAP_16BIT_CSP. -d2223d8d Fix missing cpu-features for Android. -bf16a4b4 Merge "cpu.cmake: improve webp_check_compiler_flag output" -ee1057e3 cpu.cmake: improve webp_check_compiler_flag output -b551e587 cosmetics: add {}s on continued control statements -d2e4484e dsp/Makefile.am: put msa source in correct lib -c7f66c82 Merge "utils/thread.c,cosmetics: join a few lines" -98d8f295 Merge "examples/Makefile.am,cosmetics: sort binary targets" -39f4ffbc utils/thread.c,cosmetics: join a few lines -a86ce2b1 Merge "extras/Makefile.am: don't install libwebpextras" -6fa9fe24 extras/Makefile.am: don't install libwebpextras -0b2c58a9 Fix an unsigned integer overflow error in enc/cost.h -d7ce4a2e examples/Makefile.am,cosmetics: sort binary targets -386e4ba2 Reset segment id if we decide not to update segment map -7b87e848 Merge "Add MSA optimized YUV to RGB upsampling functions" -d3ddacb6 Add MSA optimized YUV to RGB upsampling functions -eb98d8d8 webp_quality: detect lossless format and features -ebee57f4 move imageio/example_util.[hc] (back to) examples/ -99542bbf webpdec: s/ExUtil// -da573cf4 imageio_util: s/ExUtil/ImgIoUtil/ -bdda5bd4 split example_util.h -15ed462b .gitignore: add extras/{get_disto,webp_quality} -7be57489 Merge "VP8EstimateQuality(): roughty estimate webp bitstream quality factor" -57020525 Makefile.vc: add missing imageio target -e8ab6a82 VP8EstimateQuality(): roughty estimate webp bitstream quality factor -fee7b3d6 Merge "'extras/get_disto' example: compute PSNR between two files" -1e7d4401 'extras/get_disto' example: compute PSNR between two files -4cecab63 pngdec.c,jpegdec.[hc]: remove unnecessary includes -259f0434 makefile.unix: normalize image decode lib name -ed34c39b fix: examples/libexample_dec.a => imageio/libexample_dec.a -33d8d0d4 Merge "move examples/{example_util,image_dec} to imageio/" -c960b82e Merge "extras.h: correct include guard" -fe3cd28a Merge ".gitignore: add .gradle, /build" -45fbeba5 Merge "Do token recording and counting in a single loop" -4f33c820 .gitignore: add .gradle, /build -c379b55a move examples/{example_util,image_dec} to imageio/ -5108d9aa extras.h: correct include guard -ad497fbc move src/extras to the top-level -0c0fb832 Do token recording and counting in a single loop -9ac74f92 Add MSA optimized rescaling functions -cb19dbc1 Add MSA optimized color transform functions -3f4042b5 WebPAnimEncoder: If 'minimize_size' and 'allow_mixed' on, try lossy + lossless. -5e2eb89e cosmetics,dsp/*msa.c: associate '*' with the type -5b60db5c FastMBAnalyze() for quick i16/i4 decision -567e6977 Add MSA optimized CollectHistogram function -c54ab8dd Add MSA optimized quantization functions -ec6f68c5 Merge "Remove QuantizeBlockWHT() in enc.c" -2a5c417c Apply the RLE heuristic to LZ77. -91b59e88 Remove QuantizeBlockWHT() in enc.c -fe572737 Add MSA optimized SSE functions -6b53ca87 cosmetics,(dec|enc)_sse2.c: fix indent -b15d00d9 Merge "Add MSA optimized encoder IntraChromaPreds function" -afe3cec8 Add MSA optimized encoder IntraChromaPreds function -fc8cad9f reduce the number of malloc/free cycles in huffman.c -7b4b05e0 Add MSA optimized encoder Intra16Preds function -c18787a0 Add MSA optimized encoder Intra4Preds function -479d1908 webpmux: Also print compression info per frame. -a80e8cfd Provide support for CMake on Android studio 2.2. -6c628410 Split the main CMake file. -bbb6ecd9 Merge "Add MSA optimized distortion functions" -7915396f Add MSA optimized distortion functions -652e944f Merge "build.gradle: remove tab" -c0991a14 io,EmitRescaledAlphaYUV: factor out a common expr -48bf5ed1 build.gradle: remove tab -bfef6c9f Merge tag 'v0.5.1' -3d97bb75 update ChangeLog (tag: v0.5.1, origin/0.5.1) -deb54d91 Clarify the expected 'config' lifespan in WebPIDecode() -435308e0 Add MSA optimized encoder transform functions -dce64bfa Add MSA optimized alpha filter functions -429120d0 Add MSA optimized color transform functions -c7e2d245 update ChangeLog (tag: v0.5.1-rc5) -55b2fede normalize the macros' "do {...} while (0)" constructs -701c772e Add MSA optimized colorspace conversion functions -c7eb06f7 Fix corner case in CostManagerInit. -f918cb10 fix rescaling bug: alpha plane wasn't filled with 0xff -ab7937a5 gif2webp: normalize the number of .'s in the help message -3cdec847 vwebp: normalize the number of .'s in the help message -bdf6241e cwebp: normalize the number of .'s in the help message -06a38c7b fix rescaling bug: alpha plane wasn't filled with 0xff -319e37be Improve lossless compression. -6a197937 Add MSA optimized intra pred chroma functions -447adbce 'our bug tracker' -> 'the bug tracker' -97b9e644 normalize the number of .'s in the help message -293d786f Added MSA optimized intra prediction 16x16 functions -0afa0ce2 Added MSA optimized intra prediction 4x4 functions -a6621bac Added MSA optimized simple edge filtering functions -bb50bf42 pngdec,ReadFunc: throw an error on invalid read -38063af1 decode.h,WebPGetInfo: normalize function comment -1ebf193c Added MSA optimized chroma edge filtering functions -9ad2352d Merge "Added MSA optimized edge filtering functions" -60751096 Added MSA optimized edge filtering functions -9e8e1b7b Inline GetResidual for speed. -7d58d1b7 Speed-up uniform-region processing. -8ec7032b simplify HistogramCombineEntropyBin() -23e29cb1 Merge "Fix a boundary case in BackwardReferencesHashChainDistanceOnly." into 0.5.1 -472a049b remove bin_map[] allocation altogether -0bb23b2c free -> WebPSafeFree() -a977b4b5 Merge "rewrite the bin_map clustering to use less memory" -3591ba66 rewrite the bin_map clustering to use less memory -e6ac450c utils.[hc]: s/MAX_COLOR_COUNT/MAX_PALETTE_SIZE/ -e7b91772 Merge "DecodeImageData(): change the incorrect assert" into 0.5.1 -2abfa54f DecodeImageData(): change the incorrect assert -5a48fcd8 Merge "configure: test for -Wfloat-conversion" -0174d18d Fix a boundary case in BackwardReferencesHashChainDistanceOnly. -6a9c262a Merge "Added MSA optimized transform functions" -cfbcc5ec Make sure to consider small distances in LZ77. -5e60c42a Added MSA optimized transform functions -3dc28d76 configure: test for -Wfloat-conversion -f2a0946a add some asserts to delimit the perimeter of CostManager's operation -9a583c66 fix invalid-write bug for alpha-decoding -f66512db make gradlew executable -6fda58f1 backward_references: quiet double->int warning -a48cc9d2 Merge "Fix a compression regression for images with long uniform regions." into 0.5.1 -cc2720c1 Merge "Revert an LZ77 boundary constant." into 0.5.1 -059aab4f Fix a compression regression for images with long uniform regions. -b0c7e49e Check more backward matches with higher quality. -a3611513 Revert an LZ77 boundary constant. -8190374c README: fix typo -7551db44 update NEWS -0fb2269c bump version to 0.5.1 -f4537610 update AUTHORS & .mailmap -3259571e Refactor GetColorPalette method. -1df5e260 avoid using tmp histogram in PreparePair() -7685123a fix comment typos -a246b921 Speedup backward references. -76d73f18 Merge "CostManager: introduce a free-list of ~10 intervals" -eab39d81 CostManager: introduce a free-list of ~10 intervals -4c59aac0 Merge "mips msa webp configuration" -043c33f1 Merge "Improve speed and compression in backward reference for lossless." -71be9b8c Merge "clarify variable names in HistogramRemap()" -0ba7fd70 Improve speed and compression in backward reference for lossless. -0481d42a CostManager: cache one interval and re-use it when possible -41b7e6b5 Merge "histogram: fix bin calculation" -96c3d624 histogram: fix bin calculation -fe9e31ef clarify variable names in HistogramRemap() -ce3c8247 disable near-lossless quantization if palette is used -e11da081 mips msa webp configuration -5f8f998d mux: Presence of unknown chunks should trigger VP8X chunk output. -cadec0b1 Merge "Sync mips32 and dsp_r2 YUV->RGB code with C verison" -d9637758 Compute the hash chain once and for all for lossless compression. -50a48665 Sync mips32 and dsp_r2 YUV->RGB code with C verison -eee788e2 Merge "introduce a common signature for all image reader function" -d77b877c introduce a common signature for all image reader function -ca8d9519 remove some obsolete TODOs -ae2a7222 collect all decoding utilities from examples/ in libexampledec.a -0b8ae852 Merge "Move DitherCombine8x8 to dsp/dec.c" -77cad885 Merge "ReadWebP: avoid conversion to ARGB if final format is YUVA" -ab8d6698 ReadWebP: avoid conversion to ARGB if final format is YUVA -f8b7ce9e Merge "test pointer to NULL explicitly" -5df6f214 test pointer to NULL explicitly -77f21c9c Move DitherCombine8x8 to dsp/dec.c -c9e6d865 Add gradle support -c65f41e8 Revert "Add gradle support" -bf731ede Add gradle support -08333b85 WebPAnimEncoder: Detect when canvas is modified, restore only when needed. -0209d7e6 Merge "speed-up MapToPalette() with binary search" -fdd29a3d speed-up MapToPalette() with binary search -cf4a651b Revert "Refactor GetColorPalette method." -0a27aca3 Merge changes Idfa8ce83,I19adc9c4 -f25c4406 WebPAnimEncoder: Restore original canvas between multiple encodes. -169004b1 Refactor GetColorPalette method. -576362ab VP8LDoFillBitWindow: support big-endian in fast path -ac49e4e4 bit_reader.c: s/VP8L_USE_UNALIGNED_LOAD/VP8L_USE_FAST_LOAD/ -d39ceb58 VP8LDoFillBitWindow: remove stale TODO -2ec2de14 Merge "Speed-up BackwardReferencesHashChainDistanceOnly." -3e023c17 Speed-up BackwardReferencesHashChainDistanceOnly. -f2e1efbe Improve near lossless compression when a prediction filter is used. -e15afbce dsp.h: fix ubsan macro name -e53c9ccb dsp.h: add WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW -af81fdb7 utils.h: quiet -fsanitize=undefined warnings -ea0be354 dsp.h: remove utils.h include -cd276aec utils/*.c: ../utils/utils.h -> ./utils.h -c8927131 utils/Makefile.am: add some missing headers -ea24e026 Merge "dsp.h: add WEBP_UBSAN_IGNORE_UNDEF" -369e264e dsp.h: add WEBP_UBSAN_IGNORE_UNDEF -0d020a78 Merge "add runtime NEON detection" -5ee2136a Merge "add VP8LAddPixels() to lossless.h" -47435a61 add VP8LAddPixels() to lossless.h -8fa6ac68 remove two ubsan warnings -74fb56fb add runtime NEON detection -4154a839 MIPS update to new Unfilter API -c80b9fc8 Merge "cherry-pick decoder fix for 64-bit android devices" -6235147e cherry-pick decoder fix for 64-bit android devices -d41b8c43 configure: test for -Wformat-* w/-Wformat present -5f95589f Fix WEBP_ALIGN in case the argument is a pointer to a type larger than a byte. -2309fd5c replace num_parts_ by num_parts_minus_one_ (unsigned) -9629f4bc SimplifySegments: quiet -Warray-bounds warning -de47492e Merge "update the Unfilter API in dsp to process one row independently" -2102ccd0 update the Unfilter API in dsp to process one row independently -e3912d56 WebPAnimEncoder: Restore canvas before evaluating blending possibility. -6e12e1e3 WebPAnimEncoder: Fix for single-frame optimization. -602f344a Merge changes I1d03acac,Ifcb64219 -95ecccf6 only apply color-mapping for alpha on the cropped area -47dd0708 anim_diff: Add an experimental option for max inter-frame diff. -aa809cfe only allocate alpha_plane_ up to crop_bottom row -31f2b8d8 WebPAnimEncoder: FlattenSimilarPixels(): look for similar -774dfbdc perform alpha filtering within the decoding loop -a4cae68d lossless decoding: only process decoded row up to last_row -238cdcdb Only call WebPDequantizeLevels() on cropped area -cf6c713a alpha: preparatory cleanup -b95ac0a2 Merge "VP8GetHeaders(): initialize VP8Io with sane value for crop/scale dimensions" -89231394 VP8GetHeaders(): initialize VP8Io with sane value for crop/scale dimensions -5828e199 use_8b_decode -> use_8b_decode_ -8dca0247 fix bug in alpha.c that was triggering a memory error in incremental mode -9a950c53 WebPAnimEncoder: Disable filtering when blending is used with lossy encoding. -eb423903 WebPAnimEncoder: choose max diff for framerect based on quality. -ff0a94be WebPAnimEncoder lossy: ignore small pixel differences for frame rectangles. -f8040084 gif2webp: Remove the 'prev_to_prev_canvas' buffer. -6d8c07d3 Merge "WebPDequantizeLevels(): use stride in CountLevels()" -d96fe5e0 WebPDequantizeLevels(): use stride in CountLevels() -ec1b2407 WebPPictureImport*: check output pointer -c0768769 Merge "Revert "Re-enable encoding of alpha plane with color cache for next release."" -41f14bcb WebPPictureImport*: check src pointer -64eed387 Pass stride parameter to WebPDequantizeLevels() -97934e24 Revert "Re-enable encoding of alpha plane with color cache for next release." -e88c4ca0 fix -m 2 mode-cost evaluation (causing partition0 overflow) -4562e83d Merge "add extra meaning to WebPDecBuffer::is_external_memory" -abdb109f add extra meaning to WebPDecBuffer::is_external_memory -875aec70 enc_neon,cosmetics: break long comment -71e856cf GetMBSSIM,cosmetics: fix alignment -a90edffb fix missing 'extern' for SSIM function in dsp/ -423ecaf4 move some SSIM-accumulation function for dsp/ -f08e6624 Merge "Fix FindClosestDiscretized in near lossless:" -0d40cc5e enc_neon,Disto4x4: remove an unnecessary transpose -e8feb20e Fix FindClosestDiscretized in near lossless: -82006430 anim_util: quiet static analysis warning -a6f23c49 Merge "AnimEncoder: Support progress hook and user data." -a5193774 Merge "Near lossless feature: fix some comments." -da98d31c AnimEncoder: Support progress hook and user data. -33357131 Near lossless feature: fix some comments. -0beed01a cosmetics: fix indent after 2f5e898 -6753f35c Merge "FTransformWHT optimization." -6583bb1a Improve SSE4.1 implementation of TTransform. -7561d0c3 FTransformWHT optimization. -7ccdb734 fix indentation after patch #328220 -6ec0d2a9 clarify the logic of the error path when decoding fails. -8aa352b2 Merge "Remove an unnecessary transposition in TTransform." -db860884 Merge "remove useless #include" -9960c316 Remove an unnecessary transposition in TTransform. -6e36b511 Small speedup in FTransform. -9dbd4aad Merge "fix C and SIMD flags completion." -e60853ea Add missing common_sse2.h file to makefile.unix -696eb2b0 fix C and SIMD flags completion. -2b4fe33e Merge "fix multiple allocation for transform buffer" -2f5e8986 fix multiple allocation for transform buffer -bf2b4f11 Regroup common SSE code + optimization. -4ed650a1 force "-pass 6" if -psnr or -size is used but -pass isn't. -3ef1ce98 yuv_sse2: fix -Wconstant-conversion warning -a7a03e9f Merge changes I4852d18f,I51ccb85d -5e122bd6 gif2webp: set enc_options.verbose = 0 w/-quiet -ab3c2583 anim_encode,DefaultEncoderOptions: init verbose -8f0dee77 Merge "configure: fix builtin detection w/-Werror" -4a7b85a9 cmake: fix builtin detection w/-Werror -b74657fb configure: fix builtin detection w/-Werror -3661b980 Add a CMakeLists.txt -75f4af4d remove useless #include -6c1d7631 avoid Yoda style for comparison -8ce975ac SSE optimization for vector mismatch. -7db53831 Merge tag 'v0.5.0' -37f04949 update ChangeLog (tag: v0.5.0-rc1, tag: v0.5.0, origin/0.5.0) -7e7b6ccc faster rgb565/rgb4444/argb output -4c7f565f update NEWS -1f62b6b2 update AUTHORS -e224fdc8 update mailmap -71100500 bump version to 0.5.0 -230a685e README: update help text, repo link -d48e427b Merge "demux: accept raw bitstreams" -99a01f4f Merge "Unify some entropy functions." -4b025f10 Merge "configure: disable asserts by default" -92cbddf8 Merge "fix PrintBlockInfo()" -ca509a33 Unify some entropy functions. -367bf903 fix PrintBlockInfo() -b0547ff0 move back common constants for lossless_enc*.c into the .h -fb4c7832 lossless: simpler alpha cleanup preprocessing -ba7f4b68 Merge "anim_diff: add brief description of options" -47ddd5a4 Move some codec logic out of ./dsp . -b4106c44 anim_diff: add brief description of options -357f455d yuv_sse2: fix 32-bit visual studio build -b9d80fa4 configure: disable asserts by default -7badd3da cosmetic fix: sizeof(type) -> sizeof(*var) -80ce27d3 Speed up 24-bit packing / unpacking in YUV / RGB conversions. -68eebcb0 remove a TODO about rotation -2dee2966 remove few obsolete TODO about aligned loads in SSE2 -e0c0bb34 remove TODO about unused ref_lf_delta[] -9cf1cc2b remove few TODO: * 256 -> RD_DISTO_MULT * don't use TDisto for UV mode picking -79189645 Merge changes from topic 'demux-fragment-cleanup' -47399f92 demux: remove GetFragment() -d3cfb79a demux: remove dead fragment related TODO -ab714b8a demux, Frame: remove is_fragment_ field -b105921c yuv_sse2, cosmetics: fix indent -466c92e8 demux,WebPIterator: remove fragment_num/num_fragments -11714ff1 demux: remove WebPDemuxSelectFragment -c0f7cc47 fix for bug #280: UMR in next->bits -578beeb8 Merge "enc/Makefile.am: add missing headers" -1a819f00 makefile.unix: make visibility=hidden the default -d4f9c2ef enc/Makefile.am: add missing headers -846caff4 configure: check for -fvisibility=hidden -3f3ea2c5 demux: accept raw bitstreams -d6dad5d0 man cwebp: add precision about exactness of the 'lossless' mode -46bb1e34 Merge "gifdec: remove utils.h include" -2b882e94 Merge "Makefile.vc: define WEBP_HAVE_GIF for gifdec.c" -892b9238 Merge "man/*, AUTHORS: clarify origin of the tool" -e5687a18 Merge "fix optimized build with -mcmodel=medium" -e56e6859 Makefile.vc: define WEBP_HAVE_GIF for gifdec.c -4077d944 gifdec: remove utils.h include -b5e30dac man/*, AUTHORS: clarify origin of the tool -b275e598 fix optimized build with -mcmodel=medium -64da45a9 cosmetics, cwebp: fix indent -038a060d Merge "add disto-based refinement for UV mode (if method = 1 or 2)" -2835089d Provide an SSE2 implementation of CombinedShannonEntropy. -e6c93519 add disto-based refinement for UV mode (if method = 1 or 2) -04507dc9 Merge "fix undefined behaviour during shift, using a cast" -793c5261 Merge "wicdec: add support for reading from stdin" -d3d16397 Optimize the heap usage in HistogramCombineGreedy. -202a710b fix undefined behaviour during shift, using a cast -14d27a46 improve method #2 by merging DistoRefine() and SimpleQuantize() -cb1ce996 Merge "10% faster table-less SSE2/NEON version of YUV->RGB conversion" -ac761a37 10% faster table-less SSE2/NEON version of YUV->RGB conversion -79fcf29a wicdec: add support for reading from stdin -015f173f Merge "cwebp: add support for stdin input" -a9947c32 cwebp: add support for stdin input -7eb01ff3 Merge "Improved alpha cleanup for the webp encoder when prediction transform is used." -fb8c9106 Merge "introduce WebPMemToUint32 and WebPUint32ToMem for memory access" -bd91af20 Merge "bit_reader: remove aarch64 BITS TODO" -6c702b81 Speed up hash chain initialization using memset. -4c60f63c make ReadPNG and ReadJPEG take a filename instead of a FILE -464ed10f bit_reader: remove aarch64 BITS TODO -d478e589 Merge "configure: update issue tracker" -69381113 Improved alpha cleanup for the webp encoder when prediction transform is used. -2c08aac8 introduce WebPMemToUint32 and WebPUint32ToMem for memory access -010ca3d1 Fix FindMatchLength with non-aligned buffers. -a90e1e3f README: add prerequisites for an autoconf build -458f0866 configure: update issue tracker -33914595 vwebp: work around the transparent background with GLUT bug -e4a7eed4 cosmetics: fix indent -08375129 Merge "Make a separate case for low_effort in CopyImageWithPrediction" -aa2eb2d4 Merge "cosmetics: fix indent" -b7551e90 cosmetics: fix indent -5bda52d4 Make a separate case for low_effort in CopyImageWithPrediction -66fa598a Merge "configure: fix intrinsics build w/older gcc" -5ae220be backward_references.c: Fixed compiler warning -1556da09 Merge "configure: restore 2 warnings" -71a17e58 configure: restore 2 warnings -9eeabc07 configure: fix intrinsics build w/older gcc -363babe2 Merge "fix some warning about unaligned 32b reads" -a1411782 Optimization in hash chain comparison for 64 bit Arrays were compared 32 bits at a time, it is now done 64 bits at a time. Overall encoding speed-up is only of 0.2% on @skal's small PNG corpus. It is of 3% on my initial 1.3 Mp desktop screenshot image. -829bd141 Combine Huffman cost and bit entropy into one loop -a7a954c8 Merge "lossless: make prediction in encoder work per scanline" -61b605b4 Merge "fix of undefined multiply (int32 overflow)" -239421c5 lossless: make prediction in encoder work per scanline -f5ca40e0 fix of undefined multiply (int32 overflow) -5cd2ef4c Merge changes from topic 'win-threading-compat' -76ce9187 Makefile.vc: enable WEBP_USE_THREAD for windows phone -d2afe974 thread: use CreateThread for windows phone -0fd0e12b thread: use WaitForSingleObjectEx if available -63fadc9f thread: use InitializeCriticalSectionEx if available -110ad583 thread: use native windows cond var if available -912c9fdf dec/webp: use GetLE(24|32) from utils -f1694481 utils/GetLE32: correct uint32 promotion -158763de Merge "always call WebPInitSamplers(), don't try to be smart" -3770f3bb Merge "cleanup the YFIX/TFIX difference by removing some code and #define" -a40f60a9 Merge "3% speed improvement for lossless webp encoder for low effort mode:" -ed1c2bc6 always call WebPInitSamplers(), don't try to be smart -b8c44f1a 3% speed improvement for lossless webp encoder for low effort mode: -997e1038 cleanup the YFIX/TFIX difference by removing some code and #define -d73d1c8b Merge "Make discarding invisible RGB values (cleanup alpha) the default." -1f9be97c Make discarding invisible RGB values (cleanup alpha) the default. -f240117b Make dwebp listen more to the -quiet flag -b37b0179 fix for issue #275: don't compare to out-of-bound pointers -21735e06 speed-up trivial one-symbol decoding case for lossless -397863bd Refactor CopyPlane() and CopyPixels() methods: put them in utils. -6ecd72f8 Re-enable encoding of alpha plane with color cache for next release. -1f7148a4 Merge "remove unused fields from WebPDecoderOptions and WebPBitstreamFeatures" -6ae395fa Merge "use ExReadFile() for ReadYUV()" -8076a00e gitignore list: add anim_diff. -1c1702d8 use ExReadFile() for ReadYUV() -775d3a37 remove unused fields from WebPDecoderOptions and WebPBitstreamFeatures -c13245c7 AnimEncoder: Add a GetError() method. -688b265d AnimDecoder API: Add a GetDemuxer() method. -1aa4e3d6 WebPAnimDecoder: add an option to enable multi-threaded decoding. -3584abca AnimDecoder: option to decode to common color modes. -afd5a62c Merge "mux.h does NOT need to include encode.h" -8550d443 Merge "migrate anim_diff tool from C++ to C89" -96201e50 migrate anim_diff tool from C++ to C89 -945cfa3b mux.h does NOT need to include encode.h -8da07e8d Merge "~2x faster SSE2 RGB24toY, BGR24toY, ARGBToY|UV" -bfd3fc02 ~2x faster SSE2 RGB24toY, BGR24toY, ARGBToY|UV -02432427 man/cwebp.1, cosmetics: escape '-'s -96f5b423 man/cwebp: group lossy-only options -52fdbdfe extract some RGB24 to Luma conversion function from enc/ to dsp/ -ab8c2300 add missing \n -8304179a sync NEWS with 0.4.4 -5bd04a08 sync versions with 0.4.4 -8f1fcc15 Merge "Move ARGB->YUV functions from dec/vp8l.c to dsp/yuv.c" -25bf2ce5 fix some warning about unaligned 32b reads -922268fd s/TIFF/WebP -fa8927ef Move ARGB->YUV functions from dec/vp8l.c to dsp/yuv.c -9b373598 Merge "for ReadXXXX() image-readers, use the value of pic->use_argb" -f7c507a5 Merge "remove unnecessary #include "yuv.h"" -7861578b for ReadXXXX() image-readers, use the value of pic->use_argb -14e4043b remove unnecessary #include "yuv.h" -469ba2cd vwebp: fix incorrect clipping w/NO_BLEND -4b9186b2 update issue tracker url -d64d376c change WEBP_ALIGN_CST value to 31 -f717b828 vp8l.c, cosmetics: fix indent after 95509f9 -927ccdc4 Merge "fix alignment of allocated memory in AllocateTransformBuffer" -fea94b2b fix alignment of allocated memory in AllocateTransformBuffer -5aa8d61f Merge "MIPS: rescaler code synced with C implementation" -e7fb267d MIPS: rescaler code synced with C implementation -93c86ed5 Merge "format_constants.h: MKFOURCC, correct cast" -5d791d26 format_constants.h: MKFOURCC, correct cast -65726cd3 dsp/lossless: Average2, make a constant unsigned -d26d9def Use __has_builtin to check clang support -12ec204e moved ALIGN_CST into util/utils.h and renamed WEBP_ALIGN_xxx -a2640838 Merge "rescaler: ~20% faster SSE2 implementation for lossless ImportRowExpand" -3fb600d5 Merge "wicdec: fix alpha detection w/64bpp BGRA/RGBA" -67c547fd rescaler: ~20% faster SSE2 implementation for lossless ImportRowExpand -99e3f812 Merge "large re-organization of the delta-palettization code" -95509f99 large re-organization of the delta-palettization code -74fb458b fix for weird msvc warning message -ae49ad86 Merge "SSE2 implementation of ImportRowShrink" -932fd4df SSE2 implementation of ImportRowShrink -badfcbaa wicdec: fix alpha detection w/64bpp BGRA/RGBA -35cafa6c Merge "iosbuild: fix linking with Xcode 7 / iOS SDK 9" -b0c9d8af label rename: NO_CHANGE -> NoChange -b4e731cd neon-implementation for rescaler code -db1321a6 iosbuild: fix linking with Xcode 7 / iOS SDK 9 -6dfa5e3e rescaler: better handling of the fxy_scale=0 special case. -55c05293 Revert "rescaler: better handling of the fxy_scale=0 special case." -9f226bf8 rescaler: better handling of the fxy_scale=0 special case. -f7b8f907 delta_palettization.*: add copyright -c1e1b710 Changed delta palette to compress better -0dd28267 Merge "Add delta_palettization feature to WebP" -48f66b66 Add delta_palettization feature to WebP -27933e2a anim_encoder: drop a frame if it has same pixels as the prev frame. -df9f6ec8 Merge "webpmux/DisplayInfo: send non-error output to stdout" -8af4993b Merge "rescaler_mips_dsp_r2: cosmetics, fix indent" -2b9d2495 Merge "rescaler: cosmetics, join two lines" -cc020a8c webpmux/DisplayInfo: send non-error output to stdout -a288e746 configure: add -Wshorten-64-to-32 -c4c3cf2d pngdec: fix type conversion warnings -bef8e97d webpmux: fix type conversion warning -5a84460d rescaler_mips_dsp_r2: cosmetics, fix indent -acde0aae rescaler: cosmetics, join two lines -306ce4fd rescaler: move the 1x1 or 2x1 handling one level up -cced974b remove _mm_set_epi64x(), which is too specific -56668c9f fix warnings about uint64_t -> uint32_t conversion -76a7dc39 rescaler: add some SSE2 code -1df1d0ee rescaler: harmonize function protos -9ba1894b rescaler: simplify ImportRow logic -5ff0079e fix rescaler vertical interpolation -cd82440e VP8LAllocateHistogramSet: align histogram[] entries -a406b1dd Merge "fix memory over-allocation in lossless rescaler init" -0fde33e3 add missing const in VP8InitFrame signature -ac7d5e8d fix memory over-allocation in lossless rescaler init -017f8ccc Loosen the buffer size checks for Y/U/V/A too. -15ca5014 loosen the padding check on buffer size -d623a870 dec_neon: add whitespace around stringizing operator -29377d55 dsp/mips: cosmetics: add whitespace around XSTR macro -eebaf97f dsp/mips: add whitespace around stringizing operator -d39dc8f3 Create a WebPAnimDecoder API. -03fb7522 gif2webp: print output file size -14efabbf Android: limit use of cpufeatures -7b83adbe preparatory cosmetics for Rescaler code fix and clean-up -77fb41c2 dec/vp8l/DecodeAlphaData: remove redundant cast -90fcfcd9 Insert less hash chain entries from the beginnings of long copies. -bd55604d SSE2: add yuv444 converters, re-using yuv_sse2.c -41a5d99d add a -quiet option to 'dwebp' -80ab3edb Merge "README: update dwebp help output after 1e595fe" -32b71b2e README: update dwebp help output after 1e595fe -3ec11827 use the DispatchAlpha() call from dsp -c5f00621 incorporate bzero() into WebPRescalerInit() instead of call site -3ebcdd41 remove duplicate "#include " -1e595fe1 dwebp: add -resize as a synonym for -scale -24a96932 dec: allow 0 as a scaling dimension -b9187242 utils/rescaler: add WebPRescalerGetScaledDimensions -923e8eda Merge "update NEWS" -020fd099 Merge "WebPPictureDistortion: support ARGB format for 'pic' when computing distortion." -6a5292f6 update NEWS -56a2e9f5 WebPPictureDistortion: support ARGB format for 'pic' when computing distortion. -0ae582e4 configure: test and add -Wunreachable-code -c2f9dc06 bit_writer: convert VP8L macro values to immediates -b969f888 Reduce magic in palette reordering -acb297e9 anim_diff: add a -raw_comparison flag -155c1b22 Merge changes I76f4d6fe,I45434639 -717e4d5a mips32/mipsDSPr2: function ImportRow rebased -7df93893 fix rescaling bug (uninitialized read, see bug #254). -5cdcd561 lossless_enc_neon: add VP8LTransformColor -a53c3369 lossless_neon: add VP8LTransformColorInverse -99131e7f Merge changes I9fb25a89,Ibc648e9e -c4556766 simplify the main loop for downscaling -2a010f99 lossless_neon: remove predictors 5-13 -ca221bbc ll_enc_neon: enable VP8LSubtractGreenFromBlueAndRed -585d93db Container spec: clarify ordering of ALPH chunk. -01d61fd9 lossless: ~20 % speedup -f722c8f0 lossless: Speed up ComputeCacheEntropy by 40 % -1ceecdc8 add a VP8LColorCacheSet() method for color cache -17eb6099 lossless: Allow copying from prev row in rle-mode. -f3a7a5bf lossless: bit writer optimization -d97b9ff7 Merge changes from topic 'lossless-enc-improvements' -0250dfcc msvc: fix pointer type warning in BitsLog2Floor -52931fd5 lossless: combine the Huffman code with extra bits -c4855ca2 lossless: Inlining add literal -8e9c94de lossless: simplify HashChainFindCopy heuristics -888429f4 lossless: 0.5 % compression density improvement -7b23b198 lossless: Add zeroes into the predicted histograms. -85b44d8a lossless: encoding, don't compute unnecessary histo -d92453f3 lossless: Remove about 25 % of the speed degradation -2cce0317 Faster alpha coding for webp -5e75642e lossless: rle mode not to accept lengths smaller than 4. -84326e4a lossless: Less code for the entropy selection -16ab951a lossless: 0.37 % compression density improvement -822f113e add WebPFree() to the API -0ae2c2e4 SSE2/SSE41: optimize SSE_16xN loops -39216e59 cosmetics: fix indent after 32462a07 -559e54ca Merge "SSE2: slightly faster FTransformWHT" -8ef9a63b SSE2: slightly faster FTransformWHT -f27f7735 lossless_neon: enable VP8LAddGreenToBlueAndRed -36e9c4bc SSE2: minor cosmetrics on in-loop filter code -4741fac4 dsp/lossless_*sse2: remove some unnecessary inlines -1819965e fix warning ("left shift of negative value") using a cast -70170014 SSE2: speed-up some lossless-encoding functions -abcb0128 Merge "SSE2: slightly faster (~5%) AddGreenToBlueAndRed()" -2df5bd30 Merge "Speedup to HuffmanCostCombinedCount" -9e356d6b SSE2: slightly faster (~5%) AddGreenToBlueAndRed() -fc6c75a2 SSE2: 53% faster TransformColor[Inverse] -49073da6 SSE2: 46% speed-up of TransformColor[Inverse] -32462a07 Speedup to HuffmanCostCombinedCount -f3d687e3 SSE4.1 implementation of some lossless encoding functions -bfc300c7 SSE4.1 implementation of some alpha-processing functions -7f9c98f2 Merge "sse2 in-loop: simplify SignedShift8b() a bit" -ef314a5d dec_sse2/GetNotHEV: micro optimization -a729cff9 sse2 in-loop: simplify SignedShift8b() a bit -422ec9fb simplify Load8x4() a bit -8df238ec Merge "remove some duplicate FlipSign()" -751506c4 remove some duplicate FlipSign() -65ef5afc Merge "lossless: 0.13% compression density gain" -2beef2f2 lossless: 0.13% compression density gain -3033f24c lossless: 0.06 % compression density improvement -64960da9 dec_neon: add VE8uv / VE16 -14dbd87b dec_neon: add HE8uv / HE16 -ac768011 introduce FTransform2 to perform two transforms at a time. -aa6065ae dec_neon: use vld1_dup(mem) rather than vdup(mem[0]) -8b63ac78 Merge "dec_neon: add TM16" -f51be09e Merge "dec_neon/TrueMotion: simply left border load" -dc48196b dec_neon: add TM16 -ea95b305 dec_neon/TrueMotion: simply left border load -f262d612 speed-up SetResidualSSE2 -bf46d0ac fix mips2 build target -929a0fdc enc_sse2/TTransform: simplify abs calculation -17dbd058 enc_sse2/CollectHistogram: simplify abs calculation -a6c15936 dec_neon: add DC16 intra predictors -03b4f50d Makefile.vc: add anim_diff build support. -1b989874 Merge changes I9cd84125,Iee7e387f,I7548be72 -acd7b5af Introduce a test tool anim_diff. -f274a96c dsp/enc_sse2: add luma4 intra predictors -040b11bd dsp/enc_sse2: add chroma intra predictors -aee021bb dsp/enc_sse2: add luma16 intra predictors -9e00a499 makefile.unix: remove superclean target -cefc9c09 makefile.unix: clean up after extras target -4c9af023 dec_neon: add DC8uvNoTopLeft -dd55b873 Merge "doc/webp-container-spec: update repo browser link" -f0486968 doc/webp-container-spec: update repo browser link -9287761d Merge "GetResidualCostSSE2: simplify abs calculation" -0e009366 dsp/cpu.c(x86): check maximum supported cpuid feature -b243a4bc GetResidualCostSSE2: simplify abs calculation -6d4602b8 Merge "fix typo: constitutes -> constitute" -5fe1fe37 fix typo: constitutes -> constitute -b83bd7c4 Merge "populate 'libwebpextras' with: import gray, rgb565 and rgb4444 functions" -b0114a32 Merge "histogram.h: cosmetics: remove unnecessary includes" -feab45ef gifdec: Move inclusion of webp/config.h to header. -dbba67d1 histogram.h: cosmetics: remove unnecessary includes -e978fec6 Merge "VP8LBitReader: fix remaining ubsan error with large shifts" -d6fe5884 Merge "ReconstructRow: move some one-time inits out of the main loop" -a21d647c ReconstructRow: move some one-time inits out of the main loop -7a01c3c3 VP8LBitReader: fix remaining ubsan error with large shifts -7fa67c9b change GetPixPairHash64() return type to uint32_t -ec1fb9f8 Merge "dsp/enc.c: cosmetics: move DST() def closer to use" -7073bfb3 Merge "split 64-mult hashing into two 32-bit multiplies" -0768b252 dsp/enc.c: cosmetics: move DST() def closer to use -6a48b8f0 Merge "fix MSVC size_t->int conversion warning" -1db07cde Merge "anim_encode: cosmetics: fix alignment" -e28271a3 anim_encode: cosmetics: fix alignment -7fe357b8 split 64-mult hashing into two 32-bit multiplies -af74c145 populate 'libwebpextras' with: import gray, rgb565 and rgb4444 functions -61214134 remove VP8Residual::cost unused field -e2544823 fix MSVC size_t->int conversion warning -b69a6c35 vwebp: don't redefine snprintf with VS2015+ -0ac29c51 AnimEncoder API: Consistent use of trailing underscores in struct. -d4845550 AnimEncoder API: Use timestamp instead of duration as input to Add(). -9904e365 dsp/dec_sse2: DC8uv / DC8uvNoLeft speedup -7df20497 dsp/dec_sse2: DC16 / DC16NoLeft speedup -8e515dfe Merge "makefile.unix: add some missing headers" -db12250f cosmetics: vp8enci.h: break long line -bf516a87 makefile.unix: add some missing headers -b44eda3f dsp: add DSP_INIT_STUB -03e76e96 clarify the comment about double-setting the status in SetError() -9fecdd71 remove unused EmitRGB() -43f010dd move ReconstructRow to top -82d98020 add a dec/common.h header to collect common enc/dec #defines -5d4744a2 Merge "enc_sse41: add Disto4x4 / Disto16x16" -e38886a7 mux.h: Bump up ABI version -46305ca6 configure: add --disable- -2fc8b658 CPPFLAGS->CFLAGS for detecting sse4.1 in preprocessor -1a338fb3 enc_sse41: add Disto4x4 / Disto16x16 -94055503 encoding SSE4.1 stub for StoreHistogram + Quantize + SSE_16xN -c64659e1 remove duplicate variables after the lossless{_enc}.c split -67ba7c7a enc_sse2: call local FTransform in CollectHistogram -18249799 dsp: s/VP8LSetHistogramData/VP8SetHistogramData/ -ede5e158 cosmetics: dsp/lossless.h: reorder prototypes -553051f7 dsp/lossless: split enc/dec functions -9064adc8 Merge "conditionally add -msse4.1 in Makefile.unix" -cecf5096 dsp/yuv*.c: rework WEBP_USE_ ifdef -6584d398 dsp/upsampling*.c: rework WEBP_USE_ ifdef -80809422 dsp/rescaler*.c: rework WEBP_USE_ ifdef -1d93ddec dsp/lossless*.c: rework WEBP_USE_ ifdef -73805ff2 dsp/filters*.c: rework WEBP_USE_ ifdef -fbdcef24 dsp/enc*.c: rework WEBP_USE_ ifdef -66de69c1 dsp/dec*.c: rework WEBP_USE_ ifdef -48e4ffd1 dsp/cost*.c: rework WEBP_USE_ ifdef -29fd6f90 dsp/argb*.c: rework WEBP_USE_ ifdef -80ff3813 dsp/alpha*.c: rework WEBP_USE_ ifdef -bf09cf1e conditionally add -msse4.1 in Makefile.unix -e9570dd9 stub for SSE4.1 support. -4a95384b Merge "dsp: add sse4.1 detection" -cabf4bd2 dsp: add sse4.1 detection -4ecba1ab thread.h: rename interface param -b8d706c8 Merge "sync versions with 0.4.3" -ae64a711 Merge "add shell for libwebpextras" -92a5da9c sync versions with 0.4.3 -9d4e2d16 Merge "~30% faster smart-yuv (-pre 4) with early-out criterion" -b1bdbbab ~30% faster smart-yuv (-pre 4) with early-out criterion -7efb9748 Merge "Disable NEON code on Native Client" -ac4f5784 Disable NEON code on Native Client -0873f85b AnimEncoder API: Support input frames in YUV(A) format. -5c176d2d add shell for libwebpextras -44bd9561 fix signature for VP8RecordCoeffTokens() -c9b8ea0e small cosmetics on TokenBuffer. -76394c09 Merge "MIPS: dspr2: added optimization for TrueMotion" -0f773693 WebPPictureRescale: add a note about 0 width/height -241bb5d9 MIPS: dspr2: added optimization for TrueMotion -6cef0e4f examples/Android.mk: add webpmux_example target -53c16ff0 Android.mk: add webpmux target -21852a00 Android.mk: add webpdemux target -8697a3bc Android.mk: add webpdecoder{,_static} targets -4a670491 Android.mk: split source lists per-directory -b5e79422 MIPS: dspr2: Added optimization for some convert functions -0f595db6 MIPS: dspr2: Added optimization for some convert functions -8a218b4a MIPS: [mips32|dspr2]: GetResidualCost rebased -ef987500 Speedup method StoreImageToBitMask by 5%. -602a00f9 fix iOS arm64 build with Xcode 6.3 -23820507 1-2% faster encoding by removing an indirection in GetResidualCost() -eddb7e70 MIPS: dspr2: added otpimization for DC8uv, DC8uvNoTop and DC8uvNoLeft -73ba2915 MIPS: dspr2: added optimization for functions RD4 and LD4 -c7129da5 Merge "4-5% faster encoding using SSE2 for GetResidualCost" -94380d00 MIPS: dspr2: added optimizaton for functions VE4 and DC4 -2a407092 4-5% faster encoding using SSE2 for GetResidualCost -17e19862 Merge "MIPS: dspr2: added optimization for simple filtering functions" -3ec404c4 Merge "dsp: normalize WEBP_TSAN_IGNORE_FUNCTION usage" -b969f5df dsp: normalize WEBP_TSAN_IGNORE_FUNCTION usage -d7b8e711 MIPS: dspr2: added optimization for simple filtering functions -235f774e Merge "MIPS: dspr2: Added optimization for function VP8LTransformColorInverse_C" -42a8a628 MIPS: dspr2: Added optimization for function VP8LTransformColorInverse_C -b442bef3 Merge "ApplyFiltersAndEncode: only copy lossless stats" -b510fbfe doc/webp-container-spec: note MSB order for chunk diagrams -9bc0f922 ApplyFiltersAndEncode: only copy lossless stats -3030f115 Merge "dsp/mips: add some missing TSan annotations" -dfcf4593 Merge "MIPS: dspr2: Added optimization for function VP8LAddGreenToBlueAndRed_C" -55c75a25 dsp/mips: add some missing TSan annotations -2cb879f0 MIPS: dspr2: Added optimization for function VP8LAddGreenToBlueAndRed_C -e1556010 move some cost tables from enc/ to dsp/ -c3a03168 Merge "picture_csp: fix build w/USE_GAMMA_COMPRESSION undefined" -39537d7c Merge "VP8LDspInitMIPSdspR2: add missing TSan annotation" -1dd419ce picture_csp: fix build w/USE_GAMMA_COMPRESSION undefined -43fd3543 VP8LDspInitMIPSdspR2: add missing TSan annotation -c7233dfc Merge "VP8LDspInit: remove memcpy" -0ec4da96 picture_csp::InitGammaTables*: add missing TSan annotations -35579a49 VP8LDspInit: remove memcpy -97f6aff8 VP8YUVInit: add missing TSan annotation -f9016d66 dsp/enc::InitTables: add missing TSan annotation -e3d9771a VP8EncDspCostInit*: add missing TSan annotations -d97c143d Merge "doc/webp-container-spec: cosmetics" -309b7908 MIPS: mips32: Added optimization for function SetResidualCoeffs -a987faed MIPS: dspr2: added optimization for function GetResidualCost -e7d3df23 doc/webp-container-spec: cosmetics -be6635e9 Merge "VP8TBufferClear: remove some misleading const's" -02971e72 Merge "VP8EmitTokens: remove unnecessary param void cast" -3b77e5a7 VP8TBufferClear: remove some misleading const's -aa139c8f VP8EmitTokens: remove unnecessary param void cast -c24d8f14 cosmetics: upsampling_sse2: add const to some casts -1829c42c cosmetics: lossless_sse2: add const to some casts -183168f3 cosmetics: enc_sse2: add const to some casts -860badca cosmetics: dec_sse2: add const to some casts -0254db97 cosmetics: argb_sse2: add const to some casts -1aadf856 cosmetics: alpha_processing_sse2: add const to some casts -1579de3c vwebp: clear canvas at the beginning of each loop -4b9fa5d0 Merge "webp-container-spec: clarify background clear on loop" -4c82284d Updated the near-lossless level mapping. -56039479 webp-container-spec: clarify background clear on loop -19f0ba0e Implement true-motion prediction in SSE2 -774d4cb7 make VP8PredLuma16[] array non-const -d7eabb80 Merge "MIPS: dspr2: Added optimization for function CollectHistogram" -fe42739c Use integers for kmin/kmax for simplicity. -b9df35f7 AnimEncode API: kmax=0 should imply all keyframes. -6ce296da MIPS: dspr2: Added optimization for function CollectHistogram -2c906c40 vwebp: remove unnecessary static Help() prototype -be0fd1d5 Merge "dec/vp8: clear 'dither_' on skipped blocks" -e96170fe Merge "vwebp/animation: display last frame on end-of-loop" -0f017b56 vwebp/animation: display last frame on end-of-loop -c86b40cc enc/near_lossless.c: fix alignment -66935fb9 dec/vp8: clear 'dither_' on skipped blocks -b7de7946 Merge "lossless_neon: enable subtract green for aarch64" -77724f70 SSE2 version of GradientUnfilter -416e1cea lossless_neon: enable subtract green for aarch64 -72831f6b Speedup AnalyzeAndInit for low effort compression. -a6597483 Speedup Analyze methods for lossless compression. -98c81386 Enable Near-lossless feature. -c6b24543 AnimEncoder API: Fix for kmax=1 and default kmin case. -022d2f88 add SSE2 variants for alpha filtering functions -2db15a95 Temporarily disable encoding of alpha plane with color cache. -1d575ccd Merge "Lossless decoding: Remove an unnecessary if condition." -cafa1d88 Merge "Simplify backward refs calculation for low-effort." -7afdaf84 Alpha coding: reorganize the filter/unfiltering code -4d6d7285 Simplify backward refs calculation for low-effort. -ec0d1be5 Cleaup Near-lossless code. -9814ddb6 Remove the post-transform near-lossless heuristic. -4509e32e Lossless decoding: Remove an unnecessary if condition. -f2ebc4a8 Merge "Regression fix for lossless decoding" -783a8cda Regression fix for lossless decoding -9a062b8e AnimEncoder: Bugfix for kmin = 1 and kmax = 2. -0f027a72 simplify smart RGB->YUV conversion code -0d5b334e BackwardReferencesHashChainFollowChosenPath: remove unused variable -f480d1a7 Fix to near lossless artefacts on palettized images. -d4615d08 Merge changes Ia1686828,I399fda40 -cb4a18a7 rename HashChainInit into HashChainReset -f079e487 use uint16_t for chosen_path[] -da091212 MIPS: dspr2: Added optimization for function FTransformWHT -b8c20135 Merge "wicdec: (msvs) quiet some /analyze warnings" -9b228b54 wicdec: (msvs) quiet some /analyze warnings -daeb276a Merge "MIPS: dspr2: Added optimization for MultARGBRow function" -cc087424 Merge "dsp/cpu: (msvs) add include for __cpuidex" -4a82aab5 Merge changes I87544e92,I0bb6cda5 -7a191398 dwebp/WritePNG: mark png variables volatile -775dfad2 dwebp: include setjmp.h w/WEBP_HAVE_PNG -47d26be7 dwebp: correct sign in format strings -f0e0677b VP8LEncodeStream: add an assert -c5f7747f VP8LColorCacheCopy: promote an int before shifting -0de5f33e dsp/cpu: (msvs) add include for __cpuidex -7d850f7b MIPS: dspr2: Added optimization for MultARGBRow function -54875293 MIPS: dspr2: added optimization for function QuantizeBlock -4fbe9cf2 dsp/cpu: (msvs) avoid immintrin.h on _M_ARM -3fd59039 simplify/reorganize arguments for CollectColorBlueTransforms -b9e356b9 Disable costly TraceBackwards for method=0. -a7e7caa4 MIPS: dspr2: added optimization for function TransformColorRed -2cb39180 Merge "MIPS: dspr2: added optimization for function TransformColorBlue" -279e6613 Merge "dsp/cpu: add include for _xgetbv() w/MSVS" -b6c0428e dsp/cpu: add include for _xgetbv() w/MSVS -d1c4ffae gif2webp: Move GIF decoding related code to a support library. -07c39559 Merge "AnimEncoder API: Add info in README.mux" -7b161973 MIPS: dspr2: added optimization for function TransformColorBlue -d7c4b02a cpu: fix AVX2 detection for gcc/clang targets -9d299469 AnimEncoder API: Add info in README.mux -d581ba40 follow-up: clean up WebPRescalerXXX dsp function -f8740f0d dsp: s/USE_INTRINSICS/WEBP_USE_INTRINSICS/ -ce73abe0 Merge "introduce a separate WebPRescalerDspInit to initialize pointers" -ab66beca introduce a separate WebPRescalerDspInit to initialize pointers -205c7f26 fix handling of zero-sized partition #0 corner case -cbcdd5ff Merge "move rescaler functions to rescaler* files in src/dsp/" -bf586e88 Merge changes I230b3532,Idf3057a7 -6dc79dc2 Merge "anim_encode: fix type conversion warnings" -11fce25a Merge "dec_neon: remove returns from void functions" -c4e63f99 Makefile.vc: add gif2webp target -4f43d38c enable NEON for Windows ARM builds -3f6615ac Makefile.vc: add rudimentary Windows ARM support -e7c5954c dec_neon: remove returns from void functions -f79c163b anim_encode: fix type conversion warnings -0f54f1ec Remove gif2webp_util which is no longer needed. -cbcbedd0 move rescaler functions to rescaler* files in src/dsp/ -ac79ed19 webpmux: remove experimental fragment handling -e8694d4d mux: remove experimental FRGM parsing -9e92b6ea AnimEncoder API: Optimize single-frame animated images -abbae279 Merge "Move over gif2webp to the new AnimEncoder API." -a28c4b36 MIPS: move WORK_AROUND_GCC define to appropriate place -012d2c60 MIPS: dspr2: added optimization for functions SSEAxB -67720c8b Move over gif2webp to the new AnimEncoder API. -9241ecf4 MIPS: dspr2: added optimization for function Average -9422211d Merge "Tune BackwardReferencesLz77 for low_effort (m=0)." -df40057b Merge "Speedup VP8LGetHistoImageSymbols for low effort (m=0) mode." -ea08466d Tune BackwardReferencesLz77 for low_effort (m=0). -b0b973c3 Speedup VP8LGetHistoImageSymbols for low effort (m=0) mode. -c6d32927 argb_sse2: cosmetics -67f601cd make the 'last_cpuinfo_used' variable names unique -b9489861 AnimEncoder API: Init method for default options. -856f8ec1 Merge "AnimEncoder API: Remove AnimEncoderFrameOptions." -c537514d Merge "AnimEncoder API: GenerateCandidates bugfix." -dc0ce039 Merge "AnimEncoder API: Compute change rectangle for first frame too." -f00b639b Merge "AnimEncoder API: In Assemble(), always set animation parameters." -29ed796c Merge "AnimEncoder lib cleanup: prev to prev canvas not needed." -9f0dd6e5 Merge "WebPAnimEncoder API: Header and implementation" -5e56bbe0 AnimEncoder API: Remove AnimEncoderFrameOptions. -b902c3ea AnimEncoder API: GenerateCandidates bugfix. -ef3c39bb AnimEncoder API: Compute change rectangle for first frame too. -eec423ab AnimEncoder API: In Assemble(), always set animation parameters. -ae1c046e AnimEncoder lib cleanup: prev to prev canvas not needed. -4b997ae4 WebPAnimEncoder API: Header and implementation -72208bec move argb_*.o build target to encoder list -95920538 Merge "multi-thread fix: lock each entry points with a static var" -4c1b300a Merge "SSE2 implementation of VP8PackARGB" -fbcc2004 Merge "add -Wformat-nonliteral and -Wformat-security" -80d950d9 add -Wformat-nonliteral and -Wformat-security -04c20e75 Merge "MIPS: dspr2: added optimization for function Intra4Preds" -a437694a multi-thread fix: lock each entry points with a static var -ca7f60db SSE2 implementation of VP8PackARGB -72d573f6 simplify the PackARGB signature -4e2589ff demux: restore strict fragment flag check -4ba8e074 Merge "webp-container-spec: remove references to fragments" -e752f0a6 Merge "demux: remove experimental FRGM parsing" -f8abb112 Merge changes I109ec4d9,I73fe7743 -ae2188a4 MIPS: dspr2: added optimization for function Intra4Preds -1f4b8642 move VP8EncDspARGBInit() call closer to where it's needed -14108d78 dec_neon: add DC8uvNoTop / DC8uvNoLeft -d8340da7 dec_neon: add DC8uv -a66e66c7 webp-container-spec: remove references to fragments -7ce8788b MIPS: dspr2: added optimization for function MakeARGB32 -012e623d demux: remove experimental FRGM parsing -87c3d531 method=0: Don't evaluate any predictor -6f4fcb98 Merge "MIPS: dspr2: added optimization for function ImportRow" -24284459 replace unneeded calls to HistogramCopy() by swaps -bdf7b40c MIPS: dspr2: added optimization for function ImportRow -e66a9225 Merge "MIPS: dspr2: added optimization for function ExportRowC" -c279fec1 MIPS: dspr2: added optimization for function ExportRowC -31a9cf64 Speedup WebP lossless compression for low effort (m=0) mode with following: - Disable Cross-Color transform. - Evaluate predictors #11 (paeth), #12 and #13 only. -9275d91c MIPS: dspr2: added optimization for function TrueMotion -26106d66 Merge "enc_neon: fix building with non-Xcode clang (iOS)" -1c4e3efe unroll the kBands[] indirection to remove a dereference in GetCoeffs() -a3946b89 enc_neon: fix building with non-Xcode clang (iOS) -8ed9c00d Merge "simplify the Histogram struct, to only store max_value and last_nz" -bad77571 simplify the Histogram struct, to only store max_value and last_nz -3cca0dc7 MIPS: dspr2: Added optimization for DCMode function -37e395fd MIPS: fix functions to use generic BPS istead of hardcoded value -9475bef4 PickBestUV: fix VP8Copy16x8 invocation -441f273f Merge changes I55f8da52,Id73a1e96 -4a279a68 cosmetics: add some missing != NULL comparisons -66ad3725 factorize BPS definition in dsp.h and add VP8Copy16x8 -432e5b55 make ALIGN_xxx naming consistent -57606047 encoder: switch BPS to 32 instead of 16 -1b66bbe9 MIPS: dspr2: added optimization for function TransformColor_C -c6d0f9e7 histogram: cosmetics -f399d307 Merge changes I6eac17e5,I32d2b514 -9de9074c dec_neon: add TM8uv -8e517eca bit_reader/kVP8NewRange: range_t -> uint8_t -e1857139 dsp: initialize VP8PredChroma8 in VP8DspInit() -e0c809ad Move Entropy methods to lossless.c -a96ccf8f iosbuild: add x64_64 simulator support -a0df5510 Remove handling for WEBP_HINT_GRAPH -413dfc0c Move static method definition before its usage. -0f235665 Update BackwardRefsWithLocalCache. -d69e36ec Remove TODOs from lossless encoder code. -fdaac8e0 Optmize VP8LGetBackwardReferences LZ77 references. -2f0e2ba8 MIPS: dspr2: added optimization for function Select -a3e79a46 Merge "WebPEncode: Support encoding same pic twice (even if modified)" -e4f4dddb WebPEncode: Support encoding same pic twice (even if modified) -cbc3fbb4 Merge "Updated VP8LGetBackwardReferences and color cache." -95a9bd85 Updated VP8LGetBackwardReferences and color cache. -54f2c14c MIPS: dspr2: added optimization for function FTransform -aa42f423 MIPS: dspr2: Added optimization for function VP8LSubtractGreenFromBlueAndRed -11a25f75 Merge "FlattenSimilarBlocks should only be tried when blending is possible." -5cccdadf FlattenSimilarBlocks should only be tried when blending is possible. -95ca44a7 MIPS: dspr2: added optimization for Disto4x4 -4171b672 backward_references.c: reindent after c8581b0 -c8581b06 Optimize BackwardReferences for RLE encoding. -5798eee6 MIPS: dspr2: unfilters bugfix (Ie7b7387478a6b5c3f08691628ae00f059cf6d899) -4167a3f5 Optimize backwardreferences -d18554c3 Merge "webp/types.h: use inline for clang++/-std=c++11" -7489b0e7 gif2webp: Add '-min-size' option to get best compression. -77bdddf0 Speed up BackwardReferences -6638710b webp/types.h: use inline for clang++/-std=c++11 -abf04205 Enable entropy based merge histo for (q<100) -572022a3 filters_mips_dsp_r2.c: disable unfilters -a28e21b1 MIPS: dspr2: Added optimization for function ClampedAddSubtractFull -18d5a1ef MIPS: dspr2: added optimization for function ClampedAddSubtractHalf -829a8c19 MIPS: dspr2: added optimization for ITransform -c94ed49e gif2webp: Use the default hint instead of WEBP_HINT_GRAPH. -653ace55 Increase the MAX_COLOR_CACHE_BITS from 9 to 10. -919220c7 Change the logic adjusting the Histogram bits. -53b096c0 Merge "Fix bug in VP8LCalculateEstimateForCacheSize." -e912bd55 Fix bug in VP8LCalculateEstimateForCacheSize. -541d7839 Merge "dec_neon: add RD4 intra predictor" -f8cd0672 Merge "Makefile.vc: add a 'legacy' RTLIBCFG option" -22881c99 dec_neon: add RD4 intra predictor -613d281e update NEWS -1304eb34 Merge "dec_neon: DC4: use pair-wise adds for top row" -34c20c06 Makefile.vc: add a 'legacy' RTLIBCFG option -7083006b Merge "dsp/dec_{neon,sse2}: VE4: normalize variable names" -0db9031c dsp/dec_{neon,sse2}: VE4: normalize variable names -b5bc1530 dec_neon: DC4: use pair-wise adds for top row -5b90d8fe Unify the API between VP8BitWriter and VP8LBitWriter -f7ada560 Merge changes I2e06907b,Ia9ed4ca6,I782282ff -5beb6bf0 Merge "dec_neon: add VE4 intra predictor" -eba6ce06 dec_neon: add DC4 intra predictor -79abfbd9 dec_neon: add TM4 intra predictor -fe395f0e dec_neon: add LD4 intra predictor -32de385e dec_neon: add VE4 intra predictor -72395ba9 Merge "Modify CostModel to allocate optimal memory." -65e5eb8a gif2webp: Support GIF_DISPOSE_RESTORE_PREVIOUS -e4c829ef gif2webp: Handle frames with odd offsets + disposal to background. -c2b5a039 Modify CostModel to allocate optimal memory. -b7a33d7e implement VE4/HE4/RD4/... in SSE2 -97c76f1f make VP8PredLuma4[] non-const and initialize array in VP8DspInit() -0ea8c6c2 Merge "PrintReg: output to stderr" -d7ff2f97 Merge "stopwatch.h: fix includes" -f85ec712 PrintReg: output to stderr -54edbf65 stopwatch.h: fix includes -139142e4 Optimize BackwardReferenceHashChainFollowPath. -5f36b68d enc/backward_references.c: fix indent -e0e9960d Merge "sync version numbers to 0.4.2 release" -64ac5144 sync version numbers to 0.4.2 release -c24f8954 Simplify and speedup Backward refs computation. -d1c359ef fix shared object build with -fvisibility=hidden -a4c3a31b WEBP_TSAN_IGNORE_FUNCTION: fix gcc compat warning -f358eeb8 add code for testing random incremental decoding in dwebp -80247291 mark some init function as being safe for thread_sanitizer. -79b5bdbf bit_reader.h: cosmetics: fix a typo -6c673681 Improved near-lossless mode. -0ce27e71 enc_mips32: workaround gcc-4.9 bug -aca1b98f enc/vp8l.c: fix indent -ca005027 Evaluate non-palette compression for palette image -c8a87bb6 AssignSegments: quiet -Warray-bounds warning -32f67e30 Merge "enc_neon: initialize vectors w/vdup_n_u32" -fabc65da 1-3% faster encoding optimizing SSE_NxN functions -7534d716 enc_neon: initialize vectors w/vdup_n_u32 -5f813912 Merge "Fix return code of EncodeImageInternal()" -e321abe4 Fix return code of EncodeImageInternal() -f82cb06a optimize palette ordering -f545feee don't set the alpha value for histogram index image -2d9b0a44 add WebPDispatchAlphaToGreen() to dsp -1bd4c2ad Merge "Change Entropy based Histogram Combine heuristic." -e295b8f1 Merge "iosbuild: cleanup" -1be4e760 Merge "iosbuild: output autoconf req. on failure" -d5e498d4 Change Entropy based Histogram Combine heuristic. -47a2d8e1 fix MSVC float->int conversion warning -041956f6 iosbuild: cleanup -767eb402 iosbuild: output autoconf req. on failure -35ad48b8 HistoHeapInit: correct positions allocation size -45d9635f lossless: entropy clustering for high qualities. -dc37df8c fix type warning for VS9_x64 -9f7d9e6d iosbuild: make iOS 6 the minimum requirement -fdd6528b Remove unused VP8LDecoder member variable -ea3bba5a Merge "rewrite Disto4x4 in enc_neon.c with intrinsic" -f060dfc4 add lossless incremental decoding support -ab70794d rewrite Disto4x4 in enc_neon.c with intrinsic -d4471637 MIPS: dspr2: added optimization for function FilterLoop24 -2aef54d4 Merge "prepare VP8LDecodeImage for incremental decode" -aed0f5a2 Merge "MIPS: dspr2: added optimization for function FilterLoop26" -28630685 prepare VP8LDecodeImage for incremental decode -248f3aed remove br->error_ field -49e15044 MIPS: dspr2: added optimization for function FilterLoop26 -38128cb9 iobuild.sh: only install .h files in Headers -c792d412 Premultiply with alpha during U/V downsampling -0cc811d7 gif2webp: Background color correction -d7167ff7 Amend the lossless spec according to issue #205, #206 and #224 -b901416b Record the lossless size stats. -cddd3340 Add a WebPExtractAlpha function to dsp -0716a98e fix indent after I0204949917836f74c0eb4ba5a7f4052a4797833b -f9ced95a Optimize lossless decoding for trivial(ARB) codes. -924fcfd9 Merge "webpmux: simplify InitializeConfig()" -c0a462ca webpmux: simplify InitializeConfig() -6986bb5e webpmux: fix indent -f89e1690 webpmux: fix exit status on numeric value parse error -2172cb62 Merge "webpmux: fix loop_count range check" -e3b343ec Merge "examples: warn on invalid numeric parameters" -0e23c487 webpmux: fix loop_count range check -6208338a Merge "fix loop bug in DispatchAlpha()" -d51f3e40 gif2webp: Handle frames with missing graphic control extension -690b491a fix loop bug in DispatchAlpha() -96d43a87 examples: warn on invalid numeric parameters -3101f537 MIPS: dspr2: added optimization for TransformOne -a6bb9b17 SSE2 for inverse Mult(ARGB)Row and ApplyAlphaMultiply -d84a8ffd Remove default initialization of decoder status. -be70b86c configure: simplify libpng-config invocation -e0a99321 Rectify bug in lossless incremental decoding. -e2502a97 MIPS: dspr2: added optimization for TransformAC3 -24e1072a MIPS: dspr2: added optimization for TransformDC -c0e84df8 Merge "Slightly faster lossless decoding (1%)" -8dd28bb5 Slightly faster lossless decoding (1%) -f0103595 MIPS: dspr2: added optimization for ColorIndexInverseTransforms -d3242aee make VP8LSetBitPos() set br->eos_ flag -a9decb55 Lossless decoding: fix eos_ flag condition -3fea6a28 fix erroneous dec->status_ setting -80b8099f MIPS: dspr2: add some specific mips code to commit I2c3f2b12f8df15b785fad5a9c56316e954ae0c53 -e5640625 Merge "further refine the COPY_PATTERN optim for DecodeAlpha" -854509fe enc/histogram.c: reindent after f4059d0 -34421964 Merge "~3-5% faster encoding optimizing PickBestIntra*()" -865069c1 further refine the COPY_PATTERN optim for DecodeAlpha -a5956228 added C-level optimization for DecodeAlphaData function -187d379d add a fallback to ALPHA_NO_COMPRESSION -a48a2d76 ~3-5% faster encoding optimizing PickBestIntra*() -a6140194 ExUtilReadFromStdin: (windows) open stdin in bin mode -e80eab1f webpmux: (windows) open stdout in binary mode -e9bfb116 cwebp: (windows) open stdout in binary mode -5927e15b example_util: add ExUtilSetBinaryMode -30f3b75b webpmux man page: Clarify some title, descriptions and examples -77d4c7e3 address cosmetic comments from patch #71380 -f75dfbf2 Speed up Huffman decoding for lossless -637b3888 dsp/lossless: workaround gcc-4.9 bug on arm -8323a903 dsp.h: collect gcc/clang version test macros -e6c4b52f move static initialization of WebPYUV444Converters[] to the Init function. -49911d4d Merge "fix indentation" -f4059d0c Code cleanup for HistogramRemap. -e632b092 fix indentation -f5c04d64 Merge "add a DispatchAlpha() for SSE2 that handles 8 pixels at a time" -fc98edd9 add a DispatchAlpha() for SSE2 that handles 8 pixels at a time -73d361dd introduce VP8EncQuantize2Blocks to quantize two blocks at a time -0b21c30b MIPS: dspr2: added optimization for EmitAlphaRGB -953acd56 enc_neon: enable QuantizeBlock for aarch64 -f4ae1437 MIPS: mips32: code rebase -56977154 MIPS: dspr2: added optimizations for VP8YuvTo* -2523aa73 SmartRGBYUV: fix odd-width problem with pixel replication -ee52dc4e fix some MSVC64 warning about float conversion -3fca851a cpu: check for _MSC_VER before using msvc inline asm -e2a83d71 faster RGB->YUV conversion function (~7% speedup) -de2d03e1 Merge "Add smart RGB->YUV conversion option -pre 4" -3fc4c539 Add smart RGB->YUV conversion option -pre 4 -b4dc4069 MIPS: dspr2: added optimization for (un)filters -137e6090 Merge "configure: add work around for gcc-4.9 aarch64 bug" -b61c9cec MIPS: dspr2: Optimization of some simple point-sampling functions -e2b8cec0 configure: add work around for gcc-4.9 aarch64 bug -98c54107 MIPS: mips32r2: added optimization for BSwap32 -dab702b3 Update PATENTS to reflect s/VP8/WebM/g -b564f7c7 Merge "MIPS: detect mips32r6 and disable mips32r1 code" -b7e5a5c4 MIPS: detect mips32r6 and disable mips32r1 code -63c2fc02 Correctly use the AC_CANONICAL_* macros -bb07022b Merge "cosmetics" -e300c9d8 cosmetics -0e519eea Merge "cosmetics: remove some extraneous 'extern's" -3ef0f08a Merge "vp8enci.h: cosmetics: fix '*' placement" -4c6dde37 bit_writer: cosmetics: rename kFlush() -> Flush() -f7b4c48b cosmetics: remove some extraneous 'extern's -b47fb00a vp8enci.h: cosmetics: fix '*' placement -b5a36cc9 add -near_lossless [0..100] experimental option -0524d9e5 dsp: detect mips64 & disable mips32 code -d3485d96 cwebp.1: fix quality description placement -29a9fe22 Merge tag 'v0.4.1' -8af27718 update ChangeLog (tag: v0.4.1, origin/0.4.1) -e09e9ff6 Record & log the image pre-processing time. -f59c0b4b iosbuild.sh: specify optimization flags -8d34ea3e update ChangeLog (tag: v0.4.1-rc1) -dbc3da66 makefile.unix: add vwebp.1 to the dist target -89a7c83c update ChangeLog -ffe67ee9 Merge "update NEWS for the next release" into 0.4.1 -2def1fe6 gif2webp: dust up the help message -fb668d78 remove -noalphadither option from README/vwebp.1 -e49f693b update NEWS for the next release -cd013580 Merge "update AUTHORS" into 0.4.1 -268d01eb update AUTHORS -85213b9b bump version to 0.4.1 -695f80ae Merge "restore mux API compatibility" into 0.4.1 -862d296c restore mux API compatibility -8f6f8c5d remove the !WEBP_REFERENCE_IMPLEMENTATION tweak in Put8x8uv -d713a696 Merge changes If4debc15,I437a5d5f into 0.4.1 -c2fc52e4 restore encode API compatibility -793368e8 restore decode API compatibility -b8984f31 gif2webp: fix compile with giflib 5.1.0 -222f9b1a gif2webp: simplify giflib version checking -d2cc61b7 Extend MakeARGB32() to accept Alpha channel. -4595b62b Merge "use explicit size of kErrorMessages[] arrays" -157de015 Merge "Actuate memory stats for PRINT_MEMORY_INFO" -fbda2f49 JPEG decoder: delay conversion to YUV to WebPEncode() call -0b747b1b use explicit size of kErrorMessages[] arrays -3398d81a Actuate memory stats for PRINT_MEMORY_INFO -6f3202be Merge "move WebPPictureInit to picture.c" -6c347bbb move WebPPictureInit to picture.c -fb3acf19 fix configure message for multi-thread -40b086f7 configure: check for _beginthreadex -1549d620 reorder the YUVA->ARGB and ARGB->YUVA functions correctly -c6461bfd Merge "extract colorspace code from picture.c into picture_csp.c" -736f2a17 extract colorspace code from picture.c into picture_csp.c -645daa03 Merge "configure: check for -Wformat-security" -abafed86 configure: check for -Wformat-security -fbadb480 split monolithic picture.c into picture_{tools,psnr,rescale}.c -c76f07ec dec_neon/TransformAC3: initialize vector w/vcreate -bb4fc051 gif2webp: Allow single-frame animations -46fd44c1 thread: remove harmless race on status_ in End() -5a1a7264 Merge "configure: check for __builtin_bswapXX()" -6781423b configure: check for __builtin_bswapXX() -6450c48d configure: fix iOS builds -6422e683 VP8LFillBitWindow: enable fast path for 32-bit builds -4f7f52b2 VP8LFillBitWindow: respect WEBP_FORCE_ALIGNED -e458badc endian_inl.h: implement htoleXX with BSwapXX -f2664d1a endian_inl.h: add BSwap16 -6fbf5345 Merge "configure: add --enable-aligned" -dc0f479d configure: add --enable-aligned -9cc69e2b Merge "configure: support WIC + OpenGL under mingw64" -257adfb0 remove experimental YUV444 YUV422 and YUV400 code -10f4257c configure: support WIC + OpenGL under mingw64 -380cca4f configure.ac: add AC_C_BIGENDIAN -ee70a901 endian_inl.h: add BSwap64 -47779d46 endian_inl.h: add BSwap32 -d5104b1f utils: add endian_inl.h -58ab6224 Merge "make alpha-detection loop in IsKeyFrame() in good x/y order" -9d562902 make alpha-detection loop in IsKeyFrame() in good x/y order -516971b1 lossless: Remove unaligned read warning -b8b596f6 Merge "configure.ac: add an autoconf version prerequisite" -34b02f8c configure.ac: add an autoconf version prerequisite -e59f5360 neon: normalize vdup_n_* usage -6ee7160d Merge changes I0da7b3d3,Idad2f278,I4accc305 -abc02f24 Merge "fix (uncompiled) typo" -bc03670f neon: add INIT_VECTOR4 -6c1c632b neon: add INIT_VECTOR3 -dc7687e5 neon: add INIT_VECTOR2 -4536e7c4 add WebPMuxSetCanvasSize() to the mux API -824eab10 fix (uncompiled) typo -1f3e5f1e remove unused 'shift' argument and QFIX2 define -8e867051 Merge "VP8LoadNewBytes: use __builtin_bswap32 if available" -1b6a2635 Merge "Fix handling of weird GIF with canvas dimension 0x0" -1da3d461 VP8LoadNewBytes: use __builtin_bswap32 if available -1582e402 Fix handling of weird GIF with canvas dimension 0x0 -b8811dac Merge "rename interface -> winterface" -db8b8b5f Fix logic in the GIF LOOP-detection parsing -25aaddc8 rename interface -> winterface -5584d9d2 make WebPSetWorkerInterface() check its arguments -a9ef7ef9 Merge "cosmetics: update thread.h comments" -c6af9991 Merge "dust up the help message" -0a8b8863 dust up the help message -a9cf3191 cosmetics: update thread.h comments -27bfeee4 QuantizeBlock SSE2 Optimization: -2bc0dc3e Merge "webpmux: warn when odd frame offsets are used" -3114ebe4 Merge changes Id8edd3c1,Id418eb96,Ide05e3be -c0726634 webpmux: warn when odd frame offsets are used -c5c6b408 Merge "add alpha dithering for lossy" -d5146784 examples/Android.mk: add cwebp -ca0fa7c7 Android.mk: move dwebp to examples/Android.mk -73d8fca0 Android.mk: add ENABLE_SHARED flag -6e93317f muxread: fix out of bounds read -8b0f6a48 Makefile.vc: fix CFLAGS assignment w/HAVE_AVX2=1 -bbe32df1 add alpha dithering for lossy -79020767 Merge "make error-code reporting consistent upon malloc failure" -77bf4410 make error-code reporting consistent upon malloc failure -7a93c000 **/Makefile.am: remove unused AM_CPPFLAGS -24e30805 Add an interface abstraction to the WebP worker thread implementation -d6cd6358 Merge "fix orig_rect==NULL case" -2bfd1ffa fix orig_rect==NULL case -059e21c1 Merge "configure: move config.h to src/webp/config.h" -f05fe006 properly report back encoding error code in WebPFrameCacheAddFrame() -32b31379 configure: move config.h to src/webp/config.h -90090d99 Merge changes I7c675e51,I84f7d785 -ae7661b3 makefiles: define WEBP_HAVE_AVX2 when appropriate -69fce2ea remove the special casing for res->first in VP8SetResidualCoeffs -6e61a3a9 configure: test for -msse2 -b9d2efc6 rename upsampling_mips32.c to yuv_mips32.c -bdfeebaa dsp/yuv: move sse2 functions to yuv_sse2.c -46b32e86 Merge "configure: set WEBP_HAVE_AVX2 when available" -88305db4 Merge "VP8RandomBits2: prevent signed int overflow" -73fee88c VP8RandomBits2: prevent signed int overflow -db4860b3 enc_sse2: prevent signed int overflow -3fdaf4d2 Merge "real fix for longjmp warning" -385e3340 real fix for longjmp warning -230a0555 configure: set WEBP_HAVE_AVX2 when available -a2ac8a42 restore original value_/range_ field order -5e2ee56f Merge "remove libwebpdspdecode dep on libwebpdsp_avx2" -61362db5 remove libwebpdspdecode dep on libwebpdsp_avx2 -42c447ae Merge "lossy bit-reader clean-up:" -479ffd8b Merge "remove unused #include's" -9754d39a Merge "strong filtering speed-up (~2-3% x86, ~1-2% for NEON)" -158aff9b remove unused #include's -09545eea lossy bit-reader clean-up: -ea8b0a17 strong filtering speed-up (~2-3% x86, ~1-2% for NEON) -6679f899 Optimize VP8SetResidualCoeffs. -ac591cf2 fix for gcc-4.9 warnings about longjmp + local variables -4dfa86b2 dsp/cpu: NaCl has no support for xgetbv -4c398699 Merge "cwebp: fallback to native webp decode in WIC builds" -33aa497e Merge "cwebp: add some missing newlines in longhelp output" -c9b340a2 fix missing WebPInitAlphaProcessing call for premultiplied colorspace output -57897bae Merge "lossless_neon: use vcreate_*() where appropriate" -6aa4777b Merge "(enc|dec)_neon: use vcreate_*() where appropriate" -0d346e41 Always reinit VP8TransformWHT instead of hard-coding -7d039fc3 cwebp: fallback to native webp decode in WIC builds -d471f424 cwebp: add some missing newlines in longhelp output -bf0e0030 lossless_neon: use vcreate_*() where appropriate -9251c2f6 (enc|dec)_neon: use vcreate_*() where appropriate -399b916d lossy decoding: correct alpha-rescaling for YUVA format -78c12ed8 Merge "Makefile.vc: add rudimentary avx2 support" -dc5b122f try to remove the spurious warning for static analysis -ddfefd62 Makefile.vc: add rudimentary avx2 support -a8911643 Merge "simplify VP8LInitBitReader()" -fdbcd44d simplify VP8LInitBitReader() -7c004287 makefile.unix: add rudimentary avx2 support -515e35cf Merge "add stub dsp/enc_avx2.c" -a05dc140 SSE2: yuv->rgb speed-up for point-sampling -178e9a69 add stub dsp/enc_avx2.c -1b99c09c Merge "configure: add a test for -mavx2" -fe728071 configure: add a test for -mavx2 -e46a247c cpu: fix check for __cpuidex availability -176fda26 fix the bit-writer for lossless in 32bit mode -541784c7 dsp.h: add a check for AVX2 / define WEBP_USE_AVX2 -bdb151ee dsp/cpu: add AVX2 detection -ab9f2f86 Merge "revamp the point-sampling functions by processing a full plane" -a2f8b289 revamp the point-sampling functions by processing a full plane -ef076026 use decoder's DSP functions for autofilter -2b5cb326 Merge "dsp/cpu: add AVX detection" -df08e67e dsp/cpu: add AVX detection -e2f405c9 Merge "clean-up and slight speed-up in-loop filtering SSE2" -f60957bf clean-up and slight speed-up in-loop filtering SSE2 -9fc3ae46 .gitattributes: treat .ppm as binary -3da924b5 Merge "dsp/WEBP_USE_NEON: test for __aarch64__" -c7164490 Android.mk: always include *_neon.c in the build -a577b23a dsp/WEBP_USE_NEON: test for __aarch64__ -54bfffca move RemapBitReader() from idec.c to bit_reader code -34168ecb Merge "remove all unused layer code" -f1e77173 remove all unused layer code -b0757db7 Code cleanup for VP8LGetHistoImageSymbols. -5fe628d3 make the token page size be variable instead of fixed 8192 -f948d08c memory debug: allow setting pre-defined malloc failure points -ca3d746e use block-based allocation for backward refs storage, and free-lists -1ba61b09 enable NEON intrinsics in aarch64 builds -b9d2bb67 dsp/neon.h: coalesce intrinsics-related defines -b5c75258 iosbuild: add support for iOSv7/aarch64 -9383afd5 Reduce number of memory allocations while decoding lossless. -888e63ed Merge "dsp/lossless: prevent signed int overflow in left shift ops" -8137f3ed Merge "instrument memory allocation routines for debugging" -2aa18736 instrument memory allocation routines for debugging -d3bcf72b Don't allocate VP8LHashChain, but treat like automatic object -bd6b8619 dsp/lossless: prevent signed int overflow in left shift ops -b7f19b83 Merge "dec/vp8l: prevent signed int overflow in left shift ops" -29059d51 Merge "remove some uint64_t casts and use." -e69a1df4 dec/vp8l: prevent signed int overflow in left shift ops -cf5eb8ad remove some uint64_t casts and use. -38e2db3e MIPS: MIPS32r1: Added optimization for HistogramAdd. -e0609ade dwebp: fix exit code on webp load failure -bbd358a8 Merge "example_util.h: avoid forward declaring enums" -8955da21 example_util.h: avoid forward declaring enums -6d6865f0 Added SSE2 variants for Average2/3/4 -b3a616b3 make HistogramAdd() a pointer in dsp -c8bbb636 dec_neon: relocate some inline-asm defines -4e393bb9 dec_neon: enable intrinsics-only functions -ba99a922 dec_neon: use positive tests for USE_INTRINSICS -69058ff8 Merge "example_util: add ExUtilDecodeWebPIncremental" -a7828e8b dec_neon: make WORK_AROUND_GCC conditional on version -3f3d717a Merge "enc_neon: enable intrinsics-only functions" -de3cb6c8 Merge "move LOCAL_GCC_VERSION def to dsp.h" -1b2fe14d example_util: add ExUtilDecodeWebPIncremental -ca49e7ad Merge "enc_neon: move Transpose4x4 to dsp/neon.h" -ad900abd Merge "fix warning about size_t -> int conversion" -4825b436 fix warning about size_t -> int conversion -42b35e08 enc_neon: enable intrinsics-only functions -f937e012 move LOCAL_GCC_VERSION def to dsp.h -5e1a17ef enc_neon: move Transpose4x4 to dsp/neon.h -c7b92a5a dec_neon: (WORK_AROUND_GCC) delete unused Load4x8 -8e5f90b0 Merge "make ExUtilLoadWebP() accept NULL bitstream param." -05d4c1b7 Merge "cwebp: add webpdec" -ddeb6ac8 cwebp: add webpdec -35d7d095 Merge "Reduce memory footprint for encoding WebP lossless." -0b896101 Reduce memory footprint for encoding WebP lossless. -f0b65c9a make ExUtilLoadWebP() accept NULL bitstream param. -9c0a60cc Merge "dwebp: move webp decoding to example_util" -1d62acf6 MIPS: MIPS32r1: Added optimization for HuffmanCost functions. -4a0e7390 dwebp: move webp decoding to example_util -c0220460 Merge "Bugfix: Incremental decode of lossy-alpha" -8c7cd722 Bugfix: Incremental decode of lossy-alpha -7955152d MIPS: fix error with number of registers. -b1dabe37 Merge "Move the HuffmanCost() function to dsp lib" -75b12006 Move the HuffmanCost() function to dsp lib -2772b8bd MIPS: fix assembler error revealed by clang's debug build -6653b601 enc_mips32: fix unused symbol warning in debug -8dec1209 enc_mips32: disable ITransform(One) in debug builds -98519dd5 enc_neon: convert Disto4x4 to intrinsics -fe9317c9 cosmetics: -953b0746 enc_neon: cosmetics -a9fc697c Merge "WIP: extract the float-calculation of HuffmanCost from loop" -3f84b521 Merge "replace some mult-long (vmull_u8) with mult-long-accumulate (vmlal_u8)" -4ae0533f MIPS: MIPS32r1: Added optimizations for ExtraCost functions. -b30a04cf WIP: extract the float-calculation of HuffmanCost from loop -a8fe8ce2 Merge "NEON intrinsics version of CollectHistogram" -95203d2d NEON intrinsics version of CollectHistogram -7ca2e74b replace some mult-long (vmull_u8) with mult-long-accumulate (vmlal_u8) -41c6efbd fix lossless_neon.c -8ff96a02 NEON intrinsics version of FTransform -0214f4a9 Merge "MIPS: MIPS32r1: Added optimizations for FastLog2" -baabf1ea MIPS: MIPS32r1: Added optimizations for FastLog2 -3d49871d NEON functions for lossless coding -3fe02915 MIPS: MIPS32r1: Added optimizations for SSE functions. -c503b485 Merge "fix the gcc-4.6.0 bug by implementing alternative method" -abe6f487 fix the gcc-4.6.0 bug by implementing alternative method -5598bdec enc_mips32.c: fix file mode -2b1b4d5a MIPS: MIPS32r1: Add optimization for GetResidualCost -f0a1f3cd Merge "MIPS: MIPS32r1: Added optimization for FTransform" -7231f610 MIPS: MIPS32r1: Added optimization for FTransform -869eaf6c ~30% encoding speedup: use NEON for QuantizeBlock() -f758af6b enc_neon: convert FTransformWHT to intrinsics -7dad095b MIPS: MIPS32r1: Added optimization for Disto4x4 (TTransform) -2298d5f3 MIPS: MIPS32r1: Added optimization for QuantizeBlock -e88150c9 Merge "MIPS: MIPS32r1: Add optimization for ITransform" -de693f25 lossless_neon: disable VP8LConvert* functions -4143332b NEON intrinsics for encoding -0ca2914b MIPS: MIPS32r1: Add optimization for ITransform -71bca5ec dec_neon: use vst_lane instead of vget_lane -bf061052 Intrinsics NEON version of TransformOne -19c6f1ba Merge "dec_neon: use vld?_lane instead of vset?_lane" -7a94c0cf upsampling_neon: drop NEON suffix from local functions -d14669c8 upsampling_sse2: drop SSE2 suffix from local functions -2ca42a4f enc_sse2: drop SSE2 suffix from local functions -d038e619 dec_sse2: drop SSE2 suffix from local functions -fa52d752 dec_neon: use vld?_lane instead of vset?_lane -c520e77d cosmetic: fix long line -4b0f2dae Merge "add intrinsics NEON code for chroma strong-filtering" -e351ec07 add intrinsics NEON code for chroma strong-filtering -aaf734b8 Merge "Add SSE2 version of forward cross-color transform" -c90a902e Add SSE2 version of forward cross-color transform -bc374ff3 Use histogram_bits to initalize transform_bits. -2132992d Merge "Add strong filtering intrinsics (inner and outer edges)" -5fbff3a6 Add strong filtering intrinsics (inner and outer edges) -d4813f0c Add SSE2 function for Inverse Cross-color Transform -26029568 dec_neon: add strong loopfilter intrinsics -cca7d7ef Merge "add intrinsics version of SimpleHFilter16NEON()" -1a05dfa7 windows: fix dll builds -d6c50d8a Merge "add some colorspace conversion functions in NEON" -4fd7c82e SSE2 variants of Subtract-Green: Rectify loop condition -97e5fac3 add some colorspace conversion functions in NEON -b9a7a45f add intrinsics version of SimpleHFilter16NEON() -daccbf40 add light filtering NEON intrinsics -af444608 fix typo in STORE_WHT -6af6b8e1 Tune HistogramCombineBin for large images. -af93bdd6 use WebPSafe[CM]alloc/WebPSafeFree instead of [cm]alloc/free -51f406a5 lossless_sse2: relocate VP8LDspInitSSE2 proto -0f4f721b separate SSE2 lossless functions into its own file -514fc251 VP8LConvertFromBGRA: use conversion function pointers -6d2f3527 dsp/dec: TransformDCUV: use VP8TransformDC -defc8e1b Merge "fix out-of-bound read during alpha-plane decoding" -fbed3643 Merge "dsp: reuse wht transform from dec in encoder" -d8467084 Merge "Add SSE2 version of ARGB -> BGR/RGB/... conversion functions" -207d03b4 fix out-of-bound read during alpha-plane decoding -d1b33ad5 2-5% faster trellis with clang/MacOS (and ~2-3% on ARM) -369c26dd Add SSE2 version of ARGB -> BGR/RGB/... conversion functions -df230f27 dsp: reuse wht transform from dec in encoder -80e218d4 Android.mk: fix build with APP_ABI=armeabi-v7a-hard -59daf083 Merge "cosmetics:" -53622008 cosmetics: -3e7f34a3 AssignSegments: quiet array-bounds warning -3c2ebf58 Merge "UpdateHistogramCost: avoid implicit double->float" -cf821c82 UpdateHistogramCost: avoid implicit double->float -312e638f Extend the search space for GetBestGreenRedToBlue -1c58526f Fix few nits -fef22704 Optimize and re-structure VP8LGetHistoImageSymbols -068b14ac Optimize lossless decoding. -5f0cfa80 Do a binary search to get the optimum cache bits. -24ca3678 Merge "allow 'cwebp -o -' to emit output to stdout" -e12f874e allow 'cwebp -o -' to emit output to stdout -2bcad89b allow some more stdin/stout I/O -84ed4b3a fix cwebp.1 typos after patch #69199 -65b99f1c add a -z option to cwebp, and WebPConfigLosslessPreset() function -30176619 4-5% faster trellis by removing some unneeded calculations. -687a58ec histogram.c: reindent after b33e8a0 -06d456f6 Merge "~3-4% faster lossless encoding" -c60de260 ~3-4% faster lossless encoding -42eb06fc Merge "few cosmetics after patch #69079" -82af8264 few cosmetics after patch #69079 -b33e8a05 Refactor code for HistogramCombine. -ca1bfff5 Merge "5-10% encoding speedup with faster trellis (-m 6)" -5aeeb087 5-10% encoding speedup with faster trellis (-m 6) -82ae1bf2 cosmetics: normalize VP8GetCPUInfo checks -e3dd9243 Merge "Refactor GetBestPredictorForTile for future tuning." -206cc1be Refactor GetBestPredictorForTile for future tuning. -3cb84062 Merge "speed-up trellis quant (~5-10% overall speed-up)" -b66f2227 Merge "lossy encoding: ~3% speed-up" -4287d0d4 speed-up trellis quant (~5-10% overall speed-up) -390c8b31 lossy encoding: ~3% speed-up -9a463c4a Merge "dec_neon: convert TransformWHT to intrinsics" -e8605e96 Merge "dec_neon: add ConvertU8ToS16" -4aa3e412 MIPS: MIPS32r1: rescaler bugfix -c16cd99a Speed up lossless encoder. -9d6b5ff1 dec_neon: convert TransformWHT to intrinsics -2ff0aae2 dec_neon: add ConvertU8ToS16 -77a8f919 fix compilation with USE_YUVj flag -4acbec1b Merge changes I3b240ffb,Ia9370283,Ia2d28728 -2719bb7e dec_neon: TransformAC3: work on packed vectors -b7b60ca1 dec_neon: add SaturateAndStore4x4 -b7685d73 Rescale: let ImportRow / ExportRow be pointer-to-function -e02f16ef dec_neon.c: convert TransformDC to intrinsics -9cba963f add missing file -8992ddb7 use static clipping tables -0235d5e4 1-2% faster quantization in SSE2 -b2fbc36c fix VC12-x64 warning -6e37cb94 Merge "cosmetics: backward_references.c: reindent after a7d2ee3" -a42ea974 cosmetics: backward_references.c: reindent after a7d2ee3 -6c327442 Merge "fix missing __BIG_ENDIAN__ definition on some platform" -a8b6aad1 fix missing __BIG_ENDIAN__ definition on some platform -fde2904b Increase initial buffer size for VP8L Bit Writer. -a7d2ee39 Optimize cache estimate logic. -7fb6095b Merge "dec_neon.c: add TransformAC3" -bf182e83 VP8LBitWriter: use a bit-accumulator -3f40b4a5 Merge "MIPS: MIPS32r1: clang macro warning resolved" -1684f4ee WebP Decoder: Mark some truncated bitstreams as invalid -acbedac4 MIPS: MIPS32r1: clang macro warning resolved -228e4877 dec_neon.c: add TransformAC3 -393f89b7 Android.mk: avoid gcc-specific flags with clang -32aeaf11 revamp VP8LColorSpaceTransform() a bit -0c7cc4ca Merge "Don't dereference NULL, ensure HashChain fully initialized" -391316fe Don't dereference NULL, ensure HashChain fully initialized -926ff402 WEBP_SWAP_16BIT_CSP: remove code dup -1d1cd3bb Fix decode bug for rgbA_4444/RGBA_4444 color-modes. -939e70e7 update AUTHORS file -8934a622 cosmetics: *_mips32.c -dd438c9a MIPS: MIPS32r1: Optimization of some simple point-sampling functions. PATCH [6/6] -53520911 Added support for calling sampling functions via pointers. -d16c6974 MIPS: MIPS32r1: Optimization of filter functions. PATCH [5/6] -04336fc7 MIPS: MIPS32r1: Optimization of function TransformOne. PATCH [4/6] -92d8fc7d MIPS: MIPS32r1: Optimization of function WebPRescalerImportRow. PATCH [3/6] -bbc23ff3 parse one row of intra modes altogether -a2f608f9 Merge "MIPS: MIPS32r1: Optimization of function WebPRescalerExportRow. [2/6]" -88230854 MIPS: MIPS32r1: Optimization of function WebPRescalerExportRow. [2/6] -c5a5b028 decode mt+incremental: fix segfault in debug builds -9882b2f9 always use fast-analysis for all methods. -000adac0 Merge "autoconf: update ax_pthread.m4" -2d2fc37d update .gitignore -5bf4255a Merge "Make it possible to avoid automagic dependencies" -c1cb1933 disable NEON for arm64 platform -73a304e9 Make it possible to avoid automagic dependencies -4d493f8d MIPS: MIPS32r1: Decoder bit reader function optimized. PATCH [1/6] -c741183c make WebPCleanupTransparentArea work with argb picture -5da18552 add a decoding option to flip image vertically -00c3c4e1 Merge "add man/vwebp.1" -2c6bb428 add man/vwebp.1 -ea59a8e9 Merge "Merge tag 'v0.4.0'" -7574bed4 fix comments related to array sizes -0b5a90fd dwebp.1: fix option formatting -effcb0fd Merge tag 'v0.4.0' -7c76255d autoconf: update ax_pthread.m4 -fff2a11b make -short work with -print_ssim, -print_psnr, etc. -68e7901d update ChangeLog (tag: v0.4.0-rc1, tag: v0.4.0, origin/0.4.0) -256e4333 update NEWS description with new general features -29625340 Merge "gif2webp: don't use C99 %zu" into 0.4.0 -3b9f9dd0 gif2webp: don't use C99 %zu -b5b2e3c7 cwebp: fix metadata output w/lossy+alpha -ad26df1a makefile.unix: clean up libgif2webp_util.a -c3b45570 update Changelog -ca841121 Merge "bump version to 0.4.0" into 0.4.0 -8c524db8 bump version to 0.4.0 -eec2398c update AUTHORS & .mailmap -b9bbf6a1 update NEWS for 0.4.0 -c72e0811 Merge "dec/webp.c: don't wait for data before reporting w/h" -5ad65314 dec/frame.c: fix formatting -f7fc4bc8 dec/webp.c: don't wait for data before reporting w/h -66a32af5 Merge "NEON speed up" -26d842eb NEON speed up -f307f98b Merge "webpmux: let -- stop parameter parsing" -fe051da7 Merge "README: add a section on gif2webp" -6fd2bd62 Merge "manpage pedantry" -4af19007 README: add a section on gif2webp -6f36ade9 manpage pedantry -f9016cb9 README: update dwebp options -b4fa0a47 webpmux: let -- stop parameter parsing -a9a20acf gif2webp: Add a multi-threaded encode option -495bef41 fix bug in TrellisQuantize -605a7127 simplify __cplusplus ifdef -33109f99 Merge "drop: ifdef __cplusplus checks from C files" -7f9de0b9 Merge changes I994a5587,I8467bb71,I13b50688,I1e2c9c7b -5459030b gif2webp: let -- stop parameter parsing -a4b0aa06 vwebp: let -- stop parameter parsing -98af68fe cwebp: let -- stop parameter parsing -a33831e2 dwebp: let -- stop parameter parsing -36301249 add some checks on error paths -ce4c7139 Merge "autoconf: add --disable-wic" -5227d991 drop: ifdef __cplusplus checks from C files -f6453559 dwebp.1: fix typo -f91034f2 Merge "cwebp: print metadata stats when no output file is given" -d4934553 gif2webp: Backward compatibility for giflib version <= 4.1.3 -4c617d32 gif2webp: Disable output of ICC profile by default -73b731fb introduce a special quantization function for WHT -41c0cc4b Make Forward WHT transform use 32bit fixed-point calculation -a3359f5d Only compute quantization params once -70490437 cwebp: print metadata stats when no output file is given -d513bb62 * fix off-by-one zthresh calculation * remove the sharpening for non luma-AC coeffs * adjust the bias a little bit to compensate for this -ad9dec0c Merge "cosmetics: dwebp: fix local function name format" -f737f037 Merge "dwebp: remove a dead store" -3c3a70da Merge "makefile.unix: install binaries in $(DESTDIR)/bin/" -150b655f Merge "Android.mk: add some release compile flags" -dbebd33b cosmetics: dwebp: fix local function name format -27749951 dwebp: remove a dead store -a01e04fe autoconf: add --disable-wic -5009b227 makefile.unix: install binaries in $(DESTDIR)/bin/ -bab30fca Merge "fix -print_psnr / ssim options" -ebef7fb3 fix -print_psnr / ssim options -cb637855 Merge "fix bug due to overzealous check in WebPPictureYUVAToARGB()" -8189885b Merge "EstimateBestFilter: use an int to iterate WEBP_FILTER_TYPE" -4ad7d335 Android.mk: add some release compile flags -c12e2369 cosmetics: fix a few typos -6f104034 fix bug due to overzealous check in WebPPictureYUVAToARGB() -3f6c35c6 EstimateBestFilter: use an int to iterate WEBP_FILTER_TYPE -cc55790e Merge changes I8bb7a4dc,I2c180051,I021a014f,I8a224a62 -c536afb5 Merge "cosmetics: fix some typos" -cbdd3e6e add a -dither dithering option to the decoder -e8124012 Updated iosbuild.sh for XCode 5.x -4931c329 cosmetics: fix some typos -05aacf77 mux: add some missing casts -617d9348 enc/vp8l: add a missing cast -46db2865 idec: add some missing casts -b524e336 ErrorStatusLossless: correct return type -cb261f79 fix a descaling bug for vertical/horizontal U/V interpolation -bcb3955c Merge changes I48968468,I181bc736 -73f52133 gif2webp: Add a mixed compression mode -6198715e demux: split chunk parsing from ParseVP8X -d2e3f4e6 demux: add a tail pointer for chunks -87cffcc3 demux: cosmetics: s/has_frames/is_animation/ -e18e6677 demux: strictly enforce the animation flag -c4f39f4a demux: cosmetics: remove a useless break -61cb884d demux: (non-exp) fail if the fragmented flag is set -ff379db3 few % speedup of lossless encoding -df3649a2 remove all disabled code related to P-frames -6d0cb3de Merge "gif2webp: kmin = 0 should suppress key-frame addition." -36555983 gif2webp: kmin = 0 should suppress key-frame addition. -7708e609 Merge "detect flatness in blocks and favor DC prediction" -06b1503e Merge "add comment about the kLevelsFromDelta[][] LUT generation" -5935259c add comment about the kLevelsFromDelta[][] LUT generation -e3312ea6 detect flatness in blocks and favor DC prediction -ebc9b1ee Merge "VPLBitReader bugfix: Catch error if bit_pos > LBITS too." -96ad0e0a VPLBitReader bugfix: Catch error if bit_pos > LBITS too. -a014e9c9 tune quantization biases toward higher precision -1e898619 add helpful PrintBlockInfo() function -596a6d73 make use of 'extern' consistent in function declarations -c8d48c6e Merge "extract random utils to their own file util/random.[ch]" -98aa33cf extract random utils to their own file util/random.[ch] -432a723e Merge "swig: add basic go bindings" -fab618b5 Merge "rename libwebp.i -> libwebp.swig" -e4e7fcd6 swig: add basic go bindings -d3408720 Merge "fast auto-determined filtering strength" -f8bfd5cd fast auto-determined filtering strength -ac0bf951 small clean-up in ExpandMatrix() -1939607e rename libwebp.i -> libwebp.swig -43148b6c filtering: precompute ilimit and hev_threshold -18f992ec simplify f_inner calculation a little -241d11f1 add missing const -86c0031e add a 'format' field to WebPBitstreamFeatures -dde91fde Demux: Correct the extended format validation -5d6c5bd2 add entry for '-resize' option in cwebp's man -7c098d18 Use some gamma-curve range compression when computing U/V average -0b2b0504 Use deterministic random-dithering during RGB->YUV conversion -8a2fa099 Add a second multi-thread method -7d6f2da0 Merge "up to 20% faster multi-threaded decoding" -266f63ea Merge "libwebp.jar: build w/Java 1.6 for Android compat" -0532149c up to 20% faster multi-threaded decoding -38efdc2e Simplify the gif2webp tool: move the optimization details to util -de899516 libwebp.jar: build w/Java 1.6 for Android compat -cb221552 Decode a full row of bitstream before reconstructing -dca8a4d3 Merge "NEON/simple loopfilter: avoid q4-q7 registers" -9e84d901 Merge "NEON/TransformWHT: avoid q4-q7 registers" -fc10249b NEON/simple loopfilter: avoid q4-q7 registers -2f09d63e NEON/TransformWHT: avoid q4-q7 registers -77585a2b Merge "use a macrofunc for setting NzCoeffs bits" -d155507c Merge "use HINT_GRAPH as image_hint for gif source" -9c561646 Merge "only print GIF_DISPOSE_WARNING once" -05879865 use HINT_GRAPH as image_hint for gif source -0b28d7ab use a macrofunc for setting NzCoeffs bits -f9bbc2a0 Special-case sparse transform -00125196 gif2webp: detect and flatten uniformly similar blocks -0deaf0fa only print GIF_DISPOSE_WARNING once -6a8c0eb7 Merge "small optimization in segment-smoothing loop" -f7146bc1 small optimization in segment-smoothing loop -5a7533ce small gif2webp fix -4df0c89e Merge changes Ic697660c,I27285521 -5b2e6bd3 Android.mk: add a dwebp target -f910a84e Android.mk: update build flags -63f9aba4 special-case WHT transform when there's only DC -80911aef Merge "7-8% faster decoding by rewriting GetCoeffs()" -606c4304 gif2webp: Improved compression for lossy animated WebP -fb887f7f gif2webp: Different kmin/kmax defaults for lossy and lossless -2a981366 7-8% faster decoding by rewriting GetCoeffs() -92d47e4c improve VP8L signature detection by checking the version bits too -5cd43e43 Add -incremental option to dwebp -54b8e3f6 webpmux: DisplayInfo(): remove unnecessary error checks. -40ae3520 fix memleak in WebPIDelete() -d9662658 mux.h doc: WebPMuxGetFrame() can return WEBP_MUX_MEMORY_ERROR too. -0e6747f8 webpmux -info: display dimensions and has_alpha per frame -d78a82c4 Sanity check for underflow -8498f4bf Merge "remove -Wshadow warnings" -e89c6fc8 Avoid a potential memleak -3ebe1757 Merge "break down the proba 4D-array into some handy structs" -6a44550a break down the proba 4D-array into some handy structs -2f5e8934 remove -Wshadow warnings -bf3a29b3 Merge "add proper WEBP_HAVE_GIF and WEBP_HAVE_GL flags" -2b0a7593 Merge "fix some warnings from static analysis" -22dd07ce mux.h: Some doc corrections -79ff0346 add proper WEBP_HAVE_GIF and WEBP_HAVE_GL flags -d51f45f0 fix some warnings from static analysis -d134307b fix conversion warning on MSVC -d538cea8 gif2webp: Support a 'min' and 'max' key frame interval -80b54e1c allow search with token buffer loop and fix PARTITION0 problem -b7d4e042 add VP8EstimateTokenSize() -10fddf53 enc/quant.c: silence a warning -399cd456 Merge "fix compile error on ARM/gcc" -9f24519e encoder: misc rate-related fixes -c663bb21 Merge "simplify VP8IteratorSaveBoundary() arg passing" -fa46b312 Demux.h: Correct a method name reference -f8398c9d fix compile error on ARM/gcc -f691f0e4 simplify VP8IteratorSaveBoundary() arg passing -42542be8 up to 6% faster encoding with clang compiler -93402f02 multi-threaded segment analysis -7e2d6595 Merge "remove the PACK() bit-packing tricks" -c13fecf9 remove the PACK() bit-packing tricks -2fd091c9 Merge "use NULL for lf_stats_ testing, not bool" -b11c9d62 dwebp: use default dct_method -4bb8465f Merge "(de)mux.h: wrap pseudo-code in /* */" -cfb56b17 make -pass option work with token buffers -5416aab4 (de)mux.h: wrap pseudo-code in /* */ -35dba337 use NULL for lf_stats_ testing, not bool -733a7faa enc->Iterator memory cleanup -e81fac86 Add support for "no blend" in webpmux binary -3b80bc48 gif2webp: Separate out each step into a method -bef7e9cc Add doc precision about demux object keeping pointers to data. -61405a14 dwebp: enable stdout output with WIC -6eabb886 Merge "Animated WebP: add "do no blend" option to spec" -be20decb fix compilation for BITS 24 -e58cc137 Merge "dwebp: s/unsigned char/uint8_t/" -72501d43 dwebp: s/unsigned char/uint8_t/ -2c9633e8 Merge "gif2webp: Insert independent frames at regular intervals." -f0d6a14b gif2webp: Insert independent frames at regular intervals. -b25a6fbf yuv.h: fix indent -ede3602e Merge "cosmetics: fix indent" -3a65122a dwebp: fix stdout related output -388a7249 cosmetics: fix indent -4c7322c8 Merge "dsp: msvc compatibility" -d50c7e32 Merge "5-7% faster SSE2 versions of YUV->RGB conversion functions" -b8ab7847 Merge "simplify upsampler calls: only allow 'bottom' to be NULL" -df6cebfa 5-7% faster SSE2 versions of YUV->RGB conversion functions -ad6ac32d simplify upsampler calls: only allow 'bottom' to be NULL -a5e8afaf output to stdout if file name is "-" -f358450f dsp: msvc compatibility -43a7c8eb Merge "cosmetics" -4c5f19c1 Merge "bit_reader.h: cosmetics" -f72fab70 cosmetics -14dd5e78 fix const-ness -b20aec49 Merge "Support for 'do not blend' option in vwebp" -dcf65222 Support for 'do not blend' option in vwebp -d5bad033 Animated WebP: add "do no blend" option to spec -a2f5f73d Merge "Support for "Do not blend" in mux and demux libraries" -e081f2f3 Pack code & extra_bits to Struct (VP8LPrefixCode). -6284854b Support for "Do not blend" in mux and demux libraries -f486aaa9 Merge "slightly faster ParseIntraMode" -d1718632 slightly faster ParseIntraMode -3ceca8ad bit_reader.h: cosmetics -69257f70 Create LUT for PrefixEncode. -988b7084 add WebPWorkerExecute() for convenient bypass -06e24987 Merge "VP8EncIterator clean-up" -de4d4ad5 VP8EncIterator clean-up -7bbe9529 Merge "cosmetics: thread.c: drop a redundant comment" -da411485 cosmetics: thread.c: drop a redundant comment -feb4b6e6 thread.h: #ifdef when checking WEBP_USE_THREAD -8924a3a7 thread.c: drop WebPWorker prefix from static funcs -1aed8f2a Merge "fix indent" -4038ed15 fix indent -1693fd9b Demux: A new state WEBP_DEMUX_PARSE_ERROR -8dcae8b3 fix rescaling-with-alpha inaccuracy -11249abf Merge changes I9b4dc36c,I4e0eef4d -52508a1f Mux: support parsing unknown chunks within a frame/fragment. -05db0572 WebPMuxSetChunk: remove unused variable -8ba1bf61 Stricter check for presence of alpha when writing lossless images -a03c3516 Demux: WebPIterator now also denotes if the frame has alpha. -6df743a3 Decoder: handle fragments case correctly too. -faa4b07e Support for unknown chunks in mux library -7d60bbc6 Speed up HashChainFindCopy function. -66740140 Speedup Alpha plane encoding. -b7346a1e 0.1 % speedup to decoding -c606182e webp-container-spec: Tighten language added by last -a34a5029 pngdec: output error messages from libpng -e84c625d Merge "Detect canvas and image size mismatch in decoder." -f626fe2e Detect canvas and image size mismatch in decoder. -f5fbdee0 demux: stricter image bounds check -30c8158a add extra assert in Huffman decode code -8967b9f3 SSE2 for lossless decoding (critical) functions. -699d80ea Jump-lookup for Huffman coding -c34307ab fix some VS9 warnings about type conversion -eeada35c pngdec: add missing include -54b65108 gif2webp: If aligning to even offsets, extra pixels should be transparent -0bcf5ce3 Merge "remove a malloc() in case we're using only FILTER_NONE for alpha" -2c07143b remove a malloc() in case we're using only FILTER_NONE for alpha -a4d5f59d Faster lossless decoding -fd53bb75 Merge "alternate LUT-base reverse-bits code" -d1c166ef Merge "Container spec: a clarification on background color." -fdb91779 Rename a method -5e967532 Container spec: a clarification on background color. -30e77d0f Merge branch '0.3.0' -1b631e29 alternate LUT-base reverse-bits code -24cc307a ~20% faster lossless decoding -313d853f Speedup for decoding lossless WebP photographs: -24ee098a change the bytes_per_pixels_ field into more evocative use_8b_decode -2a04b034 update ChangeLog (tag: v0.3.1-rc2, tag: v0.3.1) -7288950b Regression fix for alpha channels using color cache: -2e377b53 wicdec: silence a format warning -ad9e42a6 muxedit: silence some uninitialized warnings -3307c163 Don't set alpha-channel to 0xff for alpha->green uplift -5130770c Merge "wicdec: silence a format warning" -a37eff47 Regression fix for alpha channels using color cache: -241cf99b Merge "muxedit: silence some uninitialized warnings" -c8f9c84d Regression fix for alpha unfiltering: -14cd5c6c muxedit: silence some uninitialized warnings -a368db81 dec/vp8l: quiet vs9 x64 type conversion warning -ffae9f31 wicdec: silence a format warning -8cf0701e Alpha encoding: never filter in case of NO_COMPRESSION -825e73b1 update ChangeLog (tag: v0.3.1-rc1) -abf6f691 update NEWS -5a92c1a5 bump version to 0.3.1 -86daf77c store top Y/U/V samples in packed fashion -67bc353e Revert "add WebPBlendAlpha() function to blend colors against background" -068db59e Intertwined decoding of alpha and RGB -38cc0114 Simplify forward-WHT + SSE2 version -3fa595a5 Support decoding upto given row in DECODE_DATA_FUNC -520f005f DequantizeLevels(): Add 'row' and 'num_rows' args -47374b82 Alpha unfilter for given set of rows -f32097e0 probe input file and quick-check for WebP format. -a2aed1d0 configure: improve gl/glut library test -c7e89cbb update copyright text -a00380d2 configure: remove use of AS_VAR_APPEND -a94a88dd fix EXIF parsing in PNG -a71e5d84 add doc precision for WebPPictureCopy() and WebPPictureView() -8287012e remove datatype qualifier for vmnv -e1908430 fix a memory leak in gif2webp -0b18b9ee fix two minor memory leaks in webpmux -db5095d5 remove some cruft from swig/libwebp.jar -850e956f README: update swig notes -bddd9b0a swig/python: add minimal documentation -d573a8d5 swig: add python encode support -6b931875 swig/java: reduce wrapper function code duplication -6fe536f4 swig/java: rework uint8_t typemap -a2ea4643 Fix the bug in ApplyPalette. -7bb28d2a webp/lossless: fix big endian BGRA output -f036d4bf Speed up ApplyPalette for ARGB pixels. -8112c8cf remove some warnings: -cc128e0b Further reduce memory to decode lossy+alpha images -07db70d2 fix for big-endian -eda8a7de gif2webp: Fix signed/unsigned comparison mismatch -31f346fe Makefile.vc: fix libwebpdemux dll variable typo -6c76d28e swig: add python (decode) support -b4f5bb6c swig: cosmetics -498d4dd6 WebP-Lossless encoding improvements. -26e72442 swig: ifdef some Java specific code -8ecec686 configure: add warning related flags -e676b043 configure: add GLUT detection; build vwebp -b0ffc437 Alpha decoding: significantly reduce memory usage -20aa7a8d configure: add --enable-everything -b8307cc0 configure.ac: add some helper macros -980e7ae9 Remove the gcc compilation comments -7f25ff99 gif2webp: Fix ICC and XMP support -d8e53211 Add missing name to AUTHORS -11edf5e2 Demux: Fix a potential memleak -c7b92184 don't forward declare enums -7a650c6a prevent signed int overflow in left shift ops -31bea324 add precision about dynamic output reallocation with IDecoder -c22877f7 Add incremental support for extended format files -5051245f Makefile.vc: have 'all' target build everything -8191deca Makefile.vc: flags cleanup -b9d74735 Makefile.vc: drop /FD flag -5568dbcf update gitignore -f4c7b654 WebPEncode: An additional check. Start VP8EncLoop/VP8EncTokenLoop only if VP8EncStartAlpha succeeded. -1fb04bec pngdec: Avoid a double-free. -dcbb1ca5 add WebPBlendAlpha() function to blend colors against background -bc9f5fbe configure.ac: add AM_PROG_AR for automake >= 1.12 -bf867bf2 Tuned cross_color parameter (step) for lower qual -90e2ec5a Merge "probe input file and quick-check for WebP format." -7180d7ff Merge "update copyright text" -830f72b7 probe input file and quick-check for WebP format. -2ccf58d6 configure: improve gl/glut library test -d640614d update copyright text -c2113ad4 Merge "configure: remove use of AS_VAR_APPEND" -9326a56f configure: remove use of AS_VAR_APPEND -ea63d619 fix a type warning on VS9 x86 -bec11092 fix EXIF parsing in PNG -b6e65f3d Merge "fix warnings for vs9 x64" -438946dc fix warnings for vs9 x64 -f4710e3b collect macroblock reconstruction data in VP8MBData struct -23d28e21 add doc precision for WebPPictureCopy() and WebPPictureView() -518f2cd7 cosmetics: gif2webp: fix indent -af358e68 Merge "remove datatype qualifier for vmnv" -3fe91635 remove datatype qualifier for vmnv -764fdffa fix a memory leak in gif2webp -3e59a74d fix two minor memory leaks in webpmux -47b9862f Merge "README: update swig notes" -325d15ff remove some cruft from swig/libwebp.jar -4a7627c2 README: update swig notes -5da81e33 Merge "swig/python: add minimal documentation" -f39e08f2 Merge "swig: add python encode support" -6ca4a3e3 Merge "swig/java: reduce wrapper function code duplication" -8f8702b0 Merge "swig/java: rework uint8_t typemap" -91413be2 reduce memory for VP8MB and remove bitfields use -7413394e Fix the memory leak in ApplyFilters. -2053c2cf simplify the alpha-filter testing loop -825b64db swig/python: add minimal documentation -14677e11 swig: add python encode support -a5c297c8 swig/java: reduce wrapper function code duplication -ad4a367d swig/java: rework uint8_t typemap -0d25876b use uint8_t for inv_palette[] -afa3450c Fix the bug in ApplyPalette. -2d6ac422 Merge "webp/lossless: fix big endian BGRA output" -2ca83968 webp/lossless: fix big endian BGRA output -742110cc Speed up ApplyPalette for ARGB pixels. -2451e47d misc code cleanup -83db4043 Merge "swig: add python (decode) support" -eeeea8b5 Merge "swig: cosmetics" -d5f9b8f3 Merge "libwebp: fix vp8 encoder mem alloc offsetting" -d8edd835 libwebp: fix vp8 encoder mem alloc offsetting -8983b83e remove use of bit-fields in VP8FInfo -87a4fca2 remove some warnings: -ba8f74e2 Merge "fix for big-endian" -a65067fa Merge "Further reduce memory to decode lossy+alpha images" -64c84486 Further reduce memory to decode lossy+alpha images -332130b9 Mux: make a few methods static -44370617 fix for big-endian -5199eab5 Merge "add uncompressed TIFF output support" -a3aede97 add uncompressed TIFF output support -f975b67f Merge "gif2webp: Fix signed/unsigned comparison mismatch" -5fbc734b Merge "GetFeatures: Detect invalid VP8X/VP8/VP8L data" -d5060c87 Merge "mux.h: A comment fix + some consistency fixes" -352d0dee GetFeatures: Detect invalid VP8X/VP8/VP8L data -3ef79fef Cosmetic: "width * height" -043e1ae4 gif2webp: Fix signed/unsigned comparison mismatch -5818cff7 mux.h: A comment fix + some consistency fixes -1153f888 Merge "swig: ifdef some Java specific code" -3eeedae1 Makefile.vc: fix libwebpdemux dll variable typo -f980faf4 swig: add python (decode) support -7f5f42bb swig: cosmetics -8eae188a WebP-Lossless encoding improvements. -c7247c4c swig: ifdef some Java specific code -4cb234d5 Merge "Mux: make ValidateForSingleImage() method static" -ed6f5308 Merge "Add GetCanvasSize() method to mux" -1d530c9a Mux: make ValidateForSingleImage() method static -bba4c2b2 configure: add warning related flags -fffefd18 Add GetCanvasSize() method to mux -732da8d0 Merge "configure: add GLUT detection; build vwebp" -0e513f7a configure: add GLUT detection; build vwebp -55d1c150 Merge "Alpha decoding: significantly reduce memory usage" -13d99fb5 Merge "configure: add --enable-everything" -2bf698fe Merge "configure.ac: add some helper macros" -edccd194 Alpha decoding: significantly reduce memory usage -3cafcc9a configure: add --enable-everything -4ef14477 configure.ac: add some helper macros -a4e1cdbb Remove the gcc compilation comments -6393fe4b Cosmetic fixes -9c4ce971 Simplify forward-WHT + SSE2 version -878b9da5 fix missed optim -00046171 VP8GetInfo(): Check for zero width or height. -9bf31293 align VP8Encoder::nz_ allocation -5da165cf fix CheckMode() signature -0ece07dc Merge "explicitly pad bitfields to 32-bits" -9dbc9d19 explicitly pad bitfields to 32-bits -5369a80f Merge "prevent signed int overflow in left shift ops" -70e39712 Merge "cosmetics: remove unnecessary ';'s" -d3136ce2 Merge "don't forward declare enums" -b26e5ad5 gif2webp: Fix ICC and XMP support -46089b20 Add missing name to AUTHORS -94328d64 Demux: Fix a potential memleak -96e948d7 don't forward declare enums -f4f90880 prevent signed int overflow in left shift ops -0261545e cosmetics: remove unnecessary ';'s -7ebdf110 Merge "Fix few missing comparisons to NULL" -1579989e Fix few missing comparisons to NULL -ea1b21cf Cleaned up VP8GetHeaders() so that it parses only frame header -b66caee4 dwebp: add support for BMP output -ff885bfe add precision about dynamic output reallocation with IDecoder -79241d5a Merge "Makefile.vc: have 'all' target build everything" -ac1c729b Merge "Makefile.vc: flags cleanup" -118a055c Merge "Makefile.vc: drop /FD flag" -ecad0109 Merge "update gitignore" -a681b4f4 Rename PRE_VP8 state to WEBP_HEADER -ead4d478 Add incremental support for extended format files -69d0f926 Makefile.vc: have 'all' target build everything -52967498 Makefile.vc: flags cleanup -c61baf0c Makefile.vc: drop /FD flag -3a15125d update gitignore -5167ca47 Merge "WebPEncode: An additional check. Start VP8EncLoop/VP8EncTokenLoop only if VP8EncStartAlpha succeeded." -67708d67 WebPEncode: An additional check. Start VP8EncLoop/VP8EncTokenLoop only if VP8EncStartAlpha succeeded. -b68912af pngdec: Avoid a double-free. -82abbe12 Merge "configure.ac: add AM_PROG_AR for automake >= 1.12" -e7d9548c add WebPBlendAlpha() function to blend colors against background -ed4dc717 configure.ac: add AM_PROG_AR for automake >= 1.12 -df4a406d Merge branch '0.3.0' -1e0d4b8c Update ChangeLog (tag: v0.3.0-rc7, tag: v0.3.0) -d52b405d Cosmetic fixes -6cb4a618 misc style fix -68111ab0 add missing YUVA->ARGB automatic conversion in WebPEncode() -e9a7990b Cosmetic fixes -403bfe82 Container spec: Clarify frame disposal -2aaa423b Merge "add missing YUVA->ARGB automatic conversion in WebPEncode()" -07d87bda add missing YUVA->ARGB automatic conversion in WebPEncode() -142c4629 misc style fix -3e7a13a0 Merge "Container spec: clarify the background color field" into 0.3.0 -14af7745 container doc: add a note about the 'ANMF' payload -cc635efa Container spec: clarify the background color field -e3e33949 container doc: move RIFF description to own section -4299f398 libwebp/mux: fix double free -33f9a692 Merge "demux: keep a frame tail pointer; used in AddFrame" into 0.3.0 -a2a7b959 use WebPDataCopy() instead of re-coding it. -6f18f12f demux: keep a frame tail pointer; used in AddFrame -e5af49e9 add doc precision about WebPParseHeaders() return codes -db46daab Merge "Makefile.vc: fix dynamic builds" into 0.3.0 -53c77afc Merge "gif2webp: Bgcolor fix for a special case" into 0.3.0 -a5ebd143 gif2webp: Bgcolor fix for a special case -6378f238 Merge "vwebp/animation: fix background dispose" into 0.3.0 -3c8eb9a8 fix bad saturation order in QuantizeBlock -04c7a2ec vwebp/animation: fix background dispose -81a50695 Makefile.vc: fix dynamic builds -5f25c396 update ChangeLog (tag: v0.3.0-rc6) -14d42af2 examples: don't use C99 %zu -5ccf1fe5 update ChangeLog -2560c243 update NEWS -f43bafc3 Merge changes Iecccb09c,If5ee9fd2,I3e181ce4 into 0.3.0 -a788644f dwebp: warn when decoding animated webp's -302efcdb Decode: return more meaningful error for animation -ad452735 WebPBitstreamFeatures: add has_animation field -783dfa49 disable FRGM decoding for good in libwebpmux -4b956be0 Update ChangeLog -ad8b86d7 update NEWS -3e084f63 Merge "demux cosmetics: comments/rename internal function" into 0.3.0 -d3f8c621 Merge "move WebPFeatureFlags declaration" into 0.3.0 -7386fe50 Merge "libwebp{demux,mux}: install mux_types.h" into 0.3.0 -d6cd4e90 Merge "bump decode abi" into 0.3.0 -17f8da5c bump decode abi -97684ae2 Merge "add doc precision about WebPDemuxPartial()" into 0.3.0 -f933fd2a move WebPFeatureFlags declaration -289bc47b libwebp{demux,mux}: install mux_types.h -224e8d46 add doc precision about WebPDemuxPartial() -4c18e80c demux cosmetics: comments/rename internal function -7cfd1bf1 update AUTHORS -401f7b85 Merge "speed-up lossless (~3%) with ad-hoc histogram cost evaluation" into 0.3.0 -1fc8ffca Merge "makefile.unix: dist related changes" into 0.3.0 -8a89c6ed Merge changes I466c377f,Ib761ebd3,I694857fc into 0.3.0 -f4ffb2d5 speed-up lossless (~3%) with ad-hoc histogram cost evaluation -723847d5 gif2webp: only write error messages to stderr -701b9e2a makefile.unix: dist related changes -bb85b437 Merge "update NEWS" into 0.3.0 -59423a24 gif2webp: fix crash on open failure with libgif5 -9acb17de gif2webp: silence a unused param warning -7d9fdc23 Merge "README updates" into 0.3.0 -5621934e Merge "build: fix install race on shared headers" into 0.3.0 -70809d89 Merge "bump version to 0.3.0" into 0.3.0 -d851cd1d demux: make the parse a bit more strict -28bb4107 update NEWS -cef93882 bump version to 0.3.0 -9048494d build: fix install race on shared headers -1e67e8ef README updates -42b611a4 Merge "configure: drop experimental from mux/demux" into 0.3.0 -096a8e32 Merge "vwebp: add color profile support" into 0.3.0 -ddfee5dc vwebp: add color profile support -0d6927d3 Merge "Mark fragment options as experimental in webpmux" into 0.3.0 -5dbd4030 Mark fragment options as experimental in webpmux -a0a6648c configure: drop experimental from mux/demux -ee65bad8 Merge "add support for BITS > 32" into 0.3.0 -744930db add support for BITS > 32 -7dd288f0 cwebp: fix build -19a8dd01 Merge "Makefile.vc: add vwebp.exe target" into 0.3.0 -50eeddad Merge "examples: normalize icc related program arguments" into 0.3.0 -757f637f Merge "Makefile.vc: add libwebpdecoder target" into 0.3.0 -b65c4b7c Makefile.vc: add libwebpdecoder target -f8db7b4a Merge "vwebp: replace doubles w/floats where appropriate" into 0.3.0 -d99aa56f Makefile.vc: add vwebp.exe target -013023e7 vwebp: replace doubles w/floats where appropriate -9b3db894 README.mux: add version reference -7b6a26cf Merge "cwebp: output metadata statistics" into 0.3.0 -d8dc72a0 examples: normalize icc related program arguments -7bfc9056 Merge "make alpha unfilter work in-place" into 0.3.0 -0037b2d2 Merge "add LUT-free reference code for YUV->RGB conversion." into 0.3.0 -166bf744 Merge "demux: disable fragment parsing" into 0.3.0 -126974b4 add LUT-free reference code for YUV->RGB conversion. -0aef3ebd make alpha unfilter work in-place -14ef5005 Merge "Remove 'status: experimental' from container spec" into 0.3.0 -d40c98e1 Merge "webpmux binary: tiny style fix" into 0.3.0 -0bc42689 cwebp: output metadata statistics -bc039803 Merge "autoconf: normalize experimental define" into 0.3.0 -d1e21b13 Remove 'status: experimental' from container spec -7681bb96 webpmux binary: tiny style fix -a3dd3d0f avoid installing example_util.h -252320e2 demux: disable fragment parsing -537bde05 autoconf: normalize experimental define -5e338e0b Merge changes I33e8a613,I8e8a7b44 into 0.3.0 -d9d0ea1b Merge changes If21e3ec7,I991fc30b into 0.3.0 -627f5ca6 automake: add reference to libwebp for mux/demux -eef73d07 don't consolidate proba stats too often -05ec4cc2 libwebp{,decoder}.pc: add pthread flags -1bfcf5bf add libwebpmux.pc -26ca843d add libwebpdemux.pc -69e25906 Merge "Tune Lossless compression for lower qualities." -0478b5d2 Tune Lossless compression for lower qualities. -39f7586f add a mention of parallel alpha encoding in the NEWS -5a21d967 Merge "1.5x-2x faster encoding for method 3 and up" -9bfbdd14 1.5x-2x faster encoding for method 3 and up -27dc741b Correct frame options order in README.mux -be2fd173 Mux: fix a scenario with bad ANMF/FRGM size -19eb012c Merge "Demux: Add option to get frame count using GetI()" -7368b8cb Merge "WebPGetFeatures() out of if condition for clarity." -f604c9a4 Merge "fix windows build" -153f94e8 fix windows build -847b4924 Merge "vwebp: use magenta for 'i'nfo display" -25ea46bd Merge "vwebp: add keyboard shortcuts to help output" -bea7ccaf vwebp: use magenta for 'i'nfo display -8fab161a webpmux: correct -frame param order in help output -03cc23d6 vwebp: add keyboard shortcuts to help output -068eba8d Demux: Add option to get frame count using GetI() -988b8f56 WebPGetFeatures() out of if condition for clarity. -6933d910 Merge "gif2webp: Be lenient about background color index." -4d0f7c55 Merge "WebPGetFeatures() behavior change:" -fdeeb01d gif2webp: Be lenient about background color index. -ad250320 Merge "multi-threaded alpha encoding for lossy" -4e32d3e1 Merge "fix compilation of token.c" -f817930a multi-threaded alpha encoding for lossy -88050351 fix compilation of token.c -fc816219 code using the actual values for num_parts_, not the ones from config -72655350 Merge "move the config check from .c to .h" -dd9e76f7 move the config check from .c to .h -956b217a WebPGetFeatures() behavior change: -df02e4ce WebPDemuxGetI behavior change: -633c004d Merge "rebalance method tools (-m) for methods [0..4]" -58ca6f65 rebalance method tools (-m) for methods [0..4] -7648c3cc Merge "describe rd-opt levels introduce VP8RDLevel enum" -67fb1003 Merge "autoconf: enable silent-rules by default" -a5042a32 GetVersion() methods for mux and demux -5189957e describe rd-opt levels introduce VP8RDLevel enum -4e094ace autoconf: enable silent-rules by default -b7eaa85d inline VP8LFastLog2() and VP8LFastSLog2 for small values -5cf7792e split quant_levels.c into decoder and encoder version -e5d3ffe2 Merge "Update code example in README.mux" -ac5a9156 Update code example in README.mux -38a91e99 Add example code snippet for demux API -5f557f3c README.mux: add info about Demux API and vwebp -c0ba0903 backward_references: avoid signed integer overflow -943386db disable SSE2 for now -9479fb7d lossless encoding speedup -ec2030a8 merge two lines together -b67956c0 Merge "Remove ReadOneBit() and ReadSymbolUnsafe()" -1667bded Remove ReadOneBit() and ReadSymbolUnsafe() -3151669b wicdec + dwebp cosmetics: normalize formatting -92668da6 change default filtering parameters: * type is now 'strong' * strength is now '60' -b7490f85 introduce WEBP_REFERENCE_IMPLEMENTATION compile option -33838857 faster decoding (3%-6%) -5c3e381b Merge "add a -jpeg_like option" -c2311046 remove unused declaration of VP8Zigzag -36152957 Merge "wicdec: add alpha support for paletted formats" -c9f16490 wicdec: add alpha support for paletted formats -1262f81e Merge "wicdec: silence some warnings" -e7ea61eb wicdec: silence some warnings -23c0f354 fix missing intptr_t->int cast for MSVC -e895059a add a -jpeg_like option -1f803f64 Merge "Tune alpha quality mapping to more reasonable values." -1267d498 Tune alpha quality mapping to more reasonable values. -043076e2 Merge "speed-up lossless in BackwardTrace" -f3a44dcd remove one malloc from TraceBackwards() -0fc1a3a0 speed-up lossless in BackwardTrace -7c732e59 cwebp: centralize WebPCleanupTransparentArea() -7381254e Merge "wicdec: add ICC profile extraction" -e83ff7de wicdec: add ICC profile extraction -146c6e3b Merge "cosmetics: pngdec: normalize default label location" -a8f549d7 Merge "manpages: italicize option parameters" -e118db83 Merge "encode.h: note the need to free() WebPMemoryWriter" -1dfee6db cosmetics: pngdec: normalize default label location -14c38200 manpages: italicize option parameters -7defbfad encode.h: note the need to free() WebPMemoryWriter -88d382a0 cwebp: cleanup after memory_writer -12d6cecf fix extra space in dwebp.1 man -b01681a9 Fix for demuxer frame iteration: -56c12aa6 Demuxer creation fix: -66c810bc add a -yuv option to dwebp (very similar to -pgm) -841a3ba5 Merge "Remove -Wshadow warnings." -8fd02527 Merge "upsampling_neon.c: fix build" -6efed268 Remove -Wshadow warnings. -60904aa6 Merge "allow WebPINewRGB/YUVA to be passed a NULL output buffer." -b7adf376 allow WebPINewRGB/YUVA to be passed a NULL output buffer. -27f8f742 upsampling_neon.c: fix build -06b9cdf1 gitignore: add IOS related directories -f112221e Merge "Fix more comments for iobuild.sh" -fe4d25dd Fix more comments for iobuild.sh -1de3e252 Merge "NEON optimised yuv to rgb conversion" -090b708a NEON optimised yuv to rgb conversion -daa06476 Merge "Add ios build script for building iOS library." -79fe39e2 Add ios build script for building iOS library. -126c035f remove some more -Wshadow warnings -522e9d61 Merge "cwebp: enable '-metadata'" -76ec5fa1 cwebp: enable '-metadata' -aeb91a9d Merge "cosmetics: break a few long lines" -be7c96b0 cosmetics: break a few long lines -cff8ddb6 Merge "add libwebpdecoder.pc" -93148ab8 Merge "libwebp.pc.in: detab" -6477f955 Merge "Makefile.vc: normalize path separator" -bed1ed7c add libwebpdecoder.pc -46168b2d libwebp.pc.in: detab -a941a346 Fixed few nits in the build files. -dd7a49b2 Makefile.vc: normalize path separator -9161be86 Merge "cwebp: extract WIC decoding to its own module" -08e7c58e Merge "Provide an option to build decoder library." -0aeba528 Provide an option to build decoder library. -757ebcb1 catch malloc(0)/calloc(0) with an assert -152ec3d2 Merge "handle malloc(0) and calloc(0) uniformly on all platforms" -a452a555 cwebp: extract WIC decoding to its own module -2b252a53 Merge "Provide option to swap bytes for 16 bit colormodes" -94a48b4b Provide option to swap bytes for 16 bit colormodes -42f8f934 handle malloc(0) and calloc(0) uniformly on all platforms -8b2152c5 Merge "add an extra assert to check memory bounds" -0d19fbff remove some -Wshadow warnings -cd22f655 add an extra assert to check memory bounds -8189feda Merge "Add details and reference about the YUV->RGB conversion" -1d2702b1 Merge "Formatting fixes in lossless bitstream spec" -8425aaee Formatting fixes in lossless bitstream spec -a556cb1a Add details and reference about the YUV->RGB conversion -d8f21e0b add link to SSIM description on Wikipedia -18e9167e Merge "WebP-lossless spec clarifications:" -98e25b9b Merge "cwebp: add -metadata option" -f01c2a53 WebP-lossless spec clarifications: -f4a97970 Merge "Disto4x4 and Disto16x16 in NEON" -47b7b0ba Disto4x4 and Disto16x16 in NEON -7eaee9f1 cwebp: add -metadata option -36c52c2c tiffdec: use toff_t for exif ifd offset -7c8111e4 Merge "cwebp/tiffdec: add TIFF metadata extraction" -e6409adc Remove redundant include from dsp/lossless code. -1ab5b3a7 Merge "configure: fix --with-gifincludedir" -03c749eb configure: fix --with-gifincludedir -8b650635 multiple libgif versions support for gif2webp -476e293f gif2webp: Use DGifOpenFileName() -b50f277b tiffdec: correct format string -2b9048e3 Merge "tiffdec: check error returns for width/height" -a1b5a9a3 Merge "cwebp/tiff: use the first image directory" -079423f5 tiffdec: check error returns for width/height -d62824af Merge "cwebp/jpegdec: add JPEG metadata extraction" -03afaca4 Merge "cwebp: add PNG metadata extraction" -2c724968 cwebp/jpegdec: add JPEG metadata extraction -dba64d91 cwebp: add PNG metadata extraction -1f075f89 Lossless spec corrections/rewording/clarifications -2914ecfd cwebp/tiffdec: add TIFF metadata extraction -d82a3e33 More corrections/clarifications in lossless spec: -bd002557 cwebp/tiff: use the first image directory -df7aa076 Merge "Cleanup around jpegdec" -0f57dcc3 decoding speed-up (~1%) -bcec339b Lossless bitstream clarification: -6bf20874 add examples/metadata.c -207f89c0 Merge "configure: add libwebpdemux status to summary" -1bd287a6 Cleanup around jpegdec -91455679 Merge "cosmetics: use '== 0' in size checks" -d6b88b76 cosmetics: use '== 0' in size checks -d3dace2f cosmetics: jpegdec -2f69af73 configure: add libwebpdemux status to summary -1c1c5646 cwebp: extract tiff decoding to its own module -6a871d66 cwebp: extract jpeg decoding to its own module -2ee228f9 cwebp: extract png decoding to its own module -4679db00 Merge "cwebp: add metadata framework" -63aba3ae cwebp: add metadata framework -931bd516 lossless bitstream: block size bits correction -e4fc4c1c lossless bitstream: block size bits correction -d65ec678 fix build, move token.c to src/enc/ -657f5c91 move token buffer to its own file (token.c) -c34a3758 introduce GetLargeValue() to slim-fast GetCoeffs(). -d5838cd5 faster non-transposing SSE2 4x4 FTransform -f76191f9 speed up GetResidualCost() -ba2aa0fd Add support for BITS=24 case -2e7f6e8e makefile.unix: Dependency on libraries -dca84219 Merge "Separate out mux and demux code and libraries:" -23782f95 Separate out mux and demux code and libraries: -bd56a01f configure: add summary output -90e5e319 dwebp manual: point to webpmux, gif2webp. -540790ca gif2webp.c: add a note about prerequisites -d1edf697 cwebp man page: meaning of '-q' for lossy/lossless -79efa1d0 Add man page for gif2webp utility -2243e40c Merge "gif2webp build support with autoconf tools" -c40efca1 gif2webp build support with autoconf tools -6523e2d4 WebP Container: -4da788da Merge "simplify the fwd transform" -42c3b550 simplify the fwd transform -41a6ced9 user GLfloat instead of float -b5426119 fix indentation -68f282f7 * handle offset in anim viewer 'vwebp' * fix gif2webp to handle disposal method and odd offset correctly -118cb312 Merge "add SSE2 version of Sum of Square error for 16x16, 16x8 and 8x8 case" -8a7c3cc8 Merge "Change the order of -frame argument to be more natural" -99e0a707 Merge "Simplify the texture evaluation Disto4x4()" -0f923c3f make the bundling work in a tmp buffer -e5c3b3f5 Simplify the texture evaluation Disto4x4() -48600084 Change the order of -frame argument to be more natural -35bfd4c0 add SSE2 version of Sum of Square error for 16x16, 16x8 and 8x8 case -a7305c2e Clarification for unknown chunks -4c4398e2 Refine WebP Container Spec wrt unknown chunks. -2ca642e0 Rectify WebPMuxGetFeatures: -7caab1d8 Some cosmetic/comment fixes. -60b2651a Merge "Write a GIF to WebP converter based on libgif." -c7127a4d Merge "Add NEON version of FTransformWHT" -11b27212 Write a GIF to WebP converter based on libgif. -e9a15a37 ExUtilWriteFile() to write memory segment to file -74356eb5 Add a simple cleanup step in mux assembly: -51bb1e5d mux.h: correct WebPDemuxSelectFragment() prototype -22a0fd9d Add NEON version of FTransformWHT -fa30c863 Update mux code to match the spec wrt animation -d9c5fbef by-pass Analysis pass in case segments=1 -d2ad4450 Merge changes Ibeccffc3,Id1585b16 -5c8be251 Merge "Chunk fourCCs for XMP/EXIF" -a00a3daf Use 'frgm' instead of 'tile' in webpmux parameters -81b8a741 Design change in ANMF and FRGM chunks: -f903cbab Chunk fourCCs for XMP/EXIF -812933d6 Tune performance of HistogramCombine -52ad1979 Animation specification in container spec -001b9302 Image fragment specification in container spec -391f9db9 Ordering of description of bits in container spec -d5735776 Metadata specification in container spec -1c4609b1 Merge commit 'v0.2.1' -0ca584cb Merge "Color profile specification in container spec" -e8b41ad1 add NEON asm version for WHT inverse transform -af6f0db2 Color profile specification in container spec -a61a824b Merge "Add NULL check in chunk APIs" -0e8b7eed fix WebPPictureView() unassigned strides -75e5f17e ARM/NEON: 30% encoding speed-up -02b43568 Add NULL check in chunk APIs -a0770727 mux struct naming -6c66dde8 Merge "Tune Lossless encoder" -ab5ea217 Tune Lossless encoder -74fefc8c Update ChangeLog (tag: v0.2.1, origin/0.2.0) -92f8059c Rename some chunks: -3bb4bbeb Merge "Mux API change:" -d0c79f05 Mux API change: -abc06044 Merge "update NEWS" into 0.2.0 -57cf313b update NEWS -25f585c4 bump version to 0.2.1 -fed7c048 libwebp: validate chunk size in ParseOptionalChunks -552cd9bc cwebp (windows): fix alpha image import on XP -b14fea99 autoconf/libwebp: enable dll builds for mingw -4a8fb272 [cd]webp: always output windows errors -d6621580 fix double to float conversion warning -72b96a69 cwebp: fix jpg encodes on XP -734f762a VP8LAllocateHistogramSet: fix overflow in size calculation -f9cb58fb GetHistoBits: fix integer overflow -b30add20 EncodeImageInternal: fix uninitialized free -3de58d77 fix the -g/O3 discrepancy for 32bit compile -77aa7d50 fix the BITS=8 case -e5970bda Make *InitSSE2() functions be empty on non-SSE2 platform -ef5cc47e make *InitSSE2() functions be empty on non-SSE2 platform -c4ea259d make VP8DspInitNEON() public -8344eadf Merge "libwebp: validate chunk size in ParseOptionalChunks" -4828bb93 Merge "cwebp (windows): fix alpha image import on XP" -30763333 libwebp: validate chunk size in ParseOptionalChunks -70481898 AccumulateLSIM: fix double -> float warnings -eda8ee4b cwebp (windows): fix alpha image import on XP -c6e98658 Merge "add EXPERIMENTAL code for YUV-JPEG colorspace" -f0360b4f add EXPERIMENTAL code for YUV-JPEG colorspace -f86e6abe add LSIM metric to WebPPictureDistortion() -c3aa215a Speed up HistogramCombine for lower qualities. -1765cb1c Merge "autoconf/libwebp: enable dll builds for mingw" -a13562e8 autoconf/libwebp: enable dll builds for mingw -9f469b57 typo: no_fancy -> no_fancy_upsampling -1a27f2f8 Merge "fix double to float conversion warning" -cf1e90de Merge "cwebp: fix jpg encodes on XP" -f2b5d19b [cd]webp: always output windows errors -e855208c fix double to float conversion warning -ecd66f77 cwebp: fix jpg encodes on XP -7b3eb372 Tune lossless compression to get better gains. -ce8bff45 Merge "VP8LAllocateHistogramSet: fix overflow in size calculation" -ab5b67a1 Merge "EncodeImageInternal: fix uninitialized free" -7fee5d12 Merge "GetHistoBits: fix integer overflow" -a6ae04d4 VP8LAllocateHistogramSet: fix overflow in size calculation -80237c43 GetHistoBits: fix integer overflow -8a997235 EncodeImageInternal: fix uninitialized free -0b9e6829 minor cosmetics -a792b913 fix the -g/O3 discrepancy for 32bit compile -73ba4357 Merge "detect and merge similar segments" -fee66275 detect and merge similar segments -0c44f415 src/webp/*.h: don't forward declare enums in C++ -d7a5ac86 vwebp: use demux interface -931e0ea1 Merge "replace 'typedef struct {} X;" by "typedef struct X X; struct X {};"" -8f216f7e remove cases of equal comparison for qsort() -28d25c82 replace 'typedef struct {} X;" by "typedef struct X X; struct X {};" -2afee60a speed up for ARM using 8bit for boolean decoder -5725caba new segmentation algorithm -2cf1f815 Merge "fix the BITS=8 case" -12f78aec fix the BITS=8 case -6920c71f fix MSVC warnings regarding implicit uint64 to uint32 conversions -f6c096aa webpmux binary: Rename 'xmp' option to 'meta' -ddfe871a webpmux help correction -b7c55442 Merge "Make *InitSSE2() functions be empty on non-SSE2 platform" -1c04a0d4 Common APIs for chunks metadata and color profile. -2a3117a1 Merge "Create WebPMuxFrameInfo struct for Mux APIs" -5c3a7231 Make *InitSSE2() functions be empty on non-SSE2 platform -7c6e60f4 make *InitSSE2() functions be empty on non-SSE2 platform -c7eb4576 make VP8DspInitNEON() public -ab3234ae Create WebPMuxFrameInfo struct for Mux APIs -e3990fd8 Alignment fixes -e55fbd6d Merge branch '0.2.0' -4238bc0a Update ChangeLog (tag: v0.2.0) -c655380c dec/io.c: cosmetics -fe1958f1 RGBA4444: harmonize lossless/lossy alpha values -681cb30a fix RGBA4444 output w/fancy upsampling -f06c1d8f Merge "Alignment fix" into 0.2.0 -f56e98fd Alignment fix -6fe843ba avoid rgb-premultiply if there's only trivial alpha values -528a11af fix the ARGB4444 premultiply arithmetic -a0a48855 Lossless decoder fix for a special transform order -62dd9bb2 Update encoding heuristic w.r.t palette colors. -6f4272b0 remove unused ApplyInverseTransform() -93bf0faa Update ChangeLog (tag: v0.2.0-rc1) -5934fc59 update AUTHORS -014a711d update NEWS -43b0d610 add support for ARGB -> YUVA conversion for lossless decoder -33705ca0 bump version to 0.2.0 -c40d7ef1 fix alpha-plane check + add extra checks -a06f8023 MODE_YUVA: set alpha to opaque if the image has none -52a87dd7 Merge "silence one more warning" into 0.2.0 -3b023093 silence one more warning -f94b04f0 move some RGB->YUV functions to yuv.h -4b71ba03 README: sync [cd]webp help output -c9ae57f5 man/dwebp.1: add links to output file format details -292ec5cc quiet a few 'uninitialized' warnings -4af3f6c4 fix indentation -9b261bf5 remove the last NOT_HAVE_LOG2 instances -323dc4d9 remove use of log2(). Use VP8LFastLog2() instead. -8c515d54 Merge "harness some malloc/calloc to use WebPSafeMalloc and WebPSafeCalloc" into 0.2.0 -d4b4bb02 Merge changes I46090628,I1a41b2ce into 0.2.0 -bff34ac1 harness some malloc/calloc to use WebPSafeMalloc and WebPSafeCalloc -a3c063c7 Merge "extra size check for security" into 0.2.0 -5e796300 Merge "WebPEncode: clear stats at the start of encode" into 0.2.0 -f1edf62f Merge "rationalize use of color-cache" into 0.2.0 -c1933317 extra size check for security -906be657 rationalize use of color-cache -dd1c3873 Add image-hint for low-color images. -4eb7aa64 Merge "WebPCheckMalloc() and WebPCheckCalloc():" into 0.2.0 -80cc7303 WebPCheckMalloc() and WebPCheckCalloc(): -183cba83 check VP8LBitWriterInit return -cbfa9eec lossless: fix crash on user abort -256afefa cwebp: exit immediately on version mismatch -475d87d7 WebPEncode: clear stats at the start of encode -a7cc7291 fix type and conversion warnings -7d853d79 add stats for lossless -d39177b7 make QuantizeLevels() store the sum of squared error -5955cf5e replace x*155/100 by x*101581>>16 -7d732f90 make QuantizeLevels() store the sum of squared error -e45a446a replace x*155/100 by x*101581>>16 -159b75d3 cwebp output size consistency: -cbee59eb Merge commit 'v0.1.99' -1889e9b6 dwebp: report -alpha option -3bc3f7c0 Merge "dwebp: add PAM output support" into 0.2.0 -d919ed06 dwebp: add PAM output support -85e215d3 README/manpages/configure: update website link -c3a207b9 Update ChangeLog (tag: v0.1.99) -d1fd7826 Merge "add extra precision about default values and behaviour" into 0.2.0 -efc826e0 add extra precision about default values and behaviour -9f29635d header/doc clean up -ff9fd1ba Makefile.vc: fix webpmux.exe *-dynamic builds -8aacc7b0 remove INAM, ICOP, ... chunks from the test webp file. -2fc13015 harmonize authors as "Name (mail@address)" -4a9f37b7 Merge "update NEWS" into 0.2.0 -7415ae13 makefile.unix: provide examples/webpmux target -ce82cedc update NEWS -641e28e8 Merge "man/cwebp.1: wording, change the date" into 0.2.0 -c37c23e5 README: cosmetics -3976dcd5 man/cwebp.1: wording, change the date -3e5bbe1c Merge "rename 'use_argb_input' to 'use_argb'" into 0.2.0 -ce90847a Merge "add some padding bytes areas for later use" into 0.2.0 -2390dabc Merge "fixing the findings by Frederic Kayser to the bitstream spec" into 0.2.0 -02751591 add a very crude progress report for lossless -a4b9b1c6 Remove some unused enum values. -dd108176 rename 'use_argb_input' to 'use_argb' -90516ae8 add some padding bytes areas for later use -d03b2503 fixing the findings by Frederic Kayser to the bitstream spec -ce156afc add missing ABI compatibility checks -9d45416a Merge "Doc: container spec text tweaks" into 0.2.0 -4e2e0a8c Doc: container spec text tweaks -f7f16a29 add ABI compatibility check -2a775570 Merge "swig: add WebPEncodeLossless* wrappers" into 0.2.0 -a3ec6225 mux.h: remove '* const' from function parameters -31426eba encode.h: remove '* const' from function parameters -9838e5d5 decode.h: remove '* const' from function parameters -4972302d swig: add WebPEncodeLossless* wrappers -9ff00cae bump encoder/decoder versions -c2416c9b add lossless quick encoding functions to the public API -4c1f5d64 Merge "NEWS: mention decode_vp8.h is no longer installed" into 0.2.0 -6cb2277d NEWS: mention decode_vp8.h is no longer installed -d5e5ad63 move decode_vp8.h from webp/ to dec/ -8d3b04a2 Merge "header clean-up" into 0.2.0 -02201c35 Merge "remove one malloc() by making color_cache non dynamic" into 0.2.0 -d708ec14 Merge "move MIN/MAX_HISTO_BITS to format_constants.h" into 0.2.0 -ab2da3e9 Merge "add a malloc() check" into 0.2.0 -2d571bd8 add a malloc() check -7f0c178e remove one malloc() by making color_cache non dynamic -6569cd7c Merge "VP8LFillBitWindow: use 64-bit path for msvc x64 builds" into 0.2.0 -23d34f31 header clean-up -2a3ab6f9 move MIN/MAX_HISTO_BITS to format_constants.h -985d3da6 Merge "shuffle variables in HashChainFindCopy" into 0.2.0 -cdf885c6 shuffle variables in HashChainFindCopy -c3b014db Android.mk: add missing lossless files -8c1cc6b5 makefile.unix dist: explicitly name installed includes -7f4647ee Merge "clarify the colorspace naming and byte ordering of decoded samples" into 0.2.0 -cbf69724 clarify the colorspace naming and byte ordering of decoded samples -857650c8 Mux: Add WebPDataInit() and remove WebPImageInfo -ff771e77 don't install webp/decode_vp8.h -596dff78 VP8LFillBitWindow: use 64-bit path for msvc x64 builds -3ca7ce98 Merge "doc: remove non-finalized chunk references" into 0.2.0 -1efaa5a3 Merge "bump versions" into 0.2.0 -51fa13e1 Merge "README: update cwebp help output" into 0.2.0 -12f9aede README: update cwebp help output -f0b5defb bump versions -4c42a61b update AUTHORS -6431a1ce doc: remove non-finalized chunk references -8130c4cc Merge "build: remove libwebpmux from default targets/config" -23b44438 Merge "configure: broaden test for libpng-config" -85bff2cd Merge "doc: correct lossless prefix coding table & code" -05108f6e Merge "More spec/code matching in mux:" -6808e69d More spec/code matching in mux: -bd2b46f5 Merge "doc/webp-container-spec: light cosmetics" -20ead329 doc/webp-container-spec: light cosmetics -1d40a8bc configure: add pthread detection -b5e9067a fix some int <-> size_t mix for buffer sizes -e41a7596 build: remove libwebpmux from default targets/config -0fc2baae configure: broaden test for libpng-config -45b8272c Merge "restore authorship to lossless bitstream doc" -06ba0590 restore authorship to lossless bitstream doc -44a09a3c add missing description of the alpha filtering methods -63db87dd Merge "vwebp: add checkboard background for alpha display" -a73b8978 vwebp: add checkboard background for alpha display -939158ce Merge "vwebp: fix info display" -b35c07d9 vwebp: fix info display -48b39eb1 fix underflow for very short bitstreams -7e622984 cosmetics: param alignment, manpage wording -1bd7dd50 Merge changes I7b0afb0d,I7ecc9708 -ac69e63e Merge "Updated cwebp man's help for Alpha & Lossless." -c0e8859d Get rid of image_info_ from WebPChunk struct. -135ca69e WebP Container Spec: -eb6f9b8a Updated cwebp man's help for Alpha & Lossless. -0fa844fb cosmetic fixes on assert and 'const' where applicable -7f22bd25 check limit of width * height is 32 bits -16c46e83 autoconf/make: cosmetics: break long lines -ab22a07a configure: add helper macro to define --with-* -c17699b3 configure: add libtiff test -0e09732c Merge "cwebp: fix crash with yuv input + lossless" -88a510ff Merge "fix big-endian VP8LWriteBits" -da99e3bf Merge "Makefile.vc: split mux into separate lib" -7bda392b cwebp: fix crash with yuv input + lossless -f56a369a fix big-endian VP8LWriteBits -54169d6c Merge "cwebp: name InputFileFormat members consistently" -e2feefa9 Makefile.vc: split mux into separate lib -27caa5aa Merge "cwebp: add basic TIFF support" -d8921dd4 cwebp: name InputFileFormat members consistently -6f76d246 cwebp: add basic TIFF support -4691407b Merge changes If39ab7f5,I3658b5ae -cca7c7b8 Fixed nit: 10 -> 10.f -5d09a244 WebPMuxCreate() error handling: -777341c3 Fix a memleak in WebPMuxCreate() -61c9d161 doc: correct lossless prefix coding table & code -4c397579 Merge "mark VP8{,L}{GetInfo,CheckSignature} as WEBP_EXTERN" -e4e36cc6 Merge "Mux: Allow only some frames/tiles to have alpha." -ad2aad3c Merge "WebP Decoding error handling:" -97649c8f Mux: Allow only some frames/tiles to have alpha. -f864be3b Lower the quality settings for Alpha encoding. -3ba81bbe WebP Decoding error handling: -fcc69923 add automatic YUVA/ARGB conversion during WebPEncode() -802e012a fix compilation in non-FANCY_UPSAMPLING mode -e012dfd9 make width/height coding match the spec -228d96a5 mark VP8{,L}{GetInfo,CheckSignature} as WEBP_EXTERN -637a314f remove the now unused *KeepA variants -d11f6fcc webpmux returns error strings rather than numbers -fcec0593 makefile.unix: cwebp: fix OSX link -6b811f1b Merge "doc: remove lossless pdf" -c9634821 doc: remove lossless pdf -b9ae4f0d cosmetics after mux changes b74ed6e, b494ad5 -b494ad50 Mux: only allow adding frame/tiles at the end. -2c341b0e Merge "Added image characteristic hint for the codec." -d373076a Added image characteristic hint for the codec. -2ed2adb5 Merge "msvc: add intrinsic based BitsLog2Floor" -e595e7c5 Merge "add demux.c to the makefiles" -da47b5bd Merge "demux: add {Next,Prev}Chunk" -e5f46742 add demux.c to the makefiles -4708393c demux: add {Next,Prev}Chunk -e8a0a821 demux: quiet msvc warnings -7f8472a6 Update the WebP Container Spec. -31b68fe6 cleanup WebPPicture struct and API -9144a186 add overflow check before calling malloc() -81720c91 consistency cosmetics -2ebe8394 Merge "Add kramdown version information to README" -71443084 enc/vp8l.c: fix build -b7ac19fe Add kramdown version information to README -efdcb667 Merge "Edit for consistency, usage and grammar." -08220102 Enable alpha in vvwebp -8de9a084 Merge "Mux API change:" -b74ed6e7 Mux API change: -233a589e take picture->argb_stride into account for lossless coding -04e33f17 Edit for consistency, usage and grammar. -a575b4bc Merge "cosmetics: add missing const" -8d99b0f4 Merge "cosmetics: remove unimplemented function proto" -69d02217 cosmetics: add missing const -5b08318b cosmetics: remove unimplemented function proto -b7fb0ed5 Log warning for unsupported options for lossless. -e1f769fe msvc: add intrinsic based BitsLog2Floor -8a69c7d8 Bug-fix: Clamp backward dist to 1. -b5b6ac97 Merge "Bring the special writer 'WebPMemoryWriter' to public API" -a6a1909f Merge "Fix floating point exception with cwebp -progress" -f2cee067 Fix floating point exception with cwebp -progress -91b7a8c7 Bring the special writer 'WebPMemoryWriter' to public API -310e2972 support resize and crop for RGBA input -a89835d3 Merge changes Ice662960,Ie8d7aa90,I2d996d5e,I01c04772 -ce614c0c Merge "dec/vp8: avoid setting decoder status twice" -900285da dec/vp8: avoid setting decoder status twice -8227adc8 Merge changes I6f02b0d0,I5cbc9c0a,I9dd9d4ed,Id684d2a1 -dcda59c1 Merge "demux: rename SetTile to SelectTile" -622ef12e demux: rename SetTile to SelectTile -81ebd375 Merge "demux: add {Next,Prev}Frame" -02dd37a2 demux: add {Next,Prev}Frame -4b79fa59 Merge "Limit the maximum size of huffman Image to 16MB." -9aa34b34 Manually number "chapters," as chapter numbers are used in the narrative. -2a4c6c29 Re-wrap at <= 72 columns -a45adc19 Apply inline emphasis and monospacing, per gdoc / PDF -91011206 Incorporate gdoc changes through 2012-06-08 -7a182487 Removed CodeRay syntax declarations ... -b3ec18c5 Provide for code-block syntax highlighting. -709d7702 Replace high ASCII artifacts (curly quotes, etc.). -930e8abb Lossless WebP doc largely ported to markdown text. -18cae37b msvc: silence some build warnings -b3923084 Limit the maximum size of huffman Image to 16MB. -f180df2a Merge "libwebp/demux: add Frame/Chunk iteration" -2bbe1c9a Merge "Enable lossless encoder code" -d0601b01 Merge changes I1d97a633,I81c59093 -78f3e345 Enable lossless encoder code -d974a9cc Merge "libwebp/demux: add simple format parsing" -26bf2232 Merge "libwebp: add WebPDemux stub functions" -2f666688 Merge "modify WebPParseHeaders to allow reuse by GetFeatures" -b402b1fb libwebp/demux: add Frame/Chunk iteration -ad9ada3b libwebp/demux: add WebPDemuxGetI -2f2d4d58 libwebp/demux: add extended format parsing -962dcef6 libwebp/demux: add simple format parsing -f8f94081 libwebp: add WebPDemux stub functions -fb47bb5c Merge "NumNamedElements() should take an enum param." -7c689805 Fix asserts in Palette and BackwardReference code. -fbdcb7ea NumNamedElements() should take an enum param. -fb4943bd modify WebPParseHeaders to allow reuse by GetFeatures -3697b5ce write an ad-hoc EncodeImageInternal variant -eaee9e79 Bug-Fix: Decode small (less than 32 bytes) images. -0bceae48 Merge "cwebp: fix alpha reporting in stats output" -0424b1ef Rebase default encoding settings. -c71ff9e3 cwebp: fix alpha reporting in stats output -e2ffe446 Merge "Stop indefinite recursion for Huffman Image." -70eb2bd6 Stop indefinite recursion for Huffman Image. -f3bab8eb Update vwebp -6d5c797c Remove support for partial files in Mux. -f1df5587 WebPMuxAssemble() returns WebPData*. -814a0639 Rename 'Add' APIs to 'Set'. -bbb0218f Update Mux psuedo-code examples. -4fc4a47f Use WebPData in MUX set APIs -c67bc979 Merge "add WebPPictureImportRGBX() and WebPPictureImportBGRX()" -27519bc2 add WebPPictureImportRGBX() and WebPPictureImportBGRX() -f80cd27e factorize code in Import() -9b715026 histogram: add log2 wrapper -8c34378f Merge "fix some implicit type conversion warnings" -42f6df9d fix some implicit type conversion warnings -250c16e3 Merge "doc: update lossless pdf" -9d9daba4 Merge "add a PDF of the lossless spec" -8fbb9188 prefer webp/types.h over stdint.h -0ca170c2 doc: update lossless pdf -0862ac6e add a PDF of the lossless spec -437999fb introduce a generic WebPPictureHasTransparency() function -d2b6c6c0 cosmetic fixes after Idaba281a -b4e6645c Merge "add colorspace for premultiplied alpha" -48f82757 add colorspace for premultiplied alpha -069f903a Change in lossless bit-stream. -5f7bb3f5 Merge "WebPReportProgress: use non-encoder specific params" -f18281ff WebPReportProgress: use non-encoder specific params -9ef32283 Add support for raw lossless bitstream in decoder. -7cbee29a Fix bug: InitIo reseting fancy_upsampling flag. -880fd98c vwebp: fix exit w/freeglut -1875d926 trap two unchecked error conditions -87b4a908 no need to have mux.h as noinst clause in enc/ -88f41ec6 doc: fix bit alignment in VP8X chunk -52f5a4ef Merge "fix bug with lossy-alpha output stride" -3bde22d7 fix bug with lossy-alpha output stride -42d61b6d update the spec for the lossy-alpha compression methods. -e75dc805 Move some more defines to format_constants.h -c13f6632 Move consts to internal header format_constants.h -7f2dfc92 use a bit-set transforms_seen_ instead of looping -18da1f53 modulate alpha-compression effort according to config.method -f5f2fff6 Merge "Alpha flag fix for lossless." -c975c44e Alpha flag fix for lossless. -4f067fb2 Merge "Android: only build dec_neon with NEON support" -255c66b4 Android: only build dec_neon with NEON support -8f9117a9 cosmetics: signature fixes -39bf5d64 use header-less lossless bitstream for alpha channel -75d7f3b2 Merge "make input data be 'const' for VP8LInverseTransform()" -9a721c6d make input data be 'const' for VP8LInverseTransform() -9fc64edc Disallow re-use of same transformation. -98ec717f use a function pointer for ProcessRows() -f7ae5e37 cosmetics: join line -140b89a3 factor out buffer alloc in AllocateARGBBuffers() -a107dfa8 Rectify WebPParseOptionalChunks(). -237eab67 Add two more color-spaces for lossless decoding. -27f417ab fix orthographic typo -489ec335 add VP8LEncodeStream() to compress lossless image stream -fa8bc3db make WebPEncodingSetError() take a const picture -638528cd bitstream update for lossy alpha compression -d73e63a7 add DequantizeLevels() placeholder -ec122e09 remove arch-dependent rand() -d40e7653 fix alignment -1dd6a8b6 Merge "remove tcoder, switch alpha-plane compression to lossless" -3e863dda remove tcoder, switch alpha-plane compression to lossless -8d77dc29 Add support for lossless in mux: -831bd131 Make tile size a function of encoding method. -778c5228 Merge "remove some variable shadowing" -817c9dce Few more HuffmanTreeToken conversions. -37a77a6b remove some variable shadowing -89c07c96 Merge "normalize example header includes" -4aff411f Merge "add example_util.[hc]" -00b29e28 normalize example header includes -061263a7 add example_util.[hc] -c6882c49 merge all tree processing into a single VP8LProcessTree() -9c7a3cf5 fix VP8LHistogramNumCodes to handle the case palette_code_bits == 0 -b5551d2e Merge "Added HuffmanTreeCode Struct for tree codes." -8b85d01c Added HuffmanTreeCode Struct for tree codes. -093f76d8 Merge "Allocate single memory in GetHuffBitLengthsAndCodes." -41d80494 Allocate single memory in GetHuffBitLengthsAndCodes. -1b04f6d2 Correct size in VP8L header. -2924a5ae Makefile.vc: split object lists based on directory -c8f24165 Merge "add assert(tokens)" -43239947 add assert(tokens) -9f547450 Catch an error in DecodeImageData(). -ac8e5e42 minor typo and style fix -9f566d1d clean-up around Huffman-encode -c579a710 Introduce CHUNK_SIZE_BYTES in muxi.h. -14757f8a Make sure huffman trees always have valid symbols -41050618 makefile.unix: add support for building vwebp -48b37721 Merge "fixed signed/unsigned comparison warning" -57f696da Merge "EncodeImageInternal: fix potential leak" -d972cdf2 EncodeImageInternal: fix potential leak -5cd12c3d fixed signed/unsigned comparison warning -cdca30d0 Merge "cosmetics: shorten long line" -e025fb55 cosmetics: shorten long line -22671ed6 Merge "enc/vp8l: fix double free on error" -e1b9b052 Merge "cosmetics: VP8LCreateHuffmanTree: fix indent" -a8e725f8 enc/vp8l: fix double free on error -27541fbd cosmetics: VP8LCreateHuffmanTree: fix indent -1d38b258 cwebp/windows: use MAKE_REFGUID where appropriate -817ef6e9 Merge "cwebp: fix WIC/Microsoft SDK compatibility issue" -902d3e3b cwebp: fix WIC/Microsoft SDK compatibility issue -89d803c4 Merge "Fix a crash due to wrong pointer-integer arithmetic." -cb1bd741 Merge "Fix a crash in lossless decoder." -de2fe202 Merge "Some cleanup in VP8LCreateHuffmanTree() (and related functions CompareHuffmanTrees() and SetBitDepths()): - Move 'tree_size' initialization and malloc for 'tree + tree_pool' outside the loop. - Some renames/tweaks for readability." -ce69177a Fix a crash due to wrong pointer-integer arithmetic. -e40a3684 Fix a crash in lossless decoder. -3927ff3a remove unneeded error condition for WebPMuxNumNamedElements() -2c140e11 Some cleanup in VP8LCreateHuffmanTree() (and related functions CompareHuffmanTrees() and SetBitDepths()): - Move 'tree_size' initialization and malloc for 'tree + tree_pool' outside the loop. - Some renames/tweaks for readability. -861a5b7b add support for animation -eb5c16cc Merge "Set correct encode size in encoder's stats." -4abe04a2 fix the return value and handle missing input file case. -2fafb855 Set correct encode size in encoder's stats. -e7167a2b Provide one entry point for backward references. -c4ccab64 Print relevant lossless encoding stats in cwebp. -e3302cfd GetHuffBitLengthsAndCodes: reduce level of indirection -b5f2a9ed enc/vp8l: fix uninitialized variable warning -7885f8b2 makefile.unix: add lossless encoder files -1261a4c8 Merge "cosmetics" -3926b5be Merge "dsp/cpu.c: Android: fix crash on non-neon arm builds" -834f937f dsp/cpu.c: Android: fix crash on non-neon arm builds -126e1606 cosmetics -e38602d2 Merge branch 'lossless_encoder' -e8d3d6a0 split StoreHuffmanCode() into smaller functions -d0d88990 more consolidation: introduce VP8LHistogramSet -1a210ef1 big code clean-up and refactoring and optimization -41b5c8ff Some cosmetics in histogram.c -ada6ff77 Approximate FastLog between value range [256, 8192] -ec123ca3 Forgot to update out_bit_costs to symbol_bit_costs at one instance. -cf33ccd1 Evaluate output cluster's bit_costs once in HistogramRefine. -781c01f4 Simple Huffman code changes. -a2849bc5 Lossless decoder: remove an unneeded param in ReadHuffmanCodeLengths(). -b39e7487 Reducing emerging palette size from 11 to 9 bits. -bfc73db4 Move GetHistImageSymbols to histogram.c -889a5786 Improve predict vs no-predict heuristic. -01f50663 code-moving and clean-up -31035f3b reduce memory usage by allocating only one histo -fbb501b8 Restrict histo_bits to ensure histo_image size is under 32MB -8415ddf3 further simplification for the meta-Huffman coding -e4917299 A quick pass of cleanup in backward reference code -83332b3c Make transform bits a function of encode method (-m). -72920caa introduce -lossless option, protected by USE_LOSSLESS_ENCODER -c6ac4dfb Run TraceBackwards for higher qualities. -412222c8 Make histo_bits and transform_bits function of quality. -149b5098 Update lossless encoder strategy: -0e6fa065 cache_bits passed to EncodeImageInternal() -e38b40a9 Factorize code for clearing HtreeGroup. -6f4a16ea Removing the indirection of meta-huffman tables. -3d33ecd1 Some renaming/comments related to palette in lossless encoder. -4d02d586 Lossless encoder: correction in Palette storage -4a636235 fix a memleak in EncodeImageInternal() -0993a611 Full and final fix for prediction transform -afd2102f Fix cross-color transform in lossless encoder -b96d8740 Need to write a '0' bit at the end of transforms. -54dad7e5 Color cache size should be counted as 0 when cache bits = 0 -4f0c5caf Fix prediction transform in lossless encoder. -36dabdad Fix memory leak in method EncodeImageInternal for histogram_image. -352a4f49 Get rid of PackLiteralBitLengths() -d673b6b9 Change the predictor function to pass left pixel -b2f99465 Fix CopyTileWithPrediction() -84547f54 Add EncodeImageInternal() method. -6b38378a Guard the lossless encoder (in flux) under a flag -09f7532c Fix few nits (const qualifiers) -648be393 Added implementation for various lossless functions -32714ce3 Add VP8L prefix to backward ref & histogram methods. -fcba7be2 Fixed header file tag (WEBP_UTILS_HUFFMAN_ENCODE_H_) -bc703746 Add backward_ref, histogram & huffman encode modules from lossless. -fdccaadd Fixing nits -227110c4 libwebp interface changes for lossless encoding. -50679acf minor style fixes -b38dfccf remove unneeded reference to NUM_LITERAL_CODES -8979675b harmonize header description -c04eb7be tcoder.c: define NOT_HAVE_LOG2 for MSVC builds -9a214fa1 Merge "VP8[L]GetInfo: check input pointers" -5c5be8ba VP8[L]GetInfo: check input pointers -0c188fec Merge changes I431acdfe,I713659b7 -b3515c62 mux: drop 'chunk' from ChunkInfo member names -aea7923c muxi.h: remove some unused defines -01422492 update NEWS file for next release -29e3f7ec Merge "dec: remove deprecated WebPINew()" -4718e449 Merge "muxedit: a few more size_t changes" -82654f96 Merge "muxedit: remove a few redundant NULL checks" -02f27fbd dec: remove deprecated WebPINew() -ccddb3fc muxedit: remove a few redundant NULL checks -a6cdf710 muxedit: a few more size_t changes -a3846892 Merge "mux: remove unused LIST_ID" -11ae46ae alpha.c: quiet some size_t -> int conversion warnings -dee46692 mux: remove unused LIST_ID -03f1f493 mux: add version checked entry points -6a0abdaa Merge "doc: tile/alpha corrections" -c8139fbe Merge "few cosmetics" -68338737 Merge "lossless: remove some size_t -> int conversions" -5249e94a doc: tile/alpha corrections -d96e722b huffman: quiet int64 -> int conversion warning -532020f2 lossless: remove some size_t -> int conversions -23be6edf few cosmetics -1349edad Merge "configure: AC_ARG_* use AS_HELP_STRING" -bfbcc60a configure: AC_ARG_* use AS_HELP_STRING -1427ca8e Merge "Makefile.am: header file maintenance" -087332e3 Merge "remove unused parameter 'round' from CalcProba()" -9630e168 remove unused parameter 'round' from CalcProba() -92092eaa Merge "bit_reader.h: correct include" -a87fc3f6 Merge "mux: ensure # images = # tiles" -53af99b1 Merge "mux: use size_t consistently" -39a57dae Makefile.am: header file maintenance -1bd0bd0d bit_reader.h: correct include -326a3c6b mux: ensure # images = # tiles -95667b8d mux: use size_t consistently -231ec1fb Removing the indirection of meta-huffman tables. -15ebcbaa check return pointer from MuxImageGetListFromId -b0d6c4a7 Merge "configure: remove test for zlib.h" -8cccac50 Merge "dsp/lossless: silence some build warnings" -b08819a6 dsp/lossless: silence some build warnings -7ae22521 Android.mk: SSE2 & NEON updates -0a49e3f3 Merge "makefile.unix add missing header files" -2e75a9a1 Merge "decode.h: use size_t consistently" -fa13035e configure: remove test for zlib.h -d3adc81d makefile.unix add missing header files -262fe01b Merge "makefile.unix & Android.mk: cosmetics" -4cce137e Merge "enc_sse2 add missing stdlib.h include" -80256b85 enc_sse2 add missing stdlib.h include -9b3d1f3a decode.h: use size_t consistently -64083d3c Merge "Makefile.am: cosmetics" -dceb8b4d Merge changes If1331d3c,I86fe3847 -0e33d7bf Merge "webp/decode.h: fix prototypes" -fac0f12e rename BitReader to VP8LBitReader -fbd82b5a types.h: centralize use of stddef.h -2154835f Makefile.am: cosmetics -1c92bd37 vp8io: use size_t for buffer size -90ead710 fix some more uint32_t -> size_t typing -cbe705c7 webp/decode.h: fix prototypes -3f8ec1c2 makefile.unix & Android.mk: cosmetics -217ec7f4 Remove tabs in configure.ac -b3d35fc1 Merge "Android.mk & Makefile.vc: add new files" -0df04b9e Android.mk & Makefile.vc: add new files -e4f20c5b Merge "automake: replace 'silent-rules' w/AM_SILENT_RULES" -8d254a09 cosmetics -6860c2ea fix some uint32_t -> size_t typing -4af1858a Fix a crash due to max symbol in a tree >= alphabet size -6f01b830 split the VP8 and VP8L decoding properly -f2623dbe enable lossless decoder -b96efd7d add dec/vp8i.h changes from experimental -19f6398e add dec/vp8l{i.h,.c} from experimental -c4ae53c8 add utils/bit_reader.[hc] changes from experimental -514d0089 add dsp/lossless.[hc] from experimental -9c67291d add utils/huffman.[hc] from experimental -337914a0 add utils/color_cache.[hc] from experimental -b3bf8fe7 the read-overflow code-path wasn't reporting as an error -1db888ba take colorspace into account when cropping -61c2d51f move the rescaling code into its own file and make enc/ and dec/ use it. -efc2016a Make rescaler methods generic -3eacee81 Move rescaler methods out of io.c. -a69b893d automake: replace 'silent-rules' w/AM_SILENT_RULES -6f7bf645 issue 111: fix little-endian problem in bit-reader -ed278e22 Removed unnecessary lookup -cd8c3ba7 fix some warnings: down-cast and possibly-uninitialized variable -0a7102ba ~1% improvement of alpha compression -3bc1b141 Merge "Reformat container doc" -dc17abdc mux: cosmetics -cb5810df Merge "WebPMuxGetImage: allow image param to be NULL" -506a4af2 mux: cosmetics -135e8b19 WebPMuxGetImage: allow image param to be NULL -de556b68 Merge "README.mux: reword some descriptions" -0ee2aeb9 Makefile.vc: use batch mode rules -d9acddc0 msvc: move {i,p}db creation to object directory -237c9aa7 Merge "expose WebPFree function for DLL builds" -b3e4054f silence msvc debug build warning -45feb55d expose WebPFree function for DLL builds -11316d84 README.mux: reword some descriptions -4be52f4a factorize WebPMuxValidate -14f6b9f6 mux: light cleanup -5e96a5db add more param checks to WebPPictureDistortion() -8abaf820 Merge "silence some type size related warnings" -1601a39b silence some type size related warnings -f3abe520 Merge "idec: simplify buffer size calculation" -a9c5cd4c idec: simplify buffer size calculation -7b06bd7f Merge "configure/automake: add silent-rules option" -e9a7d145 Reformat container doc -d4e5c7f3 configure/automake: add silent-rules option -5081db78 configure/automake: no -version-info for convenience libs -85b6ff68 Merge "idec: fix WebPIUpdate failure" -7bb6a9cc idec: fix internal state corruption -89cd1bb8 idec: fix WebPIUpdate failure -01b63806 4-5% faster decoding, optimized byte loads in arithmetic decoder. -631117ea Merge "cosmetics & warnings" -a0b2736d cosmetics & warnings -f73947f4 use 32bit for storing dequant coeffs, instead of 16b. -b9600308 Merge "store prediction mode array as uint8_t[16], not int[16]." -7b67881a store prediction mode array as uint8_t[16], not int[16]. -cab8d4dc Merge "NEON TransformOne" -ba503fda NEON TransformOne -9f740e3b Merge "gcc warning fix: remove the 'const' qualifier." -f76d3587 gcc warning fix: remove the 'const' qualifier. -e78478d6 Merge "webpmux: make more use of WebPData" -f85bba3d Merge "manpages: add BUGS section" -48a43bbf Merge "makefile.unix: variable cosmetics" -c274dc96 makefile.unix: variable cosmetics -1f7b8595 re-organize the error-handling in the main loop a bit -1336fa71 Only recompute level_cost_[] when needed -771ee449 manpages: add BUGS section -0f7820e6 webpmux: make more use of WebPData -974aaff3 examples: logging updates -6c14aadd Merge "better token buffer code" -f4054250 better token buffer code -18d959fa Merge "mux: add WebPData type" -eec4b877 mux: add WebPData type -0de3096b use 16bit counters for recording proba counts -7f23678d fix for LevelCost + little speed-up -7107d544 further speed-up/cleanup of RecordCoeffs() and GetResidualCost() -fd221040 Introduce Token buffer (unused for now) -5fa148f4 Merge "speed-up GetResidualCost()" -28a9d9b4 speed-up GetResidualCost() -11e7dadd Merge "misc cosmetics" -378086bd misc cosmetics -d61479f9 add -print_psnr and -print_ssim options to cwebp. -2e3e8b2e add a WebPCleanupTransparentArea() method -552c1217 Merge "mux: plug some memory leaks on error" -a2a81f7d Merge "fix Mach-O shared library build" -b3482c43 Merge "fix gcc-4.0 apple 32-bit build" -e4e3ec19 fix gcc-4.0 apple 32-bit build -b0d2fecf mux: plug some memory leaks on error -f0d2c7a7 pass of cosmetics -b309a6f9 fix Mach-O shared library build -241ddd38 doc: delete mux container pdf -8b1ba272 doc: update VP8 decode guide link -7e4371c5 WebPMuxCreate: fix unchecked malloc -eb425586 Merge "have makefile.unix clean up src/webp/*~ too" -a85c3631 Merge "correct EncodeAlpha documentation" -a33842fd Merge "Update webp container spec with alpha filter options." -8d6490da Incremental support for some of the mux APIs. -b8375abd have makefile.unix clean up src/webp/*~ too -b5855fc7 correct EncodeAlpha documentation -dba37fea Update webp container spec with alpha filter options. -2e74ec8b fix compile under MINGW -716d1d7f fix suboptimal MAX_LEN cut-off limit -57cab7b8 Harmonize the alpha-filter predictions at boundary -3a989534 Merge "Fix bug for Alpha in RGBA_4444 color-mode." -8ca2076d Introduce a 'fast' alpha mode -221a06bb Fix bug for Alpha in RGBA_4444 color-mode. -ad1e163a cosmetics: normalize copyright headers -c77424d7 cosmetics: light include cleanup -9d0e17c9 fix msvc build breakage after 252028a -7c4c177c Some readability fixes for mux library -d8a47e66 Merge "Add predictive filtering option for Alpha." -252028aa Add predictive filtering option for Alpha. -9b69be1c Merge "Simplify mux library code" -a056170e Simplify mux library code -992187a3 improve log2 test -e852f832 update Android.mk file list -a90cb2be reduce number of copies and mallocs in alpha plane enc/dec -b1662b05 fix some more type conversion warnings w/MSVC -223d8c60 fix some uint64_t -> int conversion warnings with MSC -c1a0437b Merge "simplify checks for enabling SSE2 code" -f06817aa simplify checks for enabling SSE2 code -948d4fe9 silence a msvc build warning -91179549 vwebp: msvc build tweaks -7937b409 simple WebP viewer, based on OpenGL -6aac1df1 add a bunch of missing 'extern "C"' -421eb99d Merge "Remove assigned-but-not-used variable "br"" -91e27f45 better fitting names for upsampling functions -a5d7ed5c Remove assigned-but-not-used variable "br" -f62d2c94 remove unused 'has_alpha' from VP8GetInfo() signature -08e86582 trap alpha-decoding error -b361eca1 add cut-off to arith coder probability update. -8666a93a Some bug-fixes for images with alpha. -273a12a0 fix off-by-1 diff in case cropping and simple filtering -2f741d1e webpmux: ReadImage: fix ptr free in error case -721f3f48 fix alpha decode -60942c8c fix the has_alpha_ order -30971c9e Implement progress report (and user abort) -eda520a9 cosmetics after 9523f2a -38bd5bb5 Merge "Better alpha support in webpmux binary" -ccbaebfe Merge "Updated the includes to relative paths." -d71fbdcc fix small typo in error message array -cdf97aa2 Better alpha support in webpmux binary -885f25bc Updated the includes to relative paths. -a0ec9aac Update WebP encoder (cwebp) to support Alpha. -667b769a Fixed the include for types.h within mux.h -9523f2a5 Add Alpha Encode support from WebPEncode. -16612ddd Merge "Add Alpha Decode support from WebPDecode." -d117a940 Add Alpha Decode support from WebPDecode. -67228734 cosmetics after e1947a9 -e1947a92 Add Alpha encode/decode code. -afc4c5d6 simplify code by introducing a CopyPlane() helper func -113b3128 Merge "MUX API Updates" -c398f595 MUX API Updates -5acf04ef remove orphan source file -059f03ef Merge "dec: validate colorspace before using as array index" -70a03989 Merge "factorize some code" -9b243b3d factorize some code -372e2b46 Correct a bug in ReadPNG() with GRAY_ALPHA images -469d6eb9 Merge "Makefile.am: remove redundant noinst_HEADERS" -9fe3372f dec: validate colorspace before using as array index -8962030f remove orphan source file -ced3e3f4 Makefile.am: remove redundant noinst_HEADERS -964387ed use WEBP_INLINE for inline function declarations -90880a11 Merge "manpages: break long lines" -b5910895 Merge "manpages: minor formatting updates" -4c451e4a Merge "Rectify the Chunk parsing logic." -04e84cf1 examples: slight cleanup -099717ce manpages: break long lines -1daf39bb manpages: minor formatting updates -abd030b5 fix missing "(void)" in function signature -f6a7d758 remove useless test -f07b2138 Rectify the Chunk parsing logic. -b8634f7d webpmux: fix lib link order -42c2e682 Fix missing coma (on uncompiled code) -d8329d41 Android.mk: add missing source files -13a54df5 Merge "More aggressive copy-edit; add TODO; validate HTML5" -868b96ae More aggressive copy-edit; add TODO; validate HTML5 -767afea2 configure: check for a symbol contained in libpng -408b8918 Merge "Linewrap at 72 cols. Casual copy-edit." -3ae318c7 Merge "Restore (most) emphasis; add emphasis to normative RFC 2119 terms (MUST, etc.)" -918eb2d8 Merge "Basic container doc source clean-up; fix lists and pseudocode blocks." -03bec9e0 Linewrap at 72 cols. Casual copy-edit. -2678d819 Restore (most) emphasis; add emphasis to normative RFC 2119 terms (MUST, etc.) -428674da Basic container doc source clean-up; fix lists and pseudocode blocks. -6a77d928 Merge "Makefile.vc: cosmetics" -28c38e8c Merge "Makefile.vc: condense directory creation rules" -55be2cf8 Initial import of container spec document, from pdftotext transform. -a82a788b Makefile.vc: cosmetics -c8f41ce5 Makefile.vc: condense directory creation rules -2b877cd0 Some fixes to Makefile.vc to support the src\mux directory. -3eb969b3 Merge "Add Makefile.vc for Mux library & binary." -e78e971e Add Makefile.vc for Mux library & binary. -6aedde58 Add manual for WebPMux tool. -8a360d0a Merge "Added WebPMux Binary." -a4f32cae Added WebPMux Binary. -f3bf4c76 Added Mux Container Spec & README for MUX-API. -9f761cfa Changed function signature for WebPMuxCreate -5f31b5ec Merge "Add Mux library for manipulating WebP container." -2315785f Add Mux library for manipulating WebP container. -7e198abb update ChangeLog (tag: v0.1.3) -dfc9c1ea Harmonize the dates -28ad70c5 Fix PNG decoding bug -846e93c5 Update AUTHORS & add .mailmap -563e52d6 cosmetics after '76036f5 Refactor decoder library' -76036f54 Refactor decoder library -377ef43c configure.ac: update AC_INIT params -7a8d8762 use a user-visible MACRO for max width/height. -d4e9f559 NEON decode support in WebP -0ee683b5 update libtool version-info -fdbe02c5 windows: match _cond_destroy logic w/return variable name -206b686b README: correct advanced decode api pseudo-code -6a32a0f5 make VP8BitReader a typedef, for better re-use -b112e836 create a libwebputils under src/utils -ee697d9f harmonize the include guards and #endif comments -a1ec07a6 Fixing compiler error in non x86 arch. -dcfa509a Fixed recursive inclusion of bit_writer.h and vp8enci.h. -e06ac088 create a separate libwebpdsp under src/dsp -ebeb412a use unsigned int for bitfields -341cc56a make kNewRange a static array -227a91e5 README: minor wording update -05bd8e6a add man pages to dist -812dfa1a bump up versions in preparations for 0.1.3 -a5b78c81 wrap alpha-related options under WEBP_EXPERIMENTAL_FEATURES flag -34dc7907 regen ChangeLog for 0.1.3-rc2 -7c436630 Silence some (more) Visual Studio warnings. -60306e8c add top-level gitattributes -2aa6b80e Slience some Visual Studio warnings. -4cbbb290 Merge "bump up version for next freeze" -a3291674 bump up version for next freeze -c7e86aba cosmetics: fix comment line lengths -c9e037ab makefile.unix: add simple dist target -87d58ce9 makefile.unix: rule maintenance -d477de77 mend -fac15ec7 Update NEWS & README for next release V0.1.3 -6215595c Merge "add a -partition_limit option to limit the number of bits used by intra4x4" -3814b76c Merge "reorganize chunk-parsing code" -900286e0 add a -partition_limit option to limit the number of bits used by intra4x4 -cd12b4b0 add the missing cost for I4/I16 mode selection -dfcc2136 reorganize chunk-parsing code -3cf20306 initialize pointers to function within VP8DspInit() -d21b4795 Merge "windows: add decode threading support" -473ae953 fix hang on thread creation failure -fccca420 windows: add decode threading support -a31f843a Use the exact PNG_INCLUDES/PNG_LIBS when testing for -lpng -ad9b45f1 Merge "Makefile.vc: rule maintenance" -565a2cab Makefile.vc: rule maintenance -2d0da681 makefile.unix: disable Wvla by default -fc7815d6 multi-thread decoding: ~25-30% faster -acd8ba42 io->teardown() was not always called upon error -c85527b1 Merge "Makefile.vc: add DLL configs" -e1e9be35 cosmetics: spelling/grammar in README and lib headers -b4d0ef8f Makefile.vc: add DLL configs -998754a7 remove unused nb_i4_ and nb_i16_ fields. -9f01ce3a rename WebPDecBuffer::memory -> private_memory -fb5d659b fix an overflow bug in LUT calculation -d646d5c7 swig: add WebPDecodeARGB -78aeed40 add missing WebPDecodeARGBInto() and switch ARGB4444 to RGBA4444 as was intended -cd7c5292 explicitly mark library functions as extern -19db59f8 add support for RGB565, ARGB4444 and ARGB colorspace (decoder) -c915fb2a encoder speed-up: hardcode special level values -c558bdad Rename and improve the API to retrieve decoded area -bf599d74 Merge "makefile.unix: disable -Wvla by default" -c9ea03d7 SSE2 version of strong filtering -993af3e2 makefile.unix: disable -Wvla by default -3827e1bc Merge "examples: (windows/WIC) add alpha support" -e291fae0 SSE2 functions for the fancy upsampler. -a06bbe2e add WebPISetIOHooks() to set some custom hooks on the incremental decoder object. -7643a6f2 Merge "makefile.unix: use uname to detect OSX environment" -5142a0be export alpha channel (if present) when dumping to PGM format -14d5731c makefile.unix: use uname to detect OSX environment -08057062 examples: quiet warnings -3cfe0888 examples: (windows/WIC) add alpha support -13ed94b8 add compile warning for variable-length-array -5a18eb1a Merge "add Advanced Decoding Interface" -5c4f27f9 add missing \n -f4c4e416 80 cols fix -d2603105 add Advanced Decoding Interface -bd2f65f6 sse2 version of the complex filter -96ed9ce0 perform two idct transforms at a time when possible -01af7b69 use aligned stored -0e1d1fdf Merge "Makefile.vc: add experimental target" -2a1292a6 Makefile.vc: add experimental target -23bf351e Enable decode SSE2 for Visual Studio -131a4b7b dec/dsp_sse2: fix visual studio compile -00d9d680 swig: file reorganization -7fc7e0d9 Merge "swig/java: basic encode support" -3be57b16 fix MSVC compile for WEBP_EXPERIMENTAL_FEATURES -40a7e347 dec/dsp: disable sse2 for Visual Studio builds -e4d540c8 add SSE2 code for transform -54f2170a swig/java: basic encode support -c5d4584b call function pointers instead of C-version -ea43f045 Merge "configure: mingw32 targets: test for WIC support" -a11009d7 SSE2 version of simple in-loop filtering -42548da9 shave one unneeded filter-cache line -31f9dc6f configure: mingw32 targets: test for WIC support -19559699 Merge "split expression in two." -415dbe46 split expression in two. -e29072a8 configure: test for zlib only w/--enable-experimental -b2b0090b Simplify Visual Studio ifdefs -ca7a2fd6 Add error reporting from encoding failures. -6c9405db Merge "Makefile.vc: require CFG with clean target" -0424ecd9 Makefile.vc: require CFG with clean target -003417c7 Enable SSE2 for Visual Studio builds -af10db4a little speed up for VP8BitUpdate() -e71418f8 more MSVC files to ignore -46d90363 cosmetics -edf59ab3 typo fix -72229f5f Add support for x64 and SSE2 builds under Windows. -92e5c6e1 VP8GetInfo() + WebPResetDecParams() -416b7a6b raise the fixed-point precision for the rescaler -aa87e4e0 fix alignment -eb66670c disable WEBP_EXPERIMENTAL_FEATURES -c5ae7f65 typo fix: USE_ => WEBP_ -d041efae swig: add libwebp.jar/libwebp_java_wrap.c -f6fb3877 add swig interface -e9273902 align buffer for double too -842c009b fix -strong option -d0a70387 Merge "cosmetics" -fc0a02e5 fix the dichotomy loop -38369c03 cosmetics -8dfc4c6f factorize and unify GetAlpha() between the C and SSE2 version -6d0e66c2 prepare experimentation with yuv444 / 422 -79cc49f5 add a --enable-experimental option to './configure' -d7575238 sse2 version of CollectHistogram() -c1c728d6 add an extra #ifdef WEBP_EXPERIMENTAL_FEATURES to avoid 'unused variable' warning -60c61d2d always call VP*EncDeleteAlpha() unconditionnally, for simplicity -0f8c6384 simply don't call WriteExtensions() if WEBP_EXPERIMENTAL_FEATURES is not defined -47c661d5 rename swap -> swap_rb -10d55bbb move chunk[] declaration out of the for() loop -517cec21 fix indentation -f7d9e261 fix merge problems -8fd42b3a add a stride 'a_stride' for the alpha plane -b8dcbf2f fix alpha-plane copy and crop methods -cdef89de fix some 'unused variable' warning -fb29c262 SSE2 version of the fwd transform and the squared sum metric -2ab4b72f EXPERIMENTAL: add support for alpha channel -cfbf88a6 add SSE2 functions. ~2x faster encoding on average. -e7ff3f9a merge two ITransforms together when applicable and change the TTransform to return the sum directly. -ca554137 fix WebPIDecGetRGB() to accept any RGB(A) mode, not just MODE_RGB -8aa50efd fix some 'man' typos -d3f3bdda update ChangeLog (tag: v0.1.2) -d7e9a69c update contributor list -261abb8e add a 'superclean' section -276ae825 Remove files not mean to be in git, and update .gitignore -24868455 build: prepare libwebp.pc -14ceb6e8 add "-version" description to man pages -b247a3b2 Create the m4 directory, and also place .gitignore in there for libtool. -cdd734c9 Resolve automake warnings -c5fa726e build: add pkgconfig files -b20aaca2 build: just use autoreconf, avoid calling tools manually -4b0b0d66 cwebp: use modern functions -efbc6c41 update Android.mk -7777570b better version of ChangeLog -fa70d2b7 update version number in the DOC -f8db5d5d more C89-fixes -0de013b3 fix typos -650ffa3b add version getters for decoder and encoder -be4867d2 doc for incremental decoding -56732a1b add idec.obj in MSVC makefile -208afb5e add c++ guards -8bf76fe0 add incremental decoding -1f288328 'inline' isn't defined in strict ansi c89 -8b77c632 move the quantization function to dsp.c -b2c3575c add a 'last_y' field to WebPDecParams -2654c3da correctly pass along the exact same status returned from ParsePartitions -4704146a add missing precision in the man -6d978a6c add error messages -6463e6ab add some install instructions, and fix intel-mac flags -05fb7bfc Merge ".gitignore: initial version" -c33f0195 .gitignore: initial version -e532b9ab Makefile: allow out of tree builds -4c0da7aa enable sparse dc/ac transforms -07dbb8d5 clarify the return logic -5c69e1bb fix bigger-by-1 array -7c5267e3 fix a (harmless) typo: non_zero_ -> non_zero_ac_ -bc752135 fix missing free() -af3e2aaa remove trailing spaces -13e50da6 make the bitreader preload at least 8bits, instead of post-load them (this makes initialization easier and will be helpful for incremental decoding). Modify ParsePartitions() to accommodate for truncated input. -f4888f77 emit 9 - nb_bits trailing zeros instead of 8 -3db65255 separate block-parsing into a visible VP8DecodeMB() -a871de02 add missing extern "C" -b3ce8c52 remove a gcc warning about type pun by using a proper union'd type -e1863715 update after addition of webpi.h -3e856e2d Extract some useful functions around decoding buffer WebPDecParams. -d5bc05a4 make the filtering process match libvpx and ffvp8 -dd60138d add man pages for cwebp(1) and dwebp(1) -c4fa3644 fix header -5b70b378 * add an option to bypass_filtering in VP8Io. -b97a4003 simplify QuantizeBlock code a bit -84b58ebb add more checks around picture allocation -b65a3e10 remove absolute_delta_ field and syntax code -0744e842 Dont' open output file until we're sure the input file is valid -d5bd54c7 fix typo and buggy line -f7a9549d Add a simple top-level makefile.unix for quick & easy build. -5f36b944 update the doc for the -f option -f61d14aa a WebP encoder converts PNG & JPEG to WebP -81c96621 oops: forgotten call to Initialize() + move the error message to a more useful place -87ffa005 typo: fix a missing 'R', was confusing. -b04b857a * add decoding measurement using stopwatch.h (use -v option) * support PNG output through WIC on Win32 -746a4820 * make (*put)() hook return a bool for abort request. * add an enum for VP8Status() to make things clearer -73c973e6 * strengthen riff/chunk size checks * don't consider odd-sized chunks being an error -1dc4611a add support for PNG output (default) regularize include guards -860641df fix a typo: sizeof(kYModeProbaInter0) => sizeof(kUVModeProbaInter0) -3254fc52 fix some petty constness fix the ./configure file too -504d3393 fix eof_ mis-initialization -2bc0778f leftover Makefile.* from previous commit -d2cf04e4 move Makefile.am one level below, to src/dec fix typos here and there dwebp is now an installed program -ade92de8 typo: vp8.h -> decode_vp8.h -d7241241 forgot to declare types.h to be installed -6421a7a4 move the decoder sourcetree to a sub-location src/dec to make room for future libs sources -a9b3eab6 correct layout name is IMC4. -2330522c handle corner case of zero-dimensions -280c3658 make VP8Init() handle short buffers (< 2 bytes) correctly -b1c9e8b4 handle error cases more robustly -0e94935c Merge "table-less version of clip_8b()" -1e0a2d25 table-less version of clip_8b() -e12109ee dwebp: change -yuv option to -raw change the layout to IMC2 -d72180a4 speed-up fancy upscaler -9145f3bc reset eof_ at construction time -a7ee0559 simplify the logic of GetCoeffs() -f67b5939 lot of cosmetics -ea27d7c6 fix endian problem on PowerPC -beb0a1ba fix signature of VP8StoreBlock -b128c5e2 Merge "fancy chroma upscaling" -6a37a2aa fancy chroma upscaling -ff565edc fix two numeric typos -5a936a0a use uintptr_t for casting pointers to ints -e14a0301 for cross_compiling=yes to prevent executing any binary -83b545ee add vc9+ makefile -296f6914 fix output loop for small height -cbfbb5c3 convert to plain-C -f09f96ee Fix declaration after statement warning -5981ee55 Fix UV plane ac/dc quantizer transposition -c8d15efa convert to ANSI-C -c3f41cb4 Initial commit diff --git a/libwebp/Makefile.am b/libwebp/Makefile.am deleted file mode 100644 index e1c1dd40..00000000 --- a/libwebp/Makefile.am +++ /dev/null @@ -1,9 +0,0 @@ -ACLOCAL_AMFLAGS = -I m4 -SUBDIRS = sharpyuv src imageio man -EXTRA_DIST = COPYING autogen.sh - -if BUILD_EXTRAS - SUBDIRS += extras -endif - -SUBDIRS += examples diff --git a/libwebp/Makefile.vc b/libwebp/Makefile.vc deleted file mode 100644 index 84e9a5dd..00000000 --- a/libwebp/Makefile.vc +++ /dev/null @@ -1,531 +0,0 @@ -# -# Stem for static libs and DLLs -# -LIBWEBPDECODER_BASENAME = libwebpdecoder -LIBWEBP_BASENAME = libwebp -LIBWEBPMUX_BASENAME = libwebpmux -LIBWEBPDEMUX_BASENAME = libwebpdemux -LIBSHARPYUV_BASENAME = libsharpyuv - -!IFNDEF ARCH -!IF ! [ cl 2>&1 | find "x86" > NUL ] -ARCH = x86 -!ELSE IF ! [ cl 2>&1 | find "x64" > NUL ] -ARCH = x64 -!ELSE IF ! [ cl 2>&1 | find "ARM64" > NUL ] -ARCH = ARM64 -!ELSE IF ! [ cl 2>&1 | find "ARM" > NUL ] -ARCH = ARM -!ELSE -!ERROR Unable to auto-detect toolchain architecture! \ -If cl.exe is in your PATH rerun nmake with ARCH=. -!ENDIF -!ENDIF - -!IF "$(ARCH)" == "x86" -PLATFORM_LDFLAGS = /SAFESEH -!ENDIF - -############################################################# -## Nothing more to do below this line! - -NOLOGO = /nologo -CCNODBG = cl.exe $(NOLOGO) /O2 /DNDEBUG -CCDEBUG = cl.exe $(NOLOGO) /Od /Zi /D_DEBUG /RTC1 -CFLAGS = /I. /Isrc $(NOLOGO) /W3 /EHsc /c -CFLAGS = $(CFLAGS) /DWIN32 /D_CRT_SECURE_NO_WARNINGS /DWIN32_LEAN_AND_MEAN -LDFLAGS = /LARGEADDRESSAWARE /MANIFEST:EMBED /NXCOMPAT /DYNAMICBASE -LDFLAGS = $(LDFLAGS) $(PLATFORM_LDFLAGS) -LNKDLL = link.exe /DLL $(NOLOGO) -LNKEXE = link.exe $(NOLOGO) -LNKLIB = lib.exe $(NOLOGO) -RCNODBG = rc.exe $(NOLOGO) /l"0x0409" # 0x409 = U.S. English -RCDEBUG = $(RCNODBG) /D_DEBUG - -!IF "$(ARCH)" == "ARM" -CFLAGS = $(CFLAGS) /DWINAPI_FAMILY=WINAPI_FAMILY_PHONE_APP /DWEBP_USE_THREAD -!ELSE -CFLAGS = $(CFLAGS) /DHAVE_WINCODEC_H /DWEBP_USE_THREAD -!ENDIF - -CFGSET = FALSE -!IF "$(OBJDIR)" == "" -OUTDIR = ..\obj\ -!ELSE -OUTDIR = $(OBJDIR) -!ENDIF - -############################################################## -# Runtime library configuration -!IF "$(RTLIBCFG)" == "static" -RTLIB = /MT -RTLIBD = /MTd -!ELSE IF "$(RTLIBCFG)" == "legacy" -RTLIBCFG = static -RTLIB = /MT -RTLIBD = /MTd -CFLAGS = $(CFLAGS) /GS- /arch:IA32 -!ELSE -RTLIB = /MD -RTLIBD = /MDd -!ENDIF -DIRBASE = $(OUTDIR)\$(CFG)\$(ARCH) -DIROBJ = $(DIRBASE)\obj -DIRLIB = $(DIRBASE)\lib -DIRINC = $(DIRBASE)\include -DIRBIN = $(DIRBASE)\bin -LIBWEBP_PDBNAME = $(DIROBJ)\$(LIBWEBP_BASENAME).pdb -OUTPUT_DIRS = $(DIRBIN) $(DIRINC) $(DIRLIB) \ - $(DIROBJ)\dec \ - $(DIROBJ)\demux \ - $(DIROBJ)\dsp \ - $(DIROBJ)\enc \ - $(DIROBJ)\examples \ - $(DIROBJ)\extras \ - $(DIROBJ)\imageio \ - $(DIROBJ)\mux \ - $(DIROBJ)\sharpyuv \ - $(DIROBJ)\utils \ - -# Target configuration -!IF "$(CFG)" == "release-static" -CC = $(CCNODBG) -STATICLIBBUILD = TRUE -!ELSE IF "$(CFG)" == "debug-static" -CC = $(CCDEBUG) -RTLIB = $(RTLIBD) -STATICLIBBUILD = TRUE -LIBWEBPDECODER_BASENAME = $(LIBWEBPDECODER_BASENAME)_debug -LIBWEBP_BASENAME = $(LIBWEBP_BASENAME)_debug -LIBWEBPMUX_BASENAME = $(LIBWEBPMUX_BASENAME)_debug -LIBWEBPDEMUX_BASENAME = $(LIBWEBPDEMUX_BASENAME)_debug -LIBSHARPYUV_BASENAME = $(LIBSHARPYUV_BASENAME)_debug -!ELSE IF "$(CFG)" == "release-dynamic" -CC = $(CCNODBG) -RC = $(RCNODBG) -DLLBUILD = TRUE -!ELSE IF "$(CFG)" == "debug-dynamic" -CC = $(CCDEBUG) -RC = $(RCDEBUG) -RTLIB = $(RTLIBD) -DLLBUILD = TRUE -LIBWEBPDECODER_BASENAME = $(LIBWEBPDECODER_BASENAME)_debug -LIBWEBP_BASENAME = $(LIBWEBP_BASENAME)_debug -LIBWEBPMUX_BASENAME = $(LIBWEBPMUX_BASENAME)_debug -LIBWEBPDEMUX_BASENAME = $(LIBWEBPDEMUX_BASENAME)_debug -LIBSHARPYUV_BASENAME = $(LIBSHARPYUV_BASENAME)_debug -!ENDIF - -!IF "$(STATICLIBBUILD)" == "TRUE" -CC = $(CC) $(RTLIB) -CFGSET = TRUE -LIBWEBPDECODER = $(DIRLIB)\$(LIBWEBPDECODER_BASENAME).lib -LIBWEBP = $(DIRLIB)\$(LIBWEBP_BASENAME).lib -LIBWEBPMUX = $(DIRLIB)\$(LIBWEBPMUX_BASENAME).lib -LIBWEBPDEMUX = $(DIRLIB)\$(LIBWEBPDEMUX_BASENAME).lib -LIBSHARPYUV = $(DIRLIB)\$(LIBSHARPYUV_BASENAME).lib -!ELSE IF "$(DLLBUILD)" == "TRUE" -CC = $(CC) /I$(DIROBJ) $(RTLIB) /DWEBP_DLL -LIBWEBPDECODER = $(DIRLIB)\$(LIBWEBPDECODER_BASENAME)_dll.lib -LIBWEBP = $(DIRLIB)\$(LIBWEBP_BASENAME)_dll.lib -LIBWEBPMUX = $(DIRLIB)\$(LIBWEBPMUX_BASENAME)_dll.lib -LIBWEBPDEMUX = $(DIRLIB)\$(LIBWEBPDEMUX_BASENAME)_dll.lib -LIBSHARPYUV = $(DIRLIB)\$(LIBSHARPYUV_BASENAME)_dll.lib -LIBWEBP_PDBNAME = $(DIROBJ)\$(LIBWEBP_BASENAME)_dll.pdb -CFGSET = TRUE -!ENDIF - -!IF "$(UNICODE)" == "1" -CFLAGS = $(CFLAGS) /D_UNICODE /DUNICODE -!ENDIF - -####################### -# Usage -# -!IF "$(CFGSET)" == "FALSE" -!MESSAGE Usage: nmake /f Makefile.vc [CFG=] -!MESSAGE . [OBJDIR=] [RTLIBCFG=] [UNICODE=1] [] -!MESSAGE -!MESSAGE where is one of: -!MESSAGE - release-static - release static library -!MESSAGE - debug-static - debug static library -!MESSAGE - release-dynamic - release dynamic link library (DLL) -!MESSAGE - debug-dynamic - debug dynamic link library (DLL) -!MESSAGE -!MESSAGE may be: -!MESSAGE - clean - perform a clean for CFG -!MESSAGE - experimental - build CFG with experimental -!MESSAGE . features enabled. -!MESSAGE - (empty) - build libwebp-based targets for CFG -!MESSAGE - all - build (de)mux-based targets for CFG -!MESSAGE - gif2webp - requires libgif & >= VS2013 -!MESSAGE - anim_diff - requires libgif & >= VS2013 -!MESSAGE - anim_dump -!MESSAGE -!MESSAGE RTLIBCFG controls the runtime library linkage - 'static' or 'dynamic'. -!MESSAGE 'legacy' will produce a Windows 2000 compatible library. -!MESSAGE OBJDIR is the path where you like to build (obj, bins, etc.), -!MESSAGE defaults to ..\obj - -!IF "$(CFG)" != "" -!MESSAGE -!ERROR please choose a valid configuration instead of "$(CFG)" -!ENDIF -!ENDIF - -####################### -# Rules -# -!IF "$(CFGSET)" == "TRUE" -# A config was provided, so the library can be built. -# - -SHARPYUV_OBJS = \ - $(DIROBJ)\sharpyuv\sharpyuv.obj \ - $(DIROBJ)\sharpyuv\sharpyuv_cpu.obj \ - $(DIROBJ)\sharpyuv\sharpyuv_csp.obj \ - $(DIROBJ)\sharpyuv\sharpyuv_dsp.obj \ - $(DIROBJ)\sharpyuv\sharpyuv_gamma.obj \ - $(DIROBJ)\sharpyuv\sharpyuv_neon.obj \ - $(DIROBJ)\sharpyuv\sharpyuv_sse2.obj \ - -DEC_OBJS = \ - $(DIROBJ)\dec\alpha_dec.obj \ - $(DIROBJ)\dec\buffer_dec.obj \ - $(DIROBJ)\dec\frame_dec.obj \ - $(DIROBJ)\dec\idec_dec.obj \ - $(DIROBJ)\dec\io_dec.obj \ - $(DIROBJ)\dec\quant_dec.obj \ - $(DIROBJ)\dec\tree_dec.obj \ - $(DIROBJ)\dec\vp8_dec.obj \ - $(DIROBJ)\dec\vp8l_dec.obj \ - $(DIROBJ)\dec\webp_dec.obj \ - -DEMUX_OBJS = \ - $(DIROBJ)\demux\anim_decode.obj \ - $(DIROBJ)\demux\demux.obj \ - -DSP_DEC_OBJS = \ - $(DIROBJ)\dsp\alpha_processing.obj \ - $(DIROBJ)\dsp\alpha_processing_mips_dsp_r2.obj \ - $(DIROBJ)\dsp\alpha_processing_neon.obj \ - $(DIROBJ)\dsp\alpha_processing_sse2.obj \ - $(DIROBJ)\dsp\alpha_processing_sse41.obj \ - $(DIROBJ)\dsp\cpu.obj \ - $(DIROBJ)\dsp\dec.obj \ - $(DIROBJ)\dsp\dec_clip_tables.obj \ - $(DIROBJ)\dsp\dec_mips32.obj \ - $(DIROBJ)\dsp\dec_mips_dsp_r2.obj \ - $(DIROBJ)\dsp\dec_msa.obj \ - $(DIROBJ)\dsp\dec_neon.obj \ - $(DIROBJ)\dsp\dec_sse2.obj \ - $(DIROBJ)\dsp\dec_sse41.obj \ - $(DIROBJ)\dsp\filters.obj \ - $(DIROBJ)\dsp\filters_mips_dsp_r2.obj \ - $(DIROBJ)\dsp\filters_msa.obj \ - $(DIROBJ)\dsp\filters_neon.obj \ - $(DIROBJ)\dsp\filters_sse2.obj \ - $(DIROBJ)\dsp\lossless.obj \ - $(DIROBJ)\dsp\lossless_mips_dsp_r2.obj \ - $(DIROBJ)\dsp\lossless_msa.obj \ - $(DIROBJ)\dsp\lossless_neon.obj \ - $(DIROBJ)\dsp\lossless_sse2.obj \ - $(DIROBJ)\dsp\lossless_sse41.obj \ - $(DIROBJ)\dsp\rescaler.obj \ - $(DIROBJ)\dsp\rescaler_mips32.obj \ - $(DIROBJ)\dsp\rescaler_mips_dsp_r2.obj \ - $(DIROBJ)\dsp\rescaler_msa.obj \ - $(DIROBJ)\dsp\rescaler_neon.obj \ - $(DIROBJ)\dsp\rescaler_sse2.obj \ - $(DIROBJ)\dsp\upsampling.obj \ - $(DIROBJ)\dsp\upsampling_mips_dsp_r2.obj \ - $(DIROBJ)\dsp\upsampling_msa.obj \ - $(DIROBJ)\dsp\upsampling_neon.obj \ - $(DIROBJ)\dsp\upsampling_sse2.obj \ - $(DIROBJ)\dsp\upsampling_sse41.obj \ - $(DIROBJ)\dsp\yuv.obj \ - $(DIROBJ)\dsp\yuv_mips32.obj \ - $(DIROBJ)\dsp\yuv_mips_dsp_r2.obj \ - $(DIROBJ)\dsp\yuv_neon.obj \ - $(DIROBJ)\dsp\yuv_sse2.obj \ - $(DIROBJ)\dsp\yuv_sse41.obj \ - -DSP_ENC_OBJS = \ - $(DIROBJ)\dsp\cost.obj \ - $(DIROBJ)\dsp\cost_mips32.obj \ - $(DIROBJ)\dsp\cost_mips_dsp_r2.obj \ - $(DIROBJ)\dsp\cost_neon.obj \ - $(DIROBJ)\dsp\cost_sse2.obj \ - $(DIROBJ)\dsp\enc.obj \ - $(DIROBJ)\dsp\enc_mips32.obj \ - $(DIROBJ)\dsp\enc_mips_dsp_r2.obj \ - $(DIROBJ)\dsp\enc_msa.obj \ - $(DIROBJ)\dsp\enc_neon.obj \ - $(DIROBJ)\dsp\enc_sse2.obj \ - $(DIROBJ)\dsp\enc_sse41.obj \ - $(DIROBJ)\dsp\lossless_enc.obj \ - $(DIROBJ)\dsp\lossless_enc_mips32.obj \ - $(DIROBJ)\dsp\lossless_enc_mips_dsp_r2.obj \ - $(DIROBJ)\dsp\lossless_enc_msa.obj \ - $(DIROBJ)\dsp\lossless_enc_neon.obj \ - $(DIROBJ)\dsp\lossless_enc_sse2.obj \ - $(DIROBJ)\dsp\lossless_enc_sse41.obj \ - $(DIROBJ)\dsp\ssim.obj \ - $(DIROBJ)\dsp\ssim_sse2.obj \ - -EX_ANIM_UTIL_OBJS = \ - $(DIROBJ)\examples\anim_util.obj \ - -IMAGEIO_DEC_OBJS = \ - $(DIROBJ)\imageio\image_dec.obj \ - $(DIROBJ)\imageio\jpegdec.obj \ - $(DIROBJ)\imageio\metadata.obj \ - $(DIROBJ)\imageio\pngdec.obj \ - $(DIROBJ)\imageio\pnmdec.obj \ - $(DIROBJ)\imageio\tiffdec.obj \ - $(DIROBJ)\imageio\webpdec.obj \ - $(DIROBJ)\imageio\wicdec.obj \ - -IMAGEIO_ENC_OBJS = \ - $(DIROBJ)\imageio\image_enc.obj \ - -EX_GIF_DEC_OBJS = \ - $(DIROBJ)\examples\gifdec.obj \ - -EX_UTIL_OBJS = \ - $(DIROBJ)\examples\example_util.obj \ - -ENC_OBJS = \ - $(DIROBJ)\enc\alpha_enc.obj \ - $(DIROBJ)\enc\analysis_enc.obj \ - $(DIROBJ)\enc\backward_references_cost_enc.obj \ - $(DIROBJ)\enc\backward_references_enc.obj \ - $(DIROBJ)\enc\config_enc.obj \ - $(DIROBJ)\enc\cost_enc.obj \ - $(DIROBJ)\enc\filter_enc.obj \ - $(DIROBJ)\enc\frame_enc.obj \ - $(DIROBJ)\enc\histogram_enc.obj \ - $(DIROBJ)\enc\iterator_enc.obj \ - $(DIROBJ)\enc\near_lossless_enc.obj \ - $(DIROBJ)\enc\picture_enc.obj \ - $(DIROBJ)\enc\picture_csp_enc.obj \ - $(DIROBJ)\enc\picture_psnr_enc.obj \ - $(DIROBJ)\enc\picture_rescale_enc.obj \ - $(DIROBJ)\enc\picture_tools_enc.obj \ - $(DIROBJ)\enc\predictor_enc.obj \ - $(DIROBJ)\enc\quant_enc.obj \ - $(DIROBJ)\enc\syntax_enc.obj \ - $(DIROBJ)\enc\token_enc.obj \ - $(DIROBJ)\enc\tree_enc.obj \ - $(DIROBJ)\enc\vp8l_enc.obj \ - $(DIROBJ)\enc\webp_enc.obj \ - -EXTRAS_OBJS = \ - $(DIROBJ)\extras\extras.obj \ - $(DIROBJ)\extras\quality_estimate.obj \ - $(DIROBJ)\extras\sharpyuv_risk_table.obj \ - -IMAGEIO_UTIL_OBJS = \ - $(DIROBJ)\imageio\imageio_util.obj \ - -MUX_OBJS = \ - $(DIROBJ)\mux\anim_encode.obj \ - $(DIROBJ)\mux\muxedit.obj \ - $(DIROBJ)\mux\muxinternal.obj \ - $(DIROBJ)\mux\muxread.obj \ - -UTILS_DEC_OBJS = \ - $(DIROBJ)\utils\bit_reader_utils.obj \ - $(DIROBJ)\utils\color_cache_utils.obj \ - $(DIROBJ)\utils\filters_utils.obj \ - $(DIROBJ)\utils\huffman_utils.obj \ - $(DIROBJ)\utils\palette.obj \ - $(DIROBJ)\utils\quant_levels_dec_utils.obj \ - $(DIROBJ)\utils\rescaler_utils.obj \ - $(DIROBJ)\utils\random_utils.obj \ - $(DIROBJ)\utils\thread_utils.obj \ - $(DIROBJ)\utils\utils.obj \ - -UTILS_ENC_OBJS = \ - $(DIROBJ)\utils\bit_writer_utils.obj \ - $(DIROBJ)\utils\huffman_encode_utils.obj \ - $(DIROBJ)\utils\quant_levels_utils.obj \ - -LIBWEBPDECODER_OBJS = $(DEC_OBJS) $(DSP_DEC_OBJS) $(UTILS_DEC_OBJS) -LIBWEBP_OBJS = $(LIBWEBPDECODER_OBJS) $(ENC_OBJS) \ - $(DSP_ENC_OBJS) $(UTILS_ENC_OBJS) $(DLL_OBJS) -LIBWEBPMUX_OBJS = $(MUX_OBJS) $(LIBWEBPMUX_OBJS) -LIBWEBPDEMUX_OBJS = $(DEMUX_OBJS) $(LIBWEBPDEMUX_OBJS) -LIBSHARPYUV_OBJS = $(SHARPYUV_OBJS) - -OUT_LIBS = $(LIBWEBPDECODER) $(LIBWEBP) $(LIBSHARPYUV) -!IF "$(ARCH)" == "ARM" -ex: $(OUT_LIBS) -all: ex -!ELSE -OUT_EXAMPLES = $(DIRBIN)\cwebp.exe $(DIRBIN)\dwebp.exe -EXTRA_EXAMPLES = $(DIRBIN)\vwebp.exe $(DIRBIN)\webpmux.exe \ - $(DIRBIN)\img2webp.exe $(DIRBIN)\get_disto.exe \ - $(DIRBIN)\webp_quality.exe $(DIRBIN)\vwebp_sdl.exe \ - $(DIRBIN)\webpinfo.exe - -ex: $(OUT_LIBS) $(OUT_EXAMPLES) -all: ex $(EXTRA_EXAMPLES) -# NB: gif2webp.exe and anim_diff.exe are excluded from 'all' as libgif requires -# C99 support which is only available from VS2013 onward. -gif2webp: $(DIRBIN)\gif2webp.exe -anim_diff: $(DIRBIN)\anim_diff.exe -anim_dump: $(DIRBIN)\anim_dump.exe - -$(DIRBIN)\anim_diff.exe: $(DIROBJ)\examples\anim_diff.obj $(EX_ANIM_UTIL_OBJS) -$(DIRBIN)\anim_diff.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS) -$(DIRBIN)\anim_diff.exe: $(EX_GIF_DEC_OBJS) $(LIBWEBPDEMUX) $(LIBWEBP) -$(DIRBIN)\anim_dump.exe: $(DIROBJ)\examples\anim_dump.obj $(EX_ANIM_UTIL_OBJS) -$(DIRBIN)\anim_dump.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS) -$(DIRBIN)\anim_dump.exe: $(EX_GIF_DEC_OBJS) $(LIBWEBPDEMUX) $(LIBWEBP) -$(DIRBIN)\anim_dump.exe: $(IMAGEIO_ENC_OBJS) -$(DIRBIN)\cwebp.exe: $(DIROBJ)\examples\cwebp.obj $(IMAGEIO_DEC_OBJS) -$(DIRBIN)\cwebp.exe: $(IMAGEIO_UTIL_OBJS) -$(DIRBIN)\cwebp.exe: $(LIBWEBPDEMUX) $(LIBSHARPYUV) -$(DIRBIN)\dwebp.exe: $(DIROBJ)\examples\dwebp.obj $(IMAGEIO_DEC_OBJS) -$(DIRBIN)\dwebp.exe: $(IMAGEIO_ENC_OBJS) -$(DIRBIN)\dwebp.exe: $(IMAGEIO_UTIL_OBJS) -$(DIRBIN)\dwebp.exe: $(LIBWEBPDEMUX) -$(DIRBIN)\gif2webp.exe: $(DIROBJ)\examples\gif2webp.obj $(EX_GIF_DEC_OBJS) -$(DIRBIN)\gif2webp.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS) $(LIBWEBPMUX) -$(DIRBIN)\gif2webp.exe: $(LIBWEBP) -$(DIRBIN)\vwebp.exe: $(DIROBJ)\examples\vwebp.obj $(EX_UTIL_OBJS) -$(DIRBIN)\vwebp.exe: $(IMAGEIO_UTIL_OBJS) $(LIBWEBPDEMUX) $(LIBWEBP) -$(DIRBIN)\vwebp_sdl.exe: $(DIROBJ)\extras\vwebp_sdl.obj -$(DIRBIN)\vwebp_sdl.exe: $(DIROBJ)\extras\webp_to_sdl.obj -$(DIRBIN)\vwebp_sdl.exe: $(IMAGEIO_UTIL_OBJS) $(LIBWEBP) -$(DIRBIN)\webpmux.exe: $(DIROBJ)\examples\webpmux.obj $(LIBWEBPMUX) -$(DIRBIN)\webpmux.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS) $(LIBWEBP) -$(DIRBIN)\img2webp.exe: $(DIROBJ)\examples\img2webp.obj $(LIBWEBPMUX) -$(DIRBIN)\img2webp.exe: $(IMAGEIO_DEC_OBJS) -$(DIRBIN)\img2webp.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS) -$(DIRBIN)\img2webp.exe: $(LIBWEBPDEMUX) $(LIBWEBP) $(LIBSHARPYUV) -$(DIRBIN)\get_disto.exe: $(DIROBJ)\extras\get_disto.obj -$(DIRBIN)\get_disto.exe: $(IMAGEIO_DEC_OBJS) $(IMAGEIO_UTIL_OBJS) -$(DIRBIN)\get_disto.exe: $(LIBWEBPDEMUX) $(LIBWEBP) -$(DIRBIN)\webp_quality.exe: $(DIROBJ)\extras\webp_quality.obj -$(DIRBIN)\webp_quality.exe: $(IMAGEIO_UTIL_OBJS) -$(DIRBIN)\webp_quality.exe: $(EXTRAS_OBJS) -# EXTRA_OBJS requires private symbols from dsp. Explicitly add those when -# building libwebp as a dll. -!IF "$(DLLBUILD)" == "TRUE" -$(DIRBIN)\webp_quality.exe: $(DSP_DEC_OBJS) -!ENDIF -$(DIRBIN)\webp_quality.exe: $(LIBWEBP) -$(DIRBIN)\webpinfo.exe: $(DIROBJ)\examples\webpinfo.obj -$(DIRBIN)\webpinfo.exe: $(IMAGEIO_DEC_OBJS) -$(DIRBIN)\webpinfo.exe: $(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS) -$(DIRBIN)\webpinfo.exe: $(LIBWEBPDEMUX) $(LIBWEBP) - -$(OUT_EXAMPLES): $(EX_UTIL_OBJS) $(LIBWEBP) -$(EX_UTIL_OBJS) $(IMAGEIO_UTIL_OBJS): $(OUTPUT_DIRS) -$(IMAGEIO_DEC_OBJS) $(IMAGEIO_ENC_OBJS) $(EXTRAS_OBJS): $(OUTPUT_DIRS) -!ENDIF # ARCH == ARM - -$(LIBSHARPYUV): $(LIBSHARPYUV_OBJS) -$(LIBWEBPDECODER): $(LIBWEBPDECODER_OBJS) -$(LIBWEBP): $(LIBWEBP_OBJS) $(LIBSHARPYUV) -$(LIBWEBPMUX): $(LIBWEBPMUX_OBJS) -$(LIBWEBPDEMUX): $(LIBWEBPDEMUX_OBJS) - -$(LIBWEBP_OBJS) $(LIBWEBPMUX_OBJS) $(LIBWEBPDEMUX_OBJS) $(LIBSHARPYUV_OBJS): \ - $(OUTPUT_DIRS) - -!IF "$(DLLBUILD)" == "TRUE" -{$(DIROBJ)}.c{$(DIROBJ)}.obj: - $(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$@ $< - -{src}.rc{$(DIROBJ)}.res: - $(RC) /fo$@ $< -{src\demux}.rc{$(DIROBJ)\demux}.res: - $(RC) /fo$@ $< -{src\mux}.rc{$(DIROBJ)\mux}.res: - $(RC) /fo$@ $< -{sharpyuv}.rc{$(DIROBJ)\sharpyuv}.res: - $(RC) /fo$@ $< - -$(LIBSHARPYUV): $(DIROBJ)\sharpyuv\$(LIBSHARPYUV_BASENAME:_debug=).res -$(LIBWEBP): $(LIBSHARPYUV) $(DIROBJ)\$(LIBWEBP_BASENAME:_debug=).res -$(LIBWEBPDECODER): $(DIROBJ)\$(LIBWEBPDECODER_BASENAME:_debug=).res -$(LIBWEBPMUX): $(LIBWEBP) $(DIROBJ)\mux\$(LIBWEBPMUX_BASENAME:_debug=).res -$(LIBWEBPDEMUX): $(LIBWEBP) $(DIROBJ)\demux\$(LIBWEBPDEMUX_BASENAME:_debug=).res - -$(LIBWEBPDECODER) $(LIBWEBP) $(LIBWEBPMUX) $(LIBWEBPDEMUX) $(LIBSHARPYUV): - $(LNKDLL) /out:$(DIRBIN)\$(@B:_dll=.dll) /implib:$@ $(LFLAGS) $** - -xcopy $(DIROBJ)\*.pdb $(DIRLIB) /y -!ELSE -$(LIBWEBPDECODER) $(LIBWEBP) $(LIBWEBPMUX) $(LIBWEBPDEMUX) $(LIBSHARPYUV): - $(LNKLIB) /out:$@ $** - -xcopy $(DIROBJ)\*.pdb $(DIRLIB) /y -!ENDIF - -$(OUTPUT_DIRS): - @if not exist "$(@)" mkdir "$(@)" - -.SUFFIXES: .c .obj .res .exe -# File-specific flag builds. Note batch rules take precedence over wildcards, -# so for now name each file individually. -$(DIROBJ)\examples\anim_diff.obj: examples\anim_diff.c - $(CC) $(CFLAGS) /DWEBP_HAVE_GIF /Fd$(LIBWEBP_PDBNAME) \ - /Fo$(DIROBJ)\examples\ examples\$(@B).c -$(DIROBJ)\examples\anim_dump.obj: examples\anim_dump.c - $(CC) $(CFLAGS) /DWEBP_HAVE_GIF /Fd$(LIBWEBP_PDBNAME) \ - /Fo$(DIROBJ)\examples\ examples\$(@B).c -$(DIROBJ)\examples\anim_util.obj: examples\anim_util.c - $(CC) $(CFLAGS) /DWEBP_HAVE_GIF /Fd$(LIBWEBP_PDBNAME) \ - /Fo$(DIROBJ)\examples\ examples\$(@B).c -$(DIROBJ)\examples\gif2webp.obj: examples\gif2webp.c - $(CC) $(CFLAGS) /DWEBP_HAVE_GIF /Fd$(LIBWEBP_PDBNAME) \ - /Fo$(DIROBJ)\examples\ examples\$(@B).c -$(DIROBJ)\examples\gifdec.obj: examples\gifdec.c - $(CC) $(CFLAGS) /DWEBP_HAVE_GIF /Fd$(LIBWEBP_PDBNAME) \ - /Fo$(DIROBJ)\examples\ examples\$(@B).c -# Batch rules -{examples}.c{$(DIROBJ)\examples}.obj:: - $(CC) $(CFLAGS) /Fd$(DIROBJ)\examples\ /Fo$(DIROBJ)\examples\ $< -{extras}.c{$(DIROBJ)\extras}.obj:: - $(CC) $(CFLAGS) /Fd$(DIROBJ)\extras\ /Fo$(DIROBJ)\extras\ $< -{imageio}.c{$(DIROBJ)\imageio}.obj:: - $(CC) $(CFLAGS) /Fd$(DIROBJ)\imageio\ /Fo$(DIROBJ)\imageio\ $< -{sharpyuv}.c{$(DIROBJ)\sharpyuv}.obj:: - $(CC) $(CFLAGS) /Fd$(DIROBJ)\sharpyuv\ /Fo$(DIROBJ)\sharpyuv\ $< -{src\dec}.c{$(DIROBJ)\dec}.obj:: - $(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\dec\ $< -{src\demux}.c{$(DIROBJ)\demux}.obj:: - $(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\demux\ $< -{src\dsp}.c{$(DIROBJ)\dsp}.obj:: - $(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\dsp\ $< -{src\enc}.c{$(DIROBJ)\enc}.obj:: - $(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\enc\ $< -{src\mux}.c{$(DIROBJ)\mux}.obj:: - $(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\mux\ $< -{src\utils}.c{$(DIROBJ)\utils}.obj:: - $(CC) $(CFLAGS) /Fd$(LIBWEBP_PDBNAME) /Fo$(DIROBJ)\utils\ $< - -LNKLIBS = ole32.lib windowscodecs.lib shlwapi.lib -!IF "$(UNICODE)" == "1" -LNKLIBS = $(LNKLIBS) Shell32.lib -!ENDIF - -{$(DIROBJ)\examples}.obj{$(DIRBIN)}.exe: - $(LNKEXE) $(LDFLAGS) /OUT:$@ $** $(LNKLIBS) - -{$(DIROBJ)\extras}.obj{$(DIRBIN)}.exe: - $(LNKEXE) $(LDFLAGS) /OUT:$@ $** $(LNKLIBS) - -clean:: - @-erase /s $(DIROBJ)\*.dll 2> NUL - @-erase /s $(DIROBJ)\*.exp 2> NUL - @-erase /s $(DIROBJ)\*.idb 2> NUL - @-erase /s $(DIROBJ)\*.lib 2> NUL - @-erase /s $(DIROBJ)\*.obj 2> NUL - @-erase /s $(DIROBJ)\*.pch 2> NUL - @-erase /s $(DIROBJ)\*.pdb 2> NUL - @-erase /s $(DIROBJ)\*.res 2> NUL - -!ENDIF # End of case where a config was provided. diff --git a/libwebp/NEWS b/libwebp/NEWS deleted file mode 100644 index 47f84514..00000000 --- a/libwebp/NEWS +++ /dev/null @@ -1,315 +0,0 @@ -- 9/13/2023: version 1.3.2 - This is a binary compatible release. - * security fix for lossless decoder (chromium: #1479274, CVE-2023-4863) - -- 6/23/2023: version 1.3.1 - This is a binary compatible release. - * security fixes for lossless encoder (#603, chromium: #1420107, #1455619, - CVE-2023-1999) - * improve error reporting through WebPPicture error codes - * fix upsampling for RGB565 and RGBA4444 in NEON builds - * img2webp: add -sharp_yuv & -near_lossless - * Windows builds: - - fix compatibility with clang-cl (#607) - - improve Arm64 performance with cl.exe - - add Arm64EC support - * fix webp_js with emcc >= 3.1.27 (stack size change, #614) - * CMake fixes (#592, #610, #612) - * further updates to the container and lossless bitstream docs (#581, #611) - -- 12/16/2022: version 1.3.0 - This is a binary compatible release. - * add libsharpyuv, which exposes -sharp_yuv/config.use_sharp_yuv - functionality to other libraries; libwebp now depends on this library - * major updates to the container and lossless bitstream docs (#448, #546, - #551) - * miscellaneous warning, bug & build fixes (#576, #583, #584) - -- 8/4/2022: version 1.2.4 - This is a binary compatible release. - * restore CMake libwebpmux target name for compatibility with 1.2.2 (#575) - * fix lossless crunch mode encoding with WEBP_REDUCE_SIZE - (chromium: #1345547, #1345595, #1345772, #1345804) - -- 6/30/2022: version 1.2.3 - This is a binary compatible release. - * security fix for lossless encoder (#565, chromium:1313709) - * improved progress granularity in WebPReportProgress() when using lossless - * improved precision in Sharp YUV (-sharp_yuv) conversion - * many corrections to webp-lossless-bitstream-spec.txt (#551) - * crash/leak fixes on error/OOM and other bug fixes (#558, #563, #569, #573) - -- 1/11/2022: version 1.2.2 - This is a binary compatible release. - * webpmux: add "-set bgcolor A,R,G,B" - * add ARM64 NEON support for MSVC builds (#539) - * fix duplicate include error in Xcode when using multiple XCFrameworks in a - project (#542) - * doc updates and bug fixes (#538, #544, #548, #550) - -- 7/20/2021: version 1.2.1 - This is a binary compatible release. - * minor lossless encoder improvements and x86 color conversion speed up - * add ARM64 simulator support to xcframeworkbuild.sh (#510) - * further security related hardening in libwebp & examples - (issues: #497, #508, #518) - (chromium: #1196480, #1196773, #1196775, #1196777, #1196778, #1196850) - (oss-fuzz: #28658, #28978) - * toolchain updates and bug fixes (#498, #501, #502, #504, #505, #506, #509, - #533) - * use more inclusive language within the source (#507) - -- 12/23/2020: version 1.2.0 - * API changes: - - libwebp: - encode.h: add a qmin / qmax range for quality factor (cwebp adds -qrange) - * lossless encoder improvements - * SIMD support for Wasm builds - * add xcframeworkbuild.sh, supports Mac Catalyst builds - * import fuzzers from oss-fuzz & chromium (#409) - * webpmux: add an '-set loop ' option (#494) - * toolchain updates and bug fixes (#449, #463, #470, #475, #477, #478, #479, - #488, #491) - -- 12/18/2019: version 1.1.0 - * API changes: - - libwebp: - WebPMalloc (issue #442) - - extras: - WebPUnmultiplyARGB - * alpha decode fix (issue #439) - * toolchain updates and bug fixes - (chromium: #1026858, #1027136, #1027409, #1028620, #1028716, #995200) - (oss-fuzz: #19430, #19447) - -- 7/4/2019: version 1.0.3 - This is a binary compatible release. - * resize fixes for Nx1 sizes and the addition of non-opaque alpha values for - odd sizes (issues #418, #434) - * lossless encode/decode performance improvements - * lossy compression performance improvement at low quality levels with flat - content (issue #432) - * python swig files updated to support python 3 - Tool updates: - vwebp will now preserve the aspect ratio of images that exceed monitor - resolution by scaling the image to fit (issue #433) - -- 1/14/2019: version 1.0.2 - This is a binary compatible release. - * (Windows) unicode file support in the tools (linux and mac already had - support, issue #398) - * lossless encoder speedups - * lossy encoder speedup on ARM - * lossless multi-threaded security fix (chromium:917029) - -- 11/2/2018: version 1.0.1 - This is a binary compatible release. - * lossless encoder speedups - * big-endian fix for alpha decoding (issue #393) - * gif2webp fix for loop count=65535 transcode (issue #382) - * further security related hardening in libwebp & libwebpmux - (issues #383, #385, #386, #387, #388, #391) - (oss-fuzz #9099, #9100, #9105, #9106, #9111, #9112, #9119, #9123, #9170, - #9178, #9179, #9183, #9186, #9191, #9364, #9417, #9496, #10349, - #10423, #10634, #10700, #10838, #10922, #11021, #11088, #11152) - * miscellaneous bug & build fixes (issues #381, #394, #396, #397, #400) - -- 4/2/2018: version 1.0.0 - This is a binary compatible release. - * lossy encoder improvements to avoid chroma shifts in various circumstances - (issues #308, #340) - * big-endian fixes for decode, RGBA import and WebPPictureDistortion - Tool updates: - gifwebp, anim_diff - default duration behavior (<= 10ms) changed to match - web browsers, transcoding tools (issue #379) - img2webp, webpmux - allow options to be passed in via a file (issue #355) - -- 11/24/2017: version 0.6.1 - This is a binary compatible release. - * lossless performance and compression improvements + a new 'cruncher' mode - (-m 6 -q 100) - * ARM performance improvements with clang (15-20% w/ndk r15c, issue #339) - * webp-js: emscripten/webassembly based javascript decoder - * miscellaneous bug & build fixes (issue #329, #332, #343, #353, #360, #361, - #363) - Tool updates / additions: - added webpinfo - prints file format information (issue #330) - gif2webp - loop behavior modified to match Chrome M63+ (crbug.com/649264); - '-loop_compatibility' can be used for the old behavior - -- 1/26/2017: version 0.6.0 - * lossless performance and compression improvements - * miscellaneous performance improvements (SSE2, NEON, MSA) - * webpmux gained a -duration option allowing for frame timing modification - * new img2webp utility allowing a sequence of images to be converted to - animated webp - * API changes: - - libwebp: - WebPPictureSharpARGBToYUVA - WebPPlaneDistortion - - libwebpmux / gif2webp: - WebPAnimEncoderOptions: kmax <= 0 now disables keyframes, kmax == 1 - forces all keyframes. See mux.h and the gif2webp - manpage for details. - -- 12/13/2016: version 0.5.2 - This is a binary compatible release. - This release covers CVE-2016-8888 and CVE-2016-9085. - * further security related hardening in the tools; fixes to - gif2webp/AnimEncoder (issues #310, #314, #316, #322), cwebp/libwebp (issue - #312) - * full libwebp (encoder & decoder) iOS framework; libwebpdecoder - WebP.framework renamed to WebPDecoder.framework (issue #307) - * CMake support for Android Studio (2.2) - * miscellaneous build related fixes (issue #306, #313) - * miscellaneous documentation improvements (issue #225) - * minor lossy encoder fixes and improvements - -- 6/14/2016: version 0.5.1 - This is a binary compatible release. - * miscellaneous bug fixes (issues #280, #289) - * reverted alpha plane encoding with color cache for compatibility with - libwebp 0.4.0->0.4.3 (issues #291, #298) - * lossless encoding performance improvements - * memory reduction in both lossless encoding and decoding - * force mux output to be in the extended format (VP8X) when undefined chunks - are present (issue #294) - * gradle, cmake build support - * workaround for compiler bug causing 64-bit decode failures on android - devices using clang-3.8 in the r11c NDK - * various WebPAnimEncoder improvements - -- 12/17/2015: version 0.5.0 - * miscellaneous bug & build fixes (issues #234, #258, #274, #275, #278) - * encoder & decoder speed-ups on x86/ARM/MIPS for lossy & lossless - - note! YUV->RGB conversion was sped-up, but the results will be slightly - different from previous releases - * various lossless encoder improvements - * gif2webp improvements, -min_size option added - * tools fully support input from stdin and output to stdout (issue #168) - * New WebPAnimEncoder API for creating animations - * New WebPAnimDecoder API for decoding animations - * other API changes: - - libwebp: - WebPPictureSmartARGBToYUVA() (-pre 4 in cwebp) - WebPConfig::exact (-exact in cwebp; -alpha_cleanup is now the default) - WebPConfig::near_lossless (-near_lossless in cwebp) - WebPFree() (free'ing webp allocated memory in other languages) - WebPConfigLosslessPreset() - WebPMemoryWriterClear() - - libwebpdemux: removed experimental fragment related fields and functions - - libwebpmux: WebPMuxSetCanvasSize() - * new libwebpextras library with some uncommon import functions: - WebPImportGray/WebPImportRGB565/WebPImportRGB4444 - -- 10/15/15: version 0.4.4 - This is a binary compatible release. - * rescaling out-of-bounds read fix (issue #254) - * various build fixes and improvements (issues #253, #259, #262, #267, #268) - * container documentation update - * gif2webp transparency fix (issue #245) - -- 3/3/15: version 0.4.3 - This is a binary compatible release. - * Android / gcc / iOS / MSVS build fixes and improvements - * lossless decode fix (issue #239 -- since 0.4.0) - * documentation / vwebp updates for animation - * multi-threading fix (issue #234) - -- 10/13/14: version 0.4.2 - This is a binary compatible release. - * Android / gcc build fixes - * (Windows) fix reading from stdin and writing to stdout - * gif2webp: miscellaneous fixes - * fix 'alpha-leak' with lossy compression (issue #220) - * the lossless bitstream spec has been amended to reflect the current code - -- 7/24/14: version 0.4.1 - This is a binary compatible release. - * AArch64 (arm64) & MIPS support/optimizations - * NEON assembly additions: - - ~25% faster lossy decode / encode (-m 4) - - ~10% faster lossless decode - - ~5-10% faster lossless encode (-m 3/4) - * dwebp/vwebp can read from stdin - * cwebp/gif2webp can write to stdout - * cwebp can read webp files; useful if storing sources as webp lossless - -- 12/19/13: version 0.4.0 - * improved gif2webp tool - * numerous fixes, compression improvement and speed-up - * dither option added to decoder (dwebp -dither 50 ...) - * improved multi-threaded modes (-mt option) - * improved filtering strength determination - * New function: WebPMuxGetCanvasSize - * BMP and TIFF format output added to 'dwebp' - * Significant memory reduction for decoding lossy images with alpha. - * Intertwined decoding of RGB and alpha for a shorter - time-to-first-decoded-pixel. - * WebPIterator has a new member 'has_alpha' denoting whether the frame - contains transparency. - * Container spec amended with new 'blending method' for animation. - -- 6/13/13: version 0.3.1 - This is a binary compatible release. - * Add incremental decoding support for images containing ALPH and ICCP chunks. - * Python bindings via swig for the simple encode/decode interfaces similar to - Java. - -- 3/20/13: version 0.3.0 - This is a binary compatible release. - * WebPINewRGB/WebPINewYUVA accept being passed a NULL output buffer - and will perform auto-allocation. - * default filter option is now '-strong -f 60' - * encoding speed-up for lossy methods 3 to 6 - * alpha encoding can be done in parallel to lossy using 'cwebp -mt ...' - * color profile, metadata (XMP/EXIF) and animation support finalized in the - container. - * various NEON assembly additions - Tool updates / additions: - * gif2webp added - * vwebp given color profile & animation support - * cwebp can preserve color profile / metadata with '-metadata' - -- 10/30/12: version 0.2.1 - * Various security related fixes - * cwebp.exe: fix import errors on Windows XP - * enable DLL builds for mingw targets - -- 8/3/12: version 0.2.0 - * Add support for ARGB -> YUVA conversion for lossless decoder - New functions: WebPINewYUVA, WebPIDecGetYUVA - * Add stats for lossless and alpha encoding - * Security related hardening: allocation and size checks - * Add PAM output support to dwebp - -- 7/19/12: version 0.1.99 - * This is a pre-release of 0.2.0, not an rc to allow for further - incompatible changes based on user feedback. - * Alpha channel encode/decode support. - * Lossless encoder/decoder. - * Add TIFF input support to cwebp. - Incompatible changes: - * The encode ABI has been modified to support alpha encoding. - * Deprecated function WebPINew() has been removed. - * Decode function signatures have changed to consistently use size_t over - int/uint32_t. - * decode_vp8.h is no longer installed system-wide. - * cwebp will encode the alpha channel if present. - -- 9/19/11: version 0.1.3 - * Advanced decoding APIs. - * On-the-fly cropping and rescaling of images. - * SSE2 instructions for decoding performance optimizations on x86 based - platforms. - * Support Multi-threaded decoding. - * 40% improvement in Decoding performance. - * Add support for RGB565, RGBA4444 & ARGB image colorspace. - * Better handling of large picture encoding. - -- 3/25/11: version 0.1.2 - * Incremental decoding: picture can be decoded byte-by-byte if needs be. - * lot of bug-fixes, consolidation and stabilization - -- 2/23/11: initial release of version 0.1, with the new encoder -- 9/30/10: initial release version with only the lightweight decoder diff --git a/libwebp/PRESUBMIT.py b/libwebp/PRESUBMIT.py deleted file mode 100644 index 91ad12e1..00000000 --- a/libwebp/PRESUBMIT.py +++ /dev/null @@ -1,245 +0,0 @@ -# Copyright (c) 2021, Google Inc. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# * Neither the name of Google nor the names of its contributors may -# be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -"""Top-level presubmit script for libwebp. - -See https://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts for -details on the presubmit API built into depot_tools. -""" - -import re -import subprocess2 - -USE_PYTHON3 = True -_BASH_INDENTATION = "2" -_GIT_COMMIT_SUBJECT_LENGTH = 65 -_INCLUDE_BASH_FILES_ONLY = [r".*\.sh$"] -_INCLUDE_MAN_FILES_ONLY = [r"man/.+\.1$"] -_INCLUDE_SOURCE_FILES_ONLY = [r".*\.[ch]$"] -_LIBWEBP_MAX_LINE_LENGTH = 80 - - -def _CheckCommitSubjectLength(input_api, output_api): - """Ensures commit's subject length is no longer than 65 chars.""" - name = "git-commit subject" - cmd = ["git", "log", "-1", "--pretty=%s"] - start = input_api.time.time() - proc = subprocess2.Popen( - cmd, - stderr=subprocess2.PIPE, - stdout=subprocess2.PIPE, - universal_newlines=True) - - stdout, _ = proc.communicate() - duration = input_api.time.time() - start - - if not re.match(r"^Revert", - stdout) and (len(stdout) - 1) > _GIT_COMMIT_SUBJECT_LENGTH: - failure_msg = ( - "The commit subject: %s is too long (%d chars)\n" - "Try to keep this to 50 or less (up to 65 is permitted for " - "non-reverts).\n" - "https://www.git-scm.com/book/en/v2/Distributed-Git-Contributing-to-a-" - "Project#_commit_guidelines") % (stdout, len(stdout) - 1) - return output_api.PresubmitError("%s\n (%4.2fs) failed\n%s" % - (name, duration, failure_msg)) - - return output_api.PresubmitResult("%s\n (%4.2fs) success" % (name, duration)) - - -def _CheckDuplicateFiles(input_api, output_api): - """Ensures there are not repeated filenames.""" - all_files = [] - for f in input_api.change.AllFiles(): - for include_file in _INCLUDE_SOURCE_FILES_ONLY: - if re.match(include_file, f): - all_files.append(f) - break - - basename_to_path = {} - for f in all_files: - basename_file = input_api.basename(f) - if basename_file in basename_to_path: - basename_to_path[basename_file].append(f) - else: - basename_to_path[basename_file] = [f] - - dupes = [] - for files in basename_to_path.values(): - if len(files) > 1: - dupes.extend(files) - - if dupes: - return output_api.PresubmitError( - "Duplicate source files, rebase or rename some to make them unique:\n%s" - % dupes) - return output_api.PresubmitResult("No duplicates, success\n") - - -def _GetFilesToSkip(input_api): - return list(input_api.DEFAULT_FILES_TO_SKIP) + [ - r"swig/.*\.py$", - r"\.pylintrc$", - ] - - -def _RunManCmd(input_api, output_api, man_file): - """man command wrapper.""" - cmd = ["man", "--warnings", "-EUTF-8", "-l", "-Tutf8", "-Z", man_file] - name = "Check %s file." % man_file - start = input_api.time.time() - output, _ = subprocess2.communicate( - cmd, stdout=None, stderr=subprocess2.PIPE, universal_newlines=True) - duration = input_api.time.time() - start - if output[1]: - return output_api.PresubmitError("%s\n%s (%4.2fs) failed\n%s" % - (name, " ".join(cmd), duration, output[1])) - return output_api.PresubmitResult("%s\n%s (%4.2fs)\n" % - (name, " ".join(cmd), duration)) - - -def _RunShellCheckCmd(input_api, output_api, bash_file): - """shellcheck command wrapper.""" - cmd = ["shellcheck", "-x", "-oall", "-sbash", bash_file] - name = "Check %s file." % bash_file - start = input_api.time.time() - output, rc = subprocess2.communicate( - cmd, stdout=None, stderr=subprocess2.PIPE, universal_newlines=True) - duration = input_api.time.time() - start - if rc == 0: - return output_api.PresubmitResult("%s\n%s (%4.2fs)\n" % - (name, " ".join(cmd), duration)) - return output_api.PresubmitError("%s\n%s (%4.2fs) failed\n%s" % - (name, " ".join(cmd), duration, output[1])) - - -def _RunShfmtCheckCmd(input_api, output_api, bash_file): - """shfmt command wrapper.""" - cmd = [ - "shfmt", "-i", _BASH_INDENTATION, "-bn", "-ci", "-sr", "-kp", "-d", - bash_file - ] - name = "Check %s file." % bash_file - start = input_api.time.time() - output, rc = subprocess2.communicate( - cmd, stdout=None, stderr=subprocess2.PIPE, universal_newlines=True) - duration = input_api.time.time() - start - if rc == 0: - return output_api.PresubmitResult("%s\n%s (%4.2fs)\n" % - (name, " ".join(cmd), duration)) - return output_api.PresubmitError("%s\n%s (%4.2fs) failed\n%s" % - (name, " ".join(cmd), duration, output[1])) - - -def _RunCmdOnCheckedFiles(input_api, output_api, run_cmd, files_to_check): - """Ensure that libwebp/ files are clean.""" - file_filter = lambda x: input_api.FilterSourceFile( - x, files_to_check=files_to_check, files_to_skip=None) - - affected_files = input_api.change.AffectedFiles(file_filter=file_filter) - results = [ - run_cmd(input_api, output_api, f.AbsoluteLocalPath()) - for f in affected_files - ] - return results - - -def _CommonChecks(input_api, output_api): - """Ensures this patch does not have trailing spaces, extra EOLs, - or long lines. - """ - results = [] - results.extend( - input_api.canned_checks.CheckChangeHasNoCrAndHasOnlyOneEol( - input_api, output_api)) - results.extend( - input_api.canned_checks.CheckChangeHasNoTabs(input_api, output_api)) - results.extend( - input_api.canned_checks.CheckChangeHasNoStrayWhitespace( - input_api, output_api)) - results.append(_CheckCommitSubjectLength(input_api, output_api)) - results.append(_CheckDuplicateFiles(input_api, output_api)) - - source_file_filter = lambda x: input_api.FilterSourceFile( - x, files_to_skip=_GetFilesToSkip(input_api)) - results.extend( - input_api.canned_checks.CheckLongLines( - input_api, - output_api, - maxlen=_LIBWEBP_MAX_LINE_LENGTH, - source_file_filter=source_file_filter)) - - results.extend( - input_api.canned_checks.CheckPatchFormatted( - input_api, - output_api, - check_clang_format=False, - check_python=True, - result_factory=output_api.PresubmitError)) - results.extend( - _RunCmdOnCheckedFiles(input_api, output_api, _RunManCmd, - _INCLUDE_MAN_FILES_ONLY)) - # Run pylint. - results.extend( - input_api.canned_checks.RunPylint( - input_api, - output_api, - files_to_skip=_GetFilesToSkip(input_api), - pylintrc=".pylintrc", - version="2.7")) - - # Binaries shellcheck and shfmt are not installed in depot_tools. - # Installation is needed - try: - subprocess2.communicate(["shellcheck", "--version"]) - results.extend( - _RunCmdOnCheckedFiles(input_api, output_api, _RunShellCheckCmd, - _INCLUDE_BASH_FILES_ONLY)) - print("shfmt") - subprocess2.communicate(["shfmt", "-version"]) - results.extend( - _RunCmdOnCheckedFiles(input_api, output_api, _RunShfmtCheckCmd, - _INCLUDE_BASH_FILES_ONLY)) - except OSError as os_error: - results.append( - output_api.PresubmitPromptWarning( - "%s\nPlease install missing binaries locally." % os_error.args[0])) - return results - - -def CheckChangeOnUpload(input_api, output_api): - results = [] - results.extend(_CommonChecks(input_api, output_api)) - return results - - -def CheckChangeOnCommit(input_api, output_api): - results = [] - results.extend(_CommonChecks(input_api, output_api)) - return results diff --git a/libwebp/PaxHeaders.X/.cmake-format.py b/libwebp/PaxHeaders.X/.cmake-format.py deleted file mode 100644 index ed5cbb3c..00000000 --- a/libwebp/PaxHeaders.X/.cmake-format.py +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.1790000 diff --git a/libwebp/PaxHeaders.X/.gitattributes b/libwebp/PaxHeaders.X/.gitattributes deleted file mode 100644 index ed5cbb3c..00000000 --- a/libwebp/PaxHeaders.X/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.1790000 diff --git a/libwebp/PaxHeaders.X/.gitignore b/libwebp/PaxHeaders.X/.gitignore deleted file mode 100644 index ed5cbb3c..00000000 --- a/libwebp/PaxHeaders.X/.gitignore +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.1790000 diff --git a/libwebp/PaxHeaders.X/.mailmap b/libwebp/PaxHeaders.X/.mailmap deleted file mode 100644 index ed5cbb3c..00000000 --- a/libwebp/PaxHeaders.X/.mailmap +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.1790000 diff --git a/libwebp/PaxHeaders.X/.pylintrc b/libwebp/PaxHeaders.X/.pylintrc deleted file mode 100644 index 52ff3c8d..00000000 --- a/libwebp/PaxHeaders.X/.pylintrc +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.1800000 diff --git a/libwebp/PaxHeaders.X/.style.yapf b/libwebp/PaxHeaders.X/.style.yapf deleted file mode 100644 index 52ff3c8d..00000000 --- a/libwebp/PaxHeaders.X/.style.yapf +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.1800000 diff --git a/libwebp/PaxHeaders.X/AUTHORS b/libwebp/PaxHeaders.X/AUTHORS deleted file mode 100644 index 52ff3c8d..00000000 --- a/libwebp/PaxHeaders.X/AUTHORS +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.1800000 diff --git a/libwebp/PaxHeaders.X/Android.mk b/libwebp/PaxHeaders.X/Android.mk deleted file mode 100644 index 52ff3c8d..00000000 --- a/libwebp/PaxHeaders.X/Android.mk +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.1800000 diff --git a/libwebp/PaxHeaders.X/CMakeLists.txt b/libwebp/PaxHeaders.X/CMakeLists.txt deleted file mode 100644 index 10c7b984..00000000 --- a/libwebp/PaxHeaders.X/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.1810000 diff --git a/libwebp/PaxHeaders.X/CONTRIBUTING.md b/libwebp/PaxHeaders.X/CONTRIBUTING.md deleted file mode 100644 index 072d440f..00000000 --- a/libwebp/PaxHeaders.X/CONTRIBUTING.md +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.1820000 diff --git a/libwebp/PaxHeaders.X/COPYING b/libwebp/PaxHeaders.X/COPYING deleted file mode 100644 index 072d440f..00000000 --- a/libwebp/PaxHeaders.X/COPYING +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.1820000 diff --git a/libwebp/PaxHeaders.X/ChangeLog b/libwebp/PaxHeaders.X/ChangeLog deleted file mode 100644 index f9b44d8a..00000000 --- a/libwebp/PaxHeaders.X/ChangeLog +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.1840000 diff --git a/libwebp/PaxHeaders.X/Makefile.am b/libwebp/PaxHeaders.X/Makefile.am deleted file mode 100644 index 20e36fc6..00000000 --- a/libwebp/PaxHeaders.X/Makefile.am +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.1980000 diff --git a/libwebp/PaxHeaders.X/Makefile.vc b/libwebp/PaxHeaders.X/Makefile.vc deleted file mode 100644 index 20e36fc6..00000000 --- a/libwebp/PaxHeaders.X/Makefile.vc +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.1980000 diff --git a/libwebp/PaxHeaders.X/NEWS b/libwebp/PaxHeaders.X/NEWS deleted file mode 100644 index 20e36fc6..00000000 --- a/libwebp/PaxHeaders.X/NEWS +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.1980000 diff --git a/libwebp/PaxHeaders.X/PATENTS b/libwebp/PaxHeaders.X/PATENTS deleted file mode 100644 index 90f07219..00000000 --- a/libwebp/PaxHeaders.X/PATENTS +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2000000 diff --git a/libwebp/PaxHeaders.X/PRESUBMIT.py b/libwebp/PaxHeaders.X/PRESUBMIT.py deleted file mode 100644 index 90f07219..00000000 --- a/libwebp/PaxHeaders.X/PRESUBMIT.py +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2000000 diff --git a/libwebp/PaxHeaders.X/README.md b/libwebp/PaxHeaders.X/README.md deleted file mode 100644 index 90f07219..00000000 --- a/libwebp/PaxHeaders.X/README.md +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2000000 diff --git a/libwebp/PaxHeaders.X/autogen.sh b/libwebp/PaxHeaders.X/autogen.sh deleted file mode 100644 index 90f07219..00000000 --- a/libwebp/PaxHeaders.X/autogen.sh +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2000000 diff --git a/libwebp/PaxHeaders.X/build.gradle b/libwebp/PaxHeaders.X/build.gradle deleted file mode 100644 index 90f07219..00000000 --- a/libwebp/PaxHeaders.X/build.gradle +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2000000 diff --git a/libwebp/PaxHeaders.X/cmake_ b/libwebp/PaxHeaders.X/cmake_ deleted file mode 100644 index 3ac2d3a7..00000000 --- a/libwebp/PaxHeaders.X/cmake_ +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2010000 diff --git a/libwebp/PaxHeaders.X/cmake_WebPConfig.cmake.in b/libwebp/PaxHeaders.X/cmake_WebPConfig.cmake.in deleted file mode 100644 index 3ac2d3a7..00000000 --- a/libwebp/PaxHeaders.X/cmake_WebPConfig.cmake.in +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2010000 diff --git a/libwebp/PaxHeaders.X/cmake_config.h.in b/libwebp/PaxHeaders.X/cmake_config.h.in deleted file mode 100644 index 3ac2d3a7..00000000 --- a/libwebp/PaxHeaders.X/cmake_config.h.in +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2010000 diff --git a/libwebp/PaxHeaders.X/cmake_cpu.cmake b/libwebp/PaxHeaders.X/cmake_cpu.cmake deleted file mode 100644 index 3ac2d3a7..00000000 --- a/libwebp/PaxHeaders.X/cmake_cpu.cmake +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2010000 diff --git a/libwebp/PaxHeaders.X/cmake_deps.cmake b/libwebp/PaxHeaders.X/cmake_deps.cmake deleted file mode 100644 index 3ac2d3a7..00000000 --- a/libwebp/PaxHeaders.X/cmake_deps.cmake +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2010000 diff --git a/libwebp/PaxHeaders.X/codereview.settings b/libwebp/PaxHeaders.X/codereview.settings deleted file mode 100644 index 3ac2d3a7..00000000 --- a/libwebp/PaxHeaders.X/codereview.settings +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2010000 diff --git a/libwebp/PaxHeaders.X/configure.ac b/libwebp/PaxHeaders.X/configure.ac deleted file mode 100644 index a46b8e8e..00000000 --- a/libwebp/PaxHeaders.X/configure.ac +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2020000 diff --git a/libwebp/PaxHeaders.X/doc_ b/libwebp/PaxHeaders.X/doc_ deleted file mode 100644 index 267c1224..00000000 --- a/libwebp/PaxHeaders.X/doc_ +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2030000 diff --git a/libwebp/PaxHeaders.X/doc_TODO b/libwebp/PaxHeaders.X/doc_TODO deleted file mode 100644 index 267c1224..00000000 --- a/libwebp/PaxHeaders.X/doc_TODO +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2030000 diff --git a/libwebp/PaxHeaders.X/doc_api.md b/libwebp/PaxHeaders.X/doc_api.md deleted file mode 100644 index 267c1224..00000000 --- a/libwebp/PaxHeaders.X/doc_api.md +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2030000 diff --git a/libwebp/PaxHeaders.X/doc_building.md b/libwebp/PaxHeaders.X/doc_building.md deleted file mode 100644 index 267c1224..00000000 --- a/libwebp/PaxHeaders.X/doc_building.md +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2030000 diff --git a/libwebp/PaxHeaders.X/doc_specs_generation.md b/libwebp/PaxHeaders.X/doc_specs_generation.md deleted file mode 100644 index c9662b61..00000000 --- a/libwebp/PaxHeaders.X/doc_specs_generation.md +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2040000 diff --git a/libwebp/PaxHeaders.X/doc_template.html b/libwebp/PaxHeaders.X/doc_template.html deleted file mode 100644 index c9662b61..00000000 --- a/libwebp/PaxHeaders.X/doc_template.html +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2040000 diff --git a/libwebp/PaxHeaders.X/doc_tools.md b/libwebp/PaxHeaders.X/doc_tools.md deleted file mode 100644 index c9662b61..00000000 --- a/libwebp/PaxHeaders.X/doc_tools.md +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2040000 diff --git a/libwebp/PaxHeaders.X/doc_webp-container-spec.txt b/libwebp/PaxHeaders.X/doc_webp-container-spec.txt deleted file mode 100644 index 8ffdf5ae..00000000 --- a/libwebp/PaxHeaders.X/doc_webp-container-spec.txt +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2060000 diff --git a/libwebp/PaxHeaders.X/doc_webp-lossless-bitstream-spec.txt b/libwebp/PaxHeaders.X/doc_webp-lossless-bitstream-spec.txt deleted file mode 100644 index 760a0dbe..00000000 --- a/libwebp/PaxHeaders.X/doc_webp-lossless-bitstream-spec.txt +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2070000 diff --git a/libwebp/PaxHeaders.X/examples_ b/libwebp/PaxHeaders.X/examples_ deleted file mode 100644 index ed595410..00000000 --- a/libwebp/PaxHeaders.X/examples_ +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2110000 diff --git a/libwebp/PaxHeaders.X/examples_Android.mk b/libwebp/PaxHeaders.X/examples_Android.mk deleted file mode 100644 index ed595410..00000000 --- a/libwebp/PaxHeaders.X/examples_Android.mk +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2110000 diff --git a/libwebp/PaxHeaders.X/examples_Makefile.am b/libwebp/PaxHeaders.X/examples_Makefile.am deleted file mode 100644 index ed595410..00000000 --- a/libwebp/PaxHeaders.X/examples_Makefile.am +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2110000 diff --git a/libwebp/PaxHeaders.X/examples_anim_diff.c b/libwebp/PaxHeaders.X/examples_anim_diff.c deleted file mode 100644 index ed595410..00000000 --- a/libwebp/PaxHeaders.X/examples_anim_diff.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2110000 diff --git a/libwebp/PaxHeaders.X/examples_anim_dump.c b/libwebp/PaxHeaders.X/examples_anim_dump.c deleted file mode 100644 index 7da8c934..00000000 --- a/libwebp/PaxHeaders.X/examples_anim_dump.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2120000 diff --git a/libwebp/PaxHeaders.X/examples_anim_util.c b/libwebp/PaxHeaders.X/examples_anim_util.c deleted file mode 100644 index 7da8c934..00000000 --- a/libwebp/PaxHeaders.X/examples_anim_util.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2120000 diff --git a/libwebp/PaxHeaders.X/examples_anim_util.h b/libwebp/PaxHeaders.X/examples_anim_util.h deleted file mode 100644 index ebcded16..00000000 --- a/libwebp/PaxHeaders.X/examples_anim_util.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2130000 diff --git a/libwebp/PaxHeaders.X/examples_cwebp.c b/libwebp/PaxHeaders.X/examples_cwebp.c deleted file mode 100644 index ebcded16..00000000 --- a/libwebp/PaxHeaders.X/examples_cwebp.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2130000 diff --git a/libwebp/PaxHeaders.X/examples_dwebp.c b/libwebp/PaxHeaders.X/examples_dwebp.c deleted file mode 100644 index c06da651..00000000 --- a/libwebp/PaxHeaders.X/examples_dwebp.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2150000 diff --git a/libwebp/PaxHeaders.X/examples_example_util.c b/libwebp/PaxHeaders.X/examples_example_util.c deleted file mode 100644 index 7a9d395d..00000000 --- a/libwebp/PaxHeaders.X/examples_example_util.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2160000 diff --git a/libwebp/PaxHeaders.X/examples_example_util.h b/libwebp/PaxHeaders.X/examples_example_util.h deleted file mode 100644 index a0cb4738..00000000 --- a/libwebp/PaxHeaders.X/examples_example_util.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2170000 diff --git a/libwebp/PaxHeaders.X/examples_gif2webp.c b/libwebp/PaxHeaders.X/examples_gif2webp.c deleted file mode 100644 index a0cb4738..00000000 --- a/libwebp/PaxHeaders.X/examples_gif2webp.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2170000 diff --git a/libwebp/PaxHeaders.X/examples_gifdec.c b/libwebp/PaxHeaders.X/examples_gifdec.c deleted file mode 100644 index 0f092923..00000000 --- a/libwebp/PaxHeaders.X/examples_gifdec.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2180000 diff --git a/libwebp/PaxHeaders.X/examples_gifdec.h b/libwebp/PaxHeaders.X/examples_gifdec.h deleted file mode 100644 index ad346139..00000000 --- a/libwebp/PaxHeaders.X/examples_gifdec.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2190000 diff --git a/libwebp/PaxHeaders.X/examples_img2webp.c b/libwebp/PaxHeaders.X/examples_img2webp.c deleted file mode 100644 index ad346139..00000000 --- a/libwebp/PaxHeaders.X/examples_img2webp.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2190000 diff --git a/libwebp/PaxHeaders.X/examples_stopwatch.h b/libwebp/PaxHeaders.X/examples_stopwatch.h deleted file mode 100644 index ad346139..00000000 --- a/libwebp/PaxHeaders.X/examples_stopwatch.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2190000 diff --git a/libwebp/PaxHeaders.X/examples_test.webp b/libwebp/PaxHeaders.X/examples_test.webp deleted file mode 100644 index 6e63370d..00000000 --- a/libwebp/PaxHeaders.X/examples_test.webp +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2200000 diff --git a/libwebp/PaxHeaders.X/examples_test_ref.ppm b/libwebp/PaxHeaders.X/examples_test_ref.ppm deleted file mode 100644 index 6e63370d..00000000 --- a/libwebp/PaxHeaders.X/examples_test_ref.ppm +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2200000 diff --git a/libwebp/PaxHeaders.X/examples_unicode.h b/libwebp/PaxHeaders.X/examples_unicode.h deleted file mode 100644 index 8891b2a5..00000000 --- a/libwebp/PaxHeaders.X/examples_unicode.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2220000 diff --git a/libwebp/PaxHeaders.X/examples_unicode_gif.h b/libwebp/PaxHeaders.X/examples_unicode_gif.h deleted file mode 100644 index 8891b2a5..00000000 --- a/libwebp/PaxHeaders.X/examples_unicode_gif.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2220000 diff --git a/libwebp/PaxHeaders.X/examples_vwebp.c b/libwebp/PaxHeaders.X/examples_vwebp.c deleted file mode 100644 index d686043f..00000000 --- a/libwebp/PaxHeaders.X/examples_vwebp.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2230000 diff --git a/libwebp/PaxHeaders.X/examples_webpinfo.c b/libwebp/PaxHeaders.X/examples_webpinfo.c deleted file mode 100644 index f9f0febc..00000000 --- a/libwebp/PaxHeaders.X/examples_webpinfo.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2240000 diff --git a/libwebp/PaxHeaders.X/examples_webpmux.c b/libwebp/PaxHeaders.X/examples_webpmux.c deleted file mode 100644 index 35a84a8a..00000000 --- a/libwebp/PaxHeaders.X/examples_webpmux.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2250000 diff --git a/libwebp/PaxHeaders.X/extras_ b/libwebp/PaxHeaders.X/extras_ deleted file mode 100644 index 3a767ad5..00000000 --- a/libwebp/PaxHeaders.X/extras_ +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2270000 diff --git a/libwebp/PaxHeaders.X/extras_Makefile.am b/libwebp/PaxHeaders.X/extras_Makefile.am deleted file mode 100644 index 3a767ad5..00000000 --- a/libwebp/PaxHeaders.X/extras_Makefile.am +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2270000 diff --git a/libwebp/PaxHeaders.X/extras_extras.c b/libwebp/PaxHeaders.X/extras_extras.c deleted file mode 100644 index 3a767ad5..00000000 --- a/libwebp/PaxHeaders.X/extras_extras.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2270000 diff --git a/libwebp/PaxHeaders.X/extras_extras.h b/libwebp/PaxHeaders.X/extras_extras.h deleted file mode 100644 index 9242c383..00000000 --- a/libwebp/PaxHeaders.X/extras_extras.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2280000 diff --git a/libwebp/PaxHeaders.X/extras_get_disto.c b/libwebp/PaxHeaders.X/extras_get_disto.c deleted file mode 100644 index 0aa5483e..00000000 --- a/libwebp/PaxHeaders.X/extras_get_disto.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2290000 diff --git a/libwebp/PaxHeaders.X/extras_quality_estimate.c b/libwebp/PaxHeaders.X/extras_quality_estimate.c deleted file mode 100644 index 0aa5483e..00000000 --- a/libwebp/PaxHeaders.X/extras_quality_estimate.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2290000 diff --git a/libwebp/PaxHeaders.X/extras_sharpyuv_risk_table.c b/libwebp/PaxHeaders.X/extras_sharpyuv_risk_table.c deleted file mode 100644 index de7e20f9..00000000 --- a/libwebp/PaxHeaders.X/extras_sharpyuv_risk_table.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2310000 diff --git a/libwebp/PaxHeaders.X/extras_sharpyuv_risk_table.h b/libwebp/PaxHeaders.X/extras_sharpyuv_risk_table.h deleted file mode 100644 index 34c59772..00000000 --- a/libwebp/PaxHeaders.X/extras_sharpyuv_risk_table.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2850000 diff --git a/libwebp/PaxHeaders.X/extras_vwebp_sdl.c b/libwebp/PaxHeaders.X/extras_vwebp_sdl.c deleted file mode 100644 index 34c59772..00000000 --- a/libwebp/PaxHeaders.X/extras_vwebp_sdl.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2850000 diff --git a/libwebp/PaxHeaders.X/extras_webp_quality.c b/libwebp/PaxHeaders.X/extras_webp_quality.c deleted file mode 100644 index 34c59772..00000000 --- a/libwebp/PaxHeaders.X/extras_webp_quality.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2850000 diff --git a/libwebp/PaxHeaders.X/extras_webp_to_sdl.c b/libwebp/PaxHeaders.X/extras_webp_to_sdl.c deleted file mode 100644 index 34c59772..00000000 --- a/libwebp/PaxHeaders.X/extras_webp_to_sdl.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2850000 diff --git a/libwebp/PaxHeaders.X/extras_webp_to_sdl.h b/libwebp/PaxHeaders.X/extras_webp_to_sdl.h deleted file mode 100644 index 34c59772..00000000 --- a/libwebp/PaxHeaders.X/extras_webp_to_sdl.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2850000 diff --git a/libwebp/PaxHeaders.X/gradle.properties b/libwebp/PaxHeaders.X/gradle.properties deleted file mode 100644 index 34c59772..00000000 --- a/libwebp/PaxHeaders.X/gradle.properties +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2850000 diff --git a/libwebp/PaxHeaders.X/gradle_ b/libwebp/PaxHeaders.X/gradle_ deleted file mode 100644 index 34c59772..00000000 --- a/libwebp/PaxHeaders.X/gradle_ +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2850000 diff --git a/libwebp/PaxHeaders.X/gradle_wrapper_ b/libwebp/PaxHeaders.X/gradle_wrapper_ deleted file mode 100644 index 34c59772..00000000 --- a/libwebp/PaxHeaders.X/gradle_wrapper_ +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2850000 diff --git a/libwebp/PaxHeaders.X/gradle_wrapper_gradle-wrapper.jar b/libwebp/PaxHeaders.X/gradle_wrapper_gradle-wrapper.jar deleted file mode 100644 index 26174a4c..00000000 --- a/libwebp/PaxHeaders.X/gradle_wrapper_gradle-wrapper.jar +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2860000 diff --git a/libwebp/PaxHeaders.X/gradle_wrapper_gradle-wrapper.properties b/libwebp/PaxHeaders.X/gradle_wrapper_gradle-wrapper.properties deleted file mode 100644 index 8520fc3e..00000000 --- a/libwebp/PaxHeaders.X/gradle_wrapper_gradle-wrapper.properties +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2880000 diff --git a/libwebp/PaxHeaders.X/gradlew b/libwebp/PaxHeaders.X/gradlew deleted file mode 100644 index 8520fc3e..00000000 --- a/libwebp/PaxHeaders.X/gradlew +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2880000 diff --git a/libwebp/PaxHeaders.X/gradlew.bat b/libwebp/PaxHeaders.X/gradlew.bat deleted file mode 100644 index e489ca78..00000000 --- a/libwebp/PaxHeaders.X/gradlew.bat +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2890000 diff --git a/libwebp/PaxHeaders.X/imageio_ b/libwebp/PaxHeaders.X/imageio_ deleted file mode 100644 index e489ca78..00000000 --- a/libwebp/PaxHeaders.X/imageio_ +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2890000 diff --git a/libwebp/PaxHeaders.X/imageio_Android.mk b/libwebp/PaxHeaders.X/imageio_Android.mk deleted file mode 100644 index e489ca78..00000000 --- a/libwebp/PaxHeaders.X/imageio_Android.mk +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2890000 diff --git a/libwebp/PaxHeaders.X/imageio_Makefile.am b/libwebp/PaxHeaders.X/imageio_Makefile.am deleted file mode 100644 index e489ca78..00000000 --- a/libwebp/PaxHeaders.X/imageio_Makefile.am +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2890000 diff --git a/libwebp/PaxHeaders.X/imageio_image_dec.c b/libwebp/PaxHeaders.X/imageio_image_dec.c deleted file mode 100644 index e489ca78..00000000 --- a/libwebp/PaxHeaders.X/imageio_image_dec.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2890000 diff --git a/libwebp/PaxHeaders.X/imageio_image_dec.h b/libwebp/PaxHeaders.X/imageio_image_dec.h deleted file mode 100644 index e489ca78..00000000 --- a/libwebp/PaxHeaders.X/imageio_image_dec.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2890000 diff --git a/libwebp/PaxHeaders.X/imageio_image_enc.c b/libwebp/PaxHeaders.X/imageio_image_enc.c deleted file mode 100644 index 80f678a0..00000000 --- a/libwebp/PaxHeaders.X/imageio_image_enc.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2900000 diff --git a/libwebp/PaxHeaders.X/imageio_image_enc.h b/libwebp/PaxHeaders.X/imageio_image_enc.h deleted file mode 100644 index 80f678a0..00000000 --- a/libwebp/PaxHeaders.X/imageio_image_enc.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2900000 diff --git a/libwebp/PaxHeaders.X/imageio_imageio_util.c b/libwebp/PaxHeaders.X/imageio_imageio_util.c deleted file mode 100644 index ccf42e97..00000000 --- a/libwebp/PaxHeaders.X/imageio_imageio_util.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2910000 diff --git a/libwebp/PaxHeaders.X/imageio_imageio_util.h b/libwebp/PaxHeaders.X/imageio_imageio_util.h deleted file mode 100644 index ccf42e97..00000000 --- a/libwebp/PaxHeaders.X/imageio_imageio_util.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2910000 diff --git a/libwebp/PaxHeaders.X/imageio_jpegdec.c b/libwebp/PaxHeaders.X/imageio_jpegdec.c deleted file mode 100644 index ccf42e97..00000000 --- a/libwebp/PaxHeaders.X/imageio_jpegdec.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2910000 diff --git a/libwebp/PaxHeaders.X/imageio_jpegdec.h b/libwebp/PaxHeaders.X/imageio_jpegdec.h deleted file mode 100644 index ccf42e97..00000000 --- a/libwebp/PaxHeaders.X/imageio_jpegdec.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2910000 diff --git a/libwebp/PaxHeaders.X/imageio_metadata.c b/libwebp/PaxHeaders.X/imageio_metadata.c deleted file mode 100644 index 708c9592..00000000 --- a/libwebp/PaxHeaders.X/imageio_metadata.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2920000 diff --git a/libwebp/PaxHeaders.X/imageio_metadata.h b/libwebp/PaxHeaders.X/imageio_metadata.h deleted file mode 100644 index 708c9592..00000000 --- a/libwebp/PaxHeaders.X/imageio_metadata.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2920000 diff --git a/libwebp/PaxHeaders.X/imageio_pngdec.c b/libwebp/PaxHeaders.X/imageio_pngdec.c deleted file mode 100644 index 708c9592..00000000 --- a/libwebp/PaxHeaders.X/imageio_pngdec.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2920000 diff --git a/libwebp/PaxHeaders.X/imageio_pngdec.h b/libwebp/PaxHeaders.X/imageio_pngdec.h deleted file mode 100644 index 708c9592..00000000 --- a/libwebp/PaxHeaders.X/imageio_pngdec.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2920000 diff --git a/libwebp/PaxHeaders.X/imageio_pnmdec.c b/libwebp/PaxHeaders.X/imageio_pnmdec.c deleted file mode 100644 index 708c9592..00000000 --- a/libwebp/PaxHeaders.X/imageio_pnmdec.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2920000 diff --git a/libwebp/PaxHeaders.X/imageio_pnmdec.h b/libwebp/PaxHeaders.X/imageio_pnmdec.h deleted file mode 100644 index 19ae07e9..00000000 --- a/libwebp/PaxHeaders.X/imageio_pnmdec.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2930000 diff --git a/libwebp/PaxHeaders.X/imageio_tiffdec.c b/libwebp/PaxHeaders.X/imageio_tiffdec.c deleted file mode 100644 index 19ae07e9..00000000 --- a/libwebp/PaxHeaders.X/imageio_tiffdec.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2930000 diff --git a/libwebp/PaxHeaders.X/imageio_tiffdec.h b/libwebp/PaxHeaders.X/imageio_tiffdec.h deleted file mode 100644 index 19ae07e9..00000000 --- a/libwebp/PaxHeaders.X/imageio_tiffdec.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2930000 diff --git a/libwebp/PaxHeaders.X/imageio_webpdec.c b/libwebp/PaxHeaders.X/imageio_webpdec.c deleted file mode 100644 index 19ae07e9..00000000 --- a/libwebp/PaxHeaders.X/imageio_webpdec.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2930000 diff --git a/libwebp/PaxHeaders.X/imageio_webpdec.h b/libwebp/PaxHeaders.X/imageio_webpdec.h deleted file mode 100644 index 5e939beb..00000000 --- a/libwebp/PaxHeaders.X/imageio_webpdec.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2940000 diff --git a/libwebp/PaxHeaders.X/imageio_wicdec.c b/libwebp/PaxHeaders.X/imageio_wicdec.c deleted file mode 100644 index 5e939beb..00000000 --- a/libwebp/PaxHeaders.X/imageio_wicdec.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2940000 diff --git a/libwebp/PaxHeaders.X/imageio_wicdec.h b/libwebp/PaxHeaders.X/imageio_wicdec.h deleted file mode 100644 index aec7d18c..00000000 --- a/libwebp/PaxHeaders.X/imageio_wicdec.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2950000 diff --git a/libwebp/PaxHeaders.X/infra_ b/libwebp/PaxHeaders.X/infra_ deleted file mode 100644 index aec7d18c..00000000 --- a/libwebp/PaxHeaders.X/infra_ +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2950000 diff --git a/libwebp/PaxHeaders.X/infra_common.sh b/libwebp/PaxHeaders.X/infra_common.sh deleted file mode 100644 index aec7d18c..00000000 --- a/libwebp/PaxHeaders.X/infra_common.sh +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2950000 diff --git a/libwebp/PaxHeaders.X/infra_compile.sh b/libwebp/PaxHeaders.X/infra_compile.sh deleted file mode 100644 index aec7d18c..00000000 --- a/libwebp/PaxHeaders.X/infra_compile.sh +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2950000 diff --git a/libwebp/PaxHeaders.X/infra_compile_android.sh b/libwebp/PaxHeaders.X/infra_compile_android.sh deleted file mode 100644 index 9ce059f2..00000000 --- a/libwebp/PaxHeaders.X/infra_compile_android.sh +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2960000 diff --git a/libwebp/PaxHeaders.X/infra_compile_js.sh b/libwebp/PaxHeaders.X/infra_compile_js.sh deleted file mode 100644 index 9ce059f2..00000000 --- a/libwebp/PaxHeaders.X/infra_compile_js.sh +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2960000 diff --git a/libwebp/PaxHeaders.X/infra_run_static_analysis.sh b/libwebp/PaxHeaders.X/infra_run_static_analysis.sh deleted file mode 100644 index 9ce059f2..00000000 --- a/libwebp/PaxHeaders.X/infra_run_static_analysis.sh +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2960000 diff --git a/libwebp/PaxHeaders.X/iosbuild.sh b/libwebp/PaxHeaders.X/iosbuild.sh deleted file mode 100644 index 9ce059f2..00000000 --- a/libwebp/PaxHeaders.X/iosbuild.sh +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2960000 diff --git a/libwebp/PaxHeaders.X/m4_ b/libwebp/PaxHeaders.X/m4_ deleted file mode 100644 index 4e9a0f39..00000000 --- a/libwebp/PaxHeaders.X/m4_ +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2970000 diff --git a/libwebp/PaxHeaders.X/m4_.gitignore b/libwebp/PaxHeaders.X/m4_.gitignore deleted file mode 100644 index 4e9a0f39..00000000 --- a/libwebp/PaxHeaders.X/m4_.gitignore +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2970000 diff --git a/libwebp/PaxHeaders.X/m4_ax_pthread.m4 b/libwebp/PaxHeaders.X/m4_ax_pthread.m4 deleted file mode 100644 index 4e9a0f39..00000000 --- a/libwebp/PaxHeaders.X/m4_ax_pthread.m4 +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2970000 diff --git a/libwebp/PaxHeaders.X/makefile.unix b/libwebp/PaxHeaders.X/makefile.unix deleted file mode 100644 index 4e9a0f39..00000000 --- a/libwebp/PaxHeaders.X/makefile.unix +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2970000 diff --git a/libwebp/PaxHeaders.X/man_ b/libwebp/PaxHeaders.X/man_ deleted file mode 100644 index 2f91d73c..00000000 --- a/libwebp/PaxHeaders.X/man_ +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2980000 diff --git a/libwebp/PaxHeaders.X/man_Makefile.am b/libwebp/PaxHeaders.X/man_Makefile.am deleted file mode 100644 index 2f91d73c..00000000 --- a/libwebp/PaxHeaders.X/man_Makefile.am +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2980000 diff --git a/libwebp/PaxHeaders.X/man_cwebp.1 b/libwebp/PaxHeaders.X/man_cwebp.1 deleted file mode 100644 index 2f91d73c..00000000 --- a/libwebp/PaxHeaders.X/man_cwebp.1 +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2980000 diff --git a/libwebp/PaxHeaders.X/man_dwebp.1 b/libwebp/PaxHeaders.X/man_dwebp.1 deleted file mode 100644 index e83396a4..00000000 --- a/libwebp/PaxHeaders.X/man_dwebp.1 +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2990000 diff --git a/libwebp/PaxHeaders.X/man_gif2webp.1 b/libwebp/PaxHeaders.X/man_gif2webp.1 deleted file mode 100644 index e83396a4..00000000 --- a/libwebp/PaxHeaders.X/man_gif2webp.1 +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2990000 diff --git a/libwebp/PaxHeaders.X/man_img2webp.1 b/libwebp/PaxHeaders.X/man_img2webp.1 deleted file mode 100644 index e83396a4..00000000 --- a/libwebp/PaxHeaders.X/man_img2webp.1 +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2990000 diff --git a/libwebp/PaxHeaders.X/man_vwebp.1 b/libwebp/PaxHeaders.X/man_vwebp.1 deleted file mode 100644 index e83396a4..00000000 --- a/libwebp/PaxHeaders.X/man_vwebp.1 +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.2990000 diff --git a/libwebp/PaxHeaders.X/man_webpinfo.1 b/libwebp/PaxHeaders.X/man_webpinfo.1 deleted file mode 100644 index 76f55975..00000000 --- a/libwebp/PaxHeaders.X/man_webpinfo.1 +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3000000 diff --git a/libwebp/PaxHeaders.X/man_webpmux.1 b/libwebp/PaxHeaders.X/man_webpmux.1 deleted file mode 100644 index 76f55975..00000000 --- a/libwebp/PaxHeaders.X/man_webpmux.1 +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3000000 diff --git a/libwebp/PaxHeaders.X/sharpyuv_ b/libwebp/PaxHeaders.X/sharpyuv_ deleted file mode 100644 index 39bf5516..00000000 --- a/libwebp/PaxHeaders.X/sharpyuv_ +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3010000 diff --git a/libwebp/PaxHeaders.X/sharpyuv_Makefile.am b/libwebp/PaxHeaders.X/sharpyuv_Makefile.am deleted file mode 100644 index 39bf5516..00000000 --- a/libwebp/PaxHeaders.X/sharpyuv_Makefile.am +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3010000 diff --git a/libwebp/PaxHeaders.X/sharpyuv_libsharpyuv.pc.in b/libwebp/PaxHeaders.X/sharpyuv_libsharpyuv.pc.in deleted file mode 100644 index 39bf5516..00000000 --- a/libwebp/PaxHeaders.X/sharpyuv_libsharpyuv.pc.in +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3010000 diff --git a/libwebp/PaxHeaders.X/sharpyuv_libsharpyuv.rc b/libwebp/PaxHeaders.X/sharpyuv_libsharpyuv.rc deleted file mode 100644 index 39bf5516..00000000 --- a/libwebp/PaxHeaders.X/sharpyuv_libsharpyuv.rc +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3010000 diff --git a/libwebp/PaxHeaders.X/sharpyuv_sharpyuv.c b/libwebp/PaxHeaders.X/sharpyuv_sharpyuv.c deleted file mode 100644 index 39bf5516..00000000 --- a/libwebp/PaxHeaders.X/sharpyuv_sharpyuv.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3010000 diff --git a/libwebp/PaxHeaders.X/sharpyuv_sharpyuv.h b/libwebp/PaxHeaders.X/sharpyuv_sharpyuv.h deleted file mode 100644 index 02169f75..00000000 --- a/libwebp/PaxHeaders.X/sharpyuv_sharpyuv.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3020000 diff --git a/libwebp/PaxHeaders.X/sharpyuv_sharpyuv_cpu.c b/libwebp/PaxHeaders.X/sharpyuv_sharpyuv_cpu.c deleted file mode 100644 index 02169f75..00000000 --- a/libwebp/PaxHeaders.X/sharpyuv_sharpyuv_cpu.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3020000 diff --git a/libwebp/PaxHeaders.X/sharpyuv_sharpyuv_cpu.h b/libwebp/PaxHeaders.X/sharpyuv_sharpyuv_cpu.h deleted file mode 100644 index 02169f75..00000000 --- a/libwebp/PaxHeaders.X/sharpyuv_sharpyuv_cpu.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3020000 diff --git a/libwebp/PaxHeaders.X/sharpyuv_sharpyuv_csp.c b/libwebp/PaxHeaders.X/sharpyuv_sharpyuv_csp.c deleted file mode 100644 index 220a5c3d..00000000 --- a/libwebp/PaxHeaders.X/sharpyuv_sharpyuv_csp.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3030000 diff --git a/libwebp/PaxHeaders.X/sharpyuv_sharpyuv_csp.h b/libwebp/PaxHeaders.X/sharpyuv_sharpyuv_csp.h deleted file mode 100644 index 220a5c3d..00000000 --- a/libwebp/PaxHeaders.X/sharpyuv_sharpyuv_csp.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3030000 diff --git a/libwebp/PaxHeaders.X/sharpyuv_sharpyuv_dsp.c b/libwebp/PaxHeaders.X/sharpyuv_sharpyuv_dsp.c deleted file mode 100644 index 220a5c3d..00000000 --- a/libwebp/PaxHeaders.X/sharpyuv_sharpyuv_dsp.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3030000 diff --git a/libwebp/PaxHeaders.X/sharpyuv_sharpyuv_dsp.h b/libwebp/PaxHeaders.X/sharpyuv_sharpyuv_dsp.h deleted file mode 100644 index 220a5c3d..00000000 --- a/libwebp/PaxHeaders.X/sharpyuv_sharpyuv_dsp.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3030000 diff --git a/libwebp/PaxHeaders.X/sharpyuv_sharpyuv_gamma.c b/libwebp/PaxHeaders.X/sharpyuv_sharpyuv_gamma.c deleted file mode 100644 index 220a5c3d..00000000 --- a/libwebp/PaxHeaders.X/sharpyuv_sharpyuv_gamma.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3030000 diff --git a/libwebp/PaxHeaders.X/sharpyuv_sharpyuv_gamma.h b/libwebp/PaxHeaders.X/sharpyuv_sharpyuv_gamma.h deleted file mode 100644 index c822c5f5..00000000 --- a/libwebp/PaxHeaders.X/sharpyuv_sharpyuv_gamma.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3040000 diff --git a/libwebp/PaxHeaders.X/sharpyuv_sharpyuv_neon.c b/libwebp/PaxHeaders.X/sharpyuv_sharpyuv_neon.c deleted file mode 100644 index c822c5f5..00000000 --- a/libwebp/PaxHeaders.X/sharpyuv_sharpyuv_neon.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3040000 diff --git a/libwebp/PaxHeaders.X/sharpyuv_sharpyuv_sse2.c b/libwebp/PaxHeaders.X/sharpyuv_sharpyuv_sse2.c deleted file mode 100644 index c822c5f5..00000000 --- a/libwebp/PaxHeaders.X/sharpyuv_sharpyuv_sse2.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3040000 diff --git a/libwebp/PaxHeaders.X/src_ b/libwebp/PaxHeaders.X/src_ deleted file mode 100644 index c822c5f5..00000000 --- a/libwebp/PaxHeaders.X/src_ +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3040000 diff --git a/libwebp/PaxHeaders.X/src_Makefile.am b/libwebp/PaxHeaders.X/src_Makefile.am deleted file mode 100644 index c822c5f5..00000000 --- a/libwebp/PaxHeaders.X/src_Makefile.am +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3040000 diff --git a/libwebp/PaxHeaders.X/src_dec_ b/libwebp/PaxHeaders.X/src_dec_ deleted file mode 100644 index c822c5f5..00000000 --- a/libwebp/PaxHeaders.X/src_dec_ +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3040000 diff --git a/libwebp/PaxHeaders.X/src_dec_Makefile.am b/libwebp/PaxHeaders.X/src_dec_Makefile.am deleted file mode 100644 index 9f2e7b5d..00000000 --- a/libwebp/PaxHeaders.X/src_dec_Makefile.am +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3050000 diff --git a/libwebp/PaxHeaders.X/src_dec_alpha_dec.c b/libwebp/PaxHeaders.X/src_dec_alpha_dec.c deleted file mode 100644 index 9f2e7b5d..00000000 --- a/libwebp/PaxHeaders.X/src_dec_alpha_dec.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3050000 diff --git a/libwebp/PaxHeaders.X/src_dec_alphai_dec.h b/libwebp/PaxHeaders.X/src_dec_alphai_dec.h deleted file mode 100644 index 9f2e7b5d..00000000 --- a/libwebp/PaxHeaders.X/src_dec_alphai_dec.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3050000 diff --git a/libwebp/PaxHeaders.X/src_dec_buffer_dec.c b/libwebp/PaxHeaders.X/src_dec_buffer_dec.c deleted file mode 100644 index 9f2e7b5d..00000000 --- a/libwebp/PaxHeaders.X/src_dec_buffer_dec.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3050000 diff --git a/libwebp/PaxHeaders.X/src_dec_common_dec.h b/libwebp/PaxHeaders.X/src_dec_common_dec.h deleted file mode 100644 index d79ef05e..00000000 --- a/libwebp/PaxHeaders.X/src_dec_common_dec.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3060000 diff --git a/libwebp/PaxHeaders.X/src_dec_frame_dec.c b/libwebp/PaxHeaders.X/src_dec_frame_dec.c deleted file mode 100644 index d79ef05e..00000000 --- a/libwebp/PaxHeaders.X/src_dec_frame_dec.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3060000 diff --git a/libwebp/PaxHeaders.X/src_dec_idec_dec.c b/libwebp/PaxHeaders.X/src_dec_idec_dec.c deleted file mode 100644 index 24d4a878..00000000 --- a/libwebp/PaxHeaders.X/src_dec_idec_dec.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3080000 diff --git a/libwebp/PaxHeaders.X/src_dec_io_dec.c b/libwebp/PaxHeaders.X/src_dec_io_dec.c deleted file mode 100644 index 458e1403..00000000 --- a/libwebp/PaxHeaders.X/src_dec_io_dec.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3100000 diff --git a/libwebp/PaxHeaders.X/src_dec_quant_dec.c b/libwebp/PaxHeaders.X/src_dec_quant_dec.c deleted file mode 100644 index 331522ac..00000000 --- a/libwebp/PaxHeaders.X/src_dec_quant_dec.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3110000 diff --git a/libwebp/PaxHeaders.X/src_dec_tree_dec.c b/libwebp/PaxHeaders.X/src_dec_tree_dec.c deleted file mode 100644 index 331522ac..00000000 --- a/libwebp/PaxHeaders.X/src_dec_tree_dec.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3110000 diff --git a/libwebp/PaxHeaders.X/src_dec_vp8_dec.c b/libwebp/PaxHeaders.X/src_dec_vp8_dec.c deleted file mode 100644 index 10886c70..00000000 --- a/libwebp/PaxHeaders.X/src_dec_vp8_dec.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3130000 diff --git a/libwebp/PaxHeaders.X/src_dec_vp8_dec.h b/libwebp/PaxHeaders.X/src_dec_vp8_dec.h deleted file mode 100644 index f8b3f12f..00000000 --- a/libwebp/PaxHeaders.X/src_dec_vp8_dec.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3140000 diff --git a/libwebp/PaxHeaders.X/src_dec_vp8i_dec.h b/libwebp/PaxHeaders.X/src_dec_vp8i_dec.h deleted file mode 100644 index ae4e9624..00000000 --- a/libwebp/PaxHeaders.X/src_dec_vp8i_dec.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3150000 diff --git a/libwebp/PaxHeaders.X/src_dec_vp8l_dec.c b/libwebp/PaxHeaders.X/src_dec_vp8l_dec.c deleted file mode 100644 index d9678bd4..00000000 --- a/libwebp/PaxHeaders.X/src_dec_vp8l_dec.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3160000 diff --git a/libwebp/PaxHeaders.X/src_dec_vp8li_dec.h b/libwebp/PaxHeaders.X/src_dec_vp8li_dec.h deleted file mode 100644 index 36c6d993..00000000 --- a/libwebp/PaxHeaders.X/src_dec_vp8li_dec.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3190000 diff --git a/libwebp/PaxHeaders.X/src_dec_webp_dec.c b/libwebp/PaxHeaders.X/src_dec_webp_dec.c deleted file mode 100644 index 10f64612..00000000 --- a/libwebp/PaxHeaders.X/src_dec_webp_dec.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3200000 diff --git a/libwebp/PaxHeaders.X/src_dec_webpi_dec.h b/libwebp/PaxHeaders.X/src_dec_webpi_dec.h deleted file mode 100644 index 790168ba..00000000 --- a/libwebp/PaxHeaders.X/src_dec_webpi_dec.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3210000 diff --git a/libwebp/PaxHeaders.X/src_demux_ b/libwebp/PaxHeaders.X/src_demux_ deleted file mode 100644 index 6eb205e8..00000000 --- a/libwebp/PaxHeaders.X/src_demux_ +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3220000 diff --git a/libwebp/PaxHeaders.X/src_demux_Makefile.am b/libwebp/PaxHeaders.X/src_demux_Makefile.am deleted file mode 100644 index 6eb205e8..00000000 --- a/libwebp/PaxHeaders.X/src_demux_Makefile.am +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3220000 diff --git a/libwebp/PaxHeaders.X/src_demux_anim_decode.c b/libwebp/PaxHeaders.X/src_demux_anim_decode.c deleted file mode 100644 index 6eb205e8..00000000 --- a/libwebp/PaxHeaders.X/src_demux_anim_decode.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3220000 diff --git a/libwebp/PaxHeaders.X/src_demux_demux.c b/libwebp/PaxHeaders.X/src_demux_demux.c deleted file mode 100644 index 1131613e..00000000 --- a/libwebp/PaxHeaders.X/src_demux_demux.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3230000 diff --git a/libwebp/PaxHeaders.X/src_demux_libwebpdemux.pc.in b/libwebp/PaxHeaders.X/src_demux_libwebpdemux.pc.in deleted file mode 100644 index 06cafb8f..00000000 --- a/libwebp/PaxHeaders.X/src_demux_libwebpdemux.pc.in +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3250000 diff --git a/libwebp/PaxHeaders.X/src_demux_libwebpdemux.rc b/libwebp/PaxHeaders.X/src_demux_libwebpdemux.rc deleted file mode 100644 index 06cafb8f..00000000 --- a/libwebp/PaxHeaders.X/src_demux_libwebpdemux.rc +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3250000 diff --git a/libwebp/PaxHeaders.X/src_dsp_ b/libwebp/PaxHeaders.X/src_dsp_ deleted file mode 100644 index 06cafb8f..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_ +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3250000 diff --git a/libwebp/PaxHeaders.X/src_dsp_Makefile.am b/libwebp/PaxHeaders.X/src_dsp_Makefile.am deleted file mode 100644 index 06cafb8f..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_Makefile.am +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3250000 diff --git a/libwebp/PaxHeaders.X/src_dsp_alpha_processing.c b/libwebp/PaxHeaders.X/src_dsp_alpha_processing.c deleted file mode 100644 index 06cafb8f..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_alpha_processing.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3250000 diff --git a/libwebp/PaxHeaders.X/src_dsp_alpha_processing_mips_dsp_r2.c b/libwebp/PaxHeaders.X/src_dsp_alpha_processing_mips_dsp_r2.c deleted file mode 100644 index 3f0cce98..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_alpha_processing_mips_dsp_r2.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3260000 diff --git a/libwebp/PaxHeaders.X/src_dsp_alpha_processing_neon.c b/libwebp/PaxHeaders.X/src_dsp_alpha_processing_neon.c deleted file mode 100644 index 137dd17b..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_alpha_processing_neon.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3270000 diff --git a/libwebp/PaxHeaders.X/src_dsp_alpha_processing_sse2.c b/libwebp/PaxHeaders.X/src_dsp_alpha_processing_sse2.c deleted file mode 100644 index 137dd17b..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_alpha_processing_sse2.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3270000 diff --git a/libwebp/PaxHeaders.X/src_dsp_alpha_processing_sse41.c b/libwebp/PaxHeaders.X/src_dsp_alpha_processing_sse41.c deleted file mode 100644 index f77750c9..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_alpha_processing_sse41.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3280000 diff --git a/libwebp/PaxHeaders.X/src_dsp_common_sse2.h b/libwebp/PaxHeaders.X/src_dsp_common_sse2.h deleted file mode 100644 index f77750c9..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_common_sse2.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3280000 diff --git a/libwebp/PaxHeaders.X/src_dsp_common_sse41.h b/libwebp/PaxHeaders.X/src_dsp_common_sse41.h deleted file mode 100644 index ae365994..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_common_sse41.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3290000 diff --git a/libwebp/PaxHeaders.X/src_dsp_cost.c b/libwebp/PaxHeaders.X/src_dsp_cost.c deleted file mode 100644 index ae365994..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_cost.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3290000 diff --git a/libwebp/PaxHeaders.X/src_dsp_cost_mips32.c b/libwebp/PaxHeaders.X/src_dsp_cost_mips32.c deleted file mode 100644 index d26c3d00..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_cost_mips32.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3320000 diff --git a/libwebp/PaxHeaders.X/src_dsp_cost_mips_dsp_r2.c b/libwebp/PaxHeaders.X/src_dsp_cost_mips_dsp_r2.c deleted file mode 100644 index d26c3d00..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_cost_mips_dsp_r2.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3320000 diff --git a/libwebp/PaxHeaders.X/src_dsp_cost_neon.c b/libwebp/PaxHeaders.X/src_dsp_cost_neon.c deleted file mode 100644 index d26c3d00..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_cost_neon.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3320000 diff --git a/libwebp/PaxHeaders.X/src_dsp_cost_sse2.c b/libwebp/PaxHeaders.X/src_dsp_cost_sse2.c deleted file mode 100644 index d26c3d00..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_cost_sse2.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3320000 diff --git a/libwebp/PaxHeaders.X/src_dsp_cpu.c b/libwebp/PaxHeaders.X/src_dsp_cpu.c deleted file mode 100644 index 8014cd70..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_cpu.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3330000 diff --git a/libwebp/PaxHeaders.X/src_dsp_cpu.h b/libwebp/PaxHeaders.X/src_dsp_cpu.h deleted file mode 100644 index 8014cd70..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_cpu.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3330000 diff --git a/libwebp/PaxHeaders.X/src_dsp_dec.c b/libwebp/PaxHeaders.X/src_dsp_dec.c deleted file mode 100644 index 6db7eb52..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_dec.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3340000 diff --git a/libwebp/PaxHeaders.X/src_dsp_dec_clip_tables.c b/libwebp/PaxHeaders.X/src_dsp_dec_clip_tables.c deleted file mode 100644 index 33aa8025..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_dec_clip_tables.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3350000 diff --git a/libwebp/PaxHeaders.X/src_dsp_dec_mips32.c b/libwebp/PaxHeaders.X/src_dsp_dec_mips32.c deleted file mode 100644 index 229cc28c..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_dec_mips32.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3360000 diff --git a/libwebp/PaxHeaders.X/src_dsp_dec_mips_dsp_r2.c b/libwebp/PaxHeaders.X/src_dsp_dec_mips_dsp_r2.c deleted file mode 100644 index 3caf9460..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_dec_mips_dsp_r2.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3380000 diff --git a/libwebp/PaxHeaders.X/src_dsp_dec_msa.c b/libwebp/PaxHeaders.X/src_dsp_dec_msa.c deleted file mode 100644 index 8027b1ab..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_dec_msa.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3400000 diff --git a/libwebp/PaxHeaders.X/src_dsp_dec_neon.c b/libwebp/PaxHeaders.X/src_dsp_dec_neon.c deleted file mode 100644 index 13dc8295..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_dec_neon.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3420000 diff --git a/libwebp/PaxHeaders.X/src_dsp_dec_sse2.c b/libwebp/PaxHeaders.X/src_dsp_dec_sse2.c deleted file mode 100644 index b33cec0c..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_dec_sse2.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3450000 diff --git a/libwebp/PaxHeaders.X/src_dsp_dec_sse41.c b/libwebp/PaxHeaders.X/src_dsp_dec_sse41.c deleted file mode 100644 index c0e72a0f..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_dec_sse41.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3470000 diff --git a/libwebp/PaxHeaders.X/src_dsp_dsp.h b/libwebp/PaxHeaders.X/src_dsp_dsp.h deleted file mode 100644 index c0e72a0f..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_dsp.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3470000 diff --git a/libwebp/PaxHeaders.X/src_dsp_enc.c b/libwebp/PaxHeaders.X/src_dsp_enc.c deleted file mode 100644 index 80004b4d..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_enc.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3480000 diff --git a/libwebp/PaxHeaders.X/src_dsp_enc_mips32.c b/libwebp/PaxHeaders.X/src_dsp_enc_mips32.c deleted file mode 100644 index f8a1c77f..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_enc_mips32.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3490000 diff --git a/libwebp/PaxHeaders.X/src_dsp_enc_mips_dsp_r2.c b/libwebp/PaxHeaders.X/src_dsp_enc_mips_dsp_r2.c deleted file mode 100644 index 74e2b2c5..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_enc_mips_dsp_r2.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3510000 diff --git a/libwebp/PaxHeaders.X/src_dsp_enc_msa.c b/libwebp/PaxHeaders.X/src_dsp_enc_msa.c deleted file mode 100644 index 0cb68cda..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_enc_msa.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3530000 diff --git a/libwebp/PaxHeaders.X/src_dsp_enc_neon.c b/libwebp/PaxHeaders.X/src_dsp_enc_neon.c deleted file mode 100644 index 94b23469..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_enc_neon.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3550000 diff --git a/libwebp/PaxHeaders.X/src_dsp_enc_sse2.c b/libwebp/PaxHeaders.X/src_dsp_enc_sse2.c deleted file mode 100644 index e9c31129..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_enc_sse2.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3570000 diff --git a/libwebp/PaxHeaders.X/src_dsp_enc_sse41.c b/libwebp/PaxHeaders.X/src_dsp_enc_sse41.c deleted file mode 100644 index 4a761f51..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_enc_sse41.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3590000 diff --git a/libwebp/PaxHeaders.X/src_dsp_filters.c b/libwebp/PaxHeaders.X/src_dsp_filters.c deleted file mode 100644 index a0865c9b..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_filters.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3600000 diff --git a/libwebp/PaxHeaders.X/src_dsp_filters_mips_dsp_r2.c b/libwebp/PaxHeaders.X/src_dsp_filters_mips_dsp_r2.c deleted file mode 100644 index 17591a2c..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_filters_mips_dsp_r2.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3610000 diff --git a/libwebp/PaxHeaders.X/src_dsp_filters_msa.c b/libwebp/PaxHeaders.X/src_dsp_filters_msa.c deleted file mode 100644 index 17591a2c..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_filters_msa.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3610000 diff --git a/libwebp/PaxHeaders.X/src_dsp_filters_neon.c b/libwebp/PaxHeaders.X/src_dsp_filters_neon.c deleted file mode 100644 index a940ad8c..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_filters_neon.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3620000 diff --git a/libwebp/PaxHeaders.X/src_dsp_filters_sse2.c b/libwebp/PaxHeaders.X/src_dsp_filters_sse2.c deleted file mode 100644 index a940ad8c..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_filters_sse2.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3620000 diff --git a/libwebp/PaxHeaders.X/src_dsp_lossless.c b/libwebp/PaxHeaders.X/src_dsp_lossless.c deleted file mode 100644 index 9264b04c..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_lossless.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3630000 diff --git a/libwebp/PaxHeaders.X/src_dsp_lossless.h b/libwebp/PaxHeaders.X/src_dsp_lossless.h deleted file mode 100644 index 9aea7d6e..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_lossless.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3640000 diff --git a/libwebp/PaxHeaders.X/src_dsp_lossless_common.h b/libwebp/PaxHeaders.X/src_dsp_lossless_common.h deleted file mode 100644 index 9aea7d6e..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_lossless_common.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3640000 diff --git a/libwebp/PaxHeaders.X/src_dsp_lossless_enc.c b/libwebp/PaxHeaders.X/src_dsp_lossless_enc.c deleted file mode 100644 index 614d459d..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_lossless_enc.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3650000 diff --git a/libwebp/PaxHeaders.X/src_dsp_lossless_enc_mips32.c b/libwebp/PaxHeaders.X/src_dsp_lossless_enc_mips32.c deleted file mode 100644 index dcaf1ba6..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_lossless_enc_mips32.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3670000 diff --git a/libwebp/PaxHeaders.X/src_dsp_lossless_enc_mips_dsp_r2.c b/libwebp/PaxHeaders.X/src_dsp_lossless_enc_mips_dsp_r2.c deleted file mode 100644 index dcaf1ba6..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_lossless_enc_mips_dsp_r2.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3670000 diff --git a/libwebp/PaxHeaders.X/src_dsp_lossless_enc_msa.c b/libwebp/PaxHeaders.X/src_dsp_lossless_enc_msa.c deleted file mode 100644 index 863bbb9b..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_lossless_enc_msa.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3680000 diff --git a/libwebp/PaxHeaders.X/src_dsp_lossless_enc_neon.c b/libwebp/PaxHeaders.X/src_dsp_lossless_enc_neon.c deleted file mode 100644 index 863bbb9b..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_lossless_enc_neon.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3680000 diff --git a/libwebp/PaxHeaders.X/src_dsp_lossless_enc_sse2.c b/libwebp/PaxHeaders.X/src_dsp_lossless_enc_sse2.c deleted file mode 100644 index 863bbb9b..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_lossless_enc_sse2.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3680000 diff --git a/libwebp/PaxHeaders.X/src_dsp_lossless_enc_sse41.c b/libwebp/PaxHeaders.X/src_dsp_lossless_enc_sse41.c deleted file mode 100644 index 3e954344..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_lossless_enc_sse41.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3690000 diff --git a/libwebp/PaxHeaders.X/src_dsp_lossless_mips_dsp_r2.c b/libwebp/PaxHeaders.X/src_dsp_lossless_mips_dsp_r2.c deleted file mode 100644 index 9b1b1b09..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_lossless_mips_dsp_r2.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3700000 diff --git a/libwebp/PaxHeaders.X/src_dsp_lossless_msa.c b/libwebp/PaxHeaders.X/src_dsp_lossless_msa.c deleted file mode 100644 index ae8a509c..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_lossless_msa.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3710000 diff --git a/libwebp/PaxHeaders.X/src_dsp_lossless_neon.c b/libwebp/PaxHeaders.X/src_dsp_lossless_neon.c deleted file mode 100644 index ca637ff7..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_lossless_neon.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3720000 diff --git a/libwebp/PaxHeaders.X/src_dsp_lossless_sse2.c b/libwebp/PaxHeaders.X/src_dsp_lossless_sse2.c deleted file mode 100644 index 569ec8d5..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_lossless_sse2.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3730000 diff --git a/libwebp/PaxHeaders.X/src_dsp_lossless_sse41.c b/libwebp/PaxHeaders.X/src_dsp_lossless_sse41.c deleted file mode 100644 index bee9ff70..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_lossless_sse41.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3740000 diff --git a/libwebp/PaxHeaders.X/src_dsp_mips_macro.h b/libwebp/PaxHeaders.X/src_dsp_mips_macro.h deleted file mode 100644 index 42aaec9a..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_mips_macro.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3750000 diff --git a/libwebp/PaxHeaders.X/src_dsp_msa_macro.h b/libwebp/PaxHeaders.X/src_dsp_msa_macro.h deleted file mode 100644 index 42aaec9a..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_msa_macro.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3750000 diff --git a/libwebp/PaxHeaders.X/src_dsp_neon.h b/libwebp/PaxHeaders.X/src_dsp_neon.h deleted file mode 100644 index 5322e7fd..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_neon.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3770000 diff --git a/libwebp/PaxHeaders.X/src_dsp_quant.h b/libwebp/PaxHeaders.X/src_dsp_quant.h deleted file mode 100644 index 5322e7fd..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_quant.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3770000 diff --git a/libwebp/PaxHeaders.X/src_dsp_rescaler.c b/libwebp/PaxHeaders.X/src_dsp_rescaler.c deleted file mode 100644 index 5322e7fd..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_rescaler.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3770000 diff --git a/libwebp/PaxHeaders.X/src_dsp_rescaler_mips32.c b/libwebp/PaxHeaders.X/src_dsp_rescaler_mips32.c deleted file mode 100644 index 5322e7fd..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_rescaler_mips32.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3770000 diff --git a/libwebp/PaxHeaders.X/src_dsp_rescaler_mips_dsp_r2.c b/libwebp/PaxHeaders.X/src_dsp_rescaler_mips_dsp_r2.c deleted file mode 100644 index 7570310c..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_rescaler_mips_dsp_r2.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3780000 diff --git a/libwebp/PaxHeaders.X/src_dsp_rescaler_msa.c b/libwebp/PaxHeaders.X/src_dsp_rescaler_msa.c deleted file mode 100644 index 7570310c..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_rescaler_msa.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3780000 diff --git a/libwebp/PaxHeaders.X/src_dsp_rescaler_neon.c b/libwebp/PaxHeaders.X/src_dsp_rescaler_neon.c deleted file mode 100644 index 063cdfac..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_rescaler_neon.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3790000 diff --git a/libwebp/PaxHeaders.X/src_dsp_rescaler_sse2.c b/libwebp/PaxHeaders.X/src_dsp_rescaler_sse2.c deleted file mode 100644 index 063cdfac..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_rescaler_sse2.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3790000 diff --git a/libwebp/PaxHeaders.X/src_dsp_ssim.c b/libwebp/PaxHeaders.X/src_dsp_ssim.c deleted file mode 100644 index a47c28be..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_ssim.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3800000 diff --git a/libwebp/PaxHeaders.X/src_dsp_ssim_sse2.c b/libwebp/PaxHeaders.X/src_dsp_ssim_sse2.c deleted file mode 100644 index a47c28be..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_ssim_sse2.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3800000 diff --git a/libwebp/PaxHeaders.X/src_dsp_upsampling.c b/libwebp/PaxHeaders.X/src_dsp_upsampling.c deleted file mode 100644 index 45ee128b..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_upsampling.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3810000 diff --git a/libwebp/PaxHeaders.X/src_dsp_upsampling_mips_dsp_r2.c b/libwebp/PaxHeaders.X/src_dsp_upsampling_mips_dsp_r2.c deleted file mode 100644 index d465df1d..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_upsampling_mips_dsp_r2.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3820000 diff --git a/libwebp/PaxHeaders.X/src_dsp_upsampling_msa.c b/libwebp/PaxHeaders.X/src_dsp_upsampling_msa.c deleted file mode 100644 index d465df1d..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_upsampling_msa.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3820000 diff --git a/libwebp/PaxHeaders.X/src_dsp_upsampling_neon.c b/libwebp/PaxHeaders.X/src_dsp_upsampling_neon.c deleted file mode 100644 index d2ce4ead..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_upsampling_neon.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3830000 diff --git a/libwebp/PaxHeaders.X/src_dsp_upsampling_sse2.c b/libwebp/PaxHeaders.X/src_dsp_upsampling_sse2.c deleted file mode 100644 index d2ce4ead..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_upsampling_sse2.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3830000 diff --git a/libwebp/PaxHeaders.X/src_dsp_upsampling_sse41.c b/libwebp/PaxHeaders.X/src_dsp_upsampling_sse41.c deleted file mode 100644 index e3d35828..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_upsampling_sse41.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3840000 diff --git a/libwebp/PaxHeaders.X/src_dsp_yuv.c b/libwebp/PaxHeaders.X/src_dsp_yuv.c deleted file mode 100644 index e3d35828..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_yuv.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3840000 diff --git a/libwebp/PaxHeaders.X/src_dsp_yuv.h b/libwebp/PaxHeaders.X/src_dsp_yuv.h deleted file mode 100644 index e3d35828..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_yuv.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3840000 diff --git a/libwebp/PaxHeaders.X/src_dsp_yuv_mips32.c b/libwebp/PaxHeaders.X/src_dsp_yuv_mips32.c deleted file mode 100644 index 1a781668..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_yuv_mips32.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3850000 diff --git a/libwebp/PaxHeaders.X/src_dsp_yuv_mips_dsp_r2.c b/libwebp/PaxHeaders.X/src_dsp_yuv_mips_dsp_r2.c deleted file mode 100644 index 1a781668..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_yuv_mips_dsp_r2.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3850000 diff --git a/libwebp/PaxHeaders.X/src_dsp_yuv_neon.c b/libwebp/PaxHeaders.X/src_dsp_yuv_neon.c deleted file mode 100644 index 1a781668..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_yuv_neon.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3850000 diff --git a/libwebp/PaxHeaders.X/src_dsp_yuv_sse2.c b/libwebp/PaxHeaders.X/src_dsp_yuv_sse2.c deleted file mode 100644 index f696fa89..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_yuv_sse2.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3860000 diff --git a/libwebp/PaxHeaders.X/src_dsp_yuv_sse41.c b/libwebp/PaxHeaders.X/src_dsp_yuv_sse41.c deleted file mode 100644 index f696fa89..00000000 --- a/libwebp/PaxHeaders.X/src_dsp_yuv_sse41.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3860000 diff --git a/libwebp/PaxHeaders.X/src_enc_ b/libwebp/PaxHeaders.X/src_enc_ deleted file mode 100644 index 6b9a4161..00000000 --- a/libwebp/PaxHeaders.X/src_enc_ +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3870000 diff --git a/libwebp/PaxHeaders.X/src_enc_Makefile.am b/libwebp/PaxHeaders.X/src_enc_Makefile.am deleted file mode 100644 index 6b9a4161..00000000 --- a/libwebp/PaxHeaders.X/src_enc_Makefile.am +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3870000 diff --git a/libwebp/PaxHeaders.X/src_enc_alpha_enc.c b/libwebp/PaxHeaders.X/src_enc_alpha_enc.c deleted file mode 100644 index 6b9a4161..00000000 --- a/libwebp/PaxHeaders.X/src_enc_alpha_enc.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3870000 diff --git a/libwebp/PaxHeaders.X/src_enc_analysis_enc.c b/libwebp/PaxHeaders.X/src_enc_analysis_enc.c deleted file mode 100644 index 0f0a470d..00000000 --- a/libwebp/PaxHeaders.X/src_enc_analysis_enc.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3880000 diff --git a/libwebp/PaxHeaders.X/src_enc_backward_references_cost_enc.c b/libwebp/PaxHeaders.X/src_enc_backward_references_cost_enc.c deleted file mode 100644 index 03532b14..00000000 --- a/libwebp/PaxHeaders.X/src_enc_backward_references_cost_enc.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3890000 diff --git a/libwebp/PaxHeaders.X/src_enc_backward_references_enc.c b/libwebp/PaxHeaders.X/src_enc_backward_references_enc.c deleted file mode 100644 index 1bb776fb..00000000 --- a/libwebp/PaxHeaders.X/src_enc_backward_references_enc.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3910000 diff --git a/libwebp/PaxHeaders.X/src_enc_backward_references_enc.h b/libwebp/PaxHeaders.X/src_enc_backward_references_enc.h deleted file mode 100644 index fc500ec1..00000000 --- a/libwebp/PaxHeaders.X/src_enc_backward_references_enc.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3930000 diff --git a/libwebp/PaxHeaders.X/src_enc_config_enc.c b/libwebp/PaxHeaders.X/src_enc_config_enc.c deleted file mode 100644 index aea1eb0c..00000000 --- a/libwebp/PaxHeaders.X/src_enc_config_enc.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3940000 diff --git a/libwebp/PaxHeaders.X/src_enc_cost_enc.c b/libwebp/PaxHeaders.X/src_enc_cost_enc.c deleted file mode 100644 index aea1eb0c..00000000 --- a/libwebp/PaxHeaders.X/src_enc_cost_enc.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3940000 diff --git a/libwebp/PaxHeaders.X/src_enc_cost_enc.h b/libwebp/PaxHeaders.X/src_enc_cost_enc.h deleted file mode 100644 index 795ab4fe..00000000 --- a/libwebp/PaxHeaders.X/src_enc_cost_enc.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3950000 diff --git a/libwebp/PaxHeaders.X/src_enc_filter_enc.c b/libwebp/PaxHeaders.X/src_enc_filter_enc.c deleted file mode 100644 index 795ab4fe..00000000 --- a/libwebp/PaxHeaders.X/src_enc_filter_enc.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3950000 diff --git a/libwebp/PaxHeaders.X/src_enc_frame_enc.c b/libwebp/PaxHeaders.X/src_enc_frame_enc.c deleted file mode 100644 index 992c6ddf..00000000 --- a/libwebp/PaxHeaders.X/src_enc_frame_enc.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3960000 diff --git a/libwebp/PaxHeaders.X/src_enc_histogram_enc.c b/libwebp/PaxHeaders.X/src_enc_histogram_enc.c deleted file mode 100644 index 2bc7c52a..00000000 --- a/libwebp/PaxHeaders.X/src_enc_histogram_enc.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.3970000 diff --git a/libwebp/PaxHeaders.X/src_enc_histogram_enc.h b/libwebp/PaxHeaders.X/src_enc_histogram_enc.h deleted file mode 100644 index b7cb2f25..00000000 --- a/libwebp/PaxHeaders.X/src_enc_histogram_enc.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4000000 diff --git a/libwebp/PaxHeaders.X/src_enc_iterator_enc.c b/libwebp/PaxHeaders.X/src_enc_iterator_enc.c deleted file mode 100644 index b7cb2f25..00000000 --- a/libwebp/PaxHeaders.X/src_enc_iterator_enc.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4000000 diff --git a/libwebp/PaxHeaders.X/src_enc_near_lossless_enc.c b/libwebp/PaxHeaders.X/src_enc_near_lossless_enc.c deleted file mode 100644 index 69080672..00000000 --- a/libwebp/PaxHeaders.X/src_enc_near_lossless_enc.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4010000 diff --git a/libwebp/PaxHeaders.X/src_enc_picture_csp_enc.c b/libwebp/PaxHeaders.X/src_enc_picture_csp_enc.c deleted file mode 100644 index 69080672..00000000 --- a/libwebp/PaxHeaders.X/src_enc_picture_csp_enc.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4010000 diff --git a/libwebp/PaxHeaders.X/src_enc_picture_enc.c b/libwebp/PaxHeaders.X/src_enc_picture_enc.c deleted file mode 100644 index e389af4a..00000000 --- a/libwebp/PaxHeaders.X/src_enc_picture_enc.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4030000 diff --git a/libwebp/PaxHeaders.X/src_enc_picture_psnr_enc.c b/libwebp/PaxHeaders.X/src_enc_picture_psnr_enc.c deleted file mode 100644 index 25c8ddd7..00000000 --- a/libwebp/PaxHeaders.X/src_enc_picture_psnr_enc.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4040000 diff --git a/libwebp/PaxHeaders.X/src_enc_picture_rescale_enc.c b/libwebp/PaxHeaders.X/src_enc_picture_rescale_enc.c deleted file mode 100644 index 25c8ddd7..00000000 --- a/libwebp/PaxHeaders.X/src_enc_picture_rescale_enc.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4040000 diff --git a/libwebp/PaxHeaders.X/src_enc_picture_tools_enc.c b/libwebp/PaxHeaders.X/src_enc_picture_tools_enc.c deleted file mode 100644 index 25c8ddd7..00000000 --- a/libwebp/PaxHeaders.X/src_enc_picture_tools_enc.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4040000 diff --git a/libwebp/PaxHeaders.X/src_enc_predictor_enc.c b/libwebp/PaxHeaders.X/src_enc_predictor_enc.c deleted file mode 100644 index b2bcb61b..00000000 --- a/libwebp/PaxHeaders.X/src_enc_predictor_enc.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4050000 diff --git a/libwebp/PaxHeaders.X/src_enc_quant_enc.c b/libwebp/PaxHeaders.X/src_enc_quant_enc.c deleted file mode 100644 index 1be41f24..00000000 --- a/libwebp/PaxHeaders.X/src_enc_quant_enc.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4070000 diff --git a/libwebp/PaxHeaders.X/src_enc_syntax_enc.c b/libwebp/PaxHeaders.X/src_enc_syntax_enc.c deleted file mode 100644 index 38e3f007..00000000 --- a/libwebp/PaxHeaders.X/src_enc_syntax_enc.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4090000 diff --git a/libwebp/PaxHeaders.X/src_enc_token_enc.c b/libwebp/PaxHeaders.X/src_enc_token_enc.c deleted file mode 100644 index 4e10593c..00000000 --- a/libwebp/PaxHeaders.X/src_enc_token_enc.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4100000 diff --git a/libwebp/PaxHeaders.X/src_enc_tree_enc.c b/libwebp/PaxHeaders.X/src_enc_tree_enc.c deleted file mode 100644 index a6f8636a..00000000 --- a/libwebp/PaxHeaders.X/src_enc_tree_enc.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4110000 diff --git a/libwebp/PaxHeaders.X/src_enc_vp8i_enc.h b/libwebp/PaxHeaders.X/src_enc_vp8i_enc.h deleted file mode 100644 index e9ce27a8..00000000 --- a/libwebp/PaxHeaders.X/src_enc_vp8i_enc.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4120000 diff --git a/libwebp/PaxHeaders.X/src_enc_vp8l_enc.c b/libwebp/PaxHeaders.X/src_enc_vp8l_enc.c deleted file mode 100644 index 4debf204..00000000 --- a/libwebp/PaxHeaders.X/src_enc_vp8l_enc.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4130000 diff --git a/libwebp/PaxHeaders.X/src_enc_vp8li_enc.h b/libwebp/PaxHeaders.X/src_enc_vp8li_enc.h deleted file mode 100644 index 2732af84..00000000 --- a/libwebp/PaxHeaders.X/src_enc_vp8li_enc.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4170000 diff --git a/libwebp/PaxHeaders.X/src_enc_webp_enc.c b/libwebp/PaxHeaders.X/src_enc_webp_enc.c deleted file mode 100644 index 2732af84..00000000 --- a/libwebp/PaxHeaders.X/src_enc_webp_enc.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4170000 diff --git a/libwebp/PaxHeaders.X/src_libwebp.pc.in b/libwebp/PaxHeaders.X/src_libwebp.pc.in deleted file mode 100644 index 4c5efe93..00000000 --- a/libwebp/PaxHeaders.X/src_libwebp.pc.in +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4180000 diff --git a/libwebp/PaxHeaders.X/src_libwebp.rc b/libwebp/PaxHeaders.X/src_libwebp.rc deleted file mode 100644 index 4c5efe93..00000000 --- a/libwebp/PaxHeaders.X/src_libwebp.rc +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4180000 diff --git a/libwebp/PaxHeaders.X/src_libwebpdecoder.pc.in b/libwebp/PaxHeaders.X/src_libwebpdecoder.pc.in deleted file mode 100644 index 4c5efe93..00000000 --- a/libwebp/PaxHeaders.X/src_libwebpdecoder.pc.in +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4180000 diff --git a/libwebp/PaxHeaders.X/src_libwebpdecoder.rc b/libwebp/PaxHeaders.X/src_libwebpdecoder.rc deleted file mode 100644 index 4c5efe93..00000000 --- a/libwebp/PaxHeaders.X/src_libwebpdecoder.rc +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4180000 diff --git a/libwebp/PaxHeaders.X/src_mux_ b/libwebp/PaxHeaders.X/src_mux_ deleted file mode 100644 index 4c5efe93..00000000 --- a/libwebp/PaxHeaders.X/src_mux_ +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4180000 diff --git a/libwebp/PaxHeaders.X/src_mux_Makefile.am b/libwebp/PaxHeaders.X/src_mux_Makefile.am deleted file mode 100644 index 4c5efe93..00000000 --- a/libwebp/PaxHeaders.X/src_mux_Makefile.am +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4180000 diff --git a/libwebp/PaxHeaders.X/src_mux_anim_encode.c b/libwebp/PaxHeaders.X/src_mux_anim_encode.c deleted file mode 100644 index 96c8d1a8..00000000 --- a/libwebp/PaxHeaders.X/src_mux_anim_encode.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4190000 diff --git a/libwebp/PaxHeaders.X/src_mux_animi.h b/libwebp/PaxHeaders.X/src_mux_animi.h deleted file mode 100644 index 9dc1260d..00000000 --- a/libwebp/PaxHeaders.X/src_mux_animi.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4220000 diff --git a/libwebp/PaxHeaders.X/src_mux_libwebpmux.pc.in b/libwebp/PaxHeaders.X/src_mux_libwebpmux.pc.in deleted file mode 100644 index 9dc1260d..00000000 --- a/libwebp/PaxHeaders.X/src_mux_libwebpmux.pc.in +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4220000 diff --git a/libwebp/PaxHeaders.X/src_mux_libwebpmux.rc b/libwebp/PaxHeaders.X/src_mux_libwebpmux.rc deleted file mode 100644 index 9dc1260d..00000000 --- a/libwebp/PaxHeaders.X/src_mux_libwebpmux.rc +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4220000 diff --git a/libwebp/PaxHeaders.X/src_mux_muxedit.c b/libwebp/PaxHeaders.X/src_mux_muxedit.c deleted file mode 100644 index 9dc1260d..00000000 --- a/libwebp/PaxHeaders.X/src_mux_muxedit.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4220000 diff --git a/libwebp/PaxHeaders.X/src_mux_muxi.h b/libwebp/PaxHeaders.X/src_mux_muxi.h deleted file mode 100644 index 925105ea..00000000 --- a/libwebp/PaxHeaders.X/src_mux_muxi.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4230000 diff --git a/libwebp/PaxHeaders.X/src_mux_muxinternal.c b/libwebp/PaxHeaders.X/src_mux_muxinternal.c deleted file mode 100644 index 3cdd0acd..00000000 --- a/libwebp/PaxHeaders.X/src_mux_muxinternal.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4240000 diff --git a/libwebp/PaxHeaders.X/src_mux_muxread.c b/libwebp/PaxHeaders.X/src_mux_muxread.c deleted file mode 100644 index 3cdd0acd..00000000 --- a/libwebp/PaxHeaders.X/src_mux_muxread.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4240000 diff --git a/libwebp/PaxHeaders.X/src_utils_ b/libwebp/PaxHeaders.X/src_utils_ deleted file mode 100644 index 9bee24b8..00000000 --- a/libwebp/PaxHeaders.X/src_utils_ +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4250000 diff --git a/libwebp/PaxHeaders.X/src_utils_Makefile.am b/libwebp/PaxHeaders.X/src_utils_Makefile.am deleted file mode 100644 index 9bee24b8..00000000 --- a/libwebp/PaxHeaders.X/src_utils_Makefile.am +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4250000 diff --git a/libwebp/PaxHeaders.X/src_utils_bit_reader_inl_utils.h b/libwebp/PaxHeaders.X/src_utils_bit_reader_inl_utils.h deleted file mode 100644 index 9bee24b8..00000000 --- a/libwebp/PaxHeaders.X/src_utils_bit_reader_inl_utils.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4250000 diff --git a/libwebp/PaxHeaders.X/src_utils_bit_reader_utils.c b/libwebp/PaxHeaders.X/src_utils_bit_reader_utils.c deleted file mode 100644 index 18463c64..00000000 --- a/libwebp/PaxHeaders.X/src_utils_bit_reader_utils.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4260000 diff --git a/libwebp/PaxHeaders.X/src_utils_bit_reader_utils.h b/libwebp/PaxHeaders.X/src_utils_bit_reader_utils.h deleted file mode 100644 index 18463c64..00000000 --- a/libwebp/PaxHeaders.X/src_utils_bit_reader_utils.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4260000 diff --git a/libwebp/PaxHeaders.X/src_utils_bit_writer_utils.c b/libwebp/PaxHeaders.X/src_utils_bit_writer_utils.c deleted file mode 100644 index 3091f52b..00000000 --- a/libwebp/PaxHeaders.X/src_utils_bit_writer_utils.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4270000 diff --git a/libwebp/PaxHeaders.X/src_utils_bit_writer_utils.h b/libwebp/PaxHeaders.X/src_utils_bit_writer_utils.h deleted file mode 100644 index 3091f52b..00000000 --- a/libwebp/PaxHeaders.X/src_utils_bit_writer_utils.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4270000 diff --git a/libwebp/PaxHeaders.X/src_utils_color_cache_utils.c b/libwebp/PaxHeaders.X/src_utils_color_cache_utils.c deleted file mode 100644 index 3091f52b..00000000 --- a/libwebp/PaxHeaders.X/src_utils_color_cache_utils.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4270000 diff --git a/libwebp/PaxHeaders.X/src_utils_color_cache_utils.h b/libwebp/PaxHeaders.X/src_utils_color_cache_utils.h deleted file mode 100644 index 85eccdab..00000000 --- a/libwebp/PaxHeaders.X/src_utils_color_cache_utils.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4280000 diff --git a/libwebp/PaxHeaders.X/src_utils_endian_inl_utils.h b/libwebp/PaxHeaders.X/src_utils_endian_inl_utils.h deleted file mode 100644 index 85eccdab..00000000 --- a/libwebp/PaxHeaders.X/src_utils_endian_inl_utils.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4280000 diff --git a/libwebp/PaxHeaders.X/src_utils_filters_utils.c b/libwebp/PaxHeaders.X/src_utils_filters_utils.c deleted file mode 100644 index 85eccdab..00000000 --- a/libwebp/PaxHeaders.X/src_utils_filters_utils.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4280000 diff --git a/libwebp/PaxHeaders.X/src_utils_filters_utils.h b/libwebp/PaxHeaders.X/src_utils_filters_utils.h deleted file mode 100644 index f8748088..00000000 --- a/libwebp/PaxHeaders.X/src_utils_filters_utils.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4290000 diff --git a/libwebp/PaxHeaders.X/src_utils_huffman_encode_utils.c b/libwebp/PaxHeaders.X/src_utils_huffman_encode_utils.c deleted file mode 100644 index f8748088..00000000 --- a/libwebp/PaxHeaders.X/src_utils_huffman_encode_utils.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4290000 diff --git a/libwebp/PaxHeaders.X/src_utils_huffman_encode_utils.h b/libwebp/PaxHeaders.X/src_utils_huffman_encode_utils.h deleted file mode 100644 index bd57b7fb..00000000 --- a/libwebp/PaxHeaders.X/src_utils_huffman_encode_utils.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4300000 diff --git a/libwebp/PaxHeaders.X/src_utils_huffman_utils.c b/libwebp/PaxHeaders.X/src_utils_huffman_utils.c deleted file mode 100644 index bd57b7fb..00000000 --- a/libwebp/PaxHeaders.X/src_utils_huffman_utils.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4300000 diff --git a/libwebp/PaxHeaders.X/src_utils_huffman_utils.h b/libwebp/PaxHeaders.X/src_utils_huffman_utils.h deleted file mode 100644 index bd57b7fb..00000000 --- a/libwebp/PaxHeaders.X/src_utils_huffman_utils.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4300000 diff --git a/libwebp/PaxHeaders.X/src_utils_palette.c b/libwebp/PaxHeaders.X/src_utils_palette.c deleted file mode 100644 index fe666ce8..00000000 --- a/libwebp/PaxHeaders.X/src_utils_palette.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4310000 diff --git a/libwebp/PaxHeaders.X/src_utils_palette.h b/libwebp/PaxHeaders.X/src_utils_palette.h deleted file mode 100644 index fe666ce8..00000000 --- a/libwebp/PaxHeaders.X/src_utils_palette.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4310000 diff --git a/libwebp/PaxHeaders.X/src_utils_quant_levels_dec_utils.c b/libwebp/PaxHeaders.X/src_utils_quant_levels_dec_utils.c deleted file mode 100644 index 8086ceba..00000000 --- a/libwebp/PaxHeaders.X/src_utils_quant_levels_dec_utils.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4320000 diff --git a/libwebp/PaxHeaders.X/src_utils_quant_levels_dec_utils.h b/libwebp/PaxHeaders.X/src_utils_quant_levels_dec_utils.h deleted file mode 100644 index 8086ceba..00000000 --- a/libwebp/PaxHeaders.X/src_utils_quant_levels_dec_utils.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4320000 diff --git a/libwebp/PaxHeaders.X/src_utils_quant_levels_utils.c b/libwebp/PaxHeaders.X/src_utils_quant_levels_utils.c deleted file mode 100644 index 4d202f77..00000000 --- a/libwebp/PaxHeaders.X/src_utils_quant_levels_utils.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4330000 diff --git a/libwebp/PaxHeaders.X/src_utils_quant_levels_utils.h b/libwebp/PaxHeaders.X/src_utils_quant_levels_utils.h deleted file mode 100644 index 4d202f77..00000000 --- a/libwebp/PaxHeaders.X/src_utils_quant_levels_utils.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4330000 diff --git a/libwebp/PaxHeaders.X/src_utils_random_utils.c b/libwebp/PaxHeaders.X/src_utils_random_utils.c deleted file mode 100644 index 4d202f77..00000000 --- a/libwebp/PaxHeaders.X/src_utils_random_utils.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4330000 diff --git a/libwebp/PaxHeaders.X/src_utils_random_utils.h b/libwebp/PaxHeaders.X/src_utils_random_utils.h deleted file mode 100644 index 4d202f77..00000000 --- a/libwebp/PaxHeaders.X/src_utils_random_utils.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4330000 diff --git a/libwebp/PaxHeaders.X/src_utils_rescaler_utils.c b/libwebp/PaxHeaders.X/src_utils_rescaler_utils.c deleted file mode 100644 index 4d202f77..00000000 --- a/libwebp/PaxHeaders.X/src_utils_rescaler_utils.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4330000 diff --git a/libwebp/PaxHeaders.X/src_utils_rescaler_utils.h b/libwebp/PaxHeaders.X/src_utils_rescaler_utils.h deleted file mode 100644 index 7c6318a6..00000000 --- a/libwebp/PaxHeaders.X/src_utils_rescaler_utils.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4340000 diff --git a/libwebp/PaxHeaders.X/src_utils_thread_utils.c b/libwebp/PaxHeaders.X/src_utils_thread_utils.c deleted file mode 100644 index 7c6318a6..00000000 --- a/libwebp/PaxHeaders.X/src_utils_thread_utils.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4340000 diff --git a/libwebp/PaxHeaders.X/src_utils_thread_utils.h b/libwebp/PaxHeaders.X/src_utils_thread_utils.h deleted file mode 100644 index 39f87dfa..00000000 --- a/libwebp/PaxHeaders.X/src_utils_thread_utils.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4350000 diff --git a/libwebp/PaxHeaders.X/src_utils_utils.c b/libwebp/PaxHeaders.X/src_utils_utils.c deleted file mode 100644 index 39f87dfa..00000000 --- a/libwebp/PaxHeaders.X/src_utils_utils.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4350000 diff --git a/libwebp/PaxHeaders.X/src_utils_utils.h b/libwebp/PaxHeaders.X/src_utils_utils.h deleted file mode 100644 index 39f87dfa..00000000 --- a/libwebp/PaxHeaders.X/src_utils_utils.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4350000 diff --git a/libwebp/PaxHeaders.X/src_webp_ b/libwebp/PaxHeaders.X/src_webp_ deleted file mode 100644 index 83d219ab..00000000 --- a/libwebp/PaxHeaders.X/src_webp_ +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4360000 diff --git a/libwebp/PaxHeaders.X/src_webp_decode.h b/libwebp/PaxHeaders.X/src_webp_decode.h deleted file mode 100644 index b69e99f2..00000000 --- a/libwebp/PaxHeaders.X/src_webp_decode.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4370000 diff --git a/libwebp/PaxHeaders.X/src_webp_demux.h b/libwebp/PaxHeaders.X/src_webp_demux.h deleted file mode 100644 index 101a111b..00000000 --- a/libwebp/PaxHeaders.X/src_webp_demux.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4380000 diff --git a/libwebp/PaxHeaders.X/src_webp_encode.h b/libwebp/PaxHeaders.X/src_webp_encode.h deleted file mode 100644 index 2f0af3bc..00000000 --- a/libwebp/PaxHeaders.X/src_webp_encode.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4390000 diff --git a/libwebp/PaxHeaders.X/src_webp_format_constants.h b/libwebp/PaxHeaders.X/src_webp_format_constants.h deleted file mode 100644 index 52462f7c..00000000 --- a/libwebp/PaxHeaders.X/src_webp_format_constants.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4410000 diff --git a/libwebp/PaxHeaders.X/src_webp_mux.h b/libwebp/PaxHeaders.X/src_webp_mux.h deleted file mode 100644 index 52462f7c..00000000 --- a/libwebp/PaxHeaders.X/src_webp_mux.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4410000 diff --git a/libwebp/PaxHeaders.X/src_webp_mux_types.h b/libwebp/PaxHeaders.X/src_webp_mux_types.h deleted file mode 100644 index 743ae12c..00000000 --- a/libwebp/PaxHeaders.X/src_webp_mux_types.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4430000 diff --git a/libwebp/PaxHeaders.X/src_webp_types.h b/libwebp/PaxHeaders.X/src_webp_types.h deleted file mode 100644 index 743ae12c..00000000 --- a/libwebp/PaxHeaders.X/src_webp_types.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4430000 diff --git a/libwebp/PaxHeaders.X/swig_ b/libwebp/PaxHeaders.X/swig_ deleted file mode 100644 index 743ae12c..00000000 --- a/libwebp/PaxHeaders.X/swig_ +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4430000 diff --git a/libwebp/PaxHeaders.X/swig_README.md b/libwebp/PaxHeaders.X/swig_README.md deleted file mode 100644 index 743ae12c..00000000 --- a/libwebp/PaxHeaders.X/swig_README.md +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4430000 diff --git a/libwebp/PaxHeaders.X/swig_libwebp.go b/libwebp/PaxHeaders.X/swig_libwebp.go deleted file mode 100644 index 743ae12c..00000000 --- a/libwebp/PaxHeaders.X/swig_libwebp.go +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4430000 diff --git a/libwebp/PaxHeaders.X/swig_libwebp.jar b/libwebp/PaxHeaders.X/swig_libwebp.jar deleted file mode 100644 index 743ae12c..00000000 --- a/libwebp/PaxHeaders.X/swig_libwebp.jar +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4430000 diff --git a/libwebp/PaxHeaders.X/swig_libwebp.py b/libwebp/PaxHeaders.X/swig_libwebp.py deleted file mode 100644 index 79640fb6..00000000 --- a/libwebp/PaxHeaders.X/swig_libwebp.py +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4440000 diff --git a/libwebp/PaxHeaders.X/swig_libwebp.swig b/libwebp/PaxHeaders.X/swig_libwebp.swig deleted file mode 100644 index 79640fb6..00000000 --- a/libwebp/PaxHeaders.X/swig_libwebp.swig +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4440000 diff --git a/libwebp/PaxHeaders.X/swig_libwebp_gc.c b/libwebp/PaxHeaders.X/swig_libwebp_gc.c deleted file mode 100644 index 2142036b..00000000 --- a/libwebp/PaxHeaders.X/swig_libwebp_gc.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4450000 diff --git a/libwebp/PaxHeaders.X/swig_libwebp_go_wrap.c b/libwebp/PaxHeaders.X/swig_libwebp_go_wrap.c deleted file mode 100644 index 2142036b..00000000 --- a/libwebp/PaxHeaders.X/swig_libwebp_go_wrap.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4450000 diff --git a/libwebp/PaxHeaders.X/swig_libwebp_java_wrap.c b/libwebp/PaxHeaders.X/swig_libwebp_java_wrap.c deleted file mode 100644 index 2142036b..00000000 --- a/libwebp/PaxHeaders.X/swig_libwebp_java_wrap.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4450000 diff --git a/libwebp/PaxHeaders.X/swig_libwebp_python_wrap.c b/libwebp/PaxHeaders.X/swig_libwebp_python_wrap.c deleted file mode 100644 index 2ce9daf7..00000000 --- a/libwebp/PaxHeaders.X/swig_libwebp_python_wrap.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4470000 diff --git a/libwebp/PaxHeaders.X/swig_setup.py b/libwebp/PaxHeaders.X/swig_setup.py deleted file mode 100644 index bdb64a0d..00000000 --- a/libwebp/PaxHeaders.X/swig_setup.py +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4530000 diff --git a/libwebp/PaxHeaders.X/tests_ b/libwebp/PaxHeaders.X/tests_ deleted file mode 100644 index bdb64a0d..00000000 --- a/libwebp/PaxHeaders.X/tests_ +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4530000 diff --git a/libwebp/PaxHeaders.X/tests_README.md b/libwebp/PaxHeaders.X/tests_README.md deleted file mode 100644 index bdb64a0d..00000000 --- a/libwebp/PaxHeaders.X/tests_README.md +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4530000 diff --git a/libwebp/PaxHeaders.X/tests_fuzzer_ b/libwebp/PaxHeaders.X/tests_fuzzer_ deleted file mode 100644 index ac8ba677..00000000 --- a/libwebp/PaxHeaders.X/tests_fuzzer_ +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4540000 diff --git a/libwebp/PaxHeaders.X/tests_fuzzer_advanced_api_fuzzer.c b/libwebp/PaxHeaders.X/tests_fuzzer_advanced_api_fuzzer.c deleted file mode 100644 index ac8ba677..00000000 --- a/libwebp/PaxHeaders.X/tests_fuzzer_advanced_api_fuzzer.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4540000 diff --git a/libwebp/PaxHeaders.X/tests_fuzzer_animation_api_fuzzer.c b/libwebp/PaxHeaders.X/tests_fuzzer_animation_api_fuzzer.c deleted file mode 100644 index ac8ba677..00000000 --- a/libwebp/PaxHeaders.X/tests_fuzzer_animation_api_fuzzer.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4540000 diff --git a/libwebp/PaxHeaders.X/tests_fuzzer_animdecoder_fuzzer.cc b/libwebp/PaxHeaders.X/tests_fuzzer_animdecoder_fuzzer.cc deleted file mode 100644 index ac8ba677..00000000 --- a/libwebp/PaxHeaders.X/tests_fuzzer_animdecoder_fuzzer.cc +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4540000 diff --git a/libwebp/PaxHeaders.X/tests_fuzzer_animencoder_fuzzer.cc b/libwebp/PaxHeaders.X/tests_fuzzer_animencoder_fuzzer.cc deleted file mode 100644 index ac8ba677..00000000 --- a/libwebp/PaxHeaders.X/tests_fuzzer_animencoder_fuzzer.cc +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4540000 diff --git a/libwebp/PaxHeaders.X/tests_fuzzer_enc_dec_fuzzer.cc b/libwebp/PaxHeaders.X/tests_fuzzer_enc_dec_fuzzer.cc deleted file mode 100644 index ac8ba677..00000000 --- a/libwebp/PaxHeaders.X/tests_fuzzer_enc_dec_fuzzer.cc +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4540000 diff --git a/libwebp/PaxHeaders.X/tests_fuzzer_fuzz.dict b/libwebp/PaxHeaders.X/tests_fuzzer_fuzz.dict deleted file mode 100644 index 6e409fbd..00000000 --- a/libwebp/PaxHeaders.X/tests_fuzzer_fuzz.dict +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4550000 diff --git a/libwebp/PaxHeaders.X/tests_fuzzer_fuzz_utils.h b/libwebp/PaxHeaders.X/tests_fuzzer_fuzz_utils.h deleted file mode 100644 index 6e409fbd..00000000 --- a/libwebp/PaxHeaders.X/tests_fuzzer_fuzz_utils.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4550000 diff --git a/libwebp/PaxHeaders.X/tests_fuzzer_huffman_fuzzer.c b/libwebp/PaxHeaders.X/tests_fuzzer_huffman_fuzzer.c deleted file mode 100644 index 6e409fbd..00000000 --- a/libwebp/PaxHeaders.X/tests_fuzzer_huffman_fuzzer.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4550000 diff --git a/libwebp/PaxHeaders.X/tests_fuzzer_img_alpha.h b/libwebp/PaxHeaders.X/tests_fuzzer_img_alpha.h deleted file mode 100644 index 6e409fbd..00000000 --- a/libwebp/PaxHeaders.X/tests_fuzzer_img_alpha.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4550000 diff --git a/libwebp/PaxHeaders.X/tests_fuzzer_img_grid.h b/libwebp/PaxHeaders.X/tests_fuzzer_img_grid.h deleted file mode 100644 index b8d1b7b0..00000000 --- a/libwebp/PaxHeaders.X/tests_fuzzer_img_grid.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4570000 diff --git a/libwebp/PaxHeaders.X/tests_fuzzer_img_peak.h b/libwebp/PaxHeaders.X/tests_fuzzer_img_peak.h deleted file mode 100644 index 6f162637..00000000 --- a/libwebp/PaxHeaders.X/tests_fuzzer_img_peak.h +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4580000 diff --git a/libwebp/PaxHeaders.X/tests_fuzzer_makefile.unix b/libwebp/PaxHeaders.X/tests_fuzzer_makefile.unix deleted file mode 100644 index 4e8741d8..00000000 --- a/libwebp/PaxHeaders.X/tests_fuzzer_makefile.unix +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4690000 diff --git a/libwebp/PaxHeaders.X/tests_fuzzer_mux_demux_api_fuzzer.c b/libwebp/PaxHeaders.X/tests_fuzzer_mux_demux_api_fuzzer.c deleted file mode 100644 index 4e8741d8..00000000 --- a/libwebp/PaxHeaders.X/tests_fuzzer_mux_demux_api_fuzzer.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4690000 diff --git a/libwebp/PaxHeaders.X/tests_fuzzer_simple_api_fuzzer.c b/libwebp/PaxHeaders.X/tests_fuzzer_simple_api_fuzzer.c deleted file mode 100644 index 79f188db..00000000 --- a/libwebp/PaxHeaders.X/tests_fuzzer_simple_api_fuzzer.c +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4700000 diff --git a/libwebp/PaxHeaders.X/webp_js_ b/libwebp/PaxHeaders.X/webp_js_ deleted file mode 100644 index 79f188db..00000000 --- a/libwebp/PaxHeaders.X/webp_js_ +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4700000 diff --git a/libwebp/PaxHeaders.X/webp_js_README.md b/libwebp/PaxHeaders.X/webp_js_README.md deleted file mode 100644 index 79f188db..00000000 --- a/libwebp/PaxHeaders.X/webp_js_README.md +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4700000 diff --git a/libwebp/PaxHeaders.X/webp_js_index.html b/libwebp/PaxHeaders.X/webp_js_index.html deleted file mode 100644 index 79f188db..00000000 --- a/libwebp/PaxHeaders.X/webp_js_index.html +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4700000 diff --git a/libwebp/PaxHeaders.X/webp_js_index_wasm.html b/libwebp/PaxHeaders.X/webp_js_index_wasm.html deleted file mode 100644 index 79f188db..00000000 --- a/libwebp/PaxHeaders.X/webp_js_index_wasm.html +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4700000 diff --git a/libwebp/PaxHeaders.X/webp_js_test_webp_js.webp b/libwebp/PaxHeaders.X/webp_js_test_webp_js.webp deleted file mode 100644 index 8de3afa4..00000000 --- a/libwebp/PaxHeaders.X/webp_js_test_webp_js.webp +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.4720000 diff --git a/libwebp/PaxHeaders.X/webp_js_test_webp_wasm.webp b/libwebp/PaxHeaders.X/webp_js_test_webp_wasm.webp deleted file mode 100644 index c8c8b577..00000000 --- a/libwebp/PaxHeaders.X/webp_js_test_webp_wasm.webp +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.5280000 diff --git a/libwebp/PaxHeaders.X/xcframeworkbuild.sh b/libwebp/PaxHeaders.X/xcframeworkbuild.sh deleted file mode 100644 index 0591f921..00000000 --- a/libwebp/PaxHeaders.X/xcframeworkbuild.sh +++ /dev/null @@ -1 +0,0 @@ -28 mtime=1710028689.5820000 diff --git a/libwebp/README.md b/libwebp/README.md index a9f2c0e1..90f2b059 100644 --- a/libwebp/README.md +++ b/libwebp/README.md @@ -7,7 +7,7 @@ \__\__/\____/\_____/__/ ____ ___ / _/ / \ \ / _ \/ _/ / \_/ / / \ \ __/ \__ - \____/____/\_____/_____/____/v1.3.2 + \____/____/\_____/_____/____/v1.6.0 ``` WebP codec is a library to encode and decode images in WebP format. This package @@ -42,7 +42,8 @@ See the [APIs documentation](doc/api.md), and API usage examples in the ## Bugs -Please report all bugs to the issue tracker: https://bugs.chromium.org/p/webp +Please report all bugs to the [issue tracker](https://issues.webmproject.org). +For security reports, select 'Security report' from the Template dropdown. Patches welcome! See [how to contribute](CONTRIBUTING.md). diff --git a/libwebp/VERSION.imported b/libwebp/VERSION.imported new file mode 100644 index 00000000..9f617e55 --- /dev/null +++ b/libwebp/VERSION.imported @@ -0,0 +1,54 @@ +libwebp vendored import - provenance record +============================================ + +upstream: https://github.com/webmproject/libwebp +version: 1.6.0 (stable, announced 2025-06-30) +source tarball: libwebp-1.6.0.tar.gz (GitHub tag v1.6.0 archive) +tarball sha256: 93a852c2b3efafee3723efd4636de855b46f9fe1efddd607e1f42f60fc8f2136 +imported: 2026-09-04 (voidImageViewer_PLUS rc.5, user-approved D1) + +what is compiled (vs2019/vs2026 vcxproj, 66 ClCompile entries): + the upstream "decode only" file set (libwebpdecoder semantics) as + classified by libwebp 1.6.0's own build files: + src/dec (10) + src/demux (2) + src/dsp decode set (44) + + src/utils decode set (10) + upgrade audit against the previous 1.3.2 import: every previously + compiled decode file still exists unchanged in name; the only new + file is src/dsp/lossless_avx2.c (AVX2 lossless prediction, enabled + on MSVC via the WEBP_MSC_AVX2 path in src/dsp/cpu.h). + +IMPORTANT correction to the original pruning plan: + the plan assumed the old 89-file project list compiled no encoder + code (because no file lived under src/enc/). in fact the old list + compiled 24 encoder-side files living in src/dsp and src/utils + (cost*.c, enc*.c, lossless_enc*.c, ssim*.c, bit_writer_utils.c, + huffman_encode_utils.c, quant_levels_utils.c) - encoder code that + shipped inside voidImageViewer.exe and #included src/enc headers. + this import switches to the upstream decode-only set, so the + encoder is now genuinely absent from both the tree and the binary + (the attack-surface reduction the plan actually wanted). + +pruned at import (not present in this tree at all): + webp_js/ examples/ imageio/ swig/ man/ gradle/ (+ gradle + top-level files) infra/ extras/ sharpyuv/ src/enc/ src/mux/ + and the 24 encoder-side .c files inside src/dsp and src/utils + listed above. the decode set was verified self-contained by an + include-closure scan (no kept file references anything pruned). + +post-import sweep (rc.5 carpet review, 2026-09-05): the first + pruning pass missed files that only exist in 1.6.0 (they were not + in the old 1.3.2 project list the pass was diffed against): + src/dsp/lossless_enc_avx2.c (new-in-1.6.0 encoder file) and the + three encoder-side headers src/utils/{bit_writer_utils.h, + huffman_encode_utils.h, quant_levels_utils.h} were still on disk + (and the headers still listed as ClInclude). none of them were + compiled or referenced - the shipped binary was already + encoder-free - but the tree was not. they are now removed, so the + tree matches this record exactly: zero encoder files anywhere. + +kept: tests/ doc/ cmake/ src/{dec,demux,dsp,utils,webp} with + all upstream headers COPYING PATENTS AUTHORS ChangeLog NEWS + README.md and the top-level build files (CMakeLists.txt, + Makefile.am, Makefile.vc, Android.mk, ...) + +license: BSD-3-Clause (COPYING); the WebP patent grant is in PATENTS. diff --git a/libwebp/autogen.sh b/libwebp/autogen.sh deleted file mode 100644 index 8ef9babb..00000000 --- a/libwebp/autogen.sh +++ /dev/null @@ -1,2 +0,0 @@ -#! /bin/sh -e -exec autoreconf -fi diff --git a/libwebp/build.gradle b/libwebp/build.gradle deleted file mode 100644 index 14ceebf7..00000000 --- a/libwebp/build.gradle +++ /dev/null @@ -1,444 +0,0 @@ -// Define dependencies. -buildscript { - repositories { - maven { - url "https://jcenter.bintray.com" - } - } - dependencies { - classpath "com.android.tools.build:gradle:${ANDROID_GRADLE_PLUGIN_VERSION}" - } -} - -// Define versions in the project. -project.ext { - buildToolsVersion = "${BUILD_TOOLS_VERSION}" - compileSdkVersion = COMPILE_SDK_VERSION.toInteger() -} - -// Core libraries and executables. -apply plugin: "c" -def NEON -model { - buildTypes { - debug - release - } - platforms { - arm { - architecture "arm" - } - arm64 { - architecture "arm64" - } - x86 { - architecture "x86" - } - x64 { - architecture "x86_64" - } - mips32r2 - mips32r5 - mips64r6 - } - toolChains { - gcc(Gcc) { - target("mips32r2") { - cCompiler.args "-mips32r2" - } - target("mips32r5") { - cCompiler.args "-mips32r5" - } - target("mips64r6") { - cCompiler.args "-mips64r6" - } - } - } - binaries { - all { - if (toolChain in Gcc) { - cCompiler.args "-fPIC" - cCompiler.args "-Wall" - cCompiler.define "ANDROID" - cCompiler.define "HAVE_MALLOC_H" - } - // Optimizations. - if (buildType == buildTypes.release) { - if (toolChain in Gcc) { - cCompiler.args "-finline-functions" - cCompiler.args "-ffast-math" - cCompiler.args "-ffunction-sections" - cCompiler.args "-fdata-sections" - } - if (toolChain in Clang) { - cCompiler.args "-frename-registers -s" - } - } - // mips32 fails to build with clang from r14b - // https://bugs.chromium.org/p/webp/issues/detail?id=343 - if (toolChain in Clang) { - if (getTargetPlatform() == "mips") { - cCompiler.args "-no-integrated-as" - } - } - // Check for NEON usage. - if (getTargetPlatform() == "arm") { - NEON = "c.neon" - cCompiler.define "HAVE_CPU_FEATURES_H" - } else { - NEON = "c" - } - - cCompiler.args "-I" + file(".").absolutePath - } - // Link to pthread for shared libraries. - withType(SharedLibraryBinarySpec) { - if (toolChain in Gcc) { - cCompiler.define "HAVE_PTHREAD" - cCompiler.define "WEBP_USE_THREAD" - linker.args "-pthread" - } - } - } - components { - webp(NativeLibrarySpec) { - sources { - c { - source { - srcDir "sharpyuv" - include "sharpyuv.c" - include "sharpyuv_cpu.c" - include "sharpyuv_csp.c" - include "sharpyuv_dsp.c" - include "sharpyuv_gamma.c" - include "sharpyuv_neon.c" - include "sharpyuv_sse2.c" - srcDir "src/dec" - include "alpha_dec.c" - include "buffer_dec.c" - include "frame_dec.c" - include "idec_dec.c" - include "io_dec.c" - include "quant_dec.c" - include "tree_dec.c" - include "vp8_dec.c" - include "vp8l_dec.c" - include "webp_dec.c" - srcDir "src/dsp" - include "alpha_processing.c" - include "alpha_processing_mips_dsp_r2.c" - include "alpha_processing_neon.$NEON" - include "alpha_processing_sse2.c" - include "alpha_processing_sse41.c" - include "cpu.c" - include "dec.c" - include "dec_clip_tables.c" - include "dec_mips32.c" - include "dec_mips_dsp_r2.c" - include "dec_msa.c" - include "dec_neon.$NEON" - include "dec_sse2.c" - include "dec_sse41.c" - include "filters.c" - include "filters_mips_dsp_r2.c" - include "filters_msa.c" - include "filters_neon.$NEON" - include "filters_sse2.c" - include "lossless.c" - include "lossless_mips_dsp_r2.c" - include "lossless_msa.c" - include "lossless_neon.$NEON" - include "lossless_sse2.c" - include "lossless_sse41.c" - include "rescaler.c" - include "rescaler_mips32.c" - include "rescaler_mips_dsp_r2.c" - include "rescaler_msa.c" - include "rescaler_neon.$NEON" - include "rescaler_sse2.c" - include "upsampling.c" - include "upsampling_mips_dsp_r2.c" - include "upsampling_msa.c" - include "upsampling_neon.$NEON" - include "upsampling_sse2.c" - include "upsampling_sse41.c" - include "yuv.c" - include "yuv_mips32.c" - include "yuv_mips_dsp_r2.c" - include "yuv_neon.$NEON" - include "yuv_sse2.c" - include "yuv_sse41.c" - srcDir "src/utils" - include "bit_reader_utils.c" - include "color_cache_utils.c" - include "filters_utils.c" - include "huffman_utils.c" - include "palette.c" - include "quant_levels_dec_utils.c" - include "random_utils.c" - include "rescaler_utils.c" - include "thread_utils.c" - include "utils.c" - srcDir "src/dsp" - include "cost.c" - include "cost_mips32.c" - include "cost_mips_dsp_r2.c" - include "cost_neon.$NEON" - include "cost_sse2.c" - include "enc.c" - include "enc_mips32.c" - include "enc_mips_dsp_r2.c" - include "enc_msa.c" - include "enc_neon.$NEON" - include "enc_sse2.c" - include "enc_sse41.c" - include "lossless_enc.c" - include "lossless_enc_mips32.c" - include "lossless_enc_mips_dsp_r2.c" - include "lossless_enc_msa.c" - include "lossless_enc_neon.$NEON" - include "lossless_enc_sse2.c" - include "lossless_enc_sse41.c" - include "ssim.c" - include "ssim_sse2.c" - srcDir "src/enc" - include "alpha_enc.c" - include "analysis_enc.c" - include "backward_references_cost_enc.c" - include "backward_references_enc.c" - include "config_enc.c" - include "cost_enc.c" - include "filter_enc.c" - include "frame_enc.c" - include "histogram_enc.c" - include "iterator_enc.c" - include "near_lossless_enc.c" - include "picture_enc.c" - include "picture_csp_enc.c" - include "picture_psnr_enc.c" - include "picture_rescale_enc.c" - include "picture_tools_enc.c" - include "predictor_enc.c" - include "quant_enc.c" - include "syntax_enc.c" - include "token_enc.c" - include "tree_enc.c" - include "vp8l_enc.c" - include "webp_enc.c" - srcDir "src/utils" - include "bit_writer_utils.c" - include "huffman_encode_utils.c" - include "quant_levels_utils.c" - } - exportedHeaders { - srcDir "src" - } - } - } - } - - webpdemux(NativeLibrarySpec) { - sources { - c { - source { - srcDir "src/demux" - include "anim_decode.c" - include "demux.c" - } - } - } - } - - webpmux(NativeLibrarySpec) { - sources { - c { - source { - srcDir "src/mux/" - include "anim_encode.c" - include "muxedit.c" - include "muxinternal.c" - include "muxread.c" - } - } - } - } - - // Executables from examples. - example_util(NativeLibrarySpec) { - binaries { - all { - lib library: "webp", linkage: "static" - } - } - sources { - c { - source { - srcDir "./examples" - include "example_util.c" - } - } - } - } - - imageio_util(NativeLibrarySpec) { - binaries { - all { - lib library: "webp", linkage: "static" - } - } - sources { - c { - source { - srcDir "./imageio" - include "imageio_util.c" - } - } - } - } - - imagedec(NativeLibrarySpec) { - binaries { - all { - lib library: "webpdemux", linkage: "static" - lib library: "webp", linkage: "static" - } - } - sources { - c { - source { - srcDir "./imageio" - include "image_dec.c" - include "jpegdec.c" - include "metadata.c" - include "pngdec.c" - include "pnmdec.c" - include "tiffdec.c" - include "webpdec.c" - } - } - } - } - - imageenc(NativeLibrarySpec) { - binaries { - all { - lib library: "webp", linkage: "static" - lib library: "imageio_util", linkage: "static" - } - } - sources { - c { - source { - srcDir "./imageio" - include "image_enc.c" - } - } - } - } - - cwebp(NativeExecutableSpec) { - binaries { - all { - lib library: "example_util", linkage: "static" - lib library: "imagedec", linkage: "static" - lib library: "imageio_util", linkage: "static" - lib library: "webpdemux", linkage: "static" - lib library: "webp", linkage: "static" - } - } - sources { - c { - source { - srcDir "./examples" - include "cwebp.c" - } - } - } - } - - dwebp(NativeExecutableSpec) { - binaries { - all { - lib library: "example_util", linkage: "static" - lib library: "imagedec", linkage: "static" - lib library: "imageenc", linkage: "static" - lib library: "imageio_util", linkage: "static" - lib library: "webpdemux", linkage: "static" - lib library: "webp" - } - } - sources { - c { - source { - srcDir "./examples" - include "dwebp.c" - } - } - } - } - - webpmux_example(NativeExecutableSpec) { - binaries { - all { - lib library: "example_util", linkage: "static" - lib library: "imageio_util", linkage: "static" - lib library: "webpmux", linkage: "static" - lib library: "webp" - } - } - sources { - c { - source { - srcDir "./examples" - include "webpmux.c" - } - } - } - } - - img2webp_example(NativeExecutableSpec) { - binaries { - all { - lib library: "example_util", linkage: "static" - lib library: "imagedec", linkage: "static" - lib library: "imageio_util", linkage: "static" - lib library: "webpmux", linkage: "static" - lib library: "webpdemux", linkage: "static" - lib library: "webp" - } - } - sources { - c { - source { - srcDir "./examples" - include "img2webp.c" - } - } - } - } - - webpinfo_example(NativeExecutableSpec) { - binaries { - all { - lib library: "example_util", linkage: "static" - lib library: "imageio_util", linkage: "static" - lib library: "webp" - } - } - sources { - c { - source { - srcDir "./examples" - include "webpinfo.c" - } - } - } - } - } - tasks { - // Task to test all possible configurations. - buildAllExecutables(Task) { - dependsOn $.binaries.findAll { it.buildable } - } - } -} diff --git a/libwebp/cmake/WebPConfig.cmake.in b/libwebp/cmake/WebPConfig.cmake.in deleted file mode 100644 index a0d721f3..00000000 --- a/libwebp/cmake/WebPConfig.cmake.in +++ /dev/null @@ -1,19 +0,0 @@ -set(WebP_VERSION @PROJECT_VERSION@) -set(WEBP_VERSION ${WebP_VERSION}) - -@PACKAGE_INIT@ - -if(@WEBP_USE_THREAD@) - include(CMakeFindDependencyMacro) - find_dependency(Threads REQUIRED) -endif() - -include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") - -set_and_check(WebP_INCLUDE_DIR "@PACKAGE_CMAKE_INSTALL_INCLUDEDIR@") -set(WebP_INCLUDE_DIRS ${WebP_INCLUDE_DIR}) -set(WEBP_INCLUDE_DIRS ${WebP_INCLUDE_DIR}) -set(WebP_LIBRARIES "@INSTALLED_LIBRARIES@") -set(WEBP_LIBRARIES "${WebP_LIBRARIES}") - -check_required_components(WebP) diff --git a/libwebp/cmake/config.h.in b/libwebp/cmake/config.h.in deleted file mode 100644 index fe1c53ad..00000000 --- a/libwebp/cmake/config.h.in +++ /dev/null @@ -1,116 +0,0 @@ -/* Adapted from the autotools src/webp/config.h.in. */ - -/* Define if building universal (internal helper macro) */ -/* TODO: handle properly in CMake */ -#cmakedefine AC_APPLE_UNIVERSAL_BUILD 1 - -/* Set to 1 if __builtin_bswap16 is available */ -#cmakedefine HAVE_BUILTIN_BSWAP16 1 - -/* Set to 1 if __builtin_bswap32 is available */ -#cmakedefine HAVE_BUILTIN_BSWAP32 1 - -/* Set to 1 if __builtin_bswap64 is available */ -#cmakedefine HAVE_BUILTIN_BSWAP64 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_CPU_FEATURES_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_GLUT_GLUT_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_GL_GLUT_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_OPENGL_GLUT_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_SHLWAPI_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_UNISTD_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_WINCODEC_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_WINDOWS_H 1 - -/* Define to the sub-directory in which libtool stores uninstalled libraries. - */ -/* TODO: handle properly in CMake */ -#cmakedefine LT_OBJDIR "@LT_OBJDIR@" - -/* Name of package */ -#cmakedefine PACKAGE "@PROJECT_NAME@" - -/* Define to the address where bug reports for this package should be sent. */ -#cmakedefine PACKAGE_BUGREPORT "@PACKAGE_BUGREPORT@" - -/* Define to the full name of this package. */ -#cmakedefine PACKAGE_NAME "@PACKAGE_NAME@" - -/* Define to the full name and version of this package. */ -#cmakedefine PACKAGE_STRING "@PACKAGE_STRING@" - -/* Define to the one symbol short name of this package. */ -#cmakedefine PACKAGE_TARNAME "@PACKAGE_TARNAME@" - -/* Define to the home page for this package. */ -#cmakedefine PACKAGE_URL "@PACKAGE_URL@" - -/* Define to the version of this package. */ -#cmakedefine PACKAGE_VERSION "@PACKAGE_VERSION@" - -/* Version number of package */ -#cmakedefine VERSION "@VERSION@" - -/* Set to 1 if GIF library is installed */ -#cmakedefine WEBP_HAVE_GIF 1 - -/* Set to 1 if OpenGL is supported */ -#cmakedefine WEBP_HAVE_GL 1 - -/* Set to 1 if JPEG library is installed */ -#cmakedefine WEBP_HAVE_JPEG 1 - -/* Set to 1 if NEON is supported */ -#cmakedefine WEBP_HAVE_NEON - -/* Set to 1 if runtime detection of NEON is enabled */ -/* TODO: handle properly in CMake */ -#cmakedefine WEBP_HAVE_NEON_RTCD - -/* Set to 1 if PNG library is installed */ -#cmakedefine WEBP_HAVE_PNG 1 - -/* Set to 1 if SDL library is installed */ -#cmakedefine WEBP_HAVE_SDL 1 - -/* Set to 1 if SSE2 is supported */ -#cmakedefine WEBP_HAVE_SSE2 1 - -/* Set to 1 if SSE4.1 is supported */ -#cmakedefine WEBP_HAVE_SSE41 1 - -/* Set to 1 if TIFF library is installed */ -#cmakedefine WEBP_HAVE_TIFF 1 - -/* Enable near lossless encoding */ -#cmakedefine WEBP_NEAR_LOSSLESS 1 - -/* Undefine this to disable thread support. */ -#cmakedefine WEBP_USE_THREAD 1 - -/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most - significant byte first (like Motorola and SPARC, unlike Intel). */ -#if defined AC_APPLE_UNIVERSAL_BUILD -# if defined __BIG_ENDIAN__ -# define WORDS_BIGENDIAN 1 -# endif -#else -# ifndef WORDS_BIGENDIAN -# undef WORDS_BIGENDIAN -# endif -#endif diff --git a/libwebp/cmake/cpu.cmake b/libwebp/cmake/cpu.cmake deleted file mode 100644 index 040c5247..00000000 --- a/libwebp/cmake/cpu.cmake +++ /dev/null @@ -1,160 +0,0 @@ -# Copyright (c) 2021 Google LLC. -# -# Use of this source code is governed by a BSD-style license -# that can be found in the LICENSE file in the root of the source -# tree. An additional intellectual property rights grant can be found -# in the file PATENTS. All contributing project authors may -# be found in the AUTHORS file in the root of the source tree. - -# Check for SIMD extensions. -include(CMakePushCheckState) - -function(webp_check_compiler_flag WEBP_SIMD_FLAG ENABLE_SIMD) - if(NOT ENABLE_SIMD) - message(STATUS "Disabling ${WEBP_SIMD_FLAG} optimization.") - set(WEBP_HAVE_${WEBP_SIMD_FLAG} 0 PARENT_SCOPE) - return() - endif() - unset(WEBP_HAVE_FLAG_${WEBP_SIMD_FLAG} CACHE) - cmake_push_check_state() - set(CMAKE_REQUIRED_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}) - check_c_source_compiles( - " - #include \"${CMAKE_CURRENT_LIST_DIR}/../src/dsp/dsp.h\" - int main(void) { - #if !defined(WEBP_USE_${WEBP_SIMD_FLAG}) - this is not valid code - #endif - return 0; - } - " - WEBP_HAVE_FLAG_${WEBP_SIMD_FLAG}) - cmake_pop_check_state() - if(WEBP_HAVE_FLAG_${WEBP_SIMD_FLAG}) - set(WEBP_HAVE_${WEBP_SIMD_FLAG} 1 PARENT_SCOPE) - else() - set(WEBP_HAVE_${WEBP_SIMD_FLAG} 0 PARENT_SCOPE) - endif() -endfunction() - -# those are included in the names of WEBP_USE_* in c++ code. -set(WEBP_SIMD_FLAGS "SSE41;SSE2;MIPS32;MIPS_DSP_R2;NEON;MSA") -set(WEBP_SIMD_FILE_EXTENSIONS - "_sse41.c;_sse2.c;_mips32.c;_mips_dsp_r2.c;_neon.c;_msa.c") -if(MSVC AND CMAKE_C_COMPILER_ID STREQUAL "MSVC") - # With at least Visual Studio 12 (2013)+ /arch is not necessary to build SSE2 - # or SSE4 code unless a lesser /arch is forced. MSVC does not have a SSE4 - # flag, but an AVX one. Using that with SSE4 code risks generating illegal - # instructions when used on machines with SSE4 only. The flags are left for - # older (untested) versions to avoid any potential compatibility issues. - if(MSVC_VERSION GREATER_EQUAL 1800 AND NOT CMAKE_C_FLAGS MATCHES "/arch:") - set(SIMD_ENABLE_FLAGS) - else() - set(SIMD_ENABLE_FLAGS "/arch:AVX;/arch:SSE2;;;;") - endif() - set(SIMD_DISABLE_FLAGS) -else() - set(SIMD_ENABLE_FLAGS "-msse4.1;-msse2;-mips32;-mdspr2;-mfpu=neon;-mmsa") - set(SIMD_DISABLE_FLAGS "-mno-sse4.1;-mno-sse2;;-mno-dspr2;;-mno-msa") -endif() - -set(WEBP_SIMD_FILES_TO_INCLUDE) -set(WEBP_SIMD_FLAGS_TO_INCLUDE) - -if(ANDROID AND ANDROID_ABI) - if(${ANDROID_ABI} STREQUAL "armeabi-v7a") - # This is because Android studio uses the configuration "-march=armv7-a - # -mfloat-abi=softfp -mfpu=vfpv3-d16" that does not trigger neon - # optimizations but should (as this configuration does not exist anymore). - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpu=neon ") - endif() -endif() - -list(LENGTH WEBP_SIMD_FLAGS WEBP_SIMD_FLAGS_LENGTH) -math(EXPR WEBP_SIMD_FLAGS_RANGE "${WEBP_SIMD_FLAGS_LENGTH} - 1") - -foreach(I_SIMD RANGE ${WEBP_SIMD_FLAGS_RANGE}) - # With Emscripten 2.0.9 -msimd128 -mfpu=neon will enable NEON, but the source - # will fail to compile. - if(EMSCRIPTEN AND ${I_SIMD} GREATER_EQUAL 2) - break() - endif() - - list(GET WEBP_SIMD_FLAGS ${I_SIMD} WEBP_SIMD_FLAG) - - # First try with no extra flag added as the compiler might have default flags - # (especially on Android). - unset(WEBP_HAVE_${WEBP_SIMD_FLAG} CACHE) - cmake_push_check_state() - set(CMAKE_REQUIRED_FLAGS) - webp_check_compiler_flag(${WEBP_SIMD_FLAG} ${WEBP_ENABLE_SIMD}) - if(NOT WEBP_HAVE_${WEBP_SIMD_FLAG}) - list(GET SIMD_ENABLE_FLAGS ${I_SIMD} SIMD_COMPILE_FLAG) - if(EMSCRIPTEN) - set(SIMD_COMPILE_FLAG "-msimd128 ${SIMD_COMPILE_FLAG}") - endif() - set(CMAKE_REQUIRED_FLAGS ${SIMD_COMPILE_FLAG}) - webp_check_compiler_flag(${WEBP_SIMD_FLAG} ${WEBP_ENABLE_SIMD}) - else() - if(MSVC AND SIMD_ENABLE_FLAGS) - # The detection for SSE2/SSE4 support under MSVC is based on the compiler - # version so e.g., clang-cl will require flags to enable the assembly. - list(GET SIMD_ENABLE_FLAGS ${I_SIMD} SIMD_COMPILE_FLAG) - else() - set(SIMD_COMPILE_FLAG " ") - endif() - endif() - # Check which files we should include or not. - list(GET WEBP_SIMD_FILE_EXTENSIONS ${I_SIMD} WEBP_SIMD_FILE_EXTENSION) - file(GLOB SIMD_FILES - "${CMAKE_CURRENT_LIST_DIR}/../sharpyuv/*${WEBP_SIMD_FILE_EXTENSION}" - "${CMAKE_CURRENT_LIST_DIR}/../src/dsp/*${WEBP_SIMD_FILE_EXTENSION}") - if(WEBP_HAVE_${WEBP_SIMD_FLAG}) - # Memorize the file and flags. - foreach(FILE ${SIMD_FILES}) - list(APPEND WEBP_SIMD_FILES_TO_INCLUDE ${FILE}) - list(APPEND WEBP_SIMD_FLAGS_TO_INCLUDE ${SIMD_COMPILE_FLAG}) - endforeach() - else() - # Remove the file from the list. - foreach(FILE ${SIMD_FILES}) - list(APPEND WEBP_SIMD_FILES_NOT_TO_INCLUDE ${FILE}) - endforeach() - # Explicitly disable SIMD. - if(SIMD_DISABLE_FLAGS) - list(GET SIMD_DISABLE_FLAGS ${I_SIMD} SIMD_COMPILE_FLAG) - include(CheckCCompilerFlag) - if(SIMD_COMPILE_FLAG) - # Between 3.17.0 and 3.18.2 check_cxx_compiler_flag() sets a normal - # variable at parent scope while check_cxx_source_compiles() continues - # to set an internal cache variable, so we unset both to avoid the - # failure / success state persisting between checks. See - # https://gitlab.kitware.com/cmake/cmake/-/issues/21207. - unset(HAS_COMPILE_FLAG) - unset(HAS_COMPILE_FLAG CACHE) - check_c_compiler_flag(${SIMD_COMPILE_FLAG} HAS_COMPILE_FLAG) - if(HAS_COMPILE_FLAG) - # Do one more check for Clang to circumvent CMake issue 13194. - if(COMMAND check_compiler_flag_common_patterns) - # Only in CMake 3.0 and above. - check_compiler_flag_common_patterns(COMMON_PATTERNS) - else() - set(COMMON_PATTERNS) - endif() - set(CMAKE_REQUIRED_DEFINITIONS ${SIMD_COMPILE_FLAG}) - check_c_source_compiles( - "int main(void) {return 0;}" FLAG_${SIMD_COMPILE_FLAG} FAIL_REGEX - "warning: argument unused during compilation:" ${COMMON_PATTERNS}) - if(NOT FLAG_${SIMD_COMPILE_FLAG}) - unset(HAS_COMPILE_FLAG) - unset(HAS_COMPILE_FLAG CACHE) - endif() - endif() - if(HAS_COMPILE_FLAG) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${SIMD_COMPILE_FLAG}") - endif() - endif() - endif() - endif() - cmake_pop_check_state() -endforeach() diff --git a/libwebp/cmake/deps.cmake b/libwebp/cmake/deps.cmake deleted file mode 100644 index 0760ba92..00000000 --- a/libwebp/cmake/deps.cmake +++ /dev/null @@ -1,172 +0,0 @@ -# Copyright (c) 2021 Google LLC. -# -# Use of this source code is governed by a BSD-style license -# that can be found in the LICENSE file in the root of the source -# tree. An additional intellectual property rights grant can be found -# in the file PATENTS. All contributing project authors may -# be found in the AUTHORS file in the root of the source tree. - -# Generate the config.h to compile with specific intrinsics / libs. - -# Check for compiler options. -include(CheckCSourceCompiles) -check_c_source_compiles( - " - int main(void) { - (void)__builtin_bswap16(0); - return 0; - } - " - HAVE_BUILTIN_BSWAP16) -check_c_source_compiles( - " - int main(void) { - (void)__builtin_bswap32(0); - return 0; - } - " - HAVE_BUILTIN_BSWAP32) -check_c_source_compiles( - " - int main(void) { - (void)__builtin_bswap64(0); - return 0; - } - " - HAVE_BUILTIN_BSWAP64) - -# Check for libraries. -if(WEBP_USE_THREAD) - find_package(Threads) - if(Threads_FOUND) - # work around cmake bug on QNX (https://cmake.org/Bug/view.php?id=11333) - if(CMAKE_USE_PTHREADS_INIT AND NOT CMAKE_SYSTEM_NAME STREQUAL "QNX") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread") - endif() - list(APPEND WEBP_DEP_LIBRARIES Threads::Threads) - endif() - set(WEBP_USE_THREAD ${Threads_FOUND}) -endif() - -# TODO: this seems unused, check with autotools. -set(LT_OBJDIR ".libs/") - -# Only useful for vwebp, so useless for now. -find_package(OpenGL) -set(WEBP_HAVE_GL ${OPENGL_FOUND}) - -# Check if we need to link to the C math library. We do not look for it as it is -# not found when cross-compiling, while it is here. -check_c_source_compiles( - " - #include - int main(int argc, char** argv) { - return (int)pow(argc, 2.5); - } - " - HAVE_MATH_LIBRARY) -if(NOT HAVE_MATH_LIBRARY) - message(STATUS "Adding -lm flag.") - list(APPEND SHARPYUV_DEP_LIBRARIES m) - list(APPEND WEBP_DEP_LIBRARIES m) -endif() - -# Find the standard image libraries. -set(WEBP_DEP_IMG_LIBRARIES) -set(WEBP_DEP_IMG_INCLUDE_DIRS) -if(WEBP_FIND_IMG_LIBS) - foreach(I_LIB PNG JPEG TIFF) - # Disable tiff when compiling in static mode as it is failing on Ubuntu. - if(WEBP_LINK_STATIC AND ${I_LIB} STREQUAL "TIFF") - message(STATUS "TIFF is disabled when statically linking.") - continue() - endif() - find_package(${I_LIB}) - set(WEBP_HAVE_${I_LIB} ${${I_LIB}_FOUND}) - if(${I_LIB}_FOUND) - list(APPEND WEBP_DEP_IMG_LIBRARIES ${${I_LIB}_LIBRARIES}) - list(APPEND WEBP_DEP_IMG_INCLUDE_DIRS ${${I_LIB}_INCLUDE_DIR} - ${${I_LIB}_INCLUDE_DIRS}) - endif() - endforeach() - if(WEBP_DEP_IMG_INCLUDE_DIRS) - list(REMOVE_DUPLICATES WEBP_DEP_IMG_INCLUDE_DIRS) - endif() - - # GIF detection, gifdec isn't part of the imageio lib. - include(CMakePushCheckState) - set(WEBP_DEP_GIF_LIBRARIES) - set(WEBP_DEP_GIF_INCLUDE_DIRS) - find_package(GIF) - set(WEBP_HAVE_GIF ${GIF_FOUND}) - if(GIF_FOUND) - # GIF find_package only locates the header and library, it doesn't fail - # compile tests when detecting the version, but falls back to 3 (as of at - # least cmake 3.7.2). Make sure the library links to avoid incorrect - # detection when cross compiling. - cmake_push_check_state() - set(CMAKE_REQUIRED_LIBRARIES ${GIF_LIBRARIES}) - set(CMAKE_REQUIRED_INCLUDES ${GIF_INCLUDE_DIR}) - check_c_source_compiles( - " - #include - int main(void) { - (void)DGifOpenFileHandle; - return 0; - } - " - GIF_COMPILES) - cmake_pop_check_state() - if(GIF_COMPILES) - list(APPEND WEBP_DEP_GIF_LIBRARIES ${GIF_LIBRARIES}) - list(APPEND WEBP_DEP_GIF_INCLUDE_DIRS ${GIF_INCLUDE_DIR}) - else() - unset(GIF_FOUND) - endif() - endif() -endif() - -# Check for specific headers. -include(CheckIncludeFiles) -check_include_files(GLUT/glut.h HAVE_GLUT_GLUT_H) -check_include_files(GL/glut.h HAVE_GL_GLUT_H) -check_include_files(OpenGL/glut.h HAVE_OPENGL_GLUT_H) -check_include_files(shlwapi.h HAVE_SHLWAPI_H) -check_include_files(unistd.h HAVE_UNISTD_H) -check_include_files(wincodec.h HAVE_WINCODEC_H) -check_include_files(windows.h HAVE_WINDOWS_H) - -# Windows specifics -if(HAVE_WINCODEC_H) - list(APPEND WEBP_DEP_LIBRARIES shlwapi ole32 windowscodecs) -endif() - -# Check for SIMD extensions. -include(${CMAKE_CURRENT_LIST_DIR}/cpu.cmake) - -# Define extra info. -set(PACKAGE ${PROJECT_NAME}) -set(PACKAGE_NAME ${PROJECT_NAME}) - -# Read from configure.ac. -file(READ ${CMAKE_CURRENT_SOURCE_DIR}/configure.ac CONFIGURE_AC) -string(REGEX MATCHALL "\\[([0-9a-z\\.:/]*)\\]" CONFIGURE_AC_PACKAGE_INFO - ${CONFIGURE_AC}) -function(strip_bracket VAR) - string(LENGTH ${${VAR}} TMP_LEN) - math(EXPR TMP_LEN ${TMP_LEN}-2) - string(SUBSTRING ${${VAR}} 1 ${TMP_LEN} TMP_SUB) - set(${VAR} ${TMP_SUB} PARENT_SCOPE) -endfunction() - -list(GET CONFIGURE_AC_PACKAGE_INFO 1 PACKAGE_VERSION) -strip_bracket(PACKAGE_VERSION) -list(GET CONFIGURE_AC_PACKAGE_INFO 2 PACKAGE_BUGREPORT) -strip_bracket(PACKAGE_BUGREPORT) -list(GET CONFIGURE_AC_PACKAGE_INFO 3 PACKAGE_URL) -strip_bracket(PACKAGE_URL) - -# Build more info. -set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") -set(PACKAGE_TARNAME ${PACKAGE_NAME}) -set(VERSION ${PACKAGE_VERSION}) diff --git a/libwebp/codereview.settings b/libwebp/codereview.settings deleted file mode 100644 index ccba2eee..00000000 --- a/libwebp/codereview.settings +++ /dev/null @@ -1,4 +0,0 @@ -# This file is used by git cl to get repository specific information. -GERRIT_HOST: True -CODE_REVIEW_SERVER: chromium-review.googlesource.com -GERRIT_SQUASH_UPLOADS: False diff --git a/libwebp/configure.ac b/libwebp/configure.ac index 53753a67..a9a82a04 100644 --- a/libwebp/configure.ac +++ b/libwebp/configure.ac @@ -1,5 +1,5 @@ -AC_INIT([libwebp], [1.3.2], - [https://bugs.chromium.org/p/webp],, +AC_INIT([libwebp], [1.6.0], + [https://issues.webmproject.org],, [https://developers.google.com/speed/webp]) AC_CANONICAL_HOST AC_PREREQ([2.60]) @@ -161,6 +161,25 @@ AS_IF([test "$GCC" = "yes" ], [ AC_SUBST([AM_CFLAGS]) dnl === Check for machine specific flags +AC_ARG_ENABLE([avx2], + AS_HELP_STRING([--disable-avx2], + [Disable detection of AVX2 support + @<:@default=auto@:>@])) + +AS_IF([test "x$enable_avx2" != "xno" -a "x$enable_sse4_1" != "xno" + -a "x$enable_sse2" != "xno"], [ + AVX2_FLAGS="$INTRINSICS_CFLAGS $AVX2_FLAGS" + TEST_AND_ADD_CFLAGS([AVX2_FLAGS], [-mavx2]) + AS_IF([test -n "$AVX2_FLAGS"], [ + SAVED_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS $AVX2_FLAGS" + AC_CHECK_HEADER([immintrin.h], + [AC_DEFINE(WEBP_HAVE_AVX2, [1], + [Set to 1 if AVX2 is supported])], + [AVX2_FLAGS=""]) + CFLAGS=$SAVED_CFLAGS]) + AC_SUBST([AVX2_FLAGS])]) + AC_ARG_ENABLE([sse4.1], AS_HELP_STRING([--disable-sse4.1], [Disable detection of SSE4.1 support diff --git a/libwebp/doc/TODO b/libwebp/doc/TODO deleted file mode 100644 index b0a9382d..00000000 --- a/libwebp/doc/TODO +++ /dev/null @@ -1,13 +0,0 @@ -, 20111004 - -* Determine that normative RFC 2119 terms (MUST, SHOULD, MAY, etc.) are - truly intended in all cases where capitalized. - -* Several passages could be made clearer. - - * Overall edit for scope. Portions are phrased as an introduction to - the 0.1.3 RIFF container additions, rather than a holistic guide to - WebP. - - * To wit, suggest s/[spec|specification]/guide/g . "Spec" can imply a - standards track; in any case it's too formal for a work in progress. diff --git a/libwebp/doc/api.md b/libwebp/doc/api.md deleted file mode 100644 index c5d83dbb..00000000 --- a/libwebp/doc/api.md +++ /dev/null @@ -1,385 +0,0 @@ -# WebP APIs - -## Encoding API - -The main encoding functions are available in the header src/webp/encode.h - -The ready-to-use ones are: - -```c -size_t WebPEncodeRGB(const uint8_t* rgb, int width, int height, int stride, - float quality_factor, uint8_t** output); -size_t WebPEncodeBGR(const uint8_t* bgr, int width, int height, int stride, - float quality_factor, uint8_t** output); -size_t WebPEncodeRGBA(const uint8_t* rgba, int width, int height, int stride, - float quality_factor, uint8_t** output); -size_t WebPEncodeBGRA(const uint8_t* bgra, int width, int height, int stride, - float quality_factor, uint8_t** output); -``` - -They will convert raw RGB samples to a WebP data. The only control supplied is -the quality factor. - -There are some variants for using the lossless format: - -```c -size_t WebPEncodeLosslessRGB(const uint8_t* rgb, int width, int height, - int stride, uint8_t** output); -size_t WebPEncodeLosslessBGR(const uint8_t* bgr, int width, int height, - int stride, uint8_t** output); -size_t WebPEncodeLosslessRGBA(const uint8_t* rgba, int width, int height, - int stride, uint8_t** output); -size_t WebPEncodeLosslessBGRA(const uint8_t* bgra, int width, int height, - int stride, uint8_t** output); -``` - -Of course in this case, no quality factor is needed since the compression occurs -without loss of the input values, at the expense of larger output sizes. - -### Advanced encoding API - -A more advanced API is based on the WebPConfig and WebPPicture structures. - -WebPConfig contains the encoding settings and is not tied to a particular -picture. WebPPicture contains input data, on which some WebPConfig will be used -for compression. The encoding flow looks like: - -```c -#include - -// Setup a config, starting form a preset and tuning some additional -// parameters -WebPConfig config; -if (!WebPConfigPreset(&config, WEBP_PRESET_PHOTO, quality_factor)) { - return 0; // version error -} -// ... additional tuning -config.sns_strength = 90; -config.filter_sharpness = 6; -config_error = WebPValidateConfig(&config); // not mandatory, but useful - -// Setup the input data -WebPPicture pic; -if (!WebPPictureInit(&pic)) { - return 0; // version error -} -pic.width = width; -pic.height = height; -// allocated picture of dimension width x height -if (!WebPPictureAlloc(&pic)) { - return 0; // memory error -} -// at this point, 'pic' has been initialized as a container, -// and can receive the Y/U/V samples. -// Alternatively, one could use ready-made import functions like -// WebPPictureImportRGB(), which will take care of memory allocation. -// In any case, past this point, one will have to call -// WebPPictureFree(&pic) to reclaim memory. - -// Set up a byte-output write method. WebPMemoryWriter, for instance. -WebPMemoryWriter wrt; -WebPMemoryWriterInit(&wrt); // initialize 'wrt' - -pic.writer = MyFileWriter; -pic.custom_ptr = my_opaque_structure_to_make_MyFileWriter_work; - -// Compress! -int ok = WebPEncode(&config, &pic); // ok = 0 => error occurred! -WebPPictureFree(&pic); // must be called independently of the 'ok' result. - -// output data should have been handled by the writer at that point. -// -> compressed data is the memory buffer described by wrt.mem / wrt.size - -// deallocate the memory used by compressed data -WebPMemoryWriterClear(&wrt); -``` - -## Decoding API - -This is mainly just one function to call: - -```c -#include "webp/decode.h" -uint8_t* WebPDecodeRGB(const uint8_t* data, size_t data_size, - int* width, int* height); -``` - -Please have a look at the file src/webp/decode.h for the details. There are -variants for decoding in BGR/RGBA/ARGB/BGRA order, along with decoding to raw -Y'CbCr samples. One can also decode the image directly into a pre-allocated -buffer. - -To detect a WebP file and gather the picture's dimensions, the function: - -```c -int WebPGetInfo(const uint8_t* data, size_t data_size, - int* width, int* height); -``` - -is supplied. No decoding is involved when using it. - -### Incremental decoding API - -In the case when data is being progressively transmitted, pictures can still be -incrementally decoded using a slightly more complicated API. Decoder state is -stored into an instance of the WebPIDecoder object. This object can be created -with the purpose of decoding either RGB or Y'CbCr samples. For instance: - -```c -WebPDecBuffer buffer; -WebPInitDecBuffer(&buffer); -buffer.colorspace = MODE_BGR; -... -WebPIDecoder* idec = WebPINewDecoder(&buffer); -``` - -As data is made progressively available, this incremental-decoder object can be -used to decode the picture further. There are two (mutually exclusive) ways to -pass freshly arrived data: - -either by appending the fresh bytes: - -```c -WebPIAppend(idec, fresh_data, size_of_fresh_data); -``` - -or by just mentioning the new size of the transmitted data: - -```c -WebPIUpdate(idec, buffer, size_of_transmitted_buffer); -``` - -Note that 'buffer' can be modified between each call to WebPIUpdate, in -particular when the buffer is resized to accommodate larger data. - -These functions will return the decoding status: either VP8_STATUS_SUSPENDED if -decoding is not finished yet or VP8_STATUS_OK when decoding is done. Any other -status is an error condition. - -The 'idec' object must always be released (even upon an error condition) by -calling: WebPIDelete(idec). - -To retrieve partially decoded picture samples, one must use the corresponding -method: WebPIDecGetRGB or WebPIDecGetYUVA. It will return the last displayable -pixel row. - -Lastly, note that decoding can also be performed into a pre-allocated pixel -buffer. This buffer must be passed when creating a WebPIDecoder, calling -WebPINewRGB() or WebPINewYUVA(). - -Please have a look at the src/webp/decode.h header for further details. - -### Advanced Decoding API - -WebP decoding supports an advanced API which provides on-the-fly cropping and -rescaling, something of great usefulness on memory-constrained environments like -mobile phones. Basically, the memory usage will scale with the output's size, -not the input's, when one only needs a quick preview or a zoomed in portion of -an otherwise too-large picture. Some CPU can be saved too, incidentally. - -```c -// A) Init a configuration object -WebPDecoderConfig config; -CHECK(WebPInitDecoderConfig(&config)); - -// B) optional: retrieve the bitstream's features. -CHECK(WebPGetFeatures(data, data_size, &config.input) == VP8_STATUS_OK); - -// C) Adjust 'config' options, if needed -config.options.no_fancy_upsampling = 1; -config.options.use_scaling = 1; -config.options.scaled_width = scaledWidth(); -config.options.scaled_height = scaledHeight(); -// etc. - -// D) Specify 'config' output options for specifying output colorspace. -// Optionally the external image decode buffer can also be specified. -config.output.colorspace = MODE_BGRA; -// Optionally, the config.output can be pointed to an external buffer as -// well for decoding the image. This externally supplied memory buffer -// should be big enough to store the decoded picture. -config.output.u.RGBA.rgba = (uint8_t*) memory_buffer; -config.output.u.RGBA.stride = scanline_stride; -config.output.u.RGBA.size = total_size_of_the_memory_buffer; -config.output.is_external_memory = 1; - -// E) Decode the WebP image. There are two variants w.r.t decoding image. -// The first one (E.1) decodes the full image and the second one (E.2) is -// used to incrementally decode the image using small input buffers. -// Any one of these steps can be used to decode the WebP image. - -// E.1) Decode full image. -CHECK(WebPDecode(data, data_size, &config) == VP8_STATUS_OK); - -// E.2) Decode image incrementally. -WebPIDecoder* const idec = WebPIDecode(NULL, NULL, &config); -CHECK(idec != NULL); -while (bytes_remaining > 0) { - VP8StatusCode status = WebPIAppend(idec, input, bytes_read); - if (status == VP8_STATUS_OK || status == VP8_STATUS_SUSPENDED) { - bytes_remaining -= bytes_read; - } else { - break; - } -} -WebPIDelete(idec); - -// F) Decoded image is now in config.output (and config.output.u.RGBA). -// It can be saved, displayed or otherwise processed. - -// G) Reclaim memory allocated in config's object. It's safe to call -// this function even if the memory is external and wasn't allocated -// by WebPDecode(). -WebPFreeDecBuffer(&config.output); -``` - -## WebP Mux - -WebPMux is a set of two libraries 'Mux' and 'Demux' for creation, extraction and -manipulation of an extended format WebP file, which can have features like color -profile, metadata and animation. Reference command-line tools `webpmux` and -`vwebp` as well as the WebP container specification -'doc/webp-container-spec.txt' are also provided in this package, see the -[tools documentation](tools.md). - -### Mux API - -The Mux API contains methods for adding data to and reading data from WebP -files. This API currently supports XMP/EXIF metadata, ICC profile and animation. -Other features may be added in subsequent releases. - -Example#1 (pseudo code): Creating a WebPMux object with image data, color -profile and XMP metadata. - -```c -int copy_data = 0; -WebPMux* mux = WebPMuxNew(); -// ... (Prepare image data). -WebPMuxSetImage(mux, &image, copy_data); -// ... (Prepare ICC profile data). -WebPMuxSetChunk(mux, "ICCP", &icc_profile, copy_data); -// ... (Prepare XMP metadata). -WebPMuxSetChunk(mux, "XMP ", &xmp, copy_data); -// Get data from mux in WebP RIFF format. -WebPMuxAssemble(mux, &output_data); -WebPMuxDelete(mux); -// ... (Consume output_data; e.g. write output_data.bytes to file). -WebPDataClear(&output_data); -``` - -Example#2 (pseudo code): Get image and color profile data from a WebP file. - -```c -int copy_data = 0; -// ... (Read data from file). -WebPMux* mux = WebPMuxCreate(&data, copy_data); -WebPMuxGetFrame(mux, 1, &image); -// ... (Consume image; e.g. call WebPDecode() to decode the data). -WebPMuxGetChunk(mux, "ICCP", &icc_profile); -// ... (Consume icc_profile). -WebPMuxDelete(mux); -free(data); -``` - -For a detailed Mux API reference, please refer to the header file -(src/webp/mux.h). - -### Demux API - -The Demux API enables extraction of images and extended format data from WebP -files. This API currently supports reading of XMP/EXIF metadata, ICC profile and -animated images. Other features may be added in subsequent releases. - -Code example: Demuxing WebP data to extract all the frames, ICC profile and -EXIF/XMP metadata. - -```c -WebPDemuxer* demux = WebPDemux(&webp_data); -uint32_t width = WebPDemuxGetI(demux, WEBP_FF_CANVAS_WIDTH); -uint32_t height = WebPDemuxGetI(demux, WEBP_FF_CANVAS_HEIGHT); -// ... (Get information about the features present in the WebP file). -uint32_t flags = WebPDemuxGetI(demux, WEBP_FF_FORMAT_FLAGS); - -// ... (Iterate over all frames). -WebPIterator iter; -if (WebPDemuxGetFrame(demux, 1, &iter)) { - do { - // ... (Consume 'iter'; e.g. Decode 'iter.fragment' with WebPDecode(), - // ... and get other frame properties like width, height, offsets etc. - // ... see 'struct WebPIterator' below for more info). - } while (WebPDemuxNextFrame(&iter)); - WebPDemuxReleaseIterator(&iter); -} - -// ... (Extract metadata). -WebPChunkIterator chunk_iter; -if (flags & ICCP_FLAG) WebPDemuxGetChunk(demux, "ICCP", 1, &chunk_iter); -// ... (Consume the ICC profile in 'chunk_iter.chunk'). -WebPDemuxReleaseChunkIterator(&chunk_iter); -if (flags & EXIF_FLAG) WebPDemuxGetChunk(demux, "EXIF", 1, &chunk_iter); -// ... (Consume the EXIF metadata in 'chunk_iter.chunk'). -WebPDemuxReleaseChunkIterator(&chunk_iter); -if (flags & XMP_FLAG) WebPDemuxGetChunk(demux, "XMP ", 1, &chunk_iter); -// ... (Consume the XMP metadata in 'chunk_iter.chunk'). -WebPDemuxReleaseChunkIterator(&chunk_iter); -WebPDemuxDelete(demux); -``` - -For a detailed Demux API reference, please refer to the header file -(src/webp/demux.h). - -## AnimEncoder API - -The AnimEncoder API can be used to create animated WebP images. - -Code example: - -```c -WebPAnimEncoderOptions enc_options; -WebPAnimEncoderOptionsInit(&enc_options); -// ... (Tune 'enc_options' as needed). -WebPAnimEncoder* enc = WebPAnimEncoderNew(width, height, &enc_options); -while() { - WebPConfig config; - WebPConfigInit(&config); - // ... (Tune 'config' as needed). - WebPAnimEncoderAdd(enc, frame, duration, &config); -} -WebPAnimEncoderAssemble(enc, webp_data); -WebPAnimEncoderDelete(enc); -// ... (Write the 'webp_data' to a file, or re-mux it further). -``` - -For a detailed AnimEncoder API reference, please refer to the header file -(src/webp/mux.h). - -## AnimDecoder API - -This AnimDecoder API allows decoding (possibly) animated WebP images. - -Code Example: - -```c -WebPAnimDecoderOptions dec_options; -WebPAnimDecoderOptionsInit(&dec_options); -// Tune 'dec_options' as needed. -WebPAnimDecoder* dec = WebPAnimDecoderNew(webp_data, &dec_options); -WebPAnimInfo anim_info; -WebPAnimDecoderGetInfo(dec, &anim_info); -for (uint32_t i = 0; i < anim_info.loop_count; ++i) { - while (WebPAnimDecoderHasMoreFrames(dec)) { - uint8_t* buf; - int timestamp; - WebPAnimDecoderGetNext(dec, &buf, ×tamp); - // ... (Render 'buf' based on 'timestamp'). - // ... (Do NOT free 'buf', as it is owned by 'dec'). - } - WebPAnimDecoderReset(dec); -} -const WebPDemuxer* demuxer = WebPAnimDecoderGetDemuxer(dec); -// ... (Do something using 'demuxer'; e.g. get EXIF/XMP/ICC data). -WebPAnimDecoderDelete(dec); -``` - -For a detailed AnimDecoder API reference, please refer to the header file -(src/webp/demux.h). diff --git a/libwebp/doc/building.md b/libwebp/doc/building.md deleted file mode 100644 index d870e34e..00000000 --- a/libwebp/doc/building.md +++ /dev/null @@ -1,231 +0,0 @@ -# Building - -## Windows build - -By running: - -```batch -nmake /f Makefile.vc CFG=release-static RTLIBCFG=static OBJDIR=output -``` - -the directory `output\release-static\(x64|x86)\bin` will contain the tools -cwebp.exe and dwebp.exe. The directory `output\release-static\(x64|x86)\lib` -will contain the libwebp static library. The target architecture (x86/x64) is -detected by Makefile.vc from the Visual Studio compiler (cl.exe) available in -the system path. - -## Unix build using makefile.unix - -On platforms with GNU tools installed (gcc and make), running - -```shell -make -f makefile.unix -``` - -will build the binaries examples/cwebp and examples/dwebp, along with the static -library src/libwebp.a. No system-wide installation is supplied, as this is a -simple alternative to the full installation system based on the autoconf tools -(see below). Please refer to makefile.unix for additional details and -customizations. - -## Using autoconf tools - -Prerequisites: a compiler (e.g., gcc), make, autoconf, automake, libtool. - -On a Debian-like system the following should install everything you need for a -minimal build: - -```shell -$ sudo apt-get install gcc make autoconf automake libtool -``` - -When building from git sources, you will need to run autogen.sh to generate the -configure script. - -```shell -./configure -make -make install -``` - -should be all you need to have the following files - -``` -/usr/local/include/webp/decode.h -/usr/local/include/webp/encode.h -/usr/local/include/webp/types.h -/usr/local/lib/libwebp.* -/usr/local/bin/cwebp -/usr/local/bin/dwebp -``` - -installed. - -Note: A decode-only library, libwebpdecoder, is available using the -`--enable-libwebpdecoder` flag. The encode library is built separately and can -be installed independently using a minor modification in the corresponding -Makefile.am configure files (see comments there). See `./configure --help` for -more options. - -## Building for MIPS Linux - -MIPS Linux toolchain stable available releases can be found at: -https://community.imgtec.com/developers/mips/tools/codescape-mips-sdk/available-releases/ - -```shell -# Add toolchain to PATH -export PATH=$PATH:/path/to/toolchain/bin - -# 32-bit build for mips32r5 (p5600) -HOST=mips-mti-linux-gnu -MIPS_CFLAGS="-O3 -mips32r5 -mabi=32 -mtune=p5600 -mmsa -mfp64 \ - -msched-weight -mload-store-pairs -fPIE" -MIPS_LDFLAGS="-mips32r5 -mabi=32 -mmsa -mfp64 -pie" - -# 64-bit build for mips64r6 (i6400) -HOST=mips-img-linux-gnu -MIPS_CFLAGS="-O3 -mips64r6 -mabi=64 -mtune=i6400 -mmsa -mfp64 \ - -msched-weight -mload-store-pairs -fPIE" -MIPS_LDFLAGS="-mips64r6 -mabi=64 -mmsa -mfp64 -pie" - -./configure --host=${HOST} --build=`config.guess` \ - CC="${HOST}-gcc -EL" \ - CFLAGS="$MIPS_CFLAGS" \ - LDFLAGS="$MIPS_LDFLAGS" -make -make install -``` - -## Building libwebp - Using vcpkg - -You can download and install libwebp using the -[vcpkg](https://github.com/Microsoft/vcpkg) dependency manager: - -```shell -git clone https://github.com/Microsoft/vcpkg.git -cd vcpkg -./bootstrap-vcpkg.sh -./vcpkg integrate install -./vcpkg install libwebp -``` - -The libwebp port in vcpkg is kept up to date by Microsoft team members and -community contributors. If the version is out of date, please -[create an issue or pull request](https://github.com/Microsoft/vcpkg) on the -vcpkg repository. - -## CMake - -With CMake, you can compile libwebp, cwebp, dwebp, gif2webp, img2webp, webpinfo -and the JS bindings. - -Prerequisites: a compiler (e.g., gcc with autotools) and CMake. - -On a Debian-like system the following should install everything you need for a -minimal build: - -```shell -$ sudo apt-get install build-essential cmake -``` - -When building from git sources, you will need to run cmake to generate the -makefiles. - -```shell -mkdir build && cd build && cmake ../ -make -make install -``` - -If you also want any of the executables, you will need to enable them through -CMake, e.g.: - -```shell -cmake -DWEBP_BUILD_CWEBP=ON -DWEBP_BUILD_DWEBP=ON ../ -``` - -or through your favorite interface (like ccmake or cmake-qt-gui). - -Use option `-DWEBP_UNICODE=ON` for Unicode support on Windows (with chcp 65001). - -Finally, once installed, you can also use WebP in your CMake project by doing: - -```cmake -find_package(WebP) -``` - -which will define the CMake variables WebP_INCLUDE_DIRS and WebP_LIBRARIES. - -## Gradle - -The support for Gradle is minimal: it only helps you compile libwebp, cwebp and -dwebp and webpmux_example. - -Prerequisites: a compiler (e.g., gcc with autotools) and gradle. - -On a Debian-like system the following should install everything you need for a -minimal build: - -```shell -$ sudo apt-get install build-essential gradle -``` - -When building from git sources, you will need to run the Gradle wrapper with the -appropriate target, e.g. : - -```shell -./gradlew buildAllExecutables -``` - -## SWIG bindings - -To generate language bindings from swig/libwebp.swig at least swig-1.3 -(http://www.swig.org) is required. - -Currently the following functions are mapped: - -Decode: - -``` -WebPGetDecoderVersion -WebPGetInfo -WebPDecodeRGBA -WebPDecodeARGB -WebPDecodeBGRA -WebPDecodeBGR -WebPDecodeRGB -``` - -Encode: - -``` -WebPGetEncoderVersion -WebPEncodeRGBA -WebPEncodeBGRA -WebPEncodeRGB -WebPEncodeBGR -WebPEncodeLosslessRGBA -WebPEncodeLosslessBGRA -WebPEncodeLosslessRGB -WebPEncodeLosslessBGR -``` - -See also the [swig documentation](../swig/README.md) for more detailed build -instructions and usage examples. - -### Java bindings - -To build the swig-generated JNI wrapper code at least JDK-1.5 (or equivalent) is -necessary for enum support. The output is intended to be a shared object / DLL -that can be loaded via `System.loadLibrary("webp_jni")`. - -### Python bindings - -To build the swig-generated Python extension code at least Python 2.6 is -required. Python < 2.6 may build with some minor changes to libwebp.swig or the -generated code, but is untested. - -## Javascript decoder - -Libwebp can be compiled into a JavaScript decoder using Emscripten and CMake. -See the [corresponding documentation](../README.md) diff --git a/libwebp/doc/specs_generation.md b/libwebp/doc/specs_generation.md deleted file mode 100644 index 0380d664..00000000 --- a/libwebp/doc/specs_generation.md +++ /dev/null @@ -1,26 +0,0 @@ -# Generate libwebp Container Spec Docs from Text Source - -HTML generation requires [kramdown](https://kramdown.gettalong.org/), easily -installed as a [rubygem](https://rubygems.org/). Rubygems installation should -satisfy dependencies automatically. - -HTML generation can then be done from the project root: - -```shell -$ kramdown doc/webp-container-spec.txt --template doc/template.html > \ - doc/output/webp-container-spec.html -``` - -kramdown can optionally syntax highlight code blocks, using -[CodeRay](https://github.com/rubychan/coderay), a dependency of kramdown that -rubygems will install automatically. The following will apply inline CSS -styling; an external stylesheet is not needed. - -```shell -$ kramdown doc/webp-lossless-bitstream-spec.txt --template \ - doc/template.html --coderay-css style --coderay-line-numbers ' ' \ - --coderay-default-lang c > \ - doc/output/webp-lossless-bitstream-spec.html -``` - -Optimally, use kramdown 0.13.7 or newer if syntax highlighting desired. diff --git a/libwebp/doc/template.html b/libwebp/doc/template.html deleted file mode 100644 index 5dbc2894..00000000 --- a/libwebp/doc/template.html +++ /dev/null @@ -1,94 +0,0 @@ - - - - - WebP Container Specification - - - - -<%= @body %> - - diff --git a/libwebp/doc/tools.md b/libwebp/doc/tools.md deleted file mode 100644 index bf492746..00000000 --- a/libwebp/doc/tools.md +++ /dev/null @@ -1,516 +0,0 @@ -# WebP tools - -## Encoding tool - -The examples/ directory contains tools for encoding (cwebp) and decoding (dwebp) -images. - -The easiest use should look like: - -```shell -cwebp input.png -q 80 -o output.webp -``` - -which will convert the input file to a WebP file using a quality factor of 80 on -a 0->100 scale (0 being the lowest quality, 100 being the best. Default value is -75). - -You might want to try the `-lossless` flag too, which will compress the source -(in RGBA format) without any loss. The `-q` quality parameter will in this case -control the amount of processing time spent trying to make the output file as -small as possible. - -A longer list of options is available using the `-longhelp` command line flag: - -```shell -> cwebp -longhelp -Usage: - cwebp [-preset <...>] [options] in_file [-o out_file] -``` - -If input size (-s) for an image is not specified, it is assumed to be a PNG, -JPEG, TIFF or WebP file. Note: Animated PNG and WebP files are not supported. - -Options: - -``` --h / -help ............. short help --H / -longhelp ......... long help --q ............. quality factor (0:small..100:big), default=75 --alpha_q ......... transparency-compression quality (0..100), - default=100 --preset ....... preset setting, one of: - default, photo, picture, - drawing, icon, text - -preset must come first, as it overwrites other parameters --z ............... activates lossless preset with given - level in [0:fast, ..., 9:slowest] - --m ............... compression method (0=fast, 6=slowest), default=4 --segments ........ number of segments to use (1..4), default=4 --size ............ target size (in bytes) --psnr .......... target PSNR (in dB. typically: 42) - --s ......... input size (width x height) for YUV --sns ............. spatial noise shaping (0:off, 100:max), default=50 --f ............... filter strength (0=off..100), default=60 --sharpness ....... filter sharpness (0:most .. 7:least sharp), default=0 --strong ................ use strong filter instead of simple (default) --nostrong .............. use simple filter instead of strong --sharp_yuv ............. use sharper (and slower) RGB->YUV conversion --partition_limit . limit quality to fit the 512k limit on - the first partition (0=no degradation ... 100=full) --pass ............ analysis pass number (1..10) --qrange .... specifies the permissible quality range - (default: 0 100) --crop .. crop picture with the given rectangle --resize ........ resize picture (*after* any cropping) --mt .................... use multi-threading if available --low_memory ............ reduce memory usage (slower encoding) --map ............. print map of extra info --print_psnr ............ prints averaged PSNR distortion --print_ssim ............ prints averaged SSIM distortion --print_lsim ............ prints local-similarity distortion --d .......... dump the compressed output (PGM file) --alpha_method .... transparency-compression method (0..1), default=1 --alpha_filter . predictive filtering for alpha plane, - one of: none, fast (default) or best --exact ................. preserve RGB values in transparent area, default=off --blend_alpha ..... blend colors against background color - expressed as RGB values written in - hexadecimal, e.g. 0xc0e0d0 for red=0xc0 - green=0xe0 and blue=0xd0 --noalpha ............... discard any transparency information --lossless .............. encode image losslessly, default=off --near_lossless ... use near-lossless image preprocessing - (0..100=off), default=100 --hint ......... specify image characteristics hint, - one of: photo, picture or graph - --metadata ..... comma separated list of metadata to - copy from the input to the output if present. - Valid values: all, none (default), exif, icc, xmp - --short ................. condense printed message --quiet ................. don't print anything --version ............... print version number and exit --noasm ................. disable all assembly optimizations --v ..................... verbose, e.g. print encoding/decoding times --progress .............. report encoding progress -``` - -Experimental Options: - -``` --jpeg_like ............. roughly match expected JPEG size --af .................... auto-adjust filter strength --pre ............. pre-processing filter -``` - -The main options you might want to try in order to further tune the visual -quality are: - --preset -sns -f -m - -Namely: - -* `preset` will set up a default encoding configuration targeting a particular - type of input. It should appear first in the list of options, so that - subsequent options can take effect on top of this preset. Default value is - 'default'. -* `sns` will progressively turn on (when going from 0 to 100) some additional - visual optimizations (like: segmentation map re-enforcement). This option - will balance the bit allocation differently. It tries to take bits from the - "easy" parts of the picture and use them in the "difficult" ones instead. - Usually, raising the sns value (at fixed -q value) leads to larger files, - but with better quality. Typical value is around '75'. -* `f` option directly links to the filtering strength used by the codec's - in-loop processing. The higher the value, the smoother the highly-compressed - area will look. This is particularly useful when aiming at very small files. - Typical values are around 20-30. Note that using the option - -strong/-nostrong will change the type of filtering. Use "-f 0" to turn - filtering off. -* `m` controls the trade-off between encoding speed and quality. Default is 4. - You can try -m 5 or -m 6 to explore more (time-consuming) encoding - possibilities. A lower value will result in faster encoding at the expense - of quality. - -## Decoding tool - -There is a decoding sample in examples/dwebp.c which will take a .webp file and -decode it to a PNG image file (amongst other formats). This is simply to -demonstrate the use of the API. You can verify the file test.webp decodes to -exactly the same as test_ref.ppm by using: - -```shell -cd examples -./dwebp test.webp -ppm -o test.ppm -diff test.ppm test_ref.ppm -``` - -The full list of options is available using -h: - -```shell -> dwebp -h -Usage: dwebp in_file [options] [-o out_file] -``` - -Decodes the WebP image file to PNG format [Default]. Note: Animated WebP files -are not supported. - -Use following options to convert into alternate image formats: - -``` --pam ......... save the raw RGBA samples as a color PAM --ppm ......... save the raw RGB samples as a color PPM --bmp ......... save as uncompressed BMP format --tiff ........ save as uncompressed TIFF format --pgm ......... save the raw YUV samples as a grayscale PGM - file with IMC4 layout --yuv ......... save the raw YUV samples in flat layout -``` - -Other options are: - -``` --version ..... print version number and exit --nofancy ..... don't use the fancy YUV420 upscaler --nofilter .... disable in-loop filtering --nodither .... disable dithering --dither .. dithering strength (in 0..100) --alpha_dither use alpha-plane dithering if needed --mt .......... use multi-threading --crop ... crop output with the given rectangle --resize ......... resize output (*after* any cropping) --flip ........ flip the output vertically --alpha ....... only save the alpha plane --incremental . use incremental decoding (useful for tests) --h ........... this help message --v ........... verbose (e.g. print encoding/decoding times) --quiet ....... quiet mode, don't print anything --noasm ....... disable all assembly optimizations -``` - -## WebP file analysis tool - -`webpinfo` can be used to print out the chunk level structure and bitstream -header information of WebP files. It can also check if the files are of valid -WebP format. - -Usage: - -```shell -webpinfo [options] in_files -``` - -Note: there could be multiple input files; options must come before input files. - -Options: - -``` --version ........... Print version number and exit. --quiet ............. Do not show chunk parsing information. --diag .............. Show parsing error diagnosis. --summary ........... Show chunk stats summary. --bitstream_info .... Parse bitstream header. -``` - -## Visualization tool - -There's a little self-serve visualization tool called 'vwebp' under the -examples/ directory. It uses OpenGL to open a simple drawing window and show a -decoded WebP file. It's not yet integrated in the automake build system, but you -can try to manually compile it using the recommendations below. - -Usage: - -```shell -vwebp in_file [options] -``` - -Decodes the WebP image file and visualize it using OpenGL - -Options are: - -``` --version ..... print version number and exit --noicc ....... don't use the icc profile if present --nofancy ..... don't use the fancy YUV420 upscaler --nofilter .... disable in-loop filtering --dither dithering strength (0..100), default=50 --noalphadither disable alpha plane dithering --usebgcolor .. display background color --mt .......... use multi-threading --info ........ print info --h ........... this help message -``` - -Keyboard shortcuts: - -``` -'c' ................ toggle use of color profile -'b' ................ toggle background color display -'i' ................ overlay file information -'d' ................ disable blending & disposal (debug) -'q' / 'Q' / ESC .... quit -``` - -### Building - -Prerequisites: - -1. OpenGL & OpenGL Utility Toolkit (GLUT) - - Linux: `sudo apt-get install freeglut3-dev mesa-common-dev` - - Mac + Xcode: These libraries should be available in the OpenGL / GLUT - frameworks. - - Windows: http://freeglut.sourceforge.net/index.php#download - -2. (Optional) qcms (Quick Color Management System) - - 1. Download qcms from Mozilla / Chromium: - https://hg.mozilla.org/mozilla-central/file/0e7639e3bdfb/gfx/qcms - https://source.chromium.org/chromium/chromium/src/+/main:third_party/qcms/;drc=d4a2f8e1ed461d8fc05ed88d1ae2dc94c9773825 - 2. Build and archive the source files as libqcms.a / qcms.lib - 3. Update makefile.unix / Makefile.vc - 1. Define WEBP_HAVE_QCMS - 2. Update include / library paths to reference the qcms directory. - -Build using makefile.unix / Makefile.vc: - -```shell -$ make -f makefile.unix examples/vwebp -> nmake /f Makefile.vc CFG=release-static \ - ../obj/x64/release-static/bin/vwebp.exe -``` - -## Animation creation tool - -The utility `img2webp` can turn a sequence of input images (PNG, JPEG, ...) into -an animated WebP file. It offers fine control over duration, encoding modes, -etc. - -Usage: - -```shell -img2webp [file_options] [[frame_options] frame_file]... [-o webp_file] -``` - -File-level options (only used at the start of compression): - -``` --min_size ............ minimize size --kmax .......... maximum number of frame between key-frames - (0=only keyframes) --kmin .......... minimum number of frame between key-frames - (0=disable key-frames altogether) --mixed ............... use mixed lossy/lossless automatic mode --near_lossless . use near-lossless image preprocessing - (0..100=off), default=100 --sharp_yuv ........... use sharper (and slower) RGB->YUV conversion - (lossy only) --loop .......... loop count (default: 0, = infinite loop) --v ................... verbose mode --h ................... this help --version ............. print version number and exit -``` - -Per-frame options (only used for subsequent images input): - -``` --d ............. frame duration in ms (default: 100) --lossless ........... use lossless mode (default) --lossy ... ........... use lossy mode --q ........... quality --m ............. method to use -``` - -example: `img2webp -loop 2 in0.png -lossy in1.jpg -d 80 in2.tiff -o out.webp` - -Note: if a single file name is passed as the argument, the arguments will be -tokenized from this file. The file name must not start with the character '-'. - -## Animated GIF conversion - -Animated GIF files can be converted to WebP files with animation using the -gif2webp utility available under examples/. The files can then be viewed using -vwebp. - -Usage: - -```shell -gif2webp [options] gif_file -o webp_file -``` - -Options: - -``` --h / -help ............. this help --lossy ................. encode image using lossy compression --mixed ................. for each frame in the image, pick lossy - or lossless compression heuristically --q ............. quality factor (0:small..100:big) --m ............... compression method (0=fast, 6=slowest) --min_size .............. minimize output size (default:off) - lossless compression by default; can be - combined with -q, -m, -lossy or -mixed - options --kmin ............ min distance between key frames --kmax ............ max distance between key frames --f ............... filter strength (0=off..100) --metadata ..... comma separated list of metadata to - copy from the input to the output if present - Valid values: all, none, icc, xmp (default) --loop_compatibility .... use compatibility mode for Chrome - version prior to M62 (inclusive) --mt .................... use multi-threading if available - --version ............... print version number and exit --v ..................... verbose --quiet ................. don't print anything -``` - -### Building - -With the libgif development files installed, gif2webp can be built using -makefile.unix: - -```shell -$ make -f makefile.unix examples/gif2webp -``` - -or using autoconf: - -```shell -$ ./configure --enable-everything -$ make -``` - -## Comparison of animated images - -Test utility anim_diff under examples/ can be used to compare two animated -images (each can be GIF or WebP). - -Usage: - -```shell -anim_diff [options] -``` - -Options: - -``` --dump_frames dump decoded frames in PAM format --min_psnr ... minimum per-frame PSNR --raw_comparison ..... if this flag is not used, RGB is - premultiplied before comparison --max_diff ..... maximum allowed difference per channel - between corresponding pixels in subsequent - frames --h .................. this help --version ............ print version number and exit -``` - -### Building - -With the libgif development files installed, anim_diff can be built using -makefile.unix: - -```shell -$ make -f makefile.unix examples/anim_diff -``` - -or using autoconf: - -```shell -$ ./configure --enable-everything -$ make -``` - -## WebP Mux tool - -The examples/ directory contains a tool (webpmux) for manipulating WebP files. -The webpmux tool can be used to create an extended format WebP file and also to -extract or strip relevant data from such a file. - -A list of options is available using the -help command line flag: - -```shell -> webpmux -help -Usage: webpmux -get GET_OPTIONS INPUT -o OUTPUT - webpmux -set SET_OPTIONS INPUT -o OUTPUT - webpmux -duration DURATION_OPTIONS [-duration ...] - INPUT -o OUTPUT - webpmux -strip STRIP_OPTIONS INPUT -o OUTPUT - webpmux -frame FRAME_OPTIONS [-frame...] [-loop LOOP_COUNT] - [-bgcolor BACKGROUND_COLOR] -o OUTPUT - webpmux -info INPUT - webpmux [-h|-help] - webpmux -version - webpmux argument_file_name - -GET_OPTIONS: - Extract relevant data: - icc get ICC profile - exif get EXIF metadata - xmp get XMP metadata - frame n get nth frame - -SET_OPTIONS: - Set color profile/metadata/parameters: - loop LOOP_COUNT set the loop count - bgcolor BACKGROUND_COLOR set the animation background color - icc file.icc set ICC profile - exif file.exif set EXIF metadata - xmp file.xmp set XMP metadata - where: 'file.icc' contains the ICC profile to be set, - 'file.exif' contains the EXIF metadata to be set - 'file.xmp' contains the XMP metadata to be set - -DURATION_OPTIONS: - Set duration of selected frames: - duration set duration for all frames - duration,frame set duration of a particular frame - duration,start,end set duration of frames in the - interval [start,end]) - where: 'duration' is the duration in milliseconds - 'start' is the start frame index - 'end' is the inclusive end frame index - The special 'end' value '0' means: last frame. - -STRIP_OPTIONS: - Strip color profile/metadata: - icc strip ICC profile - exif strip EXIF metadata - xmp strip XMP metadata - -FRAME_OPTIONS(i): - Create animation: - file_i +di[+xi+yi[+mi[bi]]] - where: 'file_i' is the i'th animation frame (WebP format), - 'di' is the pause duration before next frame, - 'xi','yi' specify the image offset for this frame, - 'mi' is the dispose method for this frame (0 or 1), - 'bi' is the blending method for this frame (+b or -b) - -LOOP_COUNT: - Number of times to repeat the animation. - Valid range is 0 to 65535 [Default: 0 (infinite)]. - -BACKGROUND_COLOR: - Background color of the canvas. - A,R,G,B - where: 'A', 'R', 'G' and 'B' are integers in the range 0 to 255 specifying - the Alpha, Red, Green and Blue component values respectively - [Default: 255,255,255,255] - -INPUT & OUTPUT are in WebP format. - -Note: The nature of EXIF, XMP and ICC data is not checked and is assumed to be -valid. - -Note: if a single file name is passed as the argument, the arguments will be -tokenized from this file. The file name must not start with the character '-'. -``` diff --git a/libwebp/doc/webp-container-spec.txt b/libwebp/doc/webp-container-spec.txt deleted file mode 100644 index 1cd3da78..00000000 --- a/libwebp/doc/webp-container-spec.txt +++ /dev/null @@ -1,872 +0,0 @@ - - - -WebP Container Specification -============================ - -* TOC placeholder -{:toc} - - -Introduction ------------- - -WebP is an image format that uses either (i) the VP8 key frame encoding to -compress image data in a lossy way or (ii) the WebP lossless encoding. These -encoding schemes should make it more efficient than older formats, such as JPEG, -GIF, and PNG. It is optimized for fast image transfer over the network (for -example, for websites). The WebP format has feature parity (color profile, -metadata, animation, etc.) with other formats as well. This document describes -the structure of a WebP file. - -The WebP container (that is, the RIFF container for WebP) allows feature support -over and above the basic use case of WebP (that is, a file containing a single -image encoded as a VP8 key frame). The WebP container provides additional -support for the following: - - * Lossless Compression: An image can be losslessly compressed, using the - WebP Lossless Format. - - * Metadata: An image may have metadata stored in Exchangeable Image File - Format (Exif) or Extensible Metadata Platform (XMP) format. - - * Transparency: An image may have transparency, that is, an alpha channel. - - * Color Profile: An image may have an embedded ICC profile as described - by the [International Color Consortium][iccspec]. - - * Animation: An image may have multiple frames with pauses between them, - making it an animation. - -Terminology & Basics --------------------- - -The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", -"SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this -document are to be interpreted as described in BCP 14 [RFC 2119][] [RFC 8174][] -when, and only when, they appear in all capitals, as shown here. - -A WebP file contains either a still image (that is, an encoded matrix of pixels) -or an [animation](#animation). Optionally, it can also contain transparency -information, a color profile and metadata. We refer to the matrix of pixels as -the _canvas_ of the image. - -Bit numbering in chunk diagrams starts at `0` for the most significant bit -('MSB 0'), as described in [RFC 1166][]. - -Below are additional terms used throughout this document: - -_Reader/Writer_ - -: Code that reads WebP files is referred to as a _reader_, while code that - writes them is referred to as a _writer_. - -_uint16_ - -: A 16-bit, little-endian, unsigned integer. - -_uint24_ - -: A 24-bit, little-endian, unsigned integer. - -_uint32_ - -: A 32-bit, little-endian, unsigned integer. - -_FourCC_ - -: A four-character code (FourCC) is a _uint32_ created by concatenating four - ASCII characters in little-endian order. This means 'aaaa' (0x61616161) and - 'AAAA' (0x41414141) are treated as different _FourCCs_. - -_1-based_ - -: An unsigned integer field storing values offset by `-1`, for example, such a - field would store value _25_ as _24_. - -_ChunkHeader('ABCD')_ - -: Used to describe the _FourCC_ and _Chunk Size_ header of individual chunks, - where 'ABCD' is the FourCC for the chunk. This element's size is 8 bytes. - - -RIFF File Format ----------------- - -The WebP file format is based on the RIFF (Resource Interchange File Format) -document format. - -The basic element of a RIFF file is a _chunk_. It consists of: - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Chunk FourCC | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Chunk Size | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - : Chunk Payload : - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - -Chunk FourCC: 32 bits - -: ASCII four-character code used for chunk identification. - -Chunk Size: 32 bits (_uint32_) - -: The size of the chunk in bytes, not including this field, the chunk - identifier, or padding. - -Chunk Payload: _Chunk Size_ bytes - -: The data payload. If _Chunk Size_ is odd, a single padding byte -- which MUST - be `0` to conform with RIFF -- is added. - -**Note:** RIFF has a convention that all-uppercase chunk FourCCs are standard -chunks that apply to any RIFF file format, while FourCCs specific to a file -format are all lowercase. WebP does not follow this convention. - - -WebP File Header ----------------- - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | 'R' | 'I' | 'F' | 'F' | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | File Size | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | 'W' | 'E' | 'B' | 'P' | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - -'RIFF': 32 bits - -: The ASCII characters 'R', 'I', 'F', 'F'. - -File Size: 32 bits (_uint32_) - -: The size of the file in bytes, starting at offset 8. The maximum value of - this field is 2^32 minus 10 bytes and thus the size of the whole file is at - most 4 GiB minus 2 bytes. - -'WEBP': 32 bits - -: The ASCII characters 'W', 'E', 'B', 'P'. - -A WebP file MUST begin with a RIFF header with the FourCC 'WEBP'. The file size -in the header is the total size of the chunks that follow plus `4` bytes for -the 'WEBP' FourCC. The file SHOULD NOT contain any data after the data -specified by _File Size_. Readers MAY parse such files, ignoring the trailing -data. As the size of any chunk is even, the size given by the RIFF header is -also even. The contents of individual chunks are described in the following -sections. - - -Simple File Format (Lossy) --------------------------- - -This layout SHOULD be used if the image requires _lossy_ encoding and does not -require transparency or other advanced features provided by the extended format. -Files with this layout are smaller and supported by older software. - -Simple WebP (lossy) file format: - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | | - | WebP file header (12 bytes) | - | | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - : 'VP8 ' Chunk : - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - -'VP8 ' Chunk: - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | ChunkHeader('VP8 ') | - | | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - : VP8 data : - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - -VP8 data: _Chunk Size_ bytes - -: VP8 bitstream data. - -Note that the fourth character in the 'VP8 ' FourCC is an ASCII space (0x20). - -The VP8 bitstream format specification is described in [VP8 Data Format and -Decoding Guide][rfc 6386]. Note that the VP8 frame header contains the VP8 frame -width and height. That is assumed to be the width and height of the canvas. - -The VP8 specification describes how to decode the image into Y'CbCr format. To -convert to RGB, [Recommendation BT.601][rec601] SHOULD be used. Applications MAY -use another conversion method, but visual results may differ among decoders. - - -Simple File Format (Lossless) ------------------------------ - -**Note:** Older readers may not support files using the lossless format. - -This layout SHOULD be used if the image requires _lossless_ encoding (with an -optional transparency channel) and does not require advanced features provided -by the extended format. - -Simple WebP (lossless) file format: - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | | - | WebP file header (12 bytes) | - | | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - : 'VP8L' Chunk : - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - -'VP8L' Chunk: - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | ChunkHeader('VP8L') | - | | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - : VP8L data : - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - -VP8L data: _Chunk Size_ bytes - -: VP8L bitstream data. - -The current specification of the VP8L bitstream can be found at -[WebP Lossless Bitstream Format][webpllspec]. Note that the VP8L header -contains the VP8L image width and height. That is assumed to be the width -and height of the canvas. - - -Extended File Format --------------------- - -**Note:** Older readers may not support files using the extended format. - -An extended format file consists of: - - * A 'VP8X' Chunk with information about features used in the file. - - * An optional 'ICCP' Chunk with a color profile. - - * An optional 'ANIM' Chunk with animation control data. - - * Image data. - - * An optional 'EXIF' Chunk with Exif metadata. - - * An optional 'XMP ' Chunk with XMP metadata. - - * An optional list of [unknown chunks](#unknown-chunks). - -For a _still image_, the _image data_ consists of a single frame, which is made -up of: - - * An optional [alpha subchunk](#alpha). - - * A [bitstream subchunk](#bitstream-vp8vp8l). - -For an _animated image_, the _image data_ consists of multiple frames. More -details about frames can be found in the [Animation](#animation) section. - -All chunks SHOULD be placed in the same order as listed above. If a chunk -appears in the wrong place, the file is invalid, but readers MAY parse the -file, ignoring the chunks that are out of order. - -**Rationale:** Setting the order of chunks should allow quicker file -parsing. For example, if an 'ALPH' Chunk does not appear in its required -position, a decoder can choose to stop searching for it. The rule of -ignoring late chunks should make programs that need to do a full search -give the same results as the ones stopping early. - -Extended WebP file header: -{:#extended_header} - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | | - | WebP file header (12 bytes) | - | | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | ChunkHeader('VP8X') | - | | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - |Rsv|I|L|E|X|A|R| Reserved | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Canvas Width Minus One | ... - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - ... Canvas Height Minus One | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - -Reserved (Rsv): 2 bits - -: MUST be `0`. Readers MUST ignore this field. - -ICC profile (I): 1 bit - -: Set if the file contains an 'ICCP' Chunk. - -Alpha (L): 1 bit - -: Set if any of the frames of the image contain transparency information - ("alpha"). - -Exif metadata (E): 1 bit - -: Set if the file contains Exif metadata. - -XMP metadata (X): 1 bit - -: Set if the file contains XMP metadata. - -Animation (A): 1 bit - -: Set if this is an animated image. Data in 'ANIM' and 'ANMF' Chunks should be - used to control the animation. - -Reserved (R): 1 bit - -: MUST be `0`. Readers MUST ignore this field. - -Reserved: 24 bits - -: MUST be `0`. Readers MUST ignore this field. - -Canvas Width Minus One: 24 bits - -: _1-based_ width of the canvas in pixels. - The actual canvas width is `1 + Canvas Width Minus One`. - -Canvas Height Minus One: 24 bits - -: _1-based_ height of the canvas in pixels. - The actual canvas height is `1 + Canvas Height Minus One`. - -The product of _Canvas Width_ and _Canvas Height_ MUST be at most `2^32 - 1`. - -Future specifications may add more fields. Unknown fields MUST be ignored. - -### Chunks - -#### Animation - -An animation is controlled by 'ANIM' and 'ANMF' Chunks. - -'ANIM' Chunk: -{:#anim_chunk} - -For an animated image, this chunk contains the _global parameters_ of the -animation. - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | ChunkHeader('ANIM') | - | | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Background Color | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Loop Count | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - -Background Color: 32 bits (_uint32_) - -: The default background color of the canvas in \[Blue, Green, Red, Alpha\] - byte order. This color MAY be used to fill the unused space on the canvas - around the frames, as well as the transparent pixels of the first frame. - The background color is also used when the Disposal method is `1`. - -**Note**: - - * The background color MAY contain a non-opaque alpha value, even if the - _Alpha_ flag in the ['VP8X' Chunk](#extended_header) is unset. - - * Viewer applications SHOULD treat the background color value as a hint and - are not required to use it. - - * The canvas is cleared at the start of each loop. The background color MAY be - used to achieve this. - -Loop Count: 16 bits (_uint16_) - -: The number of times to loop the animation. If it is `0`, this means - infinitely. - -This chunk MUST appear if the _Animation_ flag in the 'VP8X' Chunk is set. -If the _Animation_ flag is not set and this chunk is present, it MUST be -ignored. - -'ANMF' Chunk: - -For animated images, this chunk contains information about a _single_ frame. -If the _Animation flag_ is not set, then this chunk SHOULD NOT be present. - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | ChunkHeader('ANMF') | - | | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Frame X | ... - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - ... Frame Y | Frame Width Minus One ... - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - ... | Frame Height Minus One | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Frame Duration | Reserved |B|D| - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - : Frame Data : - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - -Frame X: 24 bits (_uint24_) - -: The X coordinate of the upper left corner of the frame is `Frame X * 2`. - -Frame Y: 24 bits (_uint24_) - -: The Y coordinate of the upper left corner of the frame is `Frame Y * 2`. - -Frame Width Minus One: 24 bits (_uint24_) - -: The _1-based_ width of the frame. - The frame width is `1 + Frame Width Minus One`. - -Frame Height Minus One: 24 bits (_uint24_) - -: The _1-based_ height of the frame. - The frame height is `1 + Frame Height Minus One`. - -Frame Duration: 24 bits (_uint24_) - -: The time to wait before displaying the next frame, in 1-millisecond units. - Note that the interpretation of the Frame Duration of 0 (and often <= 10) is - defined by the implementation. Many tools and browsers assign a minimum - duration similar to GIF. - -Reserved: 6 bits - -: MUST be `0`. Readers MUST ignore this field. - -Blending method (B): 1 bit - -: Indicates how transparent pixels of _the current frame_ are to be blended - with corresponding pixels of the previous canvas: - - * `0`: Use alpha-blending. After disposing of the previous frame, render the - current frame on the canvas using [alpha-blending](#alpha-blending). If - the current frame does not have an alpha channel, assume the alpha value - is 255, effectively replacing the rectangle. - - * `1`: Do not blend. After disposing of the previous frame, render the - current frame on the canvas by overwriting the rectangle covered by the - current frame. - -Disposal method (D): 1 bit - -: Indicates how _the current frame_ is to be treated after it has been - displayed (before rendering the next frame) on the canvas: - - * `0`: Do not dispose. Leave the canvas as is. - - * `1`: Dispose to the background color. Fill the _rectangle_ on the canvas - covered by the _current frame_ with the background color specified in the - ['ANIM' Chunk](#anim_chunk). - -**Notes**: - - * The frame disposal only applies to the _frame rectangle_, that is, the - rectangle defined by _Frame X_, _Frame Y_, _frame width_, and _frame - height_. It may or may not cover the whole canvas. - -{:#alpha-blending} - * Alpha-blending: - - Given that each of the R, G, B, and A channels is 8 bits, and the RGB - channels are _not premultiplied_ by alpha, the formula for blending - 'dst' onto 'src' is: - -~~~~~ - blend.A = src.A + dst.A * (1 - src.A / 255) - if blend.A = 0 then - blend.RGB = 0 - else - blend.RGB = - (src.RGB * src.A + - dst.RGB * dst.A * (1 - src.A / 255)) / blend.A -~~~~~ - - * Alpha-blending SHOULD be done in linear color space, by taking into account - the [color profile](#color-profile) of the image. If the color profile is - not present, standard RGB (sRGB) is to be assumed. (Note that sRGB also - needs to be linearized due to a gamma of ~2.2.) - -Frame Data: _Chunk Size_ - `16` bytes - -: Consists of: - - * An optional [alpha subchunk](#alpha) for the frame. - - * A [bitstream subchunk](#bitstream-vp8vp8l) for the frame. - - * An optional list of [unknown chunks](#unknown-chunks). - -**Note**: The 'ANMF' payload, _Frame Data_ above, consists of individual -_padded_ chunks, as described by the [RIFF file format](#riff-file-format). - -#### Alpha - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | ChunkHeader('ALPH') | - | | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - |Rsv| P | F | C | Alpha Bitstream... | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - -Reserved (Rsv): 2 bits - -: MUST be `0`. Readers MUST ignore this field. - -Preprocessing (P): 2 bits - -: These _informative_ bits are used to signal the preprocessing that has - been performed during compression. The decoder can use this information to - for example, dither the values or smooth the gradients prior to display. - - * `0`: No preprocessing. - * `1`: Level reduction. - -Decoders are not required to use this information in any specified way. - -Filtering method (F): 2 bits - -: The filtering methods used are described as follows: - - * `0`: None. - * `1`: Horizontal filter. - * `2`: Vertical filter. - * `3`: Gradient filter. - -For each pixel, filtering is performed using the following calculations. -Assume the alpha values surrounding the current `X` position are labeled as: - - C | B | - ---+---+ - A | X | - -We seek to compute the alpha value at position `X`. First, a prediction is -made depending on the filtering method: - - * Method `0`: predictor = 0 - * Method `1`: predictor = A - * Method `2`: predictor = B - * Method `3`: predictor = clip(A + B - C) - -where `clip(v)` is equal to: - - * 0 if v < 0, - * 255 if v > 255, or - * v otherwise - -The final value is derived by adding the decompressed value `X` to the -predictor and using modulo-256 arithmetic to wrap the \[256..511\] range -into the \[0..255\] one: - -`alpha = (predictor + X) % 256` - -There are special cases for the left-most and top-most pixel positions. For -example, the top-left value at location (0, 0) uses 0 as the predictor value. -Otherwise: - - * For horizontal or gradient filtering methods, the left-most pixels at - location (0, y) are predicted using the location (0, y-1) just above. - * For vertical or gradient filtering methods, the top-most pixels at - location (x, 0) are predicted using the location (x-1, 0) on the left. - -Compression method (C): 2 bits - -: The compression method used: - - * `0`: No compression. - * `1`: Compressed using the WebP lossless format. - -Alpha bitstream: _Chunk Size_ - `1` bytes - -: Encoded alpha bitstream. - -This optional chunk contains encoded alpha data for this frame. A frame -containing a 'VP8L' Chunk SHOULD NOT contain this chunk. - -**Rationale**: The transparency information is already part of the 'VP8L' -Chunk. - -The alpha channel data is stored as uncompressed raw data (when the -compression method is '0') or compressed using the lossless format -(when the compression method is '1'). - - * Raw data: This consists of a byte sequence of length = width * height, - containing all the 8-bit transparency values in scan order. - - * Lossless format compression: The byte sequence is a compressed - image-stream (as described in ["WebP Lossless Bitstream Format"] - [webpllspec]) of implicit dimensions width x height. That is, this - image-stream does NOT contain any headers describing the image dimensions. - - **Rationale**: The dimensions are already known from other sources, - so storing them again would be redundant and prone to error. - - Once the image-stream is decoded into Alpha, Red, Green, Blue (ARGB) color - values, following the process described in the lossless format - specification, the transparency information must be extracted from the - *green* channel of the ARGB quadruplet. - - **Rationale**: The green channel is allowed extra transformation - steps in the specification -- unlike the other channels -- that can - improve compression. - -#### Bitstream (VP8/VP8L) - -This chunk contains compressed bitstream data for a single frame. - -A bitstream chunk may be either (i) a 'VP8 ' Chunk, using 'VP8 ' (note the -significant fourth-character space) as its FourCC, _or_ (ii) a 'VP8L' Chunk, -using 'VP8L' as its FourCC. - -The formats of 'VP8 ' and 'VP8L' Chunks are as described in sections -[Simple File Format (Lossy)](#simple-file-format-lossy) -and [Simple File Format (Lossless)](#simple-file-format-lossless), respectively. - -#### Color Profile - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | ChunkHeader('ICCP') | - | | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - : Color Profile : - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - -Color Profile: _Chunk Size_ bytes - -: ICC profile. - -This chunk MUST appear before the image data. - -There SHOULD be at most one such chunk. If there are more such chunks, readers -MAY ignore all except the first one. -See the [ICC Specification][iccspec] for details. - -If this chunk is not present, sRGB SHOULD be assumed. - -#### Metadata - -Metadata can be stored in 'EXIF' or 'XMP ' Chunks. - -There SHOULD be at most one chunk of each type ('EXIF' and 'XMP '). If there -are more such chunks, readers MAY ignore all except the first one. - -The chunks are defined as follows: - -'EXIF' Chunk: - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | ChunkHeader('EXIF') | - | | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - : Exif Metadata : - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - -Exif Metadata: _Chunk Size_ bytes - -: Image metadata in Exif format. - -'XMP ' Chunk: - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | ChunkHeader('XMP ') | - | | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - : XMP Metadata : - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - -XMP Metadata: _Chunk Size_ bytes - -: Image metadata in XMP format. - -Note that the fourth character in the 'XMP ' FourCC is an ASCII space (0x20). - -Additional guidance about handling metadata can be found in the -Metadata Working Group's ["Guidelines for Handling Metadata"][metadata]. - -#### Unknown Chunks - -A RIFF chunk (described in the [RIFF File Format](#riff-file-format) section) -whose FourCC is different from any of the chunks described in this document, is -considered an _unknown chunk_. - -**Rationale**: Allowing unknown chunks gives a provision for future extension -of the format and also allows storage of any application-specific data. - -A file MAY contain unknown chunks: - - * at the end of the file, as described in [Extended WebP file - header](#extended_header) section, or - * at the end of 'ANMF' Chunks, as described in the - [Animation](#animation) section. - -Readers SHOULD ignore these chunks. Writers SHOULD preserve them in their -original order (unless they specifically intend to modify these chunks). - -### Canvas Assembly from Frames - -Here we provide an overview of how a reader MUST assemble a canvas in the case -of an animated image. - -The process begins with creating a canvas using the dimensions given in the -'VP8X' Chunk, `Canvas Width Minus One + 1` pixels wide by `Canvas Height Minus -One + 1` pixels high. The `Loop Count` field from the 'ANIM' Chunk controls how -many times the animation process is repeated. This is `Loop Count - 1` for -nonzero `Loop Count` values or infinite if the `Loop Count` is zero. - -At the beginning of each loop iteration, the canvas is filled using the -background color from the 'ANIM' Chunk or an application-defined color. - -'ANMF' Chunks contain individual frames given in display order. Before rendering -each frame, the previous frame's `Disposal method` is applied. - -The rendering of the decoded frame begins at the Cartesian coordinates (`2 * -Frame X`, `2 * Frame Y`), using the top-left corner of the canvas as the origin. -`Frame Width Minus One + 1` pixels wide by `Frame Height Minus One + 1` pixels -high are rendered onto the canvas using the `Blending method`. - -The canvas is displayed for `Frame Duration` milliseconds. This continues until -all frames given by 'ANMF' Chunks have been displayed. A new loop iteration is -then begun, or the canvas is left in its final state if all iterations have been -completed. - -The following pseudocode illustrates the rendering process. The notation -_VP8X.field_ means the field in the 'VP8X' Chunk with the same description. - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -VP8X.flags.hasAnimation MUST be TRUE -canvas ← new image of size VP8X.canvasWidth x VP8X.canvasHeight with - background color ANIM.background_color. -loop_count ← ANIM.loopCount -dispose_method ← Dispose to background color -if loop_count == 0: - loop_count = ∞ -frame_params ← nil -next chunk in image_data is ANMF MUST be TRUE -for loop = 0..loop_count - 1 - clear canvas to ANIM.background_color or application-defined color - until eof or non-ANMF chunk - frame_params.frameX = Frame X - frame_params.frameY = Frame Y - frame_params.frameWidth = Frame Width Minus One + 1 - frame_params.frameHeight = Frame Height Minus One + 1 - frame_params.frameDuration = Frame Duration - frame_right = frame_params.frameX + frame_params.frameWidth - frame_bottom = frame_params.frameY + frame_params.frameHeight - VP8X.canvasWidth >= frame_right MUST be TRUE - VP8X.canvasHeight >= frame_bottom MUST be TRUE - for subchunk in 'Frame Data': - if subchunk.tag == "ALPH": - alpha subchunks not found in 'Frame Data' earlier MUST be - TRUE - frame_params.alpha = alpha_data - else if subchunk.tag == "VP8 " OR subchunk.tag == "VP8L": - bitstream subchunks not found in 'Frame Data' earlier MUST - be TRUE - frame_params.bitstream = bitstream_data - render frame with frame_params.alpha and frame_params.bitstream - on canvas with top-left corner at (frame_params.frameX, - frame_params.frameY), using Blending method - frame_params.blendingMethod. - canvas contains the decoded image. - Show the contents of the canvas for - frame_params.frameDuration * 1 ms. - dispose_method = frame_params.disposeMethod -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - -Example File Layouts --------------------- - -A lossy-encoded image with alpha may look as follows: - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -RIFF/WEBP -+- VP8X (descriptions of features used) -+- ALPH (alpha bitstream) -+- VP8 (bitstream) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -A lossless-encoded image may look as follows: - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -RIFF/WEBP -+- VP8X (descriptions of features used) -+- VP8L (lossless bitstream) -+- XYZW (unknown chunk) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -A lossless image with an ICC profile and XMP metadata may -look as follows: - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -RIFF/WEBP -+- VP8X (descriptions of features used) -+- ICCP (color profile) -+- VP8L (lossless bitstream) -+- XMP (metadata) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -An animated image with Exif metadata may look as follows: - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -RIFF/WEBP -+- VP8X (descriptions of features used) -+- ANIM (global animation parameters) -+- ANMF (frame1 parameters + data) -+- ANMF (frame2 parameters + data) -+- ANMF (frame3 parameters + data) -+- ANMF (frame4 parameters + data) -+- EXIF (metadata) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -[webpllspec]: https://chromium.googlesource.com/webm/libwebp/+/HEAD/doc/webp-lossless-bitstream-spec.txt -[iccspec]: https://www.color.org/icc_specs2.xalter -[metadata]: https://web.archive.org/web/20180919181934/http://www.metadataworkinggroup.org/pdf/mwg_guidance.pdf -[rec601]: https://www.itu.int/rec/R-REC-BT.601 -[rfc 1166]: https://datatracker.ietf.org/doc/html/rfc1166 -[rfc 2119]: https://datatracker.ietf.org/doc/html/rfc2119 -[rfc 6386]: https://datatracker.ietf.org/doc/html/rfc6386 -[rfc 8174]: https://datatracker.ietf.org/doc/html/rfc8174 diff --git a/libwebp/doc/webp-lossless-bitstream-spec.txt b/libwebp/doc/webp-lossless-bitstream-spec.txt deleted file mode 100644 index f4db09a7..00000000 --- a/libwebp/doc/webp-lossless-bitstream-spec.txt +++ /dev/null @@ -1,1156 +0,0 @@ - - -Specification for WebP Lossless Bitstream -========================================= - -_Jyrki Alakuijala, Ph.D., Google, Inc., 2023-03-09_ - -Abstract --------- - -WebP lossless is an image format for lossless compression of ARGB images. The -lossless format stores and restores the pixel values exactly, including the -color values for fully transparent pixels. A universal algorithm for sequential -data compression (LZ77), prefix coding, and a color cache are used for -compression of the bulk data. Decoding speeds faster than PNG have been -demonstrated, as well as 25% denser compression than can be achieved using -today's PNG format. - -* TOC placeholder -{:toc} - -1 Introduction --------------- - -This document describes the compressed data representation of a WebP lossless -image. It is intended as a detailed reference for the WebP lossless encoder and -decoder implementation. - -In this document, we extensively use C programming language syntax to describe -the bitstream and assume the existence of a function for reading bits, -`ReadBits(n)`. The bytes are read in the natural order of the stream containing -them, and bits of each byte are read in least-significant-bit-first order. When -multiple bits are read at the same time, the integer is constructed from the -original data in the original order. The most significant bits of the returned -integer are also the most significant bits of the original data. Thus, the -statement - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -b = ReadBits(2); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -is equivalent with the two statements below: - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -b = ReadBits(1); -b |= ReadBits(1) << 1; -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -We assume that each color component, that is, alpha, red, blue, and green, is -represented using an 8-bit byte. We define the corresponding type as uint8. A -whole ARGB pixel is represented by a type called uint32, which is an unsigned -integer consisting of 32 bits. In the code showing the behavior of the -transforms, these values are codified in the following bits: alpha in bits -31..24, red in bits 23..16, green in bits 15..8, and blue in bits 7..0; however, -implementations of the format are free to use another representation internally. - -Broadly, a WebP lossless image contains header data, transform information, and -actual image data. Headers contain the width and height of the image. A WebP -lossless image can go through four different types of transforms before being -entropy encoded. The transform information in the bitstream contains the data -required to apply the respective inverse transforms. - -2 Nomenclature --------------- - -ARGB -: A pixel value consisting of alpha, red, green, and blue values. - -ARGB image -: A two-dimensional array containing ARGB pixels. - -color cache -: A small hash-addressed array to store recently used colors to be able to - recall them with shorter codes. - -color indexing image -: A one-dimensional image of colors that can be indexed using a small integer - (up to 256 within WebP lossless). - -color transform image -: A two-dimensional subresolution image containing data about correlations of - color components. - -distance mapping -: Changes LZ77 distances to have the smallest values for pixels in - two-dimensional proximity. - -entropy image -: A two-dimensional subresolution image indicating which entropy coding should - be used in a respective square in the image, that is, each pixel is a meta - prefix code. - -LZ77 -: A dictionary-based sliding window compression algorithm that either emits - symbols or describes them as sequences of past symbols. - -meta prefix code -: A small integer (up to 16 bits) that indexes an element in the meta prefix - table. - -predictor image -: A two-dimensional subresolution image indicating which spatial predictor is - used for a particular square in the image. - -prefix code -: A classic way to do entropy coding where a smaller number of bits are used - for more frequent codes. - -prefix coding -: A way to entropy code larger integers, which codes a few bits of the integer - using an entropy code and codifies the remaining bits raw. This allows for - the descriptions of the entropy codes to remain relatively small even when - the range of symbols is large. - -scan-line order -: A processing order of pixels (left to right and top to bottom), starting - from the left-hand-top pixel. Once a row is completed, continue from the - left-hand column of the next row. - -3 RIFF Header -------------- - -The beginning of the header has the RIFF container. This consists of the -following 21 bytes: - - 1. String 'RIFF'. - 2. A little-endian, 32-bit value of the chunk length, which is the whole size - of the chunk controlled by the RIFF header. Normally, this equals - the payload size (file size minus 8 bytes: 4 bytes for the 'RIFF' - identifier and 4 bytes for storing the value itself). - 3. String 'WEBP' (RIFF container name). - 4. String 'VP8L' (FourCC for lossless-encoded image data). - 5. A little-endian, 32-bit value of the number of bytes in the - lossless stream. - 6. 1-byte signature 0x2f. - -The first 28 bits of the bitstream specify the width and height of the image. -Width and height are decoded as 14-bit integers as follows: - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -int image_width = ReadBits(14) + 1; -int image_height = ReadBits(14) + 1; -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The 14-bit precision for image width and height limits the maximum size of a -WebP lossless image to 16384✕16384 pixels. - -The alpha_is_used bit is a hint only, and should not impact decoding. It should -be set to 0 when all alpha values are 255 in the picture, and 1 otherwise. - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -int alpha_is_used = ReadBits(1); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The version_number is a 3 bit code that must be set to 0. Any other value should -be treated as an error. - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -int version_number = ReadBits(3); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -4 Transforms ------------- - -The transforms are reversible manipulations of the image data that can reduce -the remaining symbolic entropy by modeling spatial and color correlations. They -can make the final compression more dense. - -An image can go through four types of transforms. A 1 bit indicates the -presence of a transform. Each transform is allowed to be used only once. The -transforms are used only for the main-level ARGB image; the subresolution images -(color transform image, entropy image, and predictor image) have no transforms, -not even the 0 bit indicating the end of transforms. - -Typically, an encoder would use these transforms to reduce the Shannon entropy -in the residual image. Also, the transform data can be decided based on entropy -minimization. - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -while (ReadBits(1)) { // Transform present. - // Decode transform type. - enum TransformType transform_type = ReadBits(2); - // Decode transform data. - ... -} - -// Decode actual image data (Section 5). -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -If a transform is present, then the next two bits specify the transform type. -There are four types of transforms. - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -enum TransformType { - PREDICTOR_TRANSFORM = 0, - COLOR_TRANSFORM = 1, - SUBTRACT_GREEN_TRANSFORM = 2, - COLOR_INDEXING_TRANSFORM = 3, -}; -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The transform type is followed by the transform data. Transform data contains -the information required to apply the inverse transform and depends on the -transform type. The inverse transforms are applied in the reverse order that -they are read from the bitstream, that is, last one first. - -Next, we describe the transform data for different types. - -### 4.1 Predictor Transform - -The predictor transform can be used to reduce entropy by exploiting the fact -that neighboring pixels are often correlated. In the predictor transform, the -current pixel value is predicted from the pixels already decoded (in scan-line -order) and only the residual value (actual - predicted) is encoded. The green -component of a pixel defines which of the 14 predictors is used within a -particular block of the ARGB image. The _prediction mode_ determines the type of -prediction to use. We divide the image into squares, and all the pixels in a -square use the same prediction mode. - -The first 3 bits of prediction data define the block width and height in number -of bits. - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -int size_bits = ReadBits(3) + 2; -int block_width = (1 << size_bits); -int block_height = (1 << size_bits); -#define DIV_ROUND_UP(num, den) (((num) + (den) - 1) / (den)) -int transform_width = DIV_ROUND_UP(image_width, 1 << size_bits); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The transform data contains the prediction mode for each block of the image. It -is a subresolution image where the green component of a pixel defines which of -the 14 predictors is used for all the `block_width * block_height` pixels within -a particular block of the ARGB image. This subresolution image is encoded using -the same techniques described in [Chapter 5](#image-data). - -The number of block columns, `transform_width`, is used in two-dimensional -indexing. For a pixel (x, y), one can compute the respective filter block -address by: - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -int block_index = (y >> size_bits) * transform_width + - (x >> size_bits); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -There are 14 different prediction modes. In each prediction mode, the current -pixel value is predicted from one or more neighboring pixels whose values are -already known. - -We chose the neighboring pixels (TL, T, TR, and L) of the current pixel (P) as -follows: - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -O O O O O O O O O O O -O O O O O O O O O O O -O O O O TL T TR O O O O -O O O O L P X X X X X -X X X X X X X X X X X -X X X X X X X X X X X -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -where TL means top-left, T means top, TR means top-right, and L means left. At -the time of predicting a value for P, all O, TL, T, TR and L pixels have already -been processed, and the P pixel and all X pixels are unknown. - -Given the preceding neighboring pixels, the different prediction modes are -defined as follows. - -| Mode | Predicted value of each channel of the current pixel | -| ------ | ------------------------------------------------------- | -| 0 | 0xff000000 (represents solid black color in ARGB) | -| 1 | L | -| 2 | T | -| 3 | TR | -| 4 | TL | -| 5 | Average2(Average2(L, TR), T) | -| 6 | Average2(L, TL) | -| 7 | Average2(L, T) | -| 8 | Average2(TL, T) | -| 9 | Average2(T, TR) | -| 10 | Average2(Average2(L, TL), Average2(T, TR)) | -| 11 | Select(L, T, TL) | -| 12 | ClampAddSubtractFull(L, T, TL) | -| 13 | ClampAddSubtractHalf(Average2(L, T), TL) | - - -`Average2` is defined as follows for each ARGB component: - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -uint8 Average2(uint8 a, uint8 b) { - return (a + b) / 2; -} -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The Select predictor is defined as follows: - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -uint32 Select(uint32 L, uint32 T, uint32 TL) { - // L = left pixel, T = top pixel, TL = top-left pixel. - - // ARGB component estimates for prediction. - int pAlpha = ALPHA(L) + ALPHA(T) - ALPHA(TL); - int pRed = RED(L) + RED(T) - RED(TL); - int pGreen = GREEN(L) + GREEN(T) - GREEN(TL); - int pBlue = BLUE(L) + BLUE(T) - BLUE(TL); - - // Manhattan distances to estimates for left and top pixels. - int pL = abs(pAlpha - ALPHA(L)) + abs(pRed - RED(L)) + - abs(pGreen - GREEN(L)) + abs(pBlue - BLUE(L)); - int pT = abs(pAlpha - ALPHA(T)) + abs(pRed - RED(T)) + - abs(pGreen - GREEN(T)) + abs(pBlue - BLUE(T)); - - // Return either left or top, the one closer to the prediction. - if (pL < pT) { - return L; - } else { - return T; - } -} -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The functions `ClampAddSubtractFull` and `ClampAddSubtractHalf` are performed -for each ARGB component as follows: - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Clamp the input value between 0 and 255. -int Clamp(int a) { - return (a < 0) ? 0 : (a > 255) ? 255 : a; -} -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -int ClampAddSubtractFull(int a, int b, int c) { - return Clamp(a + b - c); -} -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -int ClampAddSubtractHalf(int a, int b) { - return Clamp(a + (a - b) / 2); -} -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -There are special handling rules for some border pixels. If there is a -prediction transform, regardless of the mode \[0..13\] for these pixels, the -predicted value for the left-topmost pixel of the image is 0xff000000, all -pixels on the top row are L-pixel, and all pixels on the leftmost column are -T-pixel. - -Addressing the TR-pixel for pixels on the rightmost column is -exceptional. The pixels on the rightmost column are predicted by using the modes -\[0..13\], just like pixels not on the border, but the leftmost pixel on the -same row as the current pixel is instead used as the TR-pixel. - -The final pixel value is obtained by adding each channel of the predicted value -to the encoded residual value. - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -void PredictorTransformOutput(uint32 residual, uint32 pred, - uint8* alpha, uint8* red, - uint8* green, uint8* blue) { - *alpha = ALPHA(residual) + ALPHA(pred); - *red = RED(residual) + RED(pred); - *green = GREEN(residual) + GREEN(pred); - *blue = BLUE(residual) + BLUE(pred); -} -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -### 4.2 Color Transform - -The goal of the color transform is to decorrelate the R, G, and B values of each -pixel. The color transform keeps the green (G) value as it is, transforms the -red (R) value based on the green value, and transforms the blue (B) value based -on the green value and then on the red value. - -As is the case for the predictor transform, first the image is divided into -blocks, and the same transform mode is used for all the pixels in a block. For -each block, there are three types of color transform elements. - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -typedef struct { - uint8 green_to_red; - uint8 green_to_blue; - uint8 red_to_blue; -} ColorTransformElement; -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The actual color transform is done by defining a color transform delta. The -color transform delta depends on the `ColorTransformElement`, which is the same -for all the pixels in a particular block. The delta is subtracted during the -color transform. The inverse color transform then is just adding those deltas. - -The color transform function is defined as follows: - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -void ColorTransform(uint8 red, uint8 blue, uint8 green, - ColorTransformElement *trans, - uint8 *new_red, uint8 *new_blue) { - // Transformed values of red and blue components - int tmp_red = red; - int tmp_blue = blue; - - // Applying the transform is just subtracting the transform deltas - tmp_red -= ColorTransformDelta(trans->green_to_red, green); - tmp_blue -= ColorTransformDelta(trans->green_to_blue, green); - tmp_blue -= ColorTransformDelta(trans->red_to_blue, red); - - *new_red = tmp_red & 0xff; - *new_blue = tmp_blue & 0xff; -} -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -`ColorTransformDelta` is computed using a signed 8-bit integer representing a -3.5-fixed-point number and a signed 8-bit RGB color channel (c) \[-128..127\] -and is defined as follows: - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -int8 ColorTransformDelta(int8 t, int8 c) { - return (t * c) >> 5; -} -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -A conversion from the 8-bit unsigned representation (uint8) to the 8-bit signed -one (int8) is required before calling `ColorTransformDelta()`. The signed value -should be interpreted as an 8-bit two's complement number (that is: uint8 range -\[128..255\] is mapped to the \[-128..-1\] range of its converted int8 value). - -The multiplication is to be done using more precision (with at least 16-bit -precision). The sign extension property of the shift operation does not matter -here; only the lowest 8 bits are used from the result, and there the sign -extension shifting and unsigned shifting are consistent with each other. - -Now, we describe the contents of color transform data so that decoding can apply -the inverse color transform and recover the original red and blue values. The -first 3 bits of the color transform data contain the width and height of the -image block in number of bits, just like the predictor transform: - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -int size_bits = ReadBits(3) + 2; -int block_width = 1 << size_bits; -int block_height = 1 << size_bits; -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The remaining part of the color transform data contains `ColorTransformElement` -instances, corresponding to each block of the image. Each -`ColorTransformElement` `'cte'` is treated as a pixel in a subresolution image -whose alpha component is `255`, red component is `cte.red_to_blue`, green -component is `cte.green_to_blue`, and blue component is `cte.green_to_red`. - -During decoding, `ColorTransformElement` instances of the blocks are decoded and -the inverse color transform is applied on the ARGB values of the pixels. As -mentioned earlier, that inverse color transform is just adding -`ColorTransformElement` values to the red and blue channels. The alpha and green -channels are left as is. - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -void InverseTransform(uint8 red, uint8 green, uint8 blue, - ColorTransformElement *trans, - uint8 *new_red, uint8 *new_blue) { - // Transformed values of red and blue components - int tmp_red = red; - int tmp_blue = blue; - - // Applying the inverse transform is just adding the - // color transform deltas - tmp_red += ColorTransformDelta(trans->green_to_red, green); - tmp_blue += ColorTransformDelta(trans->green_to_blue, green); - tmp_blue += - ColorTransformDelta(trans->red_to_blue, tmp_red & 0xff); - - *new_red = tmp_red & 0xff; - *new_blue = tmp_blue & 0xff; -} -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -### 4.3 Subtract Green Transform - -The subtract green transform subtracts green values from red and blue values of -each pixel. When this transform is present, the decoder needs to add the green -value to both the red and blue values. There is no data associated with this -transform. The decoder applies the inverse transform as follows: - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -void AddGreenToBlueAndRed(uint8 green, uint8 *red, uint8 *blue) { - *red = (*red + green) & 0xff; - *blue = (*blue + green) & 0xff; -} -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -This transform is redundant, as it can be modeled using the color transform, but -since there is no additional data here, the subtract green transform can be -coded using fewer bits than a full-blown color transform. - -### 4.4 Color Indexing Transform - -If there are not many unique pixel values, it may be more efficient to create a -color index array and replace the pixel values by the array's indices. The color -indexing transform achieves this. (In the context of WebP lossless, we -specifically do not call this a palette transform because a similar but more -dynamic concept exists in WebP lossless encoding: color cache.) - -The color indexing transform checks for the number of unique ARGB values in the -image. If that number is below a threshold (256), it creates an array of those -ARGB values, which is then used to replace the pixel values with the -corresponding index: the green channel of the pixels are replaced with the -index, all alpha values are set to 255, and all red and blue values to 0. - -The transform data contains the color table size and the entries in the color -table. The decoder reads the color indexing transform data as follows: - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// 8-bit value for the color table size -int color_table_size = ReadBits(8) + 1; -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The color table is stored using the image storage format itself. The color table -can be obtained by reading an image, without the RIFF header, image size, and -transforms, assuming the height of 1 pixel and the width of `color_table_size`. -The color table is always subtraction-coded to reduce image entropy. The deltas -of palette colors contain typically much less entropy than the colors -themselves, leading to significant savings for smaller images. In decoding, -every final color in the color table can be obtained by adding the previous -color component values by each ARGB component separately and storing the least -significant 8 bits of the result. - -The inverse transform for the image is simply replacing the pixel values (which -are indices to the color table) with the actual color table values. The indexing -is done based on the green component of the ARGB color. - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Inverse transform -argb = color_table[GREEN(argb)]; -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -If the index is equal to or larger than `color_table_size`, the argb color value -should be set to 0x00000000 (transparent black). - -When the color table is small (equal to or less than 16 colors), several pixels -are bundled into a single pixel. The pixel bundling packs several (2, 4, or 8) -pixels into a single pixel, reducing the image width respectively. Pixel -bundling allows for a more efficient joint distribution entropy coding of -neighboring pixels and gives some arithmetic coding-like benefits to the -entropy code, but it can only be used when there are 16 or fewer unique values. - -`color_table_size` specifies how many pixels are combined: - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -int width_bits; -if (color_table_size <= 2) { - width_bits = 3; -} else if (color_table_size <= 4) { - width_bits = 2; -} else if (color_table_size <= 16) { - width_bits = 1; -} else { - width_bits = 0; -} -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -`width_bits` has a value of 0, 1, 2, or 3. A value of 0 indicates no pixel -bundling is to be done for the image. A value of 1 indicates that two pixels are -combined, and each pixel has a range of \[0..15\]. A value of 2 indicates that -four pixels are combined, and each pixel has a range of \[0..3\]. A value of 3 -indicates that eight pixels are combined and each pixel has a range of \[0..1\], -that is, a binary value. - -The values are packed into the green component as follows: - - * `width_bits` = 1: For every x value, where x ≡ 0 (mod 2), a green - value at x is positioned into the 4 least significant bits of the - green value at x / 2, and a green value at x + 1 is positioned into the - 4 most significant bits of the green value at x / 2. - * `width_bits` = 2: For every x value, where x ≡ 0 (mod 4), a green - value at x is positioned into the 2 least-significant bits of the - green value at x / 4, and green values at x + 1 to x + 3 are positioned in - order to the more significant bits of the green value at x / 4. - * `width_bits` = 3: For every x value, where x ≡ 0 (mod 8), a green - value at x is positioned into the least significant bit of the green - value at x / 8, and green values at x + 1 to x + 7 are positioned in order - to the more significant bits of the green value at x / 8. - -After reading this transform, `image_width` is subsampled by `width_bits`. This -affects the size of subsequent transforms. The new size can be calculated using -`DIV_ROUND_UP`, as defined [earlier](#predictor-transform). - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -image_width = DIV_ROUND_UP(image_width, 1 << width_bits); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -5 Image Data ------------- - -Image data is an array of pixel values in scan-line order. - -### 5.1 Roles of Image Data - -We use image data in five different roles: - - 1. ARGB image: Stores the actual pixels of the image. - 1. Entropy image: Stores the meta prefix codes (see - ["Decoding of Meta Prefix Codes"](#decoding-of-meta-prefix-codes)). - 1. Predictor image: Stores the metadata for the predictor transform (see - ["Predictor Transform"](#predictor-transform)). - 1. Color transform image: Created by `ColorTransformElement` values - (defined in ["Color Transform"](#color-transform)) for different blocks of - the image. - 1. Color indexing image: An array of size `color_table_size` (up to 256 ARGB - values) storing the metadata for the color indexing transform (see - ["Color Indexing Transform"](#color-indexing-transform)). - -### 5.2 Encoding of Image Data - -The encoding of image data is independent of its role. - -The image is first divided into a set of fixed-size blocks (typically 16x16 -blocks). Each of these blocks are modeled using their own entropy codes. Also, -several blocks may share the same entropy codes. - -**Rationale:** Storing an entropy code incurs a cost. This cost can be minimized -if statistically similar blocks share an entropy code, thereby storing that code -only once. For example, an encoder can find similar blocks by clustering them -using their statistical properties or by repeatedly joining a pair of randomly -selected clusters when it reduces the overall amount of bits needed to encode -the image. - -Each pixel is encoded using one of the three possible methods: - - 1. Prefix-coded literals: Each channel (green, red, blue, and alpha) is - entropy-coded independently. - 2. LZ77 backward reference: A sequence of pixels are copied from elsewhere in - the image. - 3. Color cache code: Using a short multiplicative hash code (color cache - index) of a recently seen color. - -The following subsections describe each of these in detail. - -#### 5.2.1 Prefix-Coded Literals - -The pixel is stored as prefix-coded values of green, red, blue, and alpha (in -that order). See [Section 6.2.3](#decoding-entropy-coded-image-data) for -details. - -#### 5.2.2 LZ77 Backward Reference - -Backward references are tuples of _length_ and _distance code_: - - * Length indicates how many pixels in scan-line order are to be copied. - * Distance code is a number indicating the position of a previously seen - pixel, from which the pixels are to be copied. The exact mapping is - described [below](#distance-mapping). - -The length and distance values are stored using **LZ77 prefix coding**. - -LZ77 prefix coding divides large integer values into two parts: the _prefix -code_ and the _extra bits_. The prefix code is stored using an entropy code, -while the extra bits are stored as they are (without an entropy code). - -**Rationale**: This approach reduces the storage requirement for the entropy -code. Also, large values are usually rare, so extra bits would be used for very -few values in the image. Thus, this approach results in better compression -overall. - -The following table denotes the prefix codes and extra bits used for storing -different ranges of values. - -Note: The maximum backward reference length is limited to 4096. Hence, only the -first 24 prefix codes (with the respective extra bits) are meaningful for length -values. For distance values, however, all the 40 prefix codes are valid. - -| Value range | Prefix code | Extra bits | -| --------------- | ----------- | ---------- | -| 1 | 0 | 0 | -| 2 | 1 | 0 | -| 3 | 2 | 0 | -| 4 | 3 | 0 | -| 5..6 | 4 | 1 | -| 7..8 | 5 | 1 | -| 9..12 | 6 | 2 | -| 13..16 | 7 | 2 | -| ... | ... | ... | -| 3072..4096 | 23 | 10 | -| ... | ... | ... | -| 524289..786432 | 38 | 18 | -| 786433..1048576 | 39 | 18 | - -The pseudocode to obtain a (length or distance) value from the prefix code is as -follows: - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -if (prefix_code < 4) { - return prefix_code + 1; -} -int extra_bits = (prefix_code - 2) >> 1; -int offset = (2 + (prefix_code & 1)) << extra_bits; -return offset + ReadBits(extra_bits) + 1; -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -##### Distance Mapping - -As noted previously, a distance code is a number indicating the position of a -previously seen pixel, from which the pixels are to be copied. This subsection -defines the mapping between a distance code and the position of a previous -pixel. - -Distance codes larger than 120 denote the pixel distance in scan-line order, -offset by 120. - -The smallest distance codes \[1..120\] are special and are reserved for a close -neighborhood of the current pixel. This neighborhood consists of 120 pixels: - - * Pixels that are 1 to 7 rows above the current pixel and are up to 8 columns - to the left or up to 7 columns to the right of the current pixel. \[Total - such pixels = `7 * (8 + 1 + 7) = 112`\]. - * Pixels that are in the same row as the current pixel and are up to 8 - columns to the left of the current pixel. \[`8` such pixels\]. - -The mapping between distance code `distance_code` and the neighboring pixel -offset `(xi, yi)` is as follows: - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -(0, 1), (1, 0), (1, 1), (-1, 1), (0, 2), (2, 0), (1, 2), -(-1, 2), (2, 1), (-2, 1), (2, 2), (-2, 2), (0, 3), (3, 0), -(1, 3), (-1, 3), (3, 1), (-3, 1), (2, 3), (-2, 3), (3, 2), -(-3, 2), (0, 4), (4, 0), (1, 4), (-1, 4), (4, 1), (-4, 1), -(3, 3), (-3, 3), (2, 4), (-2, 4), (4, 2), (-4, 2), (0, 5), -(3, 4), (-3, 4), (4, 3), (-4, 3), (5, 0), (1, 5), (-1, 5), -(5, 1), (-5, 1), (2, 5), (-2, 5), (5, 2), (-5, 2), (4, 4), -(-4, 4), (3, 5), (-3, 5), (5, 3), (-5, 3), (0, 6), (6, 0), -(1, 6), (-1, 6), (6, 1), (-6, 1), (2, 6), (-2, 6), (6, 2), -(-6, 2), (4, 5), (-4, 5), (5, 4), (-5, 4), (3, 6), (-3, 6), -(6, 3), (-6, 3), (0, 7), (7, 0), (1, 7), (-1, 7), (5, 5), -(-5, 5), (7, 1), (-7, 1), (4, 6), (-4, 6), (6, 4), (-6, 4), -(2, 7), (-2, 7), (7, 2), (-7, 2), (3, 7), (-3, 7), (7, 3), -(-7, 3), (5, 6), (-5, 6), (6, 5), (-6, 5), (8, 0), (4, 7), -(-4, 7), (7, 4), (-7, 4), (8, 1), (8, 2), (6, 6), (-6, 6), -(8, 3), (5, 7), (-5, 7), (7, 5), (-7, 5), (8, 4), (6, 7), -(-6, 7), (7, 6), (-7, 6), (8, 5), (7, 7), (-7, 7), (8, 6), -(8, 7) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -For example, the distance code `1` indicates an offset of `(0, 1)` for the -neighboring pixel, that is, the pixel above the current pixel (0 pixel -difference in the X direction and 1 pixel difference in the Y direction). -Similarly, the distance code `3` indicates the top-left pixel. - -The decoder can convert a distance code `distance_code` to a scan-line order -distance `dist` as follows: - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -(xi, yi) = distance_map[distance_code - 1] -dist = xi + yi * image_width -if (dist < 1) { - dist = 1 -} -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -where `distance_map` is the mapping noted above, and `image_width` is the width -of the image in pixels. - -#### 5.2.3 Color Cache Coding -{:#color-cache-code} - -Color cache stores a set of colors that have been recently used in the image. - -**Rationale:** This way, the recently used colors can sometimes be referred to -more efficiently than emitting them using the other two methods (described in -Sections [5.2.1](#prefix-coded-literals) and [5.2.2](#lz77-backward-reference)). - -Color cache codes are stored as follows. First, there is a 1-bit value that -indicates if the color cache is used. If this bit is 0, no color cache codes -exist, and they are not transmitted in the prefix code that decodes the green -symbols and the length prefix codes. However, if this bit is 1, the color cache -size is read next: - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -int color_cache_code_bits = ReadBits(4); -int color_cache_size = 1 << color_cache_code_bits; -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -`color_cache_code_bits` defines the size of the color cache (`1 << -color_cache_code_bits`). The range of allowed values for -`color_cache_code_bits` is \[1..11\]. Compliant decoders must indicate a -corrupted bitstream for other values. - -A color cache is an array of size `color_cache_size`. Each entry stores one ARGB -color. Colors are looked up by indexing them by `(0x1e35a7bd * color) >> (32 - -color_cache_code_bits)`. Only one lookup is done in a color cache; there is no -conflict resolution. - -In the beginning of decoding or encoding of an image, all entries in all color -cache values are set to zero. The color cache code is converted to this color at -decoding time. The state of the color cache is maintained by inserting every -pixel, be it produced by backward referencing or as literals, into the cache in -the order they appear in the stream. - -6 Entropy Code --------------- - -### 6.1 Overview - -Most of the data is coded using a [canonical prefix code][canonical_huff]. -Hence, the codes are transmitted by sending the _prefix code lengths_, as -opposed to the actual _prefix codes_. - -In particular, the format uses **spatially variant prefix coding**. In other -words, different blocks of the image can potentially use different entropy -codes. - -**Rationale**: Different areas of the image may have different characteristics. -So, allowing them to use different entropy codes provides more flexibility and -potentially better compression. - -### 6.2 Details - -The encoded image data consists of several parts: - - 1. Decoding and building the prefix codes. - 1. Meta prefix codes. - 1. Entropy-coded image data. - -For any given pixel (x, y), there is a set of five prefix codes associated with -it. These codes are (in bitstream order): - - * **Prefix code #1**: Used for green channel, backward-reference length, and - color cache. - * **Prefix code #2, #3, and #4**: Used for red, blue, and alpha channels, - respectively. - * **Prefix code #5**: Used for backward-reference distance. - -From here on, we refer to this set as a **prefix code group**. - -#### 6.2.1 Decoding and Building the Prefix Codes - -This section describes how to read the prefix code lengths from the bitstream. - -The prefix code lengths can be coded in two ways. The method used is specified -by a 1-bit value. - - * If this bit is 1, it is a _simple code length code_. - * If this bit is 0, it is a _normal code length code_. - -In both cases, there can be unused code lengths that are still part of the -stream. This may be inefficient, but it is allowed by the format. -The described tree must be a complete binary tree. A single leaf node is -considered a complete binary tree and can be encoded using either the simple -code length code or the normal code length code. When coding a single leaf -node using the _normal code length code_, all but one code length are zeros, -and the single leaf node value is marked with the length of 1 -- even when no -bits are consumed when that single leaf node tree is used. - -##### Simple Code Length Code - -This variant is used in the special case when only 1 or 2 prefix symbols are in -the range \[0..255\] with code length `1`. All other prefix code lengths are -implicitly zeros. - -The first bit indicates the number of symbols: - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -int num_symbols = ReadBits(1) + 1; -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The following are the symbol values. - -This first symbol is coded using 1 or 8 bits, depending on the value of -`is_first_8bits`. The range is \[0..1\] or \[0..255\], respectively. The second -symbol, if present, is always assumed to be in the range \[0..255\] and coded -using 8 bits. - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -int is_first_8bits = ReadBits(1); -symbol0 = ReadBits(1 + 7 * is_first_8bits); -code_lengths[symbol0] = 1; -if (num_symbols == 2) { - symbol1 = ReadBits(8); - code_lengths[symbol1] = 1; -} -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The two symbols should be different. Duplicate symbols are allowed, but -inefficient. - -**Note:** Another special case is when _all_ prefix code lengths are _zeros_ (an -empty prefix code). For example, a prefix code for distance can be empty if -there are no backward references. Similarly, prefix codes for alpha, red, and -blue can be empty if all pixels within the same meta prefix code are produced -using the color cache. However, this case doesn't need special handling, as -empty prefix codes can be coded as those containing a single symbol `0`. - -##### Normal Code Length Code - -The code lengths of the prefix code fit in 8 bits and are read as follows. -First, `num_code_lengths` specifies the number of code lengths. - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -int num_code_lengths = 4 + ReadBits(4); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The code lengths are themselves encoded using prefix codes; lower-level code -lengths, `code_length_code_lengths`, first have to be read. The rest of those -`code_length_code_lengths` (according to the order in `kCodeLengthCodeOrder`) -are zeros. - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -int kCodeLengthCodes = 19; -int kCodeLengthCodeOrder[kCodeLengthCodes] = { - 17, 18, 0, 1, 2, 3, 4, 5, 16, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 -}; -int code_length_code_lengths[kCodeLengthCodes] = { 0 }; // All zeros -for (i = 0; i < num_code_lengths; ++i) { - code_length_code_lengths[kCodeLengthCodeOrder[i]] = ReadBits(3); -} -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Next, if `ReadBits(1) == 0`, the maximum number of different read symbols -(`max_symbol`) for each symbol type (A, R, G, B, and distance) is set to its -alphabet size: - - * G channel: 256 + 24 + `color_cache_size` - * Other literals (A, R, and B): 256 - * Distance code: 40 - -Otherwise, it is defined as: - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -int length_nbits = 2 + 2 * ReadBits(3); -int max_symbol = 2 + ReadBits(length_nbits); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -If `max_symbol` is larger than the size of the alphabet for the symbol type, the -bitstream is invalid. - -A prefix table is then built from `code_length_code_lengths` and used to read up -to `max_symbol` code lengths. - - * Code \[0..15\] indicates literal code lengths. - * Value 0 means no symbols have been coded. - * Values \[1..15\] indicate the bit length of the respective code. - * Code 16 repeats the previous nonzero value \[3..6\] times, that is, - `3 + ReadBits(2)` times. If code 16 is used before a nonzero - value has been emitted, a value of 8 is repeated. - * Code 17 emits a streak of zeros of length \[3..10\], that is, `3 + - ReadBits(3)` times. - * Code 18 emits a streak of zeros of length \[11..138\], that is, - `11 + ReadBits(7)` times. - -Once code lengths are read, a prefix code for each symbol type (A, R, G, B, and -distance) is formed using their respective alphabet sizes. - -The Normal Code Length Code must code a full decision tree, that is, the sum of -`2 ^ (-length)` for all non-zero codes must be exactly one. There is however -one exception to this rule, the single leaf node tree, where the leaf node -value is marked with value 1 and other values are 0s. - -#### 6.2.2 Decoding of Meta Prefix Codes - -As noted earlier, the format allows the use of different prefix codes for -different blocks of the image. _Meta prefix codes_ are indexes identifying which -prefix codes to use in different parts of the image. - -Meta prefix codes may be used _only_ when the image is being used in the -[role](#roles-of-image-data) of an _ARGB image_. - -There are two possibilities for the meta prefix codes, indicated by a 1-bit -value: - - * If this bit is zero, there is only one meta prefix code used everywhere in - the image. No more data is stored. - * If this bit is one, the image uses multiple meta prefix codes. These meta - prefix codes are stored as an _entropy image_ (described below). - -The red and green components of a pixel define a 16-bit meta prefix code used in -a particular block of the ARGB image. - -##### Entropy Image - -The entropy image defines which prefix codes are used in different parts of the -image. - -The first 3 bits contain the `prefix_bits` value. The dimensions of the entropy -image are derived from `prefix_bits`: - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -int prefix_bits = ReadBits(3) + 2; -int prefix_image_width = - DIV_ROUND_UP(image_width, 1 << prefix_bits); -int prefix_image_height = - DIV_ROUND_UP(image_height, 1 << prefix_bits); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -where `DIV_ROUND_UP` is as defined [earlier](#predictor-transform). - -The next bits contain an entropy image of width `prefix_image_width` and height -`prefix_image_height`. - -##### Interpretation of Meta Prefix Codes - -The number of prefix code groups in the ARGB image can be obtained by finding -the _largest meta prefix code_ from the entropy image: - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -int num_prefix_groups = max(entropy image) + 1; -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -where `max(entropy image)` indicates the largest prefix code stored in the -entropy image. - -As each prefix code group contains five prefix codes, the total number of prefix -codes is: - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -int num_prefix_codes = 5 * num_prefix_groups; -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Given a pixel (x, y) in the ARGB image, we can obtain the corresponding prefix -codes to be used as follows: - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -int position = - (y >> prefix_bits) * prefix_image_width + (x >> prefix_bits); -int meta_prefix_code = (entropy_image[position] >> 8) & 0xffff; -PrefixCodeGroup prefix_group = prefix_code_groups[meta_prefix_code]; -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -where we have assumed the existence of `PrefixCodeGroup` structure, which -represents a set of five prefix codes. Also, `prefix_code_groups` is an array of -`PrefixCodeGroup` (of size `num_prefix_groups`). - -The decoder then uses prefix code group `prefix_group` to decode the pixel -(x, y), as explained in ["Decoding Entropy-Coded Image -Data"](#decoding-entropy-coded-image-data). - -#### 6.2.3 Decoding Entropy-Coded Image Data - -For the current position (x, y) in the image, the decoder first identifies the -corresponding prefix code group (as explained in the last section). Given the -prefix code group, the pixel is read and decoded as follows. - -Next, read the symbol S from the bitstream using prefix code #1. Note that S is -any integer in the range `0` to -`(256 + 24 + ` [`color_cache_size`](#color-cache-code)` - 1)`. - -The interpretation of S depends on its value: - - 1. If S < 256 - 1. Use S as the green component. - 1. Read red from the bitstream using prefix code #2. - 1. Read blue from the bitstream using prefix code #3. - 1. Read alpha from the bitstream using prefix code #4. - 1. If S >= 256 & S < 256 + 24 - 1. Use S - 256 as a length prefix code. - 1. Read extra bits for the length from the bitstream. - 1. Determine backward-reference length L from length prefix code and the - extra bits read. - 1. Read the distance prefix code from the bitstream using prefix code #5. - 1. Read extra bits for the distance from the bitstream. - 1. Determine backward-reference distance D from the distance prefix code - and the extra bits read. - 1. Copy L pixels (in scan-line order) from the sequence of pixels starting - at the current position minus D pixels. - 1. If S >= 256 + 24 - 1. Use S - (256 + 24) as the index into the color cache. - 1. Get ARGB color from the color cache at that index. - -7 Overall Structure of the Format ---------------------------------- - -Below is a view into the format in Augmented Backus-Naur Form (ABNF) -[RFC 5234][] [RFC 7405][]. It does not cover all details. The end-of-image (EOI) -is only implicitly coded into the number of pixels (image_width * image_height). - -Note that `*element` means `element` can be repeated 0 or more times. `5element` -means `element` is repeated exactly 5 times. `%b` represents a binary value. - -#### 7.1 Basic Structure - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -format = RIFF-header image-header image-stream -RIFF-header = %s"RIFF" 4OCTET %s"WEBPVP8L" 4OCTET -image-header = %x2F image-size alpha-is-used version -image-size = 14BIT 14BIT ; width - 1, height - 1 -alpha-is-used = 1BIT -version = 3BIT ; 0 -image-stream = optional-transform spatially-coded-image -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -#### 7.2 Structure of Transforms - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -optional-transform = (%b1 transform optional-transform) / %b0 -transform = predictor-tx / color-tx / subtract-green-tx -transform =/ color-indexing-tx - -predictor-tx = %b00 predictor-image -predictor-image = 3BIT ; sub-pixel code - entropy-coded-image - -color-tx = %b01 color-image -color-image = 3BIT ; sub-pixel code - entropy-coded-image - -subtract-green-tx = %b10 - -color-indexing-tx = %b11 color-indexing-image -color-indexing-image = 8BIT ; color count - entropy-coded-image -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -#### 7.3 Structure of the Image Data - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -spatially-coded-image = color-cache-info meta-prefix data -entropy-coded-image = color-cache-info data - -color-cache-info = %b0 -color-cache-info =/ (%b1 4BIT) ; 1 followed by color cache size - -meta-prefix = %b0 / (%b1 entropy-image) - -data = prefix-codes lz77-coded-image -entropy-image = 3BIT ; subsample value - entropy-coded-image - -prefix-codes = prefix-code-group *prefix-codes -prefix-code-group = - 5prefix-code ; See "Interpretation of Meta Prefix Codes" to - ; understand what each of these five prefix - ; codes are for. - -prefix-code = simple-prefix-code / normal-prefix-code -simple-prefix-code = ; see "Simple Code Length Code" for details -normal-prefix-code = ; see "Normal Code Length Code" for details - -lz77-coded-image = - *((argb-pixel / lz77-copy / color-cache-code) lz77-coded-image) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The following is a possible example sequence: - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -RIFF-header image-size %b1 subtract-green-tx -%b1 predictor-tx %b0 color-cache-info -%b0 prefix-codes lz77-coded-image -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -[RFC 5234]: https://www.rfc-editor.org/rfc/rfc5234 -[RFC 7405]: https://www.rfc-editor.org/rfc/rfc7405 -[canonical_huff]: https://en.wikipedia.org/wiki/Canonical_Huffman_code diff --git a/libwebp/examples/Android.mk b/libwebp/examples/Android.mk deleted file mode 100644 index ae0f5b42..00000000 --- a/libwebp/examples/Android.mk +++ /dev/null @@ -1,96 +0,0 @@ -# Ignore this file during non-NDK builds. -ifdef NDK_ROOT -LOCAL_PATH := $(call my-dir) - -################################################################################ -# libexample_util - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - example_util.c \ - -LOCAL_CFLAGS := $(WEBP_CFLAGS) -LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src - -LOCAL_MODULE := example_util - -include $(BUILD_STATIC_LIBRARY) - -################################################################################ -# cwebp - -include $(CLEAR_VARS) - -# Note: to enable jpeg/png encoding the sources from AOSP can be used with -# minor modification to their Android.mk files. -LOCAL_SRC_FILES := \ - cwebp.c \ - -LOCAL_CFLAGS := $(WEBP_CFLAGS) -LOCAL_STATIC_LIBRARIES := example_util imageio_util imagedec webpdemux webp - -LOCAL_MODULE := cwebp - -include $(BUILD_EXECUTABLE) - -################################################################################ -# dwebp - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - dwebp.c \ - -LOCAL_CFLAGS := $(WEBP_CFLAGS) -LOCAL_STATIC_LIBRARIES := example_util imagedec imageenc webpdemux webp -LOCAL_MODULE := dwebp - -include $(BUILD_EXECUTABLE) - -################################################################################ -# webpmux - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - webpmux.c \ - -LOCAL_CFLAGS := $(WEBP_CFLAGS) -LOCAL_STATIC_LIBRARIES := example_util imageio_util webpmux webp - -LOCAL_MODULE := webpmux_example - -include $(BUILD_EXECUTABLE) - -################################################################################ -# img2webp - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - img2webp.c \ - -LOCAL_CFLAGS := $(WEBP_CFLAGS) -LOCAL_STATIC_LIBRARIES := example_util imageio_util imagedec webpmux webpdemux \ - webp - -LOCAL_MODULE := img2webp_example - -include $(BUILD_EXECUTABLE) - -################################################################################ -# webpinfo - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - webpinfo.c \ - -LOCAL_CFLAGS := $(WEBP_CFLAGS) -LOCAL_STATIC_LIBRARIES := example_util imageio_util webp - -LOCAL_MODULE := webpinfo_example - -include $(BUILD_EXECUTABLE) -endif # NDK_ROOT diff --git a/libwebp/examples/Makefile.am b/libwebp/examples/Makefile.am deleted file mode 100644 index bbf0bac9..00000000 --- a/libwebp/examples/Makefile.am +++ /dev/null @@ -1,119 +0,0 @@ -AM_CPPFLAGS += -I$(top_builddir)/src -I$(top_srcdir)/src - -bin_PROGRAMS = -if BUILD_DEMUX - bin_PROGRAMS += dwebp cwebp -endif -if BUILD_ANIMDIFF - noinst_PROGRAMS = anim_diff anim_dump -endif -if BUILD_GIF2WEBP - bin_PROGRAMS += gif2webp -endif -if BUILD_IMG2WEBP - bin_PROGRAMS += img2webp -endif -if BUILD_MUX - bin_PROGRAMS += webpmux -endif -if BUILD_VWEBP - bin_PROGRAMS += vwebp -endif -if BUILD_WEBPINFO - bin_PROGRAMS += webpinfo -endif - -noinst_LTLIBRARIES = libexample_util.la - -libexample_util_la_SOURCES = example_util.c example_util.h -libexample_util_la_LIBADD = ../src/libwebp.la - -anim_diff_SOURCES = anim_diff.c anim_util.c anim_util.h gifdec.c gifdec.h -anim_diff_CPPFLAGS = $(AM_CPPFLAGS) $(GIF_INCLUDES) -anim_diff_LDADD = -anim_diff_LDADD += ../src/demux/libwebpdemux.la -anim_diff_LDADD += libexample_util.la -anim_diff_LDADD += ../imageio/libimageio_util.la -anim_diff_LDADD += $(GIF_LIBS) -lm - -anim_dump_SOURCES = anim_dump.c anim_util.c anim_util.h gifdec.c gifdec.h -anim_dump_CPPFLAGS = $(AM_CPPFLAGS) $(PNG_INCLUDES) -anim_dump_CPPFLAGS += $(GIF_INCLUDES) -anim_dump_LDADD = -anim_dump_LDADD += ../src/demux/libwebpdemux.la -anim_dump_LDADD += libexample_util.la -anim_dump_LDADD += ../imageio/libimageio_util.la -anim_dump_LDADD += ../imageio/libimageenc.la -anim_dump_LDADD += $(PNG_LIBS) $(GIF_LIBS) $(TIFF_LIBS) -lm - -cwebp_SOURCES = cwebp.c stopwatch.h -cwebp_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir) -cwebp_LDADD = -cwebp_LDADD += libexample_util.la -cwebp_LDADD += ../imageio/libimageio_util.la -cwebp_LDADD += ../imageio/libimagedec.la -cwebp_LDADD += ../src/libwebp.la -cwebp_LDADD += $(JPEG_LIBS) $(PNG_LIBS) $(TIFF_LIBS) - -dwebp_SOURCES = dwebp.c stopwatch.h -dwebp_CPPFLAGS = $(AM_CPPFLAGS) -dwebp_CPPFLAGS += $(JPEG_INCLUDES) $(PNG_INCLUDES) -dwebp_LDADD = -dwebp_LDADD += libexample_util.la -dwebp_LDADD += ../imageio/libimagedec.la -dwebp_LDADD += ../imageio/libimageenc.la -dwebp_LDADD += ../imageio/libimageio_util.la -dwebp_LDADD += ../src/libwebp.la -dwebp_LDADD +=$(PNG_LIBS) $(JPEG_LIBS) - -gif2webp_SOURCES = gif2webp.c gifdec.c gifdec.h -gif2webp_CPPFLAGS = $(AM_CPPFLAGS) $(GIF_INCLUDES) -gif2webp_LDADD = -gif2webp_LDADD += libexample_util.la -gif2webp_LDADD += ../imageio/libimageio_util.la -gif2webp_LDADD += ../src/mux/libwebpmux.la -gif2webp_LDADD += ../src/libwebp.la -gif2webp_LDADD += $(GIF_LIBS) - -vwebp_SOURCES = vwebp.c -vwebp_CPPFLAGS = $(AM_CPPFLAGS) $(GL_INCLUDES) -vwebp_LDADD = -vwebp_LDADD += libexample_util.la -vwebp_LDADD += ../imageio/libimageio_util.la -vwebp_LDADD += ../src/demux/libwebpdemux.la -vwebp_LDADD += $(GL_LIBS) - -webpmux_SOURCES = webpmux.c -webpmux_CPPFLAGS = $(AM_CPPFLAGS) -webpmux_LDADD = -webpmux_LDADD += libexample_util.la -webpmux_LDADD += ../imageio/libimageio_util.la -webpmux_LDADD += ../src/mux/libwebpmux.la -webpmux_LDADD += ../src/libwebp.la - -img2webp_SOURCES = img2webp.c -img2webp_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir) -img2webp_LDADD = -img2webp_LDADD += libexample_util.la -img2webp_LDADD += ../imageio/libimageio_util.la -img2webp_LDADD += ../imageio/libimagedec.la -img2webp_LDADD += ../src/mux/libwebpmux.la -img2webp_LDADD += ../src/libwebp.la -img2webp_LDADD += $(PNG_LIBS) $(JPEG_LIBS) $(TIFF_LIBS) - -webpinfo_SOURCES = webpinfo.c -webpinfo_CPPFLAGS = $(AM_CPPFLAGS) -webpinfo_LDADD = -webpinfo_LDADD += libexample_util.la -webpinfo_LDADD += ../imageio/libimageio_util.la -webpinfo_LDADD += ../src/libwebp.la - -if BUILD_LIBWEBPDECODER - anim_diff_LDADD += ../src/libwebpdecoder.la - anim_dump_LDADD += ../src/libwebpdecoder.la - vwebp_LDADD += ../src/libwebpdecoder.la -else - anim_diff_LDADD += ../src/libwebp.la - anim_dump_LDADD += ../src/libwebp.la - vwebp_LDADD += ../src/libwebp.la -endif diff --git a/libwebp/examples/anim_diff.c b/libwebp/examples/anim_diff.c deleted file mode 100644 index 7ffabc8f..00000000 --- a/libwebp/examples/anim_diff.c +++ /dev/null @@ -1,317 +0,0 @@ -// Copyright 2015 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Checks if given pair of animated GIF/WebP images are identical: -// That is: their reconstructed canvases match pixel-by-pixel and their other -// animation properties (loop count etc) also match. -// -// example: anim_diff foo.gif bar.webp - -#include -#include -#include -#include // for 'strtod'. -#include // for 'strcmp'. - -#include "./anim_util.h" -#include "./example_util.h" -#include "./unicode.h" - -#if defined(_MSC_VER) && _MSC_VER < 1900 -#define snprintf _snprintf -#endif - -// Returns true if 'a + b' will overflow. -static int AdditionWillOverflow(int a, int b) { - return (b > 0) && (a > INT_MAX - b); -} - -static int FramesAreEqual(const uint8_t* const rgba1, - const uint8_t* const rgba2, int width, int height) { - const int stride = width * 4; // Always true for 'DecodedFrame.rgba'. - return !memcmp(rgba1, rgba2, stride * height); -} - -static WEBP_INLINE int PixelsAreSimilar(uint32_t src, uint32_t dst, - int max_allowed_diff) { - const int src_a = (src >> 24) & 0xff; - const int src_r = (src >> 16) & 0xff; - const int src_g = (src >> 8) & 0xff; - const int src_b = (src >> 0) & 0xff; - const int dst_a = (dst >> 24) & 0xff; - const int dst_r = (dst >> 16) & 0xff; - const int dst_g = (dst >> 8) & 0xff; - const int dst_b = (dst >> 0) & 0xff; - - return (abs(src_r * src_a - dst_r * dst_a) <= (max_allowed_diff * 255)) && - (abs(src_g * src_a - dst_g * dst_a) <= (max_allowed_diff * 255)) && - (abs(src_b * src_a - dst_b * dst_a) <= (max_allowed_diff * 255)) && - (abs(src_a - dst_a) <= max_allowed_diff); -} - -static int FramesAreSimilar(const uint8_t* const rgba1, - const uint8_t* const rgba2, - int width, int height, int max_allowed_diff) { - int i, j; - assert(max_allowed_diff > 0); - for (j = 0; j < height; ++j) { - for (i = 0; i < width; ++i) { - const int stride = width * 4; - const size_t offset = j * stride + i; - if (!PixelsAreSimilar(rgba1[offset], rgba2[offset], max_allowed_diff)) { - return 0; - } - } - } - return 1; -} - -// Minimize number of frames by combining successive frames that have at max -// 'max_diff' difference per channel between corresponding pixels. -static void MinimizeAnimationFrames(AnimatedImage* const img, int max_diff) { - uint32_t i; - for (i = 1; i < img->num_frames; ++i) { - DecodedFrame* const frame1 = &img->frames[i - 1]; - DecodedFrame* const frame2 = &img->frames[i]; - const uint8_t* const rgba1 = frame1->rgba; - const uint8_t* const rgba2 = frame2->rgba; - int should_merge_frames = 0; - // If merging frames will result in integer overflow for 'duration', - // skip merging. - if (AdditionWillOverflow(frame1->duration, frame2->duration)) continue; - if (max_diff > 0) { - should_merge_frames = FramesAreSimilar(rgba1, rgba2, img->canvas_width, - img->canvas_height, max_diff); - } else { - should_merge_frames = - FramesAreEqual(rgba1, rgba2, img->canvas_width, img->canvas_height); - } - if (should_merge_frames) { // Merge 'i+1'th frame into 'i'th frame. - frame1->duration += frame2->duration; - if (i + 1 < img->num_frames) { - memmove(&img->frames[i], &img->frames[i + 1], - (img->num_frames - i - 1) * sizeof(*img->frames)); - } - --img->num_frames; - --i; - } - } -} - -static int CompareValues(uint32_t a, uint32_t b, const char* output_str) { - if (a != b) { - fprintf(stderr, "%s: %d vs %d\n", output_str, a, b); - return 0; - } - return 1; -} - -static int CompareBackgroundColor(uint32_t bg1, uint32_t bg2, int premultiply) { - if (premultiply) { - const int alpha1 = (bg1 >> 24) & 0xff; - const int alpha2 = (bg2 >> 24) & 0xff; - if (alpha1 == 0 && alpha2 == 0) return 1; - } - if (bg1 != bg2) { - fprintf(stderr, "Background color mismatch: 0x%08x vs 0x%08x\n", - bg1, bg2); - return 0; - } - return 1; -} - -// Note: As long as frame durations and reconstructed frames are identical, it -// is OK for other aspects like offsets, dispose/blend method to vary. -static int CompareAnimatedImagePair(const AnimatedImage* const img1, - const AnimatedImage* const img2, - int premultiply, - double min_psnr) { - int ok = 1; - const int is_multi_frame_image = (img1->num_frames > 1); - uint32_t i; - - ok = CompareValues(img1->canvas_width, img2->canvas_width, - "Canvas width mismatch") && ok; - ok = CompareValues(img1->canvas_height, img2->canvas_height, - "Canvas height mismatch") && ok; - ok = CompareValues(img1->num_frames, img2->num_frames, - "Frame count mismatch") && ok; - if (!ok) return 0; // These are fatal failures, can't proceed. - - if (is_multi_frame_image) { // Checks relevant for multi-frame images only. - int max_loop_count_workaround = 0; - // Transcodes to webp increase the gif loop count by 1 for compatibility. - // When the gif has the maximum value the webp value will be off by one. - if ((img1->format == ANIM_GIF && img1->loop_count == 65536 && - img2->format == ANIM_WEBP && img2->loop_count == 65535) || - (img1->format == ANIM_WEBP && img1->loop_count == 65535 && - img2->format == ANIM_GIF && img2->loop_count == 65536)) { - max_loop_count_workaround = 1; - } - ok = (max_loop_count_workaround || - CompareValues(img1->loop_count, img2->loop_count, - "Loop count mismatch")) && ok; - ok = CompareBackgroundColor(img1->bgcolor, img2->bgcolor, - premultiply) && ok; - } - - for (i = 0; i < img1->num_frames; ++i) { - // Pixel-by-pixel comparison. - const uint8_t* const rgba1 = img1->frames[i].rgba; - const uint8_t* const rgba2 = img2->frames[i].rgba; - int max_diff; - double psnr; - if (is_multi_frame_image) { // Check relevant for multi-frame images only. - const char format[] = "Frame #%d, duration mismatch"; - char tmp[sizeof(format) + 8]; - ok = ok && (snprintf(tmp, sizeof(tmp), format, i) >= 0); - ok = ok && CompareValues(img1->frames[i].duration, - img2->frames[i].duration, tmp); - } - GetDiffAndPSNR(rgba1, rgba2, img1->canvas_width, img1->canvas_height, - premultiply, &max_diff, &psnr); - if (min_psnr > 0.) { - if (psnr < min_psnr) { - fprintf(stderr, "Frame #%d, psnr = %.2lf (min_psnr = %f)\n", i, - psnr, min_psnr); - ok = 0; - } - } else { - if (max_diff != 0) { - fprintf(stderr, "Frame #%d, max pixel diff: %d\n", i, max_diff); - ok = 0; - } - } - } - return ok; -} - -static void Help(void) { - printf("Usage: anim_diff [options]\n"); - printf("\nOptions:\n"); - printf(" -dump_frames dump decoded frames in PAM format\n"); - printf(" -min_psnr ... minimum per-frame PSNR\n"); - printf(" -raw_comparison ..... if this flag is not used, RGB is\n"); - printf(" premultiplied before comparison\n"); - printf(" -max_diff ..... maximum allowed difference per channel\n" - " between corresponding pixels in subsequent\n" - " frames\n"); - printf(" -h .................. this help\n"); - printf(" -version ............ print version number and exit\n"); -} - -int main(int argc, const char* argv[]) { - int return_code = -1; - int dump_frames = 0; - const char* dump_folder = NULL; - double min_psnr = 0.; - int got_input1 = 0; - int got_input2 = 0; - int premultiply = 1; - int max_diff = 0; - int i, c; - const char* files[2] = { NULL, NULL }; - AnimatedImage images[2]; - - INIT_WARGV(argc, argv); - - for (c = 1; c < argc; ++c) { - int parse_error = 0; - if (!strcmp(argv[c], "-dump_frames")) { - if (c < argc - 1) { - dump_frames = 1; - dump_folder = (const char*)GET_WARGV(argv, ++c); - } else { - parse_error = 1; - } - } else if (!strcmp(argv[c], "-min_psnr")) { - if (c < argc - 1) { - min_psnr = ExUtilGetFloat(argv[++c], &parse_error); - } else { - parse_error = 1; - } - } else if (!strcmp(argv[c], "-raw_comparison")) { - premultiply = 0; - } else if (!strcmp(argv[c], "-max_diff")) { - if (c < argc - 1) { - max_diff = ExUtilGetInt(argv[++c], 0, &parse_error); - } else { - parse_error = 1; - } - } else if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) { - Help(); - FREE_WARGV_AND_RETURN(0); - } else if (!strcmp(argv[c], "-version")) { - int dec_version, demux_version; - GetAnimatedImageVersions(&dec_version, &demux_version); - printf("WebP Decoder version: %d.%d.%d\nWebP Demux version: %d.%d.%d\n", - (dec_version >> 16) & 0xff, (dec_version >> 8) & 0xff, - (dec_version >> 0) & 0xff, - (demux_version >> 16) & 0xff, (demux_version >> 8) & 0xff, - (demux_version >> 0) & 0xff); - FREE_WARGV_AND_RETURN(0); - } else { - if (!got_input1) { - files[0] = (const char*)GET_WARGV(argv, c); - got_input1 = 1; - } else if (!got_input2) { - files[1] = (const char*)GET_WARGV(argv, c); - got_input2 = 1; - } else { - parse_error = 1; - } - } - if (parse_error) { - Help(); - FREE_WARGV_AND_RETURN(-1); - } - } - if (argc < 3) { - Help(); - FREE_WARGV_AND_RETURN(-1); - } - - - if (!got_input2) { - Help(); - FREE_WARGV_AND_RETURN(-1); - } - - if (dump_frames) { - WPRINTF("Dumping decoded frames in: %s\n", (const W_CHAR*)dump_folder); - } - - memset(images, 0, sizeof(images)); - for (i = 0; i < 2; ++i) { - WPRINTF("Decoding file: %s\n", (const W_CHAR*)files[i]); - if (!ReadAnimatedImage(files[i], &images[i], dump_frames, dump_folder)) { - WFPRINTF(stderr, "Error decoding file: %s\n Aborting.\n", - (const W_CHAR*)files[i]); - return_code = -2; - goto End; - } else { - MinimizeAnimationFrames(&images[i], max_diff); - } - } - - if (!CompareAnimatedImagePair(&images[0], &images[1], - premultiply, min_psnr)) { - WFPRINTF(stderr, "\nFiles %s and %s differ.\n", (const W_CHAR*)files[0], - (const W_CHAR*)files[1]); - return_code = -3; - } else { - WPRINTF("\nFiles %s and %s are identical.\n", (const W_CHAR*)files[0], - (const W_CHAR*)files[1]); - return_code = 0; - } - End: - ClearAnimatedImage(&images[0]); - ClearAnimatedImage(&images[1]); - FREE_WARGV_AND_RETURN(return_code); -} diff --git a/libwebp/examples/anim_dump.c b/libwebp/examples/anim_dump.c deleted file mode 100644 index 269cbaba..00000000 --- a/libwebp/examples/anim_dump.c +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright 2017 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Decodes an animated WebP file and dumps the decoded frames as PNG or TIFF. -// -// Author: Skal (pascal.massimino@gmail.com) - -#include -#include // for 'strcmp'. - -#include "./anim_util.h" -#include "webp/decode.h" -#include "../imageio/image_enc.h" -#include "./unicode.h" - -#if defined(_MSC_VER) && _MSC_VER < 1900 -#define snprintf _snprintf -#endif - -static void Help(void) { - printf("Usage: anim_dump [options] files...\n"); - printf("\nOptions:\n"); - printf(" -folder .... dump folder (default: '.')\n"); - printf(" -prefix .... prefix for dumped frames " - "(default: 'dump_')\n"); - printf(" -tiff ............... save frames as TIFF\n"); - printf(" -pam ................ save frames as PAM\n"); - printf(" -h .................. this help\n"); - printf(" -version ............ print version number and exit\n"); -} - -int main(int argc, const char* argv[]) { - int error = 0; - const W_CHAR* dump_folder = TO_W_CHAR("."); - const W_CHAR* prefix = TO_W_CHAR("dump_"); - const W_CHAR* suffix = TO_W_CHAR("png"); - WebPOutputFileFormat format = PNG; - int c; - - INIT_WARGV(argc, argv); - - if (argc < 2) { - Help(); - FREE_WARGV_AND_RETURN(-1); - } - - for (c = 1; !error && c < argc; ++c) { - if (!strcmp(argv[c], "-folder")) { - if (c + 1 == argc) { - fprintf(stderr, "missing argument after option '%s'\n", argv[c]); - error = 1; - break; - } - dump_folder = GET_WARGV(argv, ++c); - } else if (!strcmp(argv[c], "-prefix")) { - if (c + 1 == argc) { - fprintf(stderr, "missing argument after option '%s'\n", argv[c]); - error = 1; - break; - } - prefix = GET_WARGV(argv, ++c); - } else if (!strcmp(argv[c], "-tiff")) { - format = TIFF; - suffix = TO_W_CHAR("tiff"); - } else if (!strcmp(argv[c], "-pam")) { - format = PAM; - suffix = TO_W_CHAR("pam"); - } else if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) { - Help(); - FREE_WARGV_AND_RETURN(0); - } else if (!strcmp(argv[c], "-version")) { - int dec_version, demux_version; - GetAnimatedImageVersions(&dec_version, &demux_version); - printf("WebP Decoder version: %d.%d.%d\nWebP Demux version: %d.%d.%d\n", - (dec_version >> 16) & 0xff, (dec_version >> 8) & 0xff, - (dec_version >> 0) & 0xff, - (demux_version >> 16) & 0xff, (demux_version >> 8) & 0xff, - (demux_version >> 0) & 0xff); - FREE_WARGV_AND_RETURN(0); - } else { - uint32_t i; - AnimatedImage image; - const W_CHAR* const file = GET_WARGV(argv, c); - memset(&image, 0, sizeof(image)); - WPRINTF("Decoding file: %s as %s/%sxxxx.%s\n", - file, dump_folder, prefix, suffix); - if (!ReadAnimatedImage((const char*)file, &image, 0, NULL)) { - WFPRINTF(stderr, "Error decoding file: %s\n Aborting.\n", file); - error = 1; - break; - } - for (i = 0; !error && i < image.num_frames; ++i) { - W_CHAR out_file[1024]; - WebPDecBuffer buffer; - if (!WebPInitDecBuffer(&buffer)) { - fprintf(stderr, "Cannot init dec buffer\n"); - error = 1; - continue; - } - buffer.colorspace = MODE_RGBA; - buffer.is_external_memory = 1; - buffer.width = image.canvas_width; - buffer.height = image.canvas_height; - buffer.u.RGBA.rgba = image.frames[i].rgba; - buffer.u.RGBA.stride = buffer.width * sizeof(uint32_t); - buffer.u.RGBA.size = buffer.u.RGBA.stride * buffer.height; - WSNPRINTF(out_file, sizeof(out_file), "%s/%s%.4d.%s", - dump_folder, prefix, i, suffix); - if (!WebPSaveImage(&buffer, format, (const char*)out_file)) { - WFPRINTF(stderr, "Error while saving image '%s'\n", out_file); - error = 1; - } - WebPFreeDecBuffer(&buffer); - } - ClearAnimatedImage(&image); - } - } - FREE_WARGV_AND_RETURN(error ? 1 : 0); -} diff --git a/libwebp/examples/anim_util.c b/libwebp/examples/anim_util.c deleted file mode 100644 index cf7da4c0..00000000 --- a/libwebp/examples/anim_util.c +++ /dev/null @@ -1,782 +0,0 @@ -// Copyright 2015 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Utilities for animated images - -#include "./anim_util.h" - -#include -#include -#include -#include - -#if defined(WEBP_HAVE_GIF) -#include -#endif -#include "webp/format_constants.h" -#include "webp/decode.h" -#include "webp/demux.h" -#include "../imageio/imageio_util.h" -#include "./gifdec.h" -#include "./unicode.h" -#include "./unicode_gif.h" - -#if defined(_MSC_VER) && _MSC_VER < 1900 -#define snprintf _snprintf -#endif - -static const int kNumChannels = 4; - -// ----------------------------------------------------------------------------- -// Common utilities. - -#if defined(WEBP_HAVE_GIF) -// Returns true if the frame covers the full canvas. -static int IsFullFrame(int width, int height, - int canvas_width, int canvas_height) { - return (width == canvas_width && height == canvas_height); -} -#endif // WEBP_HAVE_GIF - -static int CheckSizeForOverflow(uint64_t size) { - return (size == (size_t)size); -} - -static int AllocateFrames(AnimatedImage* const image, uint32_t num_frames) { - uint32_t i; - uint8_t* mem = NULL; - DecodedFrame* frames = NULL; - const uint64_t rgba_size = - (uint64_t)image->canvas_width * kNumChannels * image->canvas_height; - const uint64_t total_size = (uint64_t)num_frames * rgba_size * sizeof(*mem); - const uint64_t total_frame_size = (uint64_t)num_frames * sizeof(*frames); - if (!CheckSizeForOverflow(total_size) || - !CheckSizeForOverflow(total_frame_size)) { - return 0; - } - mem = (uint8_t*)WebPMalloc((size_t)total_size); - frames = (DecodedFrame*)WebPMalloc((size_t)total_frame_size); - - if (mem == NULL || frames == NULL) { - WebPFree(mem); - WebPFree(frames); - return 0; - } - WebPFree(image->raw_mem); - image->num_frames = num_frames; - image->frames = frames; - for (i = 0; i < num_frames; ++i) { - frames[i].rgba = mem + i * rgba_size; - frames[i].duration = 0; - frames[i].is_key_frame = 0; - } - image->raw_mem = mem; - return 1; -} - -void ClearAnimatedImage(AnimatedImage* const image) { - if (image != NULL) { - WebPFree(image->raw_mem); - WebPFree(image->frames); - image->num_frames = 0; - image->frames = NULL; - image->raw_mem = NULL; - } -} - -#if defined(WEBP_HAVE_GIF) -// Clear the canvas to transparent. -static void ZeroFillCanvas(uint8_t* rgba, - uint32_t canvas_width, uint32_t canvas_height) { - memset(rgba, 0, canvas_width * kNumChannels * canvas_height); -} - -// Clear given frame rectangle to transparent. -static void ZeroFillFrameRect(uint8_t* rgba, int rgba_stride, int x_offset, - int y_offset, int width, int height) { - int j; - assert(width * kNumChannels <= rgba_stride); - rgba += y_offset * rgba_stride + x_offset * kNumChannels; - for (j = 0; j < height; ++j) { - memset(rgba, 0, width * kNumChannels); - rgba += rgba_stride; - } -} - -// Copy width * height pixels from 'src' to 'dst'. -static void CopyCanvas(const uint8_t* src, uint8_t* dst, - uint32_t width, uint32_t height) { - assert(src != NULL && dst != NULL); - memcpy(dst, src, width * kNumChannels * height); -} - -// Copy pixels in the given rectangle from 'src' to 'dst' honoring the 'stride'. -static void CopyFrameRectangle(const uint8_t* src, uint8_t* dst, int stride, - int x_offset, int y_offset, - int width, int height) { - int j; - const int width_in_bytes = width * kNumChannels; - const size_t offset = y_offset * stride + x_offset * kNumChannels; - assert(width_in_bytes <= stride); - src += offset; - dst += offset; - for (j = 0; j < height; ++j) { - memcpy(dst, src, width_in_bytes); - src += stride; - dst += stride; - } -} -#endif // WEBP_HAVE_GIF - -// Canonicalize all transparent pixels to transparent black to aid comparison. -static void CleanupTransparentPixels(uint32_t* rgba, - uint32_t width, uint32_t height) { - const uint32_t* const rgba_end = rgba + width * height; - while (rgba < rgba_end) { - const uint8_t alpha = (*rgba >> 24) & 0xff; - if (alpha == 0) { - *rgba = 0; - } - ++rgba; - } -} - -// Dump frame to a PAM file. Returns true on success. -static int DumpFrame(const char filename[], const char dump_folder[], - uint32_t frame_num, const uint8_t rgba[], - int canvas_width, int canvas_height) { - int ok = 0; - size_t max_len; - int y; - const W_CHAR* base_name = NULL; - W_CHAR* file_name = NULL; - FILE* f = NULL; - const char* row; - - if (dump_folder == NULL) dump_folder = (const char*)TO_W_CHAR("."); - - base_name = WSTRRCHR(filename, '/'); - base_name = (base_name == NULL) ? (const W_CHAR*)filename : base_name + 1; - max_len = WSTRLEN(dump_folder) + 1 + WSTRLEN(base_name) - + strlen("_frame_") + strlen(".pam") + 8; - file_name = (W_CHAR*)WebPMalloc(max_len * sizeof(*file_name)); - if (file_name == NULL) goto End; - - if (WSNPRINTF(file_name, max_len, "%s/%s_frame_%d.pam", - (const W_CHAR*)dump_folder, base_name, frame_num) < 0) { - fprintf(stderr, "Error while generating file name\n"); - goto End; - } - - f = WFOPEN(file_name, "wb"); - if (f == NULL) { - WFPRINTF(stderr, "Error opening file for writing: %s\n", file_name); - ok = 0; - goto End; - } - if (fprintf(f, "P7\nWIDTH %d\nHEIGHT %d\n" - "DEPTH 4\nMAXVAL 255\nTUPLTYPE RGB_ALPHA\nENDHDR\n", - canvas_width, canvas_height) < 0) { - WFPRINTF(stderr, "Write error for file %s\n", file_name); - goto End; - } - row = (const char*)rgba; - for (y = 0; y < canvas_height; ++y) { - if (fwrite(row, canvas_width * kNumChannels, 1, f) != 1) { - WFPRINTF(stderr, "Error writing to file: %s\n", file_name); - goto End; - } - row += canvas_width * kNumChannels; - } - ok = 1; - End: - if (f != NULL) fclose(f); - WebPFree(file_name); - return ok; -} - -// ----------------------------------------------------------------------------- -// WebP Decoding. - -// Returns true if this is a valid WebP bitstream. -static int IsWebP(const WebPData* const webp_data) { - return (WebPGetInfo(webp_data->bytes, webp_data->size, NULL, NULL) != 0); -} - -// Read animated WebP bitstream 'webp_data' into 'AnimatedImage' struct. -static int ReadAnimatedWebP(const char filename[], - const WebPData* const webp_data, - AnimatedImage* const image, int dump_frames, - const char dump_folder[]) { - int ok = 0; - int dump_ok = 1; - uint32_t frame_index = 0; - int prev_frame_timestamp = 0; - WebPAnimDecoder* dec; - WebPAnimInfo anim_info; - - memset(image, 0, sizeof(*image)); - - dec = WebPAnimDecoderNew(webp_data, NULL); - if (dec == NULL) { - WFPRINTF(stderr, "Error parsing image: %s\n", (const W_CHAR*)filename); - goto End; - } - - if (!WebPAnimDecoderGetInfo(dec, &anim_info)) { - fprintf(stderr, "Error getting global info about the animation\n"); - goto End; - } - - // Animation properties. - image->canvas_width = anim_info.canvas_width; - image->canvas_height = anim_info.canvas_height; - image->loop_count = anim_info.loop_count; - image->bgcolor = anim_info.bgcolor; - - // Allocate frames. - if (!AllocateFrames(image, anim_info.frame_count)) goto End; - - // Decode frames. - while (WebPAnimDecoderHasMoreFrames(dec)) { - DecodedFrame* curr_frame; - uint8_t* curr_rgba; - uint8_t* frame_rgba; - int timestamp; - - if (!WebPAnimDecoderGetNext(dec, &frame_rgba, ×tamp)) { - fprintf(stderr, "Error decoding frame #%u\n", frame_index); - goto End; - } - assert(frame_index < anim_info.frame_count); - curr_frame = &image->frames[frame_index]; - curr_rgba = curr_frame->rgba; - curr_frame->duration = timestamp - prev_frame_timestamp; - curr_frame->is_key_frame = 0; // Unused. - memcpy(curr_rgba, frame_rgba, - image->canvas_width * kNumChannels * image->canvas_height); - - // Needed only because we may want to compare with GIF later. - CleanupTransparentPixels((uint32_t*)curr_rgba, - image->canvas_width, image->canvas_height); - - if (dump_frames && dump_ok) { - dump_ok = DumpFrame(filename, dump_folder, frame_index, curr_rgba, - image->canvas_width, image->canvas_height); - if (!dump_ok) { // Print error once, but continue decode loop. - fprintf(stderr, "Error dumping frames to %s\n", dump_folder); - } - } - - ++frame_index; - prev_frame_timestamp = timestamp; - } - ok = dump_ok; - if (ok) image->format = ANIM_WEBP; - - End: - WebPAnimDecoderDelete(dec); - return ok; -} - -// ----------------------------------------------------------------------------- -// GIF Decoding. - -#if defined(WEBP_HAVE_GIF) - -// Returns true if this is a valid GIF bitstream. -static int IsGIF(const WebPData* const data) { - return data->size > GIF_STAMP_LEN && - (!memcmp(GIF_STAMP, data->bytes, GIF_STAMP_LEN) || - !memcmp(GIF87_STAMP, data->bytes, GIF_STAMP_LEN) || - !memcmp(GIF89_STAMP, data->bytes, GIF_STAMP_LEN)); -} - -// GIFLIB_MAJOR is only defined in libgif >= 4.2.0. -#if defined(GIFLIB_MAJOR) && defined(GIFLIB_MINOR) -# define LOCAL_GIF_VERSION ((GIFLIB_MAJOR << 8) | GIFLIB_MINOR) -# define LOCAL_GIF_PREREQ(maj, min) \ - (LOCAL_GIF_VERSION >= (((maj) << 8) | (min))) -#else -# define LOCAL_GIF_VERSION 0 -# define LOCAL_GIF_PREREQ(maj, min) 0 -#endif - -#if !LOCAL_GIF_PREREQ(5, 0) - -// Added in v5.0 -typedef struct { - int DisposalMode; -#define DISPOSAL_UNSPECIFIED 0 // No disposal specified -#define DISPOSE_DO_NOT 1 // Leave image in place -#define DISPOSE_BACKGROUND 2 // Set area to background color -#define DISPOSE_PREVIOUS 3 // Restore to previous content - int UserInputFlag; // User confirmation required before disposal - int DelayTime; // Pre-display delay in 0.01sec units - int TransparentColor; // Palette index for transparency, -1 if none -#define NO_TRANSPARENT_COLOR -1 -} GraphicsControlBlock; - -static int DGifExtensionToGCB(const size_t GifExtensionLength, - const GifByteType* GifExtension, - GraphicsControlBlock* gcb) { - if (GifExtensionLength != 4) { - return GIF_ERROR; - } - gcb->DisposalMode = (GifExtension[0] >> 2) & 0x07; - gcb->UserInputFlag = (GifExtension[0] & 0x02) != 0; - gcb->DelayTime = GifExtension[1] | (GifExtension[2] << 8); - if (GifExtension[0] & 0x01) { - gcb->TransparentColor = (int)GifExtension[3]; - } else { - gcb->TransparentColor = NO_TRANSPARENT_COLOR; - } - return GIF_OK; -} - -static int DGifSavedExtensionToGCB(GifFileType* GifFile, int ImageIndex, - GraphicsControlBlock* gcb) { - int i; - if (ImageIndex < 0 || ImageIndex > GifFile->ImageCount - 1) { - return GIF_ERROR; - } - gcb->DisposalMode = DISPOSAL_UNSPECIFIED; - gcb->UserInputFlag = 0; - gcb->DelayTime = 0; - gcb->TransparentColor = NO_TRANSPARENT_COLOR; - - for (i = 0; i < GifFile->SavedImages[ImageIndex].ExtensionBlockCount; i++) { - ExtensionBlock* ep = &GifFile->SavedImages[ImageIndex].ExtensionBlocks[i]; - if (ep->Function == GRAPHICS_EXT_FUNC_CODE) { - return DGifExtensionToGCB( - ep->ByteCount, (const GifByteType*)ep->Bytes, gcb); - } - } - return GIF_ERROR; -} - -#define CONTINUE_EXT_FUNC_CODE 0x00 - -// Signature was changed in v5.0 -#define DGifOpenFileName(a, b) DGifOpenFileName(a) - -#endif // !LOCAL_GIF_PREREQ(5, 0) - -// Signature changed in v5.1 -#if !LOCAL_GIF_PREREQ(5, 1) -#define DGifCloseFile(a, b) DGifCloseFile(a) -#endif - -static int IsKeyFrameGIF(const GifImageDesc* prev_desc, int prev_dispose, - const DecodedFrame* const prev_frame, - int canvas_width, int canvas_height) { - if (prev_frame == NULL) return 1; - if (prev_dispose == DISPOSE_BACKGROUND) { - if (IsFullFrame(prev_desc->Width, prev_desc->Height, - canvas_width, canvas_height)) { - return 1; - } - if (prev_frame->is_key_frame) return 1; - } - return 0; -} - -static int GetTransparentIndexGIF(GifFileType* gif) { - GraphicsControlBlock first_gcb; - memset(&first_gcb, 0, sizeof(first_gcb)); - DGifSavedExtensionToGCB(gif, 0, &first_gcb); - return first_gcb.TransparentColor; -} - -static uint32_t GetBackgroundColorGIF(GifFileType* gif) { - const int transparent_index = GetTransparentIndexGIF(gif); - const ColorMapObject* const color_map = gif->SColorMap; - if (transparent_index != NO_TRANSPARENT_COLOR && - gif->SBackGroundColor == transparent_index) { - return 0x00000000; // Special case: transparent black. - } else if (color_map == NULL || color_map->Colors == NULL - || gif->SBackGroundColor >= color_map->ColorCount) { - return 0xffffffff; // Invalid: assume white. - } else { - const GifColorType color = color_map->Colors[gif->SBackGroundColor]; - return (0xffu << 24) | - (color.Red << 16) | - (color.Green << 8) | - (color.Blue << 0); - } -} - -// Find appropriate app extension and get loop count from the next extension. -// We use Chrome's interpretation of the 'loop_count' semantics: -// if not present -> loop once -// if present and loop_count == 0, return 0 ('infinite'). -// if present and loop_count != 0, it's the number of *extra* loops -// so we need to return loop_count + 1 as total loop number. -static uint32_t GetLoopCountGIF(const GifFileType* const gif) { - int i; - for (i = 0; i < gif->ImageCount; ++i) { - const SavedImage* const image = &gif->SavedImages[i]; - int j; - for (j = 0; (j + 1) < image->ExtensionBlockCount; ++j) { - const ExtensionBlock* const eb1 = image->ExtensionBlocks + j; - const ExtensionBlock* const eb2 = image->ExtensionBlocks + j + 1; - const char* const signature = (const char*)eb1->Bytes; - const int signature_is_ok = - (eb1->Function == APPLICATION_EXT_FUNC_CODE) && - (eb1->ByteCount == 11) && - (!memcmp(signature, "NETSCAPE2.0", 11) || - !memcmp(signature, "ANIMEXTS1.0", 11)); - if (signature_is_ok && - eb2->Function == CONTINUE_EXT_FUNC_CODE && eb2->ByteCount >= 3 && - eb2->Bytes[0] == 1) { - const uint32_t extra_loop = ((uint32_t)(eb2->Bytes[2]) << 8) + - ((uint32_t)(eb2->Bytes[1]) << 0); - return (extra_loop > 0) ? extra_loop + 1 : 0; - } - } - } - return 1; // Default. -} - -// Get duration of 'n'th frame in milliseconds. -static int GetFrameDurationGIF(GifFileType* gif, int n) { - GraphicsControlBlock gcb; - memset(&gcb, 0, sizeof(gcb)); - DGifSavedExtensionToGCB(gif, n, &gcb); - return gcb.DelayTime * 10; -} - -// Returns true if frame 'target' completely covers 'covered'. -static int CoversFrameGIF(const GifImageDesc* const target, - const GifImageDesc* const covered) { - return target->Left <= covered->Left && - covered->Left + covered->Width <= target->Left + target->Width && - target->Top <= covered->Top && - covered->Top + covered->Height <= target->Top + target->Height; -} - -static void RemapPixelsGIF(const uint8_t* const src, - const ColorMapObject* const cmap, - int transparent_color, int len, uint8_t* dst) { - int i; - for (i = 0; i < len; ++i) { - if (src[i] != transparent_color) { - // If a pixel in the current frame is transparent, we don't modify it, so - // that we can see-through the corresponding pixel from an earlier frame. - const GifColorType c = cmap->Colors[src[i]]; - dst[4 * i + 0] = c.Red; - dst[4 * i + 1] = c.Green; - dst[4 * i + 2] = c.Blue; - dst[4 * i + 3] = 0xff; - } - } -} - -static int ReadFrameGIF(const SavedImage* const gif_image, - const ColorMapObject* cmap, int transparent_color, - int out_stride, uint8_t* const dst) { - const GifImageDesc* image_desc = &gif_image->ImageDesc; - const uint8_t* in; - uint8_t* out; - int j; - - if (image_desc->ColorMap) cmap = image_desc->ColorMap; - - if (cmap == NULL || cmap->ColorCount != (1 << cmap->BitsPerPixel)) { - fprintf(stderr, "Potentially corrupt color map.\n"); - return 0; - } - - in = (const uint8_t*)gif_image->RasterBits; - out = dst + image_desc->Top * out_stride + image_desc->Left * kNumChannels; - - for (j = 0; j < image_desc->Height; ++j) { - RemapPixelsGIF(in, cmap, transparent_color, image_desc->Width, out); - in += image_desc->Width; - out += out_stride; - } - return 1; -} - -// Read animated GIF bitstream from 'filename' into 'AnimatedImage' struct. -static int ReadAnimatedGIF(const char filename[], AnimatedImage* const image, - int dump_frames, const char dump_folder[]) { - uint32_t frame_count; - uint32_t canvas_width, canvas_height; - uint32_t i; - int gif_error; - GifFileType* gif; - - gif = DGifOpenFileUnicode((const W_CHAR*)filename, NULL); - if (gif == NULL) { - WFPRINTF(stderr, "Could not read file: %s.\n", (const W_CHAR*)filename); - return 0; - } - - gif_error = DGifSlurp(gif); - if (gif_error != GIF_OK) { - WFPRINTF(stderr, "Could not parse image: %s.\n", (const W_CHAR*)filename); - GIFDisplayError(gif, gif_error); - DGifCloseFile(gif, NULL); - return 0; - } - - // Animation properties. - image->canvas_width = (uint32_t)gif->SWidth; - image->canvas_height = (uint32_t)gif->SHeight; - if (image->canvas_width > MAX_CANVAS_SIZE || - image->canvas_height > MAX_CANVAS_SIZE) { - fprintf(stderr, "Invalid canvas dimension: %d x %d\n", - image->canvas_width, image->canvas_height); - DGifCloseFile(gif, NULL); - return 0; - } - image->loop_count = GetLoopCountGIF(gif); - image->bgcolor = GetBackgroundColorGIF(gif); - - frame_count = (uint32_t)gif->ImageCount; - if (frame_count == 0) { - DGifCloseFile(gif, NULL); - return 0; - } - - if (image->canvas_width == 0 || image->canvas_height == 0) { - image->canvas_width = gif->SavedImages[0].ImageDesc.Width; - image->canvas_height = gif->SavedImages[0].ImageDesc.Height; - gif->SavedImages[0].ImageDesc.Left = 0; - gif->SavedImages[0].ImageDesc.Top = 0; - if (image->canvas_width == 0 || image->canvas_height == 0) { - fprintf(stderr, "Invalid canvas size in GIF.\n"); - DGifCloseFile(gif, NULL); - return 0; - } - } - // Allocate frames. - if (!AllocateFrames(image, frame_count)) { - DGifCloseFile(gif, NULL); - return 0; - } - - canvas_width = image->canvas_width; - canvas_height = image->canvas_height; - - // Decode and reconstruct frames. - for (i = 0; i < frame_count; ++i) { - const int canvas_width_in_bytes = canvas_width * kNumChannels; - const SavedImage* const curr_gif_image = &gif->SavedImages[i]; - GraphicsControlBlock curr_gcb; - DecodedFrame* curr_frame; - uint8_t* curr_rgba; - - memset(&curr_gcb, 0, sizeof(curr_gcb)); - DGifSavedExtensionToGCB(gif, i, &curr_gcb); - - curr_frame = &image->frames[i]; - curr_rgba = curr_frame->rgba; - curr_frame->duration = GetFrameDurationGIF(gif, i); - // Force frames with a small or no duration to 100ms to be consistent - // with web browsers and other transcoding tools (like gif2webp itself). - if (curr_frame->duration <= 10) curr_frame->duration = 100; - - if (i == 0) { // Initialize as transparent. - curr_frame->is_key_frame = 1; - ZeroFillCanvas(curr_rgba, canvas_width, canvas_height); - } else { - DecodedFrame* const prev_frame = &image->frames[i - 1]; - const GifImageDesc* const prev_desc = &gif->SavedImages[i - 1].ImageDesc; - GraphicsControlBlock prev_gcb; - memset(&prev_gcb, 0, sizeof(prev_gcb)); - DGifSavedExtensionToGCB(gif, i - 1, &prev_gcb); - - curr_frame->is_key_frame = - IsKeyFrameGIF(prev_desc, prev_gcb.DisposalMode, prev_frame, - canvas_width, canvas_height); - - if (curr_frame->is_key_frame) { // Initialize as transparent. - ZeroFillCanvas(curr_rgba, canvas_width, canvas_height); - } else { - int prev_frame_disposed, curr_frame_opaque; - int prev_frame_completely_covered; - // Initialize with previous canvas. - uint8_t* const prev_rgba = image->frames[i - 1].rgba; - CopyCanvas(prev_rgba, curr_rgba, canvas_width, canvas_height); - - // Dispose previous frame rectangle. - prev_frame_disposed = - (prev_gcb.DisposalMode == DISPOSE_BACKGROUND || - prev_gcb.DisposalMode == DISPOSE_PREVIOUS); - curr_frame_opaque = - (curr_gcb.TransparentColor == NO_TRANSPARENT_COLOR); - prev_frame_completely_covered = - curr_frame_opaque && - CoversFrameGIF(&curr_gif_image->ImageDesc, prev_desc); - - if (prev_frame_disposed && !prev_frame_completely_covered) { - switch (prev_gcb.DisposalMode) { - case DISPOSE_BACKGROUND: { - ZeroFillFrameRect(curr_rgba, canvas_width_in_bytes, - prev_desc->Left, prev_desc->Top, - prev_desc->Width, prev_desc->Height); - break; - } - case DISPOSE_PREVIOUS: { - int src_frame_num = i - 2; - while (src_frame_num >= 0) { - GraphicsControlBlock src_frame_gcb; - memset(&src_frame_gcb, 0, sizeof(src_frame_gcb)); - DGifSavedExtensionToGCB(gif, src_frame_num, &src_frame_gcb); - if (src_frame_gcb.DisposalMode != DISPOSE_PREVIOUS) break; - --src_frame_num; - } - if (src_frame_num >= 0) { - // Restore pixels inside previous frame rectangle to - // corresponding pixels in source canvas. - uint8_t* const src_frame_rgba = - image->frames[src_frame_num].rgba; - CopyFrameRectangle(src_frame_rgba, curr_rgba, - canvas_width_in_bytes, - prev_desc->Left, prev_desc->Top, - prev_desc->Width, prev_desc->Height); - } else { - // Source canvas doesn't exist. So clear previous frame - // rectangle to background. - ZeroFillFrameRect(curr_rgba, canvas_width_in_bytes, - prev_desc->Left, prev_desc->Top, - prev_desc->Width, prev_desc->Height); - } - break; - } - default: - break; // Nothing to do. - } - } - } - } - - // Decode current frame. - if (!ReadFrameGIF(curr_gif_image, gif->SColorMap, curr_gcb.TransparentColor, - canvas_width_in_bytes, curr_rgba)) { - DGifCloseFile(gif, NULL); - return 0; - } - - if (dump_frames) { - if (!DumpFrame(filename, dump_folder, i, curr_rgba, - canvas_width, canvas_height)) { - DGifCloseFile(gif, NULL); - return 0; - } - } - } - image->format = ANIM_GIF; - DGifCloseFile(gif, NULL); - return 1; -} - -#else - -static int IsGIF(const WebPData* const data) { - (void)data; - return 0; -} - -static int ReadAnimatedGIF(const char filename[], AnimatedImage* const image, - int dump_frames, const char dump_folder[]) { - (void)filename; - (void)image; - (void)dump_frames; - (void)dump_folder; - fprintf(stderr, "GIF support not compiled. Please install the libgif-dev " - "package before building.\n"); - return 0; -} - -#endif // WEBP_HAVE_GIF - -// ----------------------------------------------------------------------------- - -int ReadAnimatedImage(const char filename[], AnimatedImage* const image, - int dump_frames, const char dump_folder[]) { - int ok = 0; - WebPData webp_data; - - WebPDataInit(&webp_data); - memset(image, 0, sizeof(*image)); - - if (!ImgIoUtilReadFile(filename, &webp_data.bytes, &webp_data.size)) { - WFPRINTF(stderr, "Error reading file: %s\n", (const W_CHAR*)filename); - return 0; - } - - if (IsWebP(&webp_data)) { - ok = ReadAnimatedWebP(filename, &webp_data, image, dump_frames, - dump_folder); - } else if (IsGIF(&webp_data)) { - ok = ReadAnimatedGIF(filename, image, dump_frames, dump_folder); - } else { - WFPRINTF(stderr, - "Unknown file type: %s. Supported file types are WebP and GIF\n", - (const W_CHAR*)filename); - ok = 0; - } - if (!ok) ClearAnimatedImage(image); - WebPDataClear(&webp_data); - return ok; -} - -static void Accumulate(double v1, double v2, double* const max_diff, - double* const sse) { - const double diff = fabs(v1 - v2); - if (diff > *max_diff) *max_diff = diff; - *sse += diff * diff; -} - -void GetDiffAndPSNR(const uint8_t rgba1[], const uint8_t rgba2[], - uint32_t width, uint32_t height, int premultiply, - int* const max_diff, double* const psnr) { - const uint32_t stride = width * kNumChannels; - const int kAlphaChannel = kNumChannels - 1; - double f_max_diff = 0.; - double sse = 0.; - uint32_t x, y; - for (y = 0; y < height; ++y) { - for (x = 0; x < stride; x += kNumChannels) { - int k; - const size_t offset = (size_t)y * stride + x; - const int alpha1 = rgba1[offset + kAlphaChannel]; - const int alpha2 = rgba2[offset + kAlphaChannel]; - Accumulate(alpha1, alpha2, &f_max_diff, &sse); - if (!premultiply) { - for (k = 0; k < kAlphaChannel; ++k) { - Accumulate(rgba1[offset + k], rgba2[offset + k], &f_max_diff, &sse); - } - } else { - // premultiply R/G/B channels with alpha value - for (k = 0; k < kAlphaChannel; ++k) { - Accumulate(rgba1[offset + k] * alpha1 / 255., - rgba2[offset + k] * alpha2 / 255., - &f_max_diff, &sse); - } - } - } - } - *max_diff = (int)f_max_diff; - if (*max_diff == 0) { - *psnr = 99.; // PSNR when images are identical. - } else { - sse /= stride * height; - *psnr = 4.3429448 * log(255. * 255. / sse); - } -} - -void GetAnimatedImageVersions(int* const decoder_version, - int* const demux_version) { - *decoder_version = WebPGetDecoderVersion(); - *demux_version = WebPGetDemuxVersion(); -} diff --git a/libwebp/examples/anim_util.h b/libwebp/examples/anim_util.h deleted file mode 100644 index 574e032d..00000000 --- a/libwebp/examples/anim_util.h +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2015 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Utilities for animated images - -#ifndef WEBP_EXAMPLES_ANIM_UTIL_H_ -#define WEBP_EXAMPLES_ANIM_UTIL_H_ - -#ifdef HAVE_CONFIG_H -#include "webp/config.h" -#endif - -#include "webp/types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - ANIM_GIF, - ANIM_WEBP -} AnimatedFileFormat; - -typedef struct { - uint8_t* rgba; // Decoded and reconstructed full frame. - int duration; // Frame duration in milliseconds. - int is_key_frame; // True if this frame is a key-frame. -} DecodedFrame; - -typedef struct { - AnimatedFileFormat format; - uint32_t canvas_width; - uint32_t canvas_height; - uint32_t bgcolor; - uint32_t loop_count; - DecodedFrame* frames; - uint32_t num_frames; - void* raw_mem; -} AnimatedImage; - -// Deallocate everything in 'image' (but not the object itself). -void ClearAnimatedImage(AnimatedImage* const image); - -// Read animated image file into 'AnimatedImage' struct. -// If 'dump_frames' is true, dump frames to 'dump_folder'. -// Previous content of 'image' is obliterated. -// Upon successful return, content of 'image' must be deleted by -// calling 'ClearAnimatedImage'. -int ReadAnimatedImage(const char filename[], AnimatedImage* const image, - int dump_frames, const char dump_folder[]); - -// Given two RGBA buffers, calculate max pixel difference and PSNR. -// If 'premultiply' is true, R/G/B values will be pre-multiplied by the -// transparency before comparison. -void GetDiffAndPSNR(const uint8_t rgba1[], const uint8_t rgba2[], - uint32_t width, uint32_t height, int premultiply, - int* const max_diff, double* const psnr); - -// Return library versions used by anim_util. -void GetAnimatedImageVersions(int* const decoder_version, - int* const demux_version); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // WEBP_EXAMPLES_ANIM_UTIL_H_ diff --git a/libwebp/examples/cwebp.c b/libwebp/examples/cwebp.c deleted file mode 100644 index cab70054..00000000 --- a/libwebp/examples/cwebp.c +++ /dev/null @@ -1,1249 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// simple command line calling the WebPEncode function. -// Encodes a raw .YUV into WebP bitstream -// -// Author: Skal (pascal.massimino@gmail.com) - -#include -#include -#include -#include - -#ifdef HAVE_CONFIG_H -#include "webp/config.h" -#endif - -#include "../examples/example_util.h" -#include "../imageio/image_dec.h" -#include "../imageio/imageio_util.h" -#include "../imageio/webpdec.h" -#include "./stopwatch.h" -#include "./unicode.h" -#include "sharpyuv/sharpyuv.h" -#include "webp/encode.h" - -#ifndef WEBP_DLL -#ifdef __cplusplus -extern "C" { -#endif - -extern void* VP8GetCPUInfo; // opaque forward declaration. - -#ifdef __cplusplus -} // extern "C" -#endif -#endif // WEBP_DLL - -//------------------------------------------------------------------------------ - -static int verbose = 0; - -static int ReadYUV(const uint8_t* const data, size_t data_size, - WebPPicture* const pic) { - const int use_argb = pic->use_argb; - const int uv_width = (pic->width + 1) / 2; - const int uv_height = (pic->height + 1) / 2; - const int y_plane_size = pic->width * pic->height; - const int uv_plane_size = uv_width * uv_height; - const size_t expected_data_size = y_plane_size + 2 * uv_plane_size; - - if (data_size != expected_data_size) { - fprintf(stderr, - "input data doesn't have the expected size (%d instead of %d)\n", - (int)data_size, (int)expected_data_size); - return 0; - } - - pic->use_argb = 0; - if (!WebPPictureAlloc(pic)) return 0; - ImgIoUtilCopyPlane(data, pic->width, pic->y, pic->y_stride, - pic->width, pic->height); - ImgIoUtilCopyPlane(data + y_plane_size, uv_width, - pic->u, pic->uv_stride, uv_width, uv_height); - ImgIoUtilCopyPlane(data + y_plane_size + uv_plane_size, uv_width, - pic->v, pic->uv_stride, uv_width, uv_height); - return use_argb ? WebPPictureYUVAToARGB(pic) : 1; -} - -#ifdef HAVE_WINCODEC_H - -static int ReadPicture(const char* const filename, WebPPicture* const pic, - int keep_alpha, Metadata* const metadata) { - int ok = 0; - const uint8_t* data = NULL; - size_t data_size = 0; - if (pic->width != 0 && pic->height != 0) { - ok = ImgIoUtilReadFile(filename, &data, &data_size); - ok = ok && ReadYUV(data, data_size, pic); - } else { - // If no size specified, try to decode it using WIC. - ok = ReadPictureWithWIC(filename, pic, keep_alpha, metadata); - if (!ok) { - ok = ImgIoUtilReadFile(filename, &data, &data_size); - ok = ok && ReadWebP(data, data_size, pic, keep_alpha, metadata); - } - } - if (!ok) { - WFPRINTF(stderr, "Error! Could not process file %s\n", - (const W_CHAR*)filename); - } - WebPFree((void*)data); - return ok; -} - -#else // !HAVE_WINCODEC_H - -static int ReadPicture(const char* const filename, WebPPicture* const pic, - int keep_alpha, Metadata* const metadata) { - const uint8_t* data = NULL; - size_t data_size = 0; - int ok = 0; - - ok = ImgIoUtilReadFile(filename, &data, &data_size); - if (!ok) goto End; - - if (pic->width == 0 || pic->height == 0) { - WebPImageReader reader = WebPGuessImageReader(data, data_size); - ok = reader(data, data_size, pic, keep_alpha, metadata); - } else { - // If image size is specified, infer it as YUV format. - ok = ReadYUV(data, data_size, pic); - } - End: - if (!ok) { - WFPRINTF(stderr, "Error! Could not process file %s\n", - (const W_CHAR*)filename); - } - WebPFree((void*)data); - return ok; -} - -#endif // !HAVE_WINCODEC_H - -static void AllocExtraInfo(WebPPicture* const pic) { - const int mb_w = (pic->width + 15) / 16; - const int mb_h = (pic->height + 15) / 16; - pic->extra_info = - (uint8_t*)WebPMalloc(mb_w * mb_h * sizeof(*pic->extra_info)); -} - -static void PrintByteCount(const int bytes[4], int total_size, - int* const totals) { - int s; - int total = 0; - for (s = 0; s < 4; ++s) { - fprintf(stderr, "| %7d ", bytes[s]); - total += bytes[s]; - if (totals) totals[s] += bytes[s]; - } - fprintf(stderr, "| %7d (%.1f%%)\n", total, 100.f * total / total_size); -} - -static void PrintPercents(const int counts[4]) { - int s; - const int total = counts[0] + counts[1] + counts[2] + counts[3]; - for (s = 0; s < 4; ++s) { - fprintf(stderr, "| %3d%%", (int)(100. * counts[s] / total + .5)); - } - fprintf(stderr, "| %7d\n", total); -} - -static void PrintValues(const int values[4]) { - int s; - for (s = 0; s < 4; ++s) { - fprintf(stderr, "| %7d ", values[s]); - } - fprintf(stderr, "|\n"); -} - -static void PrintFullLosslessInfo(const WebPAuxStats* const stats, - const char* const description) { - fprintf(stderr, "Lossless-%s compressed size: %d bytes\n", - description, stats->lossless_size); - fprintf(stderr, " * Header size: %d bytes, image data size: %d\n", - stats->lossless_hdr_size, stats->lossless_data_size); - if (stats->lossless_features) { - fprintf(stderr, " * Lossless features used:"); - if (stats->lossless_features & 1) fprintf(stderr, " PREDICTION"); - if (stats->lossless_features & 2) fprintf(stderr, " CROSS-COLOR-TRANSFORM"); - if (stats->lossless_features & 4) fprintf(stderr, " SUBTRACT-GREEN"); - if (stats->lossless_features & 8) fprintf(stderr, " PALETTE"); - fprintf(stderr, "\n"); - } - fprintf(stderr, " * Precision Bits: histogram=%d transform=%d cache=%d\n", - stats->histogram_bits, stats->transform_bits, stats->cache_bits); - if (stats->palette_size > 0) { - fprintf(stderr, " * Palette size: %d\n", stats->palette_size); - } -} - -static void PrintExtraInfoLossless(const WebPPicture* const pic, - int short_output, - const char* const file_name) { - const WebPAuxStats* const stats = pic->stats; - if (short_output) { - fprintf(stderr, "%7d %2.2f\n", stats->coded_size, stats->PSNR[3]); - } else { - WFPRINTF(stderr, "File: %s\n", (const W_CHAR*)file_name); - fprintf(stderr, "Dimension: %d x %d\n", pic->width, pic->height); - fprintf(stderr, "Output: %d bytes (%.2f bpp)\n", stats->coded_size, - 8.f * stats->coded_size / pic->width / pic->height); - PrintFullLosslessInfo(stats, "ARGB"); - } -} - -static void PrintExtraInfoLossy(const WebPPicture* const pic, int short_output, - int full_details, - const char* const file_name) { - const WebPAuxStats* const stats = pic->stats; - if (short_output) { - fprintf(stderr, "%7d %2.2f\n", stats->coded_size, stats->PSNR[3]); - } else { - const int num_i4 = stats->block_count[0]; - const int num_i16 = stats->block_count[1]; - const int num_skip = stats->block_count[2]; - const int total = num_i4 + num_i16; - WFPRINTF(stderr, "File: %s\n", (const W_CHAR*)file_name); - fprintf(stderr, "Dimension: %d x %d%s\n", - pic->width, pic->height, - stats->alpha_data_size ? " (with alpha)" : ""); - fprintf(stderr, "Output: " - "%d bytes Y-U-V-All-PSNR %2.2f %2.2f %2.2f %2.2f dB\n" - " (%.2f bpp)\n", - stats->coded_size, - stats->PSNR[0], stats->PSNR[1], stats->PSNR[2], stats->PSNR[3], - 8.f * stats->coded_size / pic->width / pic->height); - if (total > 0) { - int totals[4] = { 0, 0, 0, 0 }; - fprintf(stderr, "block count: intra4: %6d (%.2f%%)\n" - " intra16: %6d (%.2f%%)\n" - " skipped: %6d (%.2f%%)\n", - num_i4, 100.f * num_i4 / total, - num_i16, 100.f * num_i16 / total, - num_skip, 100.f * num_skip / total); - fprintf(stderr, "bytes used: header: %6d (%.1f%%)\n" - " mode-partition: %6d (%.1f%%)\n", - stats->header_bytes[0], - 100.f * stats->header_bytes[0] / stats->coded_size, - stats->header_bytes[1], - 100.f * stats->header_bytes[1] / stats->coded_size); - if (stats->alpha_data_size > 0) { - fprintf(stderr, " transparency: %6d (%.1f dB)\n", - stats->alpha_data_size, stats->PSNR[4]); - } - fprintf(stderr, " Residuals bytes " - "|segment 1|segment 2|segment 3" - "|segment 4| total\n"); - if (full_details) { - fprintf(stderr, " intra4-coeffs: "); - PrintByteCount(stats->residual_bytes[0], stats->coded_size, totals); - fprintf(stderr, " intra16-coeffs: "); - PrintByteCount(stats->residual_bytes[1], stats->coded_size, totals); - fprintf(stderr, " chroma coeffs: "); - PrintByteCount(stats->residual_bytes[2], stats->coded_size, totals); - } - fprintf(stderr, " macroblocks: "); - PrintPercents(stats->segment_size); - fprintf(stderr, " quantizer: "); - PrintValues(stats->segment_quant); - fprintf(stderr, " filter level: "); - PrintValues(stats->segment_level); - if (full_details) { - fprintf(stderr, "------------------+---------"); - fprintf(stderr, "+---------+---------+---------+-----------------\n"); - fprintf(stderr, " segments total: "); - PrintByteCount(totals, stats->coded_size, NULL); - } - } - if (stats->lossless_size > 0) { - PrintFullLosslessInfo(stats, "alpha"); - } - } -} - -static void PrintMapInfo(const WebPPicture* const pic) { - if (pic->extra_info != NULL) { - const int mb_w = (pic->width + 15) / 16; - const int mb_h = (pic->height + 15) / 16; - const int type = pic->extra_info_type; - int x, y; - for (y = 0; y < mb_h; ++y) { - for (x = 0; x < mb_w; ++x) { - const int c = pic->extra_info[x + y * mb_w]; - if (type == 1) { // intra4/intra16 - fprintf(stderr, "%c", "+."[c]); - } else if (type == 2) { // segments - fprintf(stderr, "%c", ".-*X"[c]); - } else if (type == 3) { // quantizers - fprintf(stderr, "%.2d ", c); - } else if (type == 6 || type == 7) { - fprintf(stderr, "%3d ", c); - } else { - fprintf(stderr, "0x%.2x ", c); - } - } - fprintf(stderr, "\n"); - } - } -} - -//------------------------------------------------------------------------------ - -static int MyWriter(const uint8_t* data, size_t data_size, - const WebPPicture* const pic) { - FILE* const out = (FILE*)pic->custom_ptr; - return data_size ? (fwrite(data, data_size, 1, out) == 1) : 1; -} - -// Dumps a picture as a PGM file using the IMC4 layout. -static int DumpPicture(const WebPPicture* const picture, const char* PGM_name) { - int y; - int ok = 0; - const int uv_width = (picture->width + 1) / 2; - const int uv_height = (picture->height + 1) / 2; - const int stride = (picture->width + 1) & ~1; - const uint8_t* src_y = picture->y; - const uint8_t* src_u = picture->u; - const uint8_t* src_v = picture->v; - const uint8_t* src_a = picture->a; - const int alpha_height = - WebPPictureHasTransparency(picture) ? picture->height : 0; - const int height = picture->height + uv_height + alpha_height; - FILE* const f = WFOPEN(PGM_name, "wb"); - if (f == NULL) return 0; - fprintf(f, "P5\n%d %d\n255\n", stride, height); - for (y = 0; y < picture->height; ++y) { - if (fwrite(src_y, picture->width, 1, f) != 1) goto Error; - if (picture->width & 1) fputc(0, f); // pad - src_y += picture->y_stride; - } - for (y = 0; y < uv_height; ++y) { - if (fwrite(src_u, uv_width, 1, f) != 1) goto Error; - if (fwrite(src_v, uv_width, 1, f) != 1) goto Error; - src_u += picture->uv_stride; - src_v += picture->uv_stride; - } - for (y = 0; y < alpha_height; ++y) { - if (fwrite(src_a, picture->width, 1, f) != 1) goto Error; - if (picture->width & 1) fputc(0, f); // pad - src_a += picture->a_stride; - } - ok = 1; - - Error: - fclose(f); - return ok; -} - -// ----------------------------------------------------------------------------- -// Metadata writing. - -enum { - METADATA_EXIF = (1 << 0), - METADATA_ICC = (1 << 1), - METADATA_XMP = (1 << 2), - METADATA_ALL = METADATA_EXIF | METADATA_ICC | METADATA_XMP -}; - -static const int kChunkHeaderSize = 8; -static const int kTagSize = 4; - -static void PrintMetadataInfo(const Metadata* const metadata, - int metadata_written) { - if (metadata == NULL || metadata_written == 0) return; - - fprintf(stderr, "Metadata:\n"); - if (metadata_written & METADATA_ICC) { - fprintf(stderr, " * ICC profile: %6d bytes\n", (int)metadata->iccp.size); - } - if (metadata_written & METADATA_EXIF) { - fprintf(stderr, " * EXIF data: %6d bytes\n", (int)metadata->exif.size); - } - if (metadata_written & METADATA_XMP) { - fprintf(stderr, " * XMP data: %6d bytes\n", (int)metadata->xmp.size); - } -} - -// Outputs, in little endian, 'num' bytes from 'val' to 'out'. -static int WriteLE(FILE* const out, uint32_t val, int num) { - uint8_t buf[4]; - int i; - for (i = 0; i < num; ++i) { - buf[i] = (uint8_t)(val & 0xff); - val >>= 8; - } - return (fwrite(buf, num, 1, out) == 1); -} - -static int WriteLE24(FILE* const out, uint32_t val) { - return WriteLE(out, val, 3); -} - -static int WriteLE32(FILE* const out, uint32_t val) { - return WriteLE(out, val, 4); -} - -static int WriteMetadataChunk(FILE* const out, const char fourcc[4], - const MetadataPayload* const payload) { - const uint8_t zero = 0; - const size_t need_padding = payload->size & 1; - int ok = (fwrite(fourcc, kTagSize, 1, out) == 1); - ok = ok && WriteLE32(out, (uint32_t)payload->size); - ok = ok && (fwrite(payload->bytes, payload->size, 1, out) == 1); - return ok && (fwrite(&zero, need_padding, need_padding, out) == need_padding); -} - -// Sets 'flag' in 'vp8x_flags' and updates 'metadata_size' with the size of the -// chunk if there is metadata and 'keep' is true. -static int UpdateFlagsAndSize(const MetadataPayload* const payload, - int keep, int flag, - uint32_t* vp8x_flags, uint64_t* metadata_size) { - if (keep && payload->bytes != NULL && payload->size > 0) { - *vp8x_flags |= flag; - *metadata_size += kChunkHeaderSize + payload->size + (payload->size & 1); - return 1; - } - return 0; -} - -// Writes a WebP file using the image contained in 'memory_writer' and the -// metadata from 'metadata'. Metadata is controlled by 'keep_metadata' and the -// availability in 'metadata'. Returns true on success. -// For details see doc/webp-container-spec.txt#extended-file-format. -static int WriteWebPWithMetadata(FILE* const out, - const WebPPicture* const picture, - const WebPMemoryWriter* const memory_writer, - const Metadata* const metadata, - int keep_metadata, - int* const metadata_written) { - const char kVP8XHeader[] = "VP8X\x0a\x00\x00\x00"; - const int kAlphaFlag = 0x10; - const int kEXIFFlag = 0x08; - const int kICCPFlag = 0x20; - const int kXMPFlag = 0x04; - const size_t kRiffHeaderSize = 12; - const size_t kMaxChunkPayload = ~0 - kChunkHeaderSize - 1; - const size_t kMinSize = kRiffHeaderSize + kChunkHeaderSize; - uint32_t flags = 0; - uint64_t metadata_size = 0; - const int write_exif = UpdateFlagsAndSize(&metadata->exif, - !!(keep_metadata & METADATA_EXIF), - kEXIFFlag, &flags, &metadata_size); - const int write_iccp = UpdateFlagsAndSize(&metadata->iccp, - !!(keep_metadata & METADATA_ICC), - kICCPFlag, &flags, &metadata_size); - const int write_xmp = UpdateFlagsAndSize(&metadata->xmp, - !!(keep_metadata & METADATA_XMP), - kXMPFlag, &flags, &metadata_size); - uint8_t* webp = memory_writer->mem; - size_t webp_size = memory_writer->size; - - *metadata_written = 0; - - if (webp_size < kMinSize) return 0; - if (webp_size - kChunkHeaderSize + metadata_size > kMaxChunkPayload) { - fprintf(stderr, "Error! Addition of metadata would exceed " - "container size limit.\n"); - return 0; - } - - if (metadata_size > 0) { - const int kVP8XChunkSize = 18; - const int has_vp8x = !memcmp(webp + kRiffHeaderSize, "VP8X", kTagSize); - const uint32_t riff_size = (uint32_t)(webp_size - kChunkHeaderSize + - (has_vp8x ? 0 : kVP8XChunkSize) + - metadata_size); - // RIFF - int ok = (fwrite(webp, kTagSize, 1, out) == 1); - // RIFF size (file header size is not recorded) - ok = ok && WriteLE32(out, riff_size); - webp += kChunkHeaderSize; - webp_size -= kChunkHeaderSize; - // WEBP - ok = ok && (fwrite(webp, kTagSize, 1, out) == 1); - webp += kTagSize; - webp_size -= kTagSize; - if (has_vp8x) { // update the existing VP8X flags - webp[kChunkHeaderSize] |= (uint8_t)(flags & 0xff); - ok = ok && (fwrite(webp, kVP8XChunkSize, 1, out) == 1); - webp += kVP8XChunkSize; - webp_size -= kVP8XChunkSize; - } else { - const int is_lossless = !memcmp(webp, "VP8L", kTagSize); - if (is_lossless) { - // Presence of alpha is stored in the 37th bit (29th after the - // signature) of VP8L data. - if (webp[kChunkHeaderSize + 4] & (1 << 4)) flags |= kAlphaFlag; - } - ok = ok && (fwrite(kVP8XHeader, kChunkHeaderSize, 1, out) == 1); - ok = ok && WriteLE32(out, flags); - ok = ok && WriteLE24(out, picture->width - 1); - ok = ok && WriteLE24(out, picture->height - 1); - } - if (write_iccp) { - ok = ok && WriteMetadataChunk(out, "ICCP", &metadata->iccp); - *metadata_written |= METADATA_ICC; - } - // Image - ok = ok && (fwrite(webp, webp_size, 1, out) == 1); - if (write_exif) { - ok = ok && WriteMetadataChunk(out, "EXIF", &metadata->exif); - *metadata_written |= METADATA_EXIF; - } - if (write_xmp) { - ok = ok && WriteMetadataChunk(out, "XMP ", &metadata->xmp); - *metadata_written |= METADATA_XMP; - } - return ok; - } - - // No metadata, just write the original image file. - return (fwrite(webp, webp_size, 1, out) == 1); -} - -//------------------------------------------------------------------------------ - -static int ProgressReport(int percent, const WebPPicture* const picture) { - fprintf(stderr, "[%s]: %3d %% \r", - (char*)picture->user_data, percent); - return 1; // all ok -} - -//------------------------------------------------------------------------------ - -static void HelpShort(void) { - printf("Usage:\n\n"); - printf(" cwebp [options] -q quality input.png -o output.webp\n\n"); - printf("where quality is between 0 (poor) to 100 (very good).\n"); - printf("Typical value is around 80.\n\n"); - printf("Try -longhelp for an exhaustive list of advanced options.\n"); -} - -static void HelpLong(void) { - printf("Usage:\n"); - printf(" cwebp [-preset <...>] [options] in_file [-o out_file]\n\n"); - printf("If input size (-s) for an image is not specified, it is\n" - "assumed to be a PNG, JPEG, TIFF or WebP file.\n"); - printf("Note: Animated PNG and WebP files are not supported.\n"); -#ifdef HAVE_WINCODEC_H - printf("Windows builds can take as input any of the files handled by WIC.\n"); -#endif - printf("\nOptions:\n"); - printf(" -h / -help ............. short help\n"); - printf(" -H / -longhelp ......... long help\n"); - printf(" -q ............. quality factor (0:small..100:big), " - "default=75\n"); - printf(" -alpha_q ......... transparency-compression quality (0..100)," - "\n default=100\n"); - printf(" -preset ....... preset setting, one of:\n"); - printf(" default, photo, picture,\n"); - printf(" drawing, icon, text\n"); - printf(" -preset must come first, as it overwrites other parameters\n"); - printf(" -z ............... activates lossless preset with given\n" - " level in [0:fast, ..., 9:slowest]\n"); - printf("\n"); - printf(" -m ............... compression method (0=fast, 6=slowest), " - "default=4\n"); - printf(" -segments ........ number of segments to use (1..4), " - "default=4\n"); - printf(" -size ............ target size (in bytes)\n"); - printf(" -psnr .......... target PSNR (in dB. typically: 42)\n"); - printf("\n"); - printf(" -s ......... input size (width x height) for YUV\n"); - printf(" -sns ............. spatial noise shaping (0:off, 100:max), " - "default=50\n"); - printf(" -f ............... filter strength (0=off..100), " - "default=60\n"); - printf(" -sharpness ....... " - "filter sharpness (0:most .. 7:least sharp), default=0\n"); - printf(" -strong ................ use strong filter instead " - "of simple (default)\n"); - printf(" -nostrong .............. use simple filter instead of strong\n"); - printf(" -sharp_yuv ............. use sharper (and slower) RGB->YUV " - "conversion\n"); - printf(" -partition_limit . limit quality to fit the 512k limit on\n"); - printf(" " - "the first partition (0=no degradation ... 100=full)\n"); - printf(" -pass ............ analysis pass number (1..10)\n"); - printf(" -qrange .... specifies the permissible quality range\n" - " (default: 0 100)\n"); - printf(" -crop .. crop picture with the given rectangle\n"); - printf(" -resize ........ resize picture (*after* any cropping)\n"); - printf(" -mt .................... use multi-threading if available\n"); - printf(" -low_memory ............ reduce memory usage (slower encoding)\n"); - printf(" -map ............. print map of extra info\n"); - printf(" -print_psnr ............ prints averaged PSNR distortion\n"); - printf(" -print_ssim ............ prints averaged SSIM distortion\n"); - printf(" -print_lsim ............ prints local-similarity distortion\n"); - printf(" -d .......... dump the compressed output (PGM file)\n"); - printf(" -alpha_method .... transparency-compression method (0..1), " - "default=1\n"); - printf(" -alpha_filter . predictive filtering for alpha plane,\n"); - printf(" one of: none, fast (default) or best\n"); - printf(" -exact ................. preserve RGB values in transparent area, " - "default=off\n"); - printf(" -blend_alpha ..... blend colors against background color\n" - " expressed as RGB values written in\n" - " hexadecimal, e.g. 0xc0e0d0 for red=0xc0\n" - " green=0xe0 and blue=0xd0\n"); - printf(" -noalpha ............... discard any transparency information\n"); - printf(" -lossless .............. encode image losslessly, default=off\n"); - printf(" -near_lossless ... use near-lossless image preprocessing\n" - " (0..100=off), default=100\n"); - printf(" -hint ......... specify image characteristics hint,\n"); - printf(" one of: photo, picture or graph\n"); - - printf("\n"); - printf(" -metadata ..... comma separated list of metadata to\n"); - printf(" "); - printf("copy from the input to the output if present.\n"); - printf(" " - "Valid values: all, none (default), exif, icc, xmp\n"); - - printf("\n"); - printf(" -short ................. condense printed message\n"); - printf(" -quiet ................. don't print anything\n"); - printf(" -version ............... print version number and exit\n"); -#ifndef WEBP_DLL - printf(" -noasm ................. disable all assembly optimizations\n"); -#endif - printf(" -v ..................... verbose, e.g. print encoding/decoding " - "times\n"); - printf(" -progress .............. report encoding progress\n"); - printf("\n"); - printf("Experimental Options:\n"); - printf(" -jpeg_like ............. roughly match expected JPEG size\n"); - printf(" -af .................... auto-adjust filter strength\n"); - printf(" -pre ............. pre-processing filter\n"); - printf("\n"); - printf("Supported input formats:\n %s\n", WebPGetEnabledInputFileFormats()); -} - -//------------------------------------------------------------------------------ -// Error messages - -static const char* const kErrorMessages[VP8_ENC_ERROR_LAST] = { - "OK", - "OUT_OF_MEMORY: Out of memory allocating objects", - "BITSTREAM_OUT_OF_MEMORY: Out of memory re-allocating byte buffer", - "NULL_PARAMETER: NULL parameter passed to function", - "INVALID_CONFIGURATION: configuration is invalid", - "BAD_DIMENSION: Bad picture dimension. Maximum width and height " - "allowed is 16383 pixels.", - "PARTITION0_OVERFLOW: Partition #0 is too big to fit 512k.\n" - "To reduce the size of this partition, try using less segments " - "with the -segments option, and eventually reduce the number of " - "header bits using -partition_limit. More details are available " - "in the manual (`man cwebp`)", - "PARTITION_OVERFLOW: Partition is too big to fit 16M", - "BAD_WRITE: Picture writer returned an I/O error", - "FILE_TOO_BIG: File would be too big to fit in 4G", - "USER_ABORT: encoding abort requested by user" -}; - -//------------------------------------------------------------------------------ - -int main(int argc, const char* argv[]) { - int return_value = -1; - const char* in_file = NULL, *out_file = NULL, *dump_file = NULL; - FILE* out = NULL; - int c; - int short_output = 0; - int quiet = 0; - int keep_alpha = 1; - int blend_alpha = 0; - uint32_t background_color = 0xffffffu; - int crop = 0, crop_x = 0, crop_y = 0, crop_w = 0, crop_h = 0; - int resize_w = 0, resize_h = 0; - int lossless_preset = 6; - int use_lossless_preset = -1; // -1=unset, 0=don't use, 1=use it - int show_progress = 0; - int keep_metadata = 0; - int metadata_written = 0; - WebPPicture picture; - int print_distortion = -1; // -1=off, 0=PSNR, 1=SSIM, 2=LSIM - WebPPicture original_picture; // when PSNR or SSIM is requested - WebPConfig config; - WebPAuxStats stats; - WebPMemoryWriter memory_writer; - int use_memory_writer; - Metadata metadata; - Stopwatch stop_watch; - - INIT_WARGV(argc, argv); - - MetadataInit(&metadata); - WebPMemoryWriterInit(&memory_writer); - if (!WebPPictureInit(&picture) || - !WebPPictureInit(&original_picture) || - !WebPConfigInit(&config)) { - fprintf(stderr, "Error! Version mismatch!\n"); - FREE_WARGV_AND_RETURN(-1); - } - - if (argc == 1) { - HelpShort(); - FREE_WARGV_AND_RETURN(0); - } - - for (c = 1; c < argc; ++c) { - int parse_error = 0; - if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) { - HelpShort(); - FREE_WARGV_AND_RETURN(0); - } else if (!strcmp(argv[c], "-H") || !strcmp(argv[c], "-longhelp")) { - HelpLong(); - FREE_WARGV_AND_RETURN(0); - } else if (!strcmp(argv[c], "-o") && c + 1 < argc) { - out_file = (const char*)GET_WARGV(argv, ++c); - } else if (!strcmp(argv[c], "-d") && c + 1 < argc) { - dump_file = (const char*)GET_WARGV(argv, ++c); - config.show_compressed = 1; - } else if (!strcmp(argv[c], "-print_psnr")) { - config.show_compressed = 1; - print_distortion = 0; - } else if (!strcmp(argv[c], "-print_ssim")) { - config.show_compressed = 1; - print_distortion = 1; - } else if (!strcmp(argv[c], "-print_lsim")) { - config.show_compressed = 1; - print_distortion = 2; - } else if (!strcmp(argv[c], "-short")) { - ++short_output; - } else if (!strcmp(argv[c], "-s") && c + 2 < argc) { - picture.width = ExUtilGetInt(argv[++c], 0, &parse_error); - picture.height = ExUtilGetInt(argv[++c], 0, &parse_error); - if (picture.width > WEBP_MAX_DIMENSION || picture.width < 0 || - picture.height > WEBP_MAX_DIMENSION || picture.height < 0) { - fprintf(stderr, - "Specified dimension (%d x %d) is out of range.\n", - picture.width, picture.height); - goto Error; - } - } else if (!strcmp(argv[c], "-m") && c + 1 < argc) { - config.method = ExUtilGetInt(argv[++c], 0, &parse_error); - use_lossless_preset = 0; // disable -z option - } else if (!strcmp(argv[c], "-q") && c + 1 < argc) { - config.quality = ExUtilGetFloat(argv[++c], &parse_error); - use_lossless_preset = 0; // disable -z option - } else if (!strcmp(argv[c], "-z") && c + 1 < argc) { - lossless_preset = ExUtilGetInt(argv[++c], 0, &parse_error); - if (use_lossless_preset != 0) use_lossless_preset = 1; - } else if (!strcmp(argv[c], "-alpha_q") && c + 1 < argc) { - config.alpha_quality = ExUtilGetInt(argv[++c], 0, &parse_error); - } else if (!strcmp(argv[c], "-alpha_method") && c + 1 < argc) { - config.alpha_compression = ExUtilGetInt(argv[++c], 0, &parse_error); - } else if (!strcmp(argv[c], "-alpha_cleanup")) { - // This flag is obsolete, does opposite of -exact. - config.exact = 0; - } else if (!strcmp(argv[c], "-exact")) { - config.exact = 1; - } else if (!strcmp(argv[c], "-blend_alpha") && c + 1 < argc) { - blend_alpha = 1; - // background color is given in hex with an optional '0x' prefix - background_color = ExUtilGetInt(argv[++c], 16, &parse_error); - background_color = background_color & 0x00ffffffu; - } else if (!strcmp(argv[c], "-alpha_filter") && c + 1 < argc) { - ++c; - if (!strcmp(argv[c], "none")) { - config.alpha_filtering = 0; - } else if (!strcmp(argv[c], "fast")) { - config.alpha_filtering = 1; - } else if (!strcmp(argv[c], "best")) { - config.alpha_filtering = 2; - } else { - fprintf(stderr, "Error! Unrecognized alpha filter: %s\n", argv[c]); - goto Error; - } - } else if (!strcmp(argv[c], "-noalpha")) { - keep_alpha = 0; - } else if (!strcmp(argv[c], "-lossless")) { - config.lossless = 1; - } else if (!strcmp(argv[c], "-near_lossless") && c + 1 < argc) { - config.near_lossless = ExUtilGetInt(argv[++c], 0, &parse_error); - config.lossless = 1; // use near-lossless only with lossless - } else if (!strcmp(argv[c], "-hint") && c + 1 < argc) { - ++c; - if (!strcmp(argv[c], "photo")) { - config.image_hint = WEBP_HINT_PHOTO; - } else if (!strcmp(argv[c], "picture")) { - config.image_hint = WEBP_HINT_PICTURE; - } else if (!strcmp(argv[c], "graph")) { - config.image_hint = WEBP_HINT_GRAPH; - } else { - fprintf(stderr, "Error! Unrecognized image hint: %s\n", argv[c]); - goto Error; - } - } else if (!strcmp(argv[c], "-size") && c + 1 < argc) { - config.target_size = ExUtilGetInt(argv[++c], 0, &parse_error); - } else if (!strcmp(argv[c], "-psnr") && c + 1 < argc) { - config.target_PSNR = ExUtilGetFloat(argv[++c], &parse_error); - } else if (!strcmp(argv[c], "-sns") && c + 1 < argc) { - config.sns_strength = ExUtilGetInt(argv[++c], 0, &parse_error); - } else if (!strcmp(argv[c], "-f") && c + 1 < argc) { - config.filter_strength = ExUtilGetInt(argv[++c], 0, &parse_error); - } else if (!strcmp(argv[c], "-af")) { - config.autofilter = 1; - } else if (!strcmp(argv[c], "-jpeg_like")) { - config.emulate_jpeg_size = 1; - } else if (!strcmp(argv[c], "-mt")) { - ++config.thread_level; // increase thread level - } else if (!strcmp(argv[c], "-low_memory")) { - config.low_memory = 1; - } else if (!strcmp(argv[c], "-strong")) { - config.filter_type = 1; - } else if (!strcmp(argv[c], "-nostrong")) { - config.filter_type = 0; - } else if (!strcmp(argv[c], "-sharpness") && c + 1 < argc) { - config.filter_sharpness = ExUtilGetInt(argv[++c], 0, &parse_error); - } else if (!strcmp(argv[c], "-sharp_yuv")) { - config.use_sharp_yuv = 1; - } else if (!strcmp(argv[c], "-pass") && c + 1 < argc) { - config.pass = ExUtilGetInt(argv[++c], 0, &parse_error); - } else if (!strcmp(argv[c], "-qrange") && c + 2 < argc) { - config.qmin = ExUtilGetInt(argv[++c], 0, &parse_error); - config.qmax = ExUtilGetInt(argv[++c], 0, &parse_error); - if (config.qmin < 0) config.qmin = 0; - if (config.qmax > 100) config.qmax = 100; - } else if (!strcmp(argv[c], "-pre") && c + 1 < argc) { - config.preprocessing = ExUtilGetInt(argv[++c], 0, &parse_error); - } else if (!strcmp(argv[c], "-segments") && c + 1 < argc) { - config.segments = ExUtilGetInt(argv[++c], 0, &parse_error); - } else if (!strcmp(argv[c], "-partition_limit") && c + 1 < argc) { - config.partition_limit = ExUtilGetInt(argv[++c], 0, &parse_error); - } else if (!strcmp(argv[c], "-map") && c + 1 < argc) { - picture.extra_info_type = ExUtilGetInt(argv[++c], 0, &parse_error); - } else if (!strcmp(argv[c], "-crop") && c + 4 < argc) { - crop = 1; - crop_x = ExUtilGetInt(argv[++c], 0, &parse_error); - crop_y = ExUtilGetInt(argv[++c], 0, &parse_error); - crop_w = ExUtilGetInt(argv[++c], 0, &parse_error); - crop_h = ExUtilGetInt(argv[++c], 0, &parse_error); - } else if (!strcmp(argv[c], "-resize") && c + 2 < argc) { - resize_w = ExUtilGetInt(argv[++c], 0, &parse_error); - resize_h = ExUtilGetInt(argv[++c], 0, &parse_error); -#ifndef WEBP_DLL - } else if (!strcmp(argv[c], "-noasm")) { - VP8GetCPUInfo = NULL; -#endif - } else if (!strcmp(argv[c], "-version")) { - const int version = WebPGetEncoderVersion(); - const int sharpyuv_version = SharpYuvGetVersion(); - printf("%d.%d.%d\n", - (version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff); - printf("libsharpyuv: %d.%d.%d\n", - (sharpyuv_version >> 24) & 0xff, (sharpyuv_version >> 16) & 0xffff, - sharpyuv_version & 0xff); - FREE_WARGV_AND_RETURN(0); - } else if (!strcmp(argv[c], "-progress")) { - show_progress = 1; - } else if (!strcmp(argv[c], "-quiet")) { - quiet = 1; - } else if (!strcmp(argv[c], "-preset") && c + 1 < argc) { - WebPPreset preset; - ++c; - if (!strcmp(argv[c], "default")) { - preset = WEBP_PRESET_DEFAULT; - } else if (!strcmp(argv[c], "photo")) { - preset = WEBP_PRESET_PHOTO; - } else if (!strcmp(argv[c], "picture")) { - preset = WEBP_PRESET_PICTURE; - } else if (!strcmp(argv[c], "drawing")) { - preset = WEBP_PRESET_DRAWING; - } else if (!strcmp(argv[c], "icon")) { - preset = WEBP_PRESET_ICON; - } else if (!strcmp(argv[c], "text")) { - preset = WEBP_PRESET_TEXT; - } else { - fprintf(stderr, "Error! Unrecognized preset: %s\n", argv[c]); - goto Error; - } - if (!WebPConfigPreset(&config, preset, config.quality)) { - fprintf(stderr, "Error! Could initialize configuration with preset.\n"); - goto Error; - } - } else if (!strcmp(argv[c], "-metadata") && c + 1 < argc) { - static const struct { - const char* option; - int flag; - } kTokens[] = { - { "all", METADATA_ALL }, - { "none", 0 }, - { "exif", METADATA_EXIF }, - { "icc", METADATA_ICC }, - { "xmp", METADATA_XMP }, - }; - const size_t kNumTokens = sizeof(kTokens) / sizeof(kTokens[0]); - const char* start = argv[++c]; - const char* const end = start + strlen(start); - - while (start < end) { - size_t i; - const char* token = strchr(start, ','); - if (token == NULL) token = end; - - for (i = 0; i < kNumTokens; ++i) { - if ((size_t)(token - start) == strlen(kTokens[i].option) && - !strncmp(start, kTokens[i].option, strlen(kTokens[i].option))) { - if (kTokens[i].flag != 0) { - keep_metadata |= kTokens[i].flag; - } else { - keep_metadata = 0; - } - break; - } - } - if (i == kNumTokens) { - fprintf(stderr, "Error! Unknown metadata type '%.*s'\n", - (int)(token - start), start); - FREE_WARGV_AND_RETURN(-1); - } - start = token + 1; - } -#ifdef HAVE_WINCODEC_H - if (keep_metadata != 0 && keep_metadata != METADATA_ICC) { - // TODO(jzern): remove when -metadata is supported on all platforms. - fprintf(stderr, "Warning: only ICC profile extraction is currently" - " supported on this platform!\n"); - } -#endif - } else if (!strcmp(argv[c], "-v")) { - verbose = 1; - } else if (!strcmp(argv[c], "--")) { - if (c + 1 < argc) in_file = (const char*)GET_WARGV(argv, ++c); - break; - } else if (argv[c][0] == '-') { - fprintf(stderr, "Error! Unknown option '%s'\n", argv[c]); - HelpLong(); - FREE_WARGV_AND_RETURN(-1); - } else { - in_file = (const char*)GET_WARGV(argv, c); - } - - if (parse_error) { - HelpLong(); - FREE_WARGV_AND_RETURN(-1); - } - } - if (in_file == NULL) { - fprintf(stderr, "No input file specified!\n"); - HelpShort(); - goto Error; - } - - if (use_lossless_preset == 1) { - if (!WebPConfigLosslessPreset(&config, lossless_preset)) { - fprintf(stderr, "Invalid lossless preset (-z %d)\n", lossless_preset); - goto Error; - } - } - - // Check for unsupported command line options for lossless mode and log - // warning for such options. - if (!quiet && config.lossless == 1) { - if (config.target_size > 0 || config.target_PSNR > 0) { - fprintf(stderr, "Encoding for specified size or PSNR is not supported" - " for lossless encoding. Ignoring such option(s)!\n"); - } - if (config.partition_limit > 0) { - fprintf(stderr, "Partition limit option is not required for lossless" - " encoding. Ignoring this option!\n"); - } - } - // If a target size or PSNR was given, but somehow the -pass option was - // omitted, force a reasonable value. - if (config.target_size > 0 || config.target_PSNR > 0) { - if (config.pass == 1) config.pass = 6; - } - - if (!WebPValidateConfig(&config)) { - fprintf(stderr, "Error! Invalid configuration.\n"); - goto Error; - } - - // Read the input. We need to decide if we prefer ARGB or YUVA - // samples, depending on the expected compression mode (this saves - // some conversion steps). - picture.use_argb = (config.lossless || config.use_sharp_yuv || - config.preprocessing > 0 || - crop || (resize_w | resize_h) > 0); - if (verbose) { - StopwatchReset(&stop_watch); - } - if (!ReadPicture(in_file, &picture, keep_alpha, - (keep_metadata == 0) ? NULL : &metadata)) { - WFPRINTF(stderr, "Error! Cannot read input picture file '%s'\n", - (const W_CHAR*)in_file); - goto Error; - } - picture.progress_hook = (show_progress && !quiet) ? ProgressReport : NULL; - - if (blend_alpha) { - WebPBlendAlpha(&picture, background_color); - } - - if (verbose) { - const double read_time = StopwatchReadAndReset(&stop_watch); - fprintf(stderr, "Time to read input: %.3fs\n", read_time); - } - // The bitstream should be kept in memory when metadata must be appended - // before writing it to a file/stream, and/or when the near-losslessly encoded - // bitstream must be decoded for distortion computation (lossy will modify the - // 'picture' but not the lossless pipeline). - // Otherwise directly write the bitstream to a file. - use_memory_writer = (out_file != NULL && keep_metadata) || - (!quiet && print_distortion >= 0 && config.lossless && - config.near_lossless < 100); - - // Open the output - if (out_file != NULL) { - const int use_stdout = !WSTRCMP(out_file, "-"); - out = use_stdout ? ImgIoUtilSetBinaryMode(stdout) : WFOPEN(out_file, "wb"); - if (out == NULL) { - WFPRINTF(stderr, "Error! Cannot open output file '%s'\n", - (const W_CHAR*)out_file); - goto Error; - } else { - if (!short_output && !quiet) { - WFPRINTF(stderr, "Saving file '%s'\n", (const W_CHAR*)out_file); - } - } - if (use_memory_writer) { - picture.writer = WebPMemoryWrite; - picture.custom_ptr = (void*)&memory_writer; - } else { - picture.writer = MyWriter; - picture.custom_ptr = (void*)out; - } - } else { - out = NULL; - if (use_memory_writer) { - picture.writer = WebPMemoryWrite; - picture.custom_ptr = (void*)&memory_writer; - } - if (!quiet && !short_output) { - fprintf(stderr, "No output file specified (no -o flag). Encoding will\n"); - fprintf(stderr, "be performed, but its results discarded.\n\n"); - } - } - if (!quiet) { - picture.stats = &stats; - picture.user_data = (void*)in_file; - } - - // Crop & resize. - if (verbose) { - StopwatchReset(&stop_watch); - } - if (crop != 0) { - // We use self-cropping using a view. - if (!WebPPictureView(&picture, crop_x, crop_y, crop_w, crop_h, &picture)) { - fprintf(stderr, "Error! Cannot crop picture\n"); - goto Error; - } - } - if ((resize_w | resize_h) > 0) { - WebPPicture picture_no_alpha; - if (config.exact) { - // If -exact, we can't premultiply RGB by A otherwise RGB is lost if A=0. - // We rescale an opaque copy and assemble scaled A and non-premultiplied - // RGB channels. This is slower but it's a very uncommon use case. Color - // leak at sharp alpha edges is possible. - if (!WebPPictureCopy(&picture, &picture_no_alpha)) { - fprintf(stderr, "Error! Cannot copy temporary picture\n"); - goto Error; - } - - // We enforced picture.use_argb = 1 above. Now, remove the alpha values. - { - int x, y; - uint32_t* argb_no_alpha = picture_no_alpha.argb; - for (y = 0; y < picture_no_alpha.height; ++y) { - for (x = 0; x < picture_no_alpha.width; ++x) { - argb_no_alpha[x] |= 0xff000000; // Opaque copy. - } - argb_no_alpha += picture_no_alpha.argb_stride; - } - } - - if (!WebPPictureRescale(&picture_no_alpha, resize_w, resize_h)) { - fprintf(stderr, "Error! Cannot resize temporary picture\n"); - goto Error; - } - } - - if (!WebPPictureRescale(&picture, resize_w, resize_h)) { - fprintf(stderr, "Error! Cannot resize picture\n"); - goto Error; - } - - if (config.exact) { // Put back the alpha information. - int x, y; - uint32_t* argb_no_alpha = picture_no_alpha.argb; - uint32_t* argb = picture.argb; - for (y = 0; y < picture_no_alpha.height; ++y) { - for (x = 0; x < picture_no_alpha.width; ++x) { - argb[x] = (argb[x] & 0xff000000) | (argb_no_alpha[x] & 0x00ffffff); - } - argb_no_alpha += picture_no_alpha.argb_stride; - argb += picture.argb_stride; - } - WebPPictureFree(&picture_no_alpha); - } - } - if (verbose && (crop != 0 || (resize_w | resize_h) > 0)) { - const double preproc_time = StopwatchReadAndReset(&stop_watch); - fprintf(stderr, "Time to crop/resize picture: %.3fs\n", preproc_time); - } - - if (picture.extra_info_type > 0) { - AllocExtraInfo(&picture); - } - // Save original picture for later comparison. Only for lossy as lossless does - // not modify 'picture' (even near-lossless). - if (print_distortion >= 0 && !config.lossless && - !WebPPictureCopy(&picture, &original_picture)) { - fprintf(stderr, "Error! Cannot copy temporary picture\n"); - goto Error; - } - - // Compress. - if (verbose) { - StopwatchReset(&stop_watch); - } - if (!WebPEncode(&config, &picture)) { - fprintf(stderr, "Error! Cannot encode picture as WebP\n"); - fprintf(stderr, "Error code: %d (%s)\n", - picture.error_code, kErrorMessages[picture.error_code]); - goto Error; - } - if (verbose) { - const double encode_time = StopwatchReadAndReset(&stop_watch); - fprintf(stderr, "Time to encode picture: %.3fs\n", encode_time); - } - - // Get the decompressed image for the lossless pipeline. - if (!quiet && print_distortion >= 0 && config.lossless) { - if (config.near_lossless == 100) { - // Pure lossless: image was not modified, make 'original_picture' a view - // of 'picture' by copying all members except the freeable pointers. - original_picture = picture; - original_picture.memory_ = original_picture.memory_argb_ = NULL; - } else { - // Decode the bitstream stored in 'memory_writer' to get the altered image - // to 'picture'; save the 'original_picture' beforehand. - assert(use_memory_writer); - original_picture = picture; - if (!WebPPictureInit(&picture)) { // Do not free 'picture'. - fprintf(stderr, "Error! Version mismatch!\n"); - goto Error; - } - - picture.use_argb = 1; - if (!ReadWebP( - memory_writer.mem, memory_writer.size, &picture, - /*keep_alpha=*/WebPPictureHasTransparency(&original_picture), - /*metadata=*/NULL)) { - fprintf(stderr, "Error! Cannot decode encoded WebP bitstream\n"); - fprintf(stderr, "Error code: %d (%s)\n", picture.error_code, - kErrorMessages[picture.error_code]); - goto Error; - } - picture.stats = original_picture.stats; - } - original_picture.stats = NULL; - } - - // Write the YUV planes to a PGM file. Only available for lossy. - if (dump_file) { - if (picture.use_argb) { - fprintf(stderr, "Warning: can't dump file (-d option) " - "in lossless mode.\n"); - } else if (!DumpPicture(&picture, dump_file)) { - WFPRINTF(stderr, "Warning, couldn't dump picture %s\n", - (const W_CHAR*)dump_file); - } - } - - if (use_memory_writer && out != NULL && - !WriteWebPWithMetadata(out, &picture, &memory_writer, &metadata, - keep_metadata, &metadata_written)) { - fprintf(stderr, "Error writing WebP file!\n"); - goto Error; - } - - if (out == NULL && keep_metadata) { - // output is disabled, just display the metadata stats. - const struct { - const MetadataPayload* const payload; - int flag; - } *iter, info[] = {{&metadata.exif, METADATA_EXIF}, - {&metadata.iccp, METADATA_ICC}, - {&metadata.xmp, METADATA_XMP}, - {NULL, 0}}; - uint32_t unused1 = 0; - uint64_t unused2 = 0; - - for (iter = info; iter->payload != NULL; ++iter) { - if (UpdateFlagsAndSize(iter->payload, !!(keep_metadata & iter->flag), - /*flag=*/0, &unused1, &unused2)) { - metadata_written |= iter->flag; - } - } - } - - if (!quiet) { - if (!short_output || print_distortion < 0) { - if (config.lossless) { - PrintExtraInfoLossless(&picture, short_output, in_file); - } else { - PrintExtraInfoLossy(&picture, short_output, config.low_memory, in_file); - } - } - if (!short_output && picture.extra_info_type > 0) { - PrintMapInfo(&picture); - } - if (print_distortion >= 0) { // print distortion - static const char* distortion_names[] = { "PSNR", "SSIM", "LSIM" }; - float values[5]; - if (!WebPPictureDistortion(&picture, &original_picture, - print_distortion, values)) { - fprintf(stderr, "Error while computing the distortion.\n"); - goto Error; - } - if (!short_output) { - fprintf(stderr, "%s: ", distortion_names[print_distortion]); - fprintf(stderr, "B:%.2f G:%.2f R:%.2f A:%.2f Total:%.2f\n", - values[0], values[1], values[2], values[3], values[4]); - } else { - fprintf(stderr, "%7d %.4f\n", picture.stats->coded_size, values[4]); - } - } - if (!short_output) { - PrintMetadataInfo(&metadata, metadata_written); - } - } - return_value = 0; - - Error: - WebPMemoryWriterClear(&memory_writer); - WebPFree(picture.extra_info); - MetadataFree(&metadata); - WebPPictureFree(&picture); - WebPPictureFree(&original_picture); - if (out != NULL && out != stdout) { - fclose(out); - } - - FREE_WARGV_AND_RETURN(return_value); -} - -//------------------------------------------------------------------------------ diff --git a/libwebp/examples/dwebp.c b/libwebp/examples/dwebp.c deleted file mode 100644 index 652de6a6..00000000 --- a/libwebp/examples/dwebp.c +++ /dev/null @@ -1,421 +0,0 @@ -// Copyright 2010 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Command-line tool for decoding a WebP image. -// -// Author: Skal (pascal.massimino@gmail.com) - -#include -#include -#include -#include - -#ifdef HAVE_CONFIG_H -#include "webp/config.h" -#endif - -#include "../examples/example_util.h" -#include "../imageio/image_enc.h" -#include "../imageio/webpdec.h" -#include "./stopwatch.h" -#include "./unicode.h" - -static int verbose = 0; -static int quiet = 0; -#ifndef WEBP_DLL -#ifdef __cplusplus -extern "C" { -#endif - -extern void* VP8GetCPUInfo; // opaque forward declaration. - -#ifdef __cplusplus -} // extern "C" -#endif -#endif // WEBP_DLL - - -static int SaveOutput(const WebPDecBuffer* const buffer, - WebPOutputFileFormat format, const char* const out_file) { - const int use_stdout = (out_file != NULL) && !WSTRCMP(out_file, "-"); - int ok = 1; - Stopwatch stop_watch; - - if (verbose) { - StopwatchReset(&stop_watch); - } - ok = WebPSaveImage(buffer, format, out_file); - - if (ok) { - if (!quiet) { - if (use_stdout) { - fprintf(stderr, "Saved to stdout\n"); - } else { - WFPRINTF(stderr, "Saved file %s\n", (const W_CHAR*)out_file); - } - } - if (verbose) { - const double write_time = StopwatchReadAndReset(&stop_watch); - fprintf(stderr, "Time to write output: %.3fs\n", write_time); - } - } else { - if (use_stdout) { - fprintf(stderr, "Error writing to stdout !!\n"); - } else { - WFPRINTF(stderr, "Error writing file %s !!\n", (const W_CHAR*)out_file); - } - } - return ok; -} - -static void Help(void) { - printf("Usage: dwebp in_file [options] [-o out_file]\n\n" - "Decodes the WebP image file to PNG format [Default].\n" - "Note: Animated WebP files are not supported.\n\n" - "Use following options to convert into alternate image formats:\n" - " -pam ......... save the raw RGBA samples as a color PAM\n" - " -ppm ......... save the raw RGB samples as a color PPM\n" - " -bmp ......... save as uncompressed BMP format\n" - " -tiff ........ save as uncompressed TIFF format\n" - " -pgm ......... save the raw YUV samples as a grayscale PGM\n" - " file with IMC4 layout\n" - " -yuv ......... save the raw YUV samples in flat layout\n" - "\n" - " Other options are:\n" - " -version ..... print version number and exit\n" - " -nofancy ..... don't use the fancy YUV420 upscaler\n" - " -nofilter .... disable in-loop filtering\n" - " -nodither .... disable dithering\n" - " -dither .. dithering strength (in 0..100)\n" - " -alpha_dither use alpha-plane dithering if needed\n" - " -mt .......... use multi-threading\n" - " -crop ... crop output with the given rectangle\n" - " -resize ......... resize output (*after* any cropping)\n" - " -flip ........ flip the output vertically\n" - " -alpha ....... only save the alpha plane\n" - " -incremental . use incremental decoding (useful for tests)\n" - " -h ........... this help message\n" - " -v ........... verbose (e.g. print encoding/decoding times)\n" - " -quiet ....... quiet mode, don't print anything\n" -#ifndef WEBP_DLL - " -noasm ....... disable all assembly optimizations\n" -#endif - ); -} - -static const char* const kFormatType[] = { - "unspecified", "lossy", "lossless" -}; - -static uint8_t* AllocateExternalBuffer(WebPDecoderConfig* config, - WebPOutputFileFormat format, - int use_external_memory) { - uint8_t* external_buffer = NULL; - WebPDecBuffer* const output_buffer = &config->output; - int w = config->input.width; - int h = config->input.height; - if (config->options.use_scaling) { - w = config->options.scaled_width; - h = config->options.scaled_height; - } else if (config->options.use_cropping) { - w = config->options.crop_width; - h = config->options.crop_height; - } - if (format >= RGB && format <= rgbA_4444) { - const int bpp = (format == RGB || format == BGR) ? 3 - : (format == RGBA_4444 || format == rgbA_4444 || - format == RGB_565) ? 2 - : 4; - uint32_t stride = bpp * w + 7; // <- just for exercising - external_buffer = (uint8_t*)WebPMalloc(stride * h); - if (external_buffer == NULL) return NULL; - output_buffer->u.RGBA.stride = stride; - output_buffer->u.RGBA.size = stride * h; - output_buffer->u.RGBA.rgba = external_buffer; - } else { // YUV and YUVA - const int has_alpha = WebPIsAlphaMode(output_buffer->colorspace); - uint8_t* tmp; - uint32_t stride = w + 3; - uint32_t uv_stride = (w + 1) / 2 + 13; - uint32_t total_size = stride * h * (has_alpha ? 2 : 1) - + 2 * uv_stride * (h + 1) / 2; - assert(format >= YUV && format <= YUVA); - external_buffer = (uint8_t*)WebPMalloc(total_size); - if (external_buffer == NULL) return NULL; - tmp = external_buffer; - output_buffer->u.YUVA.y = tmp; - output_buffer->u.YUVA.y_stride = stride; - output_buffer->u.YUVA.y_size = stride * h; - tmp += output_buffer->u.YUVA.y_size; - if (has_alpha) { - output_buffer->u.YUVA.a = tmp; - output_buffer->u.YUVA.a_stride = stride; - output_buffer->u.YUVA.a_size = stride * h; - tmp += output_buffer->u.YUVA.a_size; - } else { - output_buffer->u.YUVA.a = NULL; - output_buffer->u.YUVA.a_stride = 0; - } - output_buffer->u.YUVA.u = tmp; - output_buffer->u.YUVA.u_stride = uv_stride; - output_buffer->u.YUVA.u_size = uv_stride * (h + 1) / 2; - tmp += output_buffer->u.YUVA.u_size; - - output_buffer->u.YUVA.v = tmp; - output_buffer->u.YUVA.v_stride = uv_stride; - output_buffer->u.YUVA.v_size = uv_stride * (h + 1) / 2; - tmp += output_buffer->u.YUVA.v_size; - assert(tmp <= external_buffer + total_size); - } - output_buffer->is_external_memory = use_external_memory; - return external_buffer; -} - -int main(int argc, const char* argv[]) { - int ok = 0; - const char* in_file = NULL; - const char* out_file = NULL; - - WebPDecoderConfig config; - WebPDecBuffer* const output_buffer = &config.output; - WebPBitstreamFeatures* const bitstream = &config.input; - WebPOutputFileFormat format = PNG; - uint8_t* external_buffer = NULL; - int use_external_memory = 0; - const uint8_t* data = NULL; - - int incremental = 0; - int c; - - INIT_WARGV(argc, argv); - - if (!WebPInitDecoderConfig(&config)) { - fprintf(stderr, "Library version mismatch!\n"); - FREE_WARGV_AND_RETURN(-1); - } - - for (c = 1; c < argc; ++c) { - int parse_error = 0; - if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) { - Help(); - FREE_WARGV_AND_RETURN(0); - } else if (!strcmp(argv[c], "-o") && c < argc - 1) { - out_file = (const char*)GET_WARGV(argv, ++c); - } else if (!strcmp(argv[c], "-alpha")) { - format = ALPHA_PLANE_ONLY; - } else if (!strcmp(argv[c], "-nofancy")) { - config.options.no_fancy_upsampling = 1; - } else if (!strcmp(argv[c], "-nofilter")) { - config.options.bypass_filtering = 1; - } else if (!strcmp(argv[c], "-pam")) { - format = PAM; - } else if (!strcmp(argv[c], "-ppm")) { - format = PPM; - } else if (!strcmp(argv[c], "-bmp")) { - format = BMP; - } else if (!strcmp(argv[c], "-tiff")) { - format = TIFF; - } else if (!strcmp(argv[c], "-quiet")) { - quiet = 1; - } else if (!strcmp(argv[c], "-version")) { - const int version = WebPGetDecoderVersion(); - printf("%d.%d.%d\n", - (version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff); - FREE_WARGV_AND_RETURN(0); - } else if (!strcmp(argv[c], "-pgm")) { - format = PGM; - } else if (!strcmp(argv[c], "-yuv")) { - format = RAW_YUV; - } else if (!strcmp(argv[c], "-pixel_format") && c < argc - 1) { - const char* const fmt = argv[++c]; - if (!strcmp(fmt, "RGB")) format = RGB; - else if (!strcmp(fmt, "RGBA")) format = RGBA; - else if (!strcmp(fmt, "BGR")) format = BGR; - else if (!strcmp(fmt, "BGRA")) format = BGRA; - else if (!strcmp(fmt, "ARGB")) format = ARGB; - else if (!strcmp(fmt, "RGBA_4444")) format = RGBA_4444; - else if (!strcmp(fmt, "RGB_565")) format = RGB_565; - else if (!strcmp(fmt, "rgbA")) format = rgbA; - else if (!strcmp(fmt, "bgrA")) format = bgrA; - else if (!strcmp(fmt, "Argb")) format = Argb; - else if (!strcmp(fmt, "rgbA_4444")) format = rgbA_4444; - else if (!strcmp(fmt, "YUV")) format = YUV; - else if (!strcmp(fmt, "YUVA")) format = YUVA; - else { - fprintf(stderr, "Can't parse pixel_format %s\n", fmt); - parse_error = 1; - } - } else if (!strcmp(argv[c], "-external_memory") && c < argc - 1) { - use_external_memory = ExUtilGetInt(argv[++c], 0, &parse_error); - parse_error |= (use_external_memory > 2 || use_external_memory < 0); - if (parse_error) { - fprintf(stderr, "Can't parse 'external_memory' value %s\n", argv[c]); - } - } else if (!strcmp(argv[c], "-mt")) { - config.options.use_threads = 1; - } else if (!strcmp(argv[c], "-alpha_dither")) { - config.options.alpha_dithering_strength = 100; - } else if (!strcmp(argv[c], "-nodither")) { - config.options.dithering_strength = 0; - } else if (!strcmp(argv[c], "-dither") && c < argc - 1) { - config.options.dithering_strength = - ExUtilGetInt(argv[++c], 0, &parse_error); - } else if (!strcmp(argv[c], "-crop") && c < argc - 4) { - config.options.use_cropping = 1; - config.options.crop_left = ExUtilGetInt(argv[++c], 0, &parse_error); - config.options.crop_top = ExUtilGetInt(argv[++c], 0, &parse_error); - config.options.crop_width = ExUtilGetInt(argv[++c], 0, &parse_error); - config.options.crop_height = ExUtilGetInt(argv[++c], 0, &parse_error); - } else if ((!strcmp(argv[c], "-scale") || !strcmp(argv[c], "-resize")) && - c < argc - 2) { // '-scale' is left for compatibility - config.options.use_scaling = 1; - config.options.scaled_width = ExUtilGetInt(argv[++c], 0, &parse_error); - config.options.scaled_height = ExUtilGetInt(argv[++c], 0, &parse_error); - } else if (!strcmp(argv[c], "-flip")) { - config.options.flip = 1; - } else if (!strcmp(argv[c], "-v")) { - verbose = 1; -#ifndef WEBP_DLL - } else if (!strcmp(argv[c], "-noasm")) { - VP8GetCPUInfo = NULL; -#endif - } else if (!strcmp(argv[c], "-incremental")) { - incremental = 1; - } else if (!strcmp(argv[c], "--")) { - if (c < argc - 1) in_file = (const char*)GET_WARGV(argv, ++c); - break; - } else if (argv[c][0] == '-') { - fprintf(stderr, "Unknown option '%s'\n", argv[c]); - Help(); - FREE_WARGV_AND_RETURN(-1); - } else { - in_file = (const char*)GET_WARGV(argv, c); - } - - if (parse_error) { - Help(); - FREE_WARGV_AND_RETURN(-1); - } - } - - if (in_file == NULL) { - fprintf(stderr, "missing input file!!\n"); - Help(); - FREE_WARGV_AND_RETURN(-1); - } - - if (quiet) verbose = 0; - - { - VP8StatusCode status = VP8_STATUS_OK; - size_t data_size = 0; - if (!LoadWebP(in_file, &data, &data_size, bitstream)) { - FREE_WARGV_AND_RETURN(-1); - } - - switch (format) { - case PNG: -#ifdef HAVE_WINCODEC_H - output_buffer->colorspace = bitstream->has_alpha ? MODE_BGRA : MODE_BGR; -#else - output_buffer->colorspace = bitstream->has_alpha ? MODE_RGBA : MODE_RGB; -#endif - break; - case PAM: - output_buffer->colorspace = MODE_RGBA; - break; - case PPM: - output_buffer->colorspace = MODE_RGB; // drops alpha for PPM - break; - case BMP: - output_buffer->colorspace = bitstream->has_alpha ? MODE_BGRA : MODE_BGR; - break; - case TIFF: - output_buffer->colorspace = bitstream->has_alpha ? MODE_RGBA : MODE_RGB; - break; - case PGM: - case RAW_YUV: - output_buffer->colorspace = bitstream->has_alpha ? MODE_YUVA : MODE_YUV; - break; - case ALPHA_PLANE_ONLY: - output_buffer->colorspace = MODE_YUVA; - break; - // forced modes: - case RGB: output_buffer->colorspace = MODE_RGB; break; - case RGBA: output_buffer->colorspace = MODE_RGBA; break; - case BGR: output_buffer->colorspace = MODE_BGR; break; - case BGRA: output_buffer->colorspace = MODE_BGRA; break; - case ARGB: output_buffer->colorspace = MODE_ARGB; break; - case RGBA_4444: output_buffer->colorspace = MODE_RGBA_4444; break; - case RGB_565: output_buffer->colorspace = MODE_RGB_565; break; - case rgbA: output_buffer->colorspace = MODE_rgbA; break; - case bgrA: output_buffer->colorspace = MODE_bgrA; break; - case Argb: output_buffer->colorspace = MODE_Argb; break; - case rgbA_4444: output_buffer->colorspace = MODE_rgbA_4444; break; - case YUV: output_buffer->colorspace = MODE_YUV; break; - case YUVA: output_buffer->colorspace = MODE_YUVA; break; - default: goto Exit; - } - - if (use_external_memory > 0 && format >= RGB) { - external_buffer = AllocateExternalBuffer(&config, format, - use_external_memory); - if (external_buffer == NULL) goto Exit; - } - - { - Stopwatch stop_watch; - if (verbose) StopwatchReset(&stop_watch); - - if (incremental) { - status = DecodeWebPIncremental(data, data_size, &config); - } else { - status = DecodeWebP(data, data_size, &config); - } - if (verbose) { - const double decode_time = StopwatchReadAndReset(&stop_watch); - fprintf(stderr, "Time to decode picture: %.3fs\n", decode_time); - } - } - - ok = (status == VP8_STATUS_OK); - if (!ok) { - PrintWebPError(in_file, status); - goto Exit; - } - } - - if (out_file != NULL) { - if (!quiet) { - WFPRINTF(stderr, "Decoded %s.", (const W_CHAR*)in_file); - fprintf(stderr, " Dimensions: %d x %d %s. Format: %s. Now saving...\n", - output_buffer->width, output_buffer->height, - bitstream->has_alpha ? " (with alpha)" : "", - kFormatType[bitstream->format]); - } - ok = SaveOutput(output_buffer, format, out_file); - } else { - if (!quiet) { - WFPRINTF(stderr, "File %s can be decoded ", (const W_CHAR*)in_file); - fprintf(stderr, "(dimensions: %d x %d %s. Format: %s).\n", - output_buffer->width, output_buffer->height, - bitstream->has_alpha ? " (with alpha)" : "", - kFormatType[bitstream->format]); - fprintf(stderr, "Nothing written; " - "use -o flag to save the result as e.g. PNG.\n"); - } - } - Exit: - WebPFreeDecBuffer(output_buffer); - WebPFree((void*)external_buffer); - WebPFree((void*)data); - FREE_WARGV_AND_RETURN(ok ? 0 : -1); -} - -//------------------------------------------------------------------------------ diff --git a/libwebp/examples/example_util.c b/libwebp/examples/example_util.c deleted file mode 100644 index fa38d3c2..00000000 --- a/libwebp/examples/example_util.c +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright 2012 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Utility functions used by the example programs. -// - -#include "./example_util.h" - -#include -#include -#include -#include - -#include "webp/mux_types.h" -#include "../imageio/imageio_util.h" - -//------------------------------------------------------------------------------ -// String parsing - -uint32_t ExUtilGetUInt(const char* const v, int base, int* const error) { - char* end = NULL; - const uint32_t n = (v != NULL) ? (uint32_t)strtoul(v, &end, base) : 0u; - if (end == v && error != NULL && !*error) { - *error = 1; - fprintf(stderr, "Error! '%s' is not an integer.\n", - (v != NULL) ? v : "(null)"); - } - return n; -} - -int ExUtilGetInt(const char* const v, int base, int* const error) { - return (int)ExUtilGetUInt(v, base, error); -} - -int ExUtilGetInts(const char* v, int base, int max_output, int output[]) { - int n, error = 0; - for (n = 0; v != NULL && n < max_output; ++n) { - const int value = ExUtilGetInt(v, base, &error); - if (error) return -1; - output[n] = value; - v = strchr(v, ','); - if (v != NULL) ++v; // skip over the trailing ',' - } - return n; -} - -float ExUtilGetFloat(const char* const v, int* const error) { - char* end = NULL; - const float f = (v != NULL) ? (float)strtod(v, &end) : 0.f; - if (end == v && error != NULL && !*error) { - *error = 1; - fprintf(stderr, "Error! '%s' is not a floating point number.\n", - (v != NULL) ? v : "(null)"); - } - return f; -} - -//------------------------------------------------------------------------------ - -static void ResetCommandLineArguments(int argc, const char* argv[], - CommandLineArguments* const args) { - assert(args != NULL); - args->argc_ = argc; - args->argv_ = argv; - args->own_argv_ = 0; - WebPDataInit(&args->argv_data_); -} - -void ExUtilDeleteCommandLineArguments(CommandLineArguments* const args) { - if (args != NULL) { - if (args->own_argv_) { - WebPFree((void*)args->argv_); - WebPDataClear(&args->argv_data_); - } - ResetCommandLineArguments(0, NULL, args); - } -} - -#define MAX_ARGC 16384 -int ExUtilInitCommandLineArguments(int argc, const char* argv[], - CommandLineArguments* const args) { - if (args == NULL || argv == NULL) return 0; - ResetCommandLineArguments(argc, argv, args); - if (argc == 1 && argv[0][0] != '-') { - char* cur; - const char sep[] = " \t\r\n\f\v"; - -#if defined(_WIN32) && defined(_UNICODE) - fprintf(stderr, - "Error: Reading arguments from a file is a feature unavailable " - "with Unicode binaries.\n"); - return 0; -#endif - - if (!ExUtilReadFileToWebPData(argv[0], &args->argv_data_)) { - return 0; - } - args->own_argv_ = 1; - args->argv_ = (const char**)WebPMalloc(MAX_ARGC * sizeof(*args->argv_)); - if (args->argv_ == NULL) { - ExUtilDeleteCommandLineArguments(args); - return 0; - } - - argc = 0; - for (cur = strtok((char*)args->argv_data_.bytes, sep); - cur != NULL; - cur = strtok(NULL, sep)) { - if (argc == MAX_ARGC) { - fprintf(stderr, "ERROR: Arguments limit %d reached\n", MAX_ARGC); - ExUtilDeleteCommandLineArguments(args); - return 0; - } - assert(strlen(cur) != 0); - args->argv_[argc++] = cur; - } - args->argc_ = argc; - } - return 1; -} - -//------------------------------------------------------------------------------ - -int ExUtilReadFileToWebPData(const char* const filename, - WebPData* const webp_data) { - const uint8_t* data; - size_t size; - if (webp_data == NULL) return 0; - if (!ImgIoUtilReadFile(filename, &data, &size)) return 0; - webp_data->bytes = data; - webp_data->size = size; - return 1; -} diff --git a/libwebp/examples/example_util.h b/libwebp/examples/example_util.h deleted file mode 100644 index fe762a4d..00000000 --- a/libwebp/examples/example_util.h +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2012 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Utility functions used by the example programs. -// - -#ifndef WEBP_EXAMPLES_EXAMPLE_UTIL_H_ -#define WEBP_EXAMPLES_EXAMPLE_UTIL_H_ - -#include "webp/types.h" -#include "webp/mux_types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -//------------------------------------------------------------------------------ -// String parsing - -// Parses 'v' using strto(ul|l|d)(). If error is non-NULL, '*error' is set to -// true on failure while on success it is left unmodified to allow chaining of -// calls. An error is only printed on the first occurrence. -uint32_t ExUtilGetUInt(const char* const v, int base, int* const error); -int ExUtilGetInt(const char* const v, int base, int* const error); -float ExUtilGetFloat(const char* const v, int* const error); - -// This variant of ExUtilGetInt() will parse multiple integers from a -// comma-separated list. Up to 'max_output' integers are parsed. -// The result is placed in the output[] array, and the number of integers -// actually parsed is returned, or -1 if an error occurred. -int ExUtilGetInts(const char* v, int base, int max_output, int output[]); - -// Reads a file named 'filename' into a WebPData structure. The content of -// webp_data is overwritten. Returns false in case of error. -int ExUtilReadFileToWebPData(const char* const filename, - WebPData* const webp_data); - -//------------------------------------------------------------------------------ -// Command-line arguments - -typedef struct { - int argc_; - const char** argv_; - WebPData argv_data_; - int own_argv_; -} CommandLineArguments; - -// Initializes the structure from the command-line parameters. If there is -// only one parameter and it does not start with a '-', then it is assumed to -// be a file name. This file will be read and tokenized into command-line -// arguments. The content of 'args' is overwritten. -// Returns false in case of error (memory allocation failure, non -// existing file, too many arguments, ...). -int ExUtilInitCommandLineArguments(int argc, const char* argv[], - CommandLineArguments* const args); - -// Deallocate all memory and reset 'args'. -void ExUtilDeleteCommandLineArguments(CommandLineArguments* const args); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // WEBP_EXAMPLES_EXAMPLE_UTIL_H_ diff --git a/libwebp/examples/gif2webp.c b/libwebp/examples/gif2webp.c deleted file mode 100644 index cc9b25d9..00000000 --- a/libwebp/examples/gif2webp.c +++ /dev/null @@ -1,609 +0,0 @@ -// Copyright 2012 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// simple tool to convert animated GIFs to WebP -// -// Authors: Skal (pascal.massimino@gmail.com) -// Urvang (urvang@google.com) - -#include -#include -#include -#include - -#ifdef HAVE_CONFIG_H -#include "webp/config.h" -#endif - -#ifdef WEBP_HAVE_GIF - -#if defined(HAVE_UNISTD_H) && HAVE_UNISTD_H -#include -#endif - -#include -#include "webp/encode.h" -#include "webp/mux.h" -#include "../examples/example_util.h" -#include "../imageio/imageio_util.h" -#include "./gifdec.h" -#include "./unicode.h" -#include "./unicode_gif.h" - -#if !defined(STDIN_FILENO) -#define STDIN_FILENO 0 -#endif - -//------------------------------------------------------------------------------ - -static int transparent_index = GIF_INDEX_INVALID; // Opaque by default. - -static const char* const kErrorMessages[-WEBP_MUX_NOT_ENOUGH_DATA + 1] = { - "WEBP_MUX_NOT_FOUND", "WEBP_MUX_INVALID_ARGUMENT", "WEBP_MUX_BAD_DATA", - "WEBP_MUX_MEMORY_ERROR", "WEBP_MUX_NOT_ENOUGH_DATA" -}; - -static const char* ErrorString(WebPMuxError err) { - assert(err <= WEBP_MUX_NOT_FOUND && err >= WEBP_MUX_NOT_ENOUGH_DATA); - return kErrorMessages[-err]; -} - -enum { - METADATA_ICC = (1 << 0), - METADATA_XMP = (1 << 1), - METADATA_ALL = METADATA_ICC | METADATA_XMP -}; - -//------------------------------------------------------------------------------ - -static void Help(void) { - printf("Usage:\n"); - printf(" gif2webp [options] gif_file -o webp_file\n"); - printf("Options:\n"); - printf(" -h / -help ............. this help\n"); - printf(" -lossy ................. encode image using lossy compression\n"); - printf(" -mixed ................. for each frame in the image, pick lossy\n" - " or lossless compression heuristically\n"); - printf(" -q ............. quality factor (0:small..100:big)\n"); - printf(" -m ............... compression method (0=fast, 6=slowest)\n"); - printf(" -min_size .............. minimize output size (default:off)\n" - " lossless compression by default; can be\n" - " combined with -q, -m, -lossy or -mixed\n" - " options\n"); - printf(" -kmin ............ min distance between key frames\n"); - printf(" -kmax ............ max distance between key frames\n"); - printf(" -f ............... filter strength (0=off..100)\n"); - printf(" -metadata ..... comma separated list of metadata to\n"); - printf(" "); - printf("copy from the input to the output if present\n"); - printf(" "); - printf("Valid values: all, none, icc, xmp (default)\n"); - printf(" -loop_compatibility .... use compatibility mode for Chrome\n"); - printf(" version prior to M62 (inclusive)\n"); - printf(" -mt .................... use multi-threading if available\n"); - printf("\n"); - printf(" -version ............... print version number and exit\n"); - printf(" -v ..................... verbose\n"); - printf(" -quiet ................. don't print anything\n"); - printf("\n"); -} - -//------------------------------------------------------------------------------ - -int main(int argc, const char* argv[]) { - int verbose = 0; - int gif_error = GIF_ERROR; - WebPMuxError err = WEBP_MUX_OK; - int ok = 0; - const W_CHAR* in_file = NULL, *out_file = NULL; - GifFileType* gif = NULL; - int frame_duration = 0; - int frame_timestamp = 0; - GIFDisposeMethod orig_dispose = GIF_DISPOSE_NONE; - - WebPPicture frame; // Frame rectangle only (not disposed). - WebPPicture curr_canvas; // Not disposed. - WebPPicture prev_canvas; // Disposed. - - WebPAnimEncoder* enc = NULL; - WebPAnimEncoderOptions enc_options; - WebPConfig config; - - int frame_number = 0; // Whether we are processing the first frame. - int done; - int c; - int quiet = 0; - WebPData webp_data; - - int keep_metadata = METADATA_XMP; // ICC not output by default. - WebPData icc_data; - int stored_icc = 0; // Whether we have already stored an ICC profile. - WebPData xmp_data; - int stored_xmp = 0; // Whether we have already stored an XMP profile. - int loop_count = 0; // default: infinite - int stored_loop_count = 0; // Whether we have found an explicit loop count. - int loop_compatibility = 0; - WebPMux* mux = NULL; - - int default_kmin = 1; // Whether to use default kmin value. - int default_kmax = 1; - - INIT_WARGV(argc, argv); - - if (!WebPConfigInit(&config) || !WebPAnimEncoderOptionsInit(&enc_options) || - !WebPPictureInit(&frame) || !WebPPictureInit(&curr_canvas) || - !WebPPictureInit(&prev_canvas)) { - fprintf(stderr, "Error! Version mismatch!\n"); - FREE_WARGV_AND_RETURN(-1); - } - config.lossless = 1; // Use lossless compression by default. - - WebPDataInit(&webp_data); - WebPDataInit(&icc_data); - WebPDataInit(&xmp_data); - - if (argc == 1) { - Help(); - FREE_WARGV_AND_RETURN(0); - } - - for (c = 1; c < argc; ++c) { - int parse_error = 0; - if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) { - Help(); - FREE_WARGV_AND_RETURN(0); - } else if (!strcmp(argv[c], "-o") && c < argc - 1) { - out_file = GET_WARGV(argv, ++c); - } else if (!strcmp(argv[c], "-lossy")) { - config.lossless = 0; - } else if (!strcmp(argv[c], "-mixed")) { - enc_options.allow_mixed = 1; - config.lossless = 0; - } else if (!strcmp(argv[c], "-loop_compatibility")) { - loop_compatibility = 1; - } else if (!strcmp(argv[c], "-q") && c < argc - 1) { - config.quality = ExUtilGetFloat(argv[++c], &parse_error); - } else if (!strcmp(argv[c], "-m") && c < argc - 1) { - config.method = ExUtilGetInt(argv[++c], 0, &parse_error); - } else if (!strcmp(argv[c], "-min_size")) { - enc_options.minimize_size = 1; - } else if (!strcmp(argv[c], "-kmax") && c < argc - 1) { - enc_options.kmax = ExUtilGetInt(argv[++c], 0, &parse_error); - default_kmax = 0; - } else if (!strcmp(argv[c], "-kmin") && c < argc - 1) { - enc_options.kmin = ExUtilGetInt(argv[++c], 0, &parse_error); - default_kmin = 0; - } else if (!strcmp(argv[c], "-f") && c < argc - 1) { - config.filter_strength = ExUtilGetInt(argv[++c], 0, &parse_error); - } else if (!strcmp(argv[c], "-metadata") && c < argc - 1) { - static const struct { - const char* option; - int flag; - } kTokens[] = { - { "all", METADATA_ALL }, - { "none", 0 }, - { "icc", METADATA_ICC }, - { "xmp", METADATA_XMP }, - }; - const size_t kNumTokens = sizeof(kTokens) / sizeof(*kTokens); - const char* start = argv[++c]; - const char* const end = start + strlen(start); - - keep_metadata = 0; - while (start < end) { - size_t i; - const char* token = strchr(start, ','); - if (token == NULL) token = end; - - for (i = 0; i < kNumTokens; ++i) { - if ((size_t)(token - start) == strlen(kTokens[i].option) && - !strncmp(start, kTokens[i].option, strlen(kTokens[i].option))) { - if (kTokens[i].flag != 0) { - keep_metadata |= kTokens[i].flag; - } else { - keep_metadata = 0; - } - break; - } - } - if (i == kNumTokens) { - fprintf(stderr, "Error! Unknown metadata type '%.*s'\n", - (int)(token - start), start); - Help(); - FREE_WARGV_AND_RETURN(-1); - } - start = token + 1; - } - } else if (!strcmp(argv[c], "-mt")) { - ++config.thread_level; - } else if (!strcmp(argv[c], "-version")) { - const int enc_version = WebPGetEncoderVersion(); - const int mux_version = WebPGetMuxVersion(); - printf("WebP Encoder version: %d.%d.%d\nWebP Mux version: %d.%d.%d\n", - (enc_version >> 16) & 0xff, (enc_version >> 8) & 0xff, - enc_version & 0xff, (mux_version >> 16) & 0xff, - (mux_version >> 8) & 0xff, mux_version & 0xff); - FREE_WARGV_AND_RETURN(0); - } else if (!strcmp(argv[c], "-quiet")) { - quiet = 1; - enc_options.verbose = 0; - } else if (!strcmp(argv[c], "-v")) { - verbose = 1; - enc_options.verbose = 1; - } else if (!strcmp(argv[c], "--")) { - if (c < argc - 1) in_file = GET_WARGV(argv, ++c); - break; - } else if (argv[c][0] == '-') { - fprintf(stderr, "Error! Unknown option '%s'\n", argv[c]); - Help(); - FREE_WARGV_AND_RETURN(-1); - } else { - in_file = GET_WARGV(argv, c); - } - - if (parse_error) { - Help(); - FREE_WARGV_AND_RETURN(-1); - } - } - - // Appropriate default kmin, kmax values for lossy and lossless. - if (default_kmin) { - enc_options.kmin = config.lossless ? 9 : 3; - } - if (default_kmax) { - enc_options.kmax = config.lossless ? 17 : 5; - } - - if (!WebPValidateConfig(&config)) { - fprintf(stderr, "Error! Invalid configuration.\n"); - goto End; - } - - if (in_file == NULL) { - fprintf(stderr, "No input file specified!\n"); - Help(); - goto End; - } - - // Start the decoder object - gif = DGifOpenFileUnicode(in_file, &gif_error); - if (gif == NULL) goto End; - - // Loop over GIF images - done = 0; - do { - GifRecordType type; - if (DGifGetRecordType(gif, &type) == GIF_ERROR) goto End; - - switch (type) { - case IMAGE_DESC_RECORD_TYPE: { - GIFFrameRect gif_rect; - GifImageDesc* const image_desc = &gif->Image; - - if (!DGifGetImageDesc(gif)) goto End; - - if (frame_number == 0) { - if (verbose) { - printf("Canvas screen: %d x %d\n", gif->SWidth, gif->SHeight); - } - // Fix some broken GIF global headers that report - // 0 x 0 screen dimension. - if (gif->SWidth == 0 || gif->SHeight == 0) { - image_desc->Left = 0; - image_desc->Top = 0; - gif->SWidth = image_desc->Width; - gif->SHeight = image_desc->Height; - if (gif->SWidth <= 0 || gif->SHeight <= 0) { - goto End; - } - if (verbose) { - printf("Fixed canvas screen dimension to: %d x %d\n", - gif->SWidth, gif->SHeight); - } - } - // Allocate current buffer. - frame.width = gif->SWidth; - frame.height = gif->SHeight; - frame.use_argb = 1; - if (!WebPPictureAlloc(&frame)) goto End; - GIFClearPic(&frame, NULL); - if (!(WebPPictureCopy(&frame, &curr_canvas) && - WebPPictureCopy(&frame, &prev_canvas))) { - fprintf(stderr, "Error allocating canvas.\n"); - goto End; - } - - // Background color. - GIFGetBackgroundColor(gif->SColorMap, gif->SBackGroundColor, - transparent_index, - &enc_options.anim_params.bgcolor); - - // Initialize encoder. - enc = WebPAnimEncoderNew(curr_canvas.width, curr_canvas.height, - &enc_options); - if (enc == NULL) { - fprintf(stderr, - "Error! Could not create encoder object. Possibly due to " - "a memory error.\n"); - goto End; - } - } - - // Some even more broken GIF can have sub-rect with zero width/height. - if (image_desc->Width == 0 || image_desc->Height == 0) { - image_desc->Width = gif->SWidth; - image_desc->Height = gif->SHeight; - } - - if (!GIFReadFrame(gif, transparent_index, &gif_rect, &frame)) { - goto End; - } - // Blend frame rectangle with previous canvas to compose full canvas. - // Note that 'curr_canvas' is same as 'prev_canvas' at this point. - GIFBlendFrames(&frame, &gif_rect, &curr_canvas); - - if (!WebPAnimEncoderAdd(enc, &curr_canvas, frame_timestamp, &config)) { - fprintf(stderr, "Error while adding frame #%d: %s\n", frame_number, - WebPAnimEncoderGetError(enc)); - goto End; - } else { - ++frame_number; - } - - // Update canvases. - GIFDisposeFrame(orig_dispose, &gif_rect, &prev_canvas, &curr_canvas); - GIFCopyPixels(&curr_canvas, &prev_canvas); - - // Force frames with a small or no duration to 100ms to be consistent - // with web browsers and other transcoding tools. This also avoids - // incorrect durations between frames when padding frames are - // discarded. - if (frame_duration <= 10) { - frame_duration = 100; - } - - // Update timestamp (for next frame). - frame_timestamp += frame_duration; - - // In GIF, graphic control extensions are optional for a frame, so we - // may not get one before reading the next frame. To handle this case, - // we reset frame properties to reasonable defaults for the next frame. - orig_dispose = GIF_DISPOSE_NONE; - frame_duration = 0; - transparent_index = GIF_INDEX_INVALID; - break; - } - case EXTENSION_RECORD_TYPE: { - int extension; - GifByteType* data = NULL; - if (DGifGetExtension(gif, &extension, &data) == GIF_ERROR) { - goto End; - } - if (data == NULL) continue; - - switch (extension) { - case COMMENT_EXT_FUNC_CODE: { - break; // Do nothing for now. - } - case GRAPHICS_EXT_FUNC_CODE: { - if (!GIFReadGraphicsExtension(data, &frame_duration, &orig_dispose, - &transparent_index)) { - goto End; - } - break; - } - case PLAINTEXT_EXT_FUNC_CODE: { - break; - } - case APPLICATION_EXT_FUNC_CODE: { - if (data[0] != 11) break; // Chunk is too short - if (!memcmp(data + 1, "NETSCAPE2.0", 11) || - !memcmp(data + 1, "ANIMEXTS1.0", 11)) { - if (!GIFReadLoopCount(gif, &data, &loop_count)) { - goto End; - } - if (verbose) { - fprintf(stderr, "Loop count: %d\n", loop_count); - } - stored_loop_count = loop_compatibility ? (loop_count != 0) : 1; - } else { // An extension containing metadata. - // We only store the first encountered chunk of each type, and - // only if requested by the user. - const int is_xmp = (keep_metadata & METADATA_XMP) && - !stored_xmp && - !memcmp(data + 1, "XMP DataXMP", 11); - const int is_icc = (keep_metadata & METADATA_ICC) && - !stored_icc && - !memcmp(data + 1, "ICCRGBG1012", 11); - if (is_xmp || is_icc) { - if (!GIFReadMetadata(gif, &data, - is_xmp ? &xmp_data : &icc_data)) { - goto End; - } - if (is_icc) { - stored_icc = 1; - } else if (is_xmp) { - stored_xmp = 1; - } - } - } - break; - } - default: { - break; // skip - } - } - while (data != NULL) { - if (DGifGetExtensionNext(gif, &data) == GIF_ERROR) goto End; - } - break; - } - case TERMINATE_RECORD_TYPE: { - done = 1; - break; - } - default: { - if (verbose) { - fprintf(stderr, "Skipping over unknown record type %d\n", type); - } - break; - } - } - } while (!done); - - // Last NULL frame. - if (!WebPAnimEncoderAdd(enc, NULL, frame_timestamp, NULL)) { - fprintf(stderr, "Error flushing WebP muxer.\n"); - fprintf(stderr, "%s\n", WebPAnimEncoderGetError(enc)); - } - - if (!WebPAnimEncoderAssemble(enc, &webp_data)) { - fprintf(stderr, "%s\n", WebPAnimEncoderGetError(enc)); - goto End; - } - // If there's only one frame, we don't need to handle loop count. - if (frame_number == 1) { - loop_count = 0; - } else if (!loop_compatibility) { - if (!stored_loop_count) { - // if no loop-count element is seen, the default is '1' (loop-once) - // and we need to signal it explicitly in WebP. Note however that - // in case there's a single frame, we still don't need to store it. - if (frame_number > 1) { - stored_loop_count = 1; - loop_count = 1; - } - } else if (loop_count > 0 && loop_count < 65535) { - // adapt GIF's semantic to WebP's (except in the infinite-loop case) - loop_count += 1; - } - } - // loop_count of 0 is the default (infinite), so no need to signal it - if (loop_count == 0) stored_loop_count = 0; - - if (stored_loop_count || stored_icc || stored_xmp) { - // Re-mux to add loop count and/or metadata as needed. - mux = WebPMuxCreate(&webp_data, 1); - if (mux == NULL) { - fprintf(stderr, "ERROR: Could not re-mux to add loop count/metadata.\n"); - goto End; - } - WebPDataClear(&webp_data); - - if (stored_loop_count) { // Update loop count. - WebPMuxAnimParams new_params; - err = WebPMuxGetAnimationParams(mux, &new_params); - if (err != WEBP_MUX_OK) { - fprintf(stderr, "ERROR (%s): Could not fetch loop count.\n", - ErrorString(err)); - goto End; - } - new_params.loop_count = loop_count; - err = WebPMuxSetAnimationParams(mux, &new_params); - if (err != WEBP_MUX_OK) { - fprintf(stderr, "ERROR (%s): Could not update loop count.\n", - ErrorString(err)); - goto End; - } - } - - if (stored_icc) { // Add ICCP chunk. - err = WebPMuxSetChunk(mux, "ICCP", &icc_data, 1); - if (verbose) { - fprintf(stderr, "ICC size: %d\n", (int)icc_data.size); - } - if (err != WEBP_MUX_OK) { - fprintf(stderr, "ERROR (%s): Could not set ICC chunk.\n", - ErrorString(err)); - goto End; - } - } - - if (stored_xmp) { // Add XMP chunk. - err = WebPMuxSetChunk(mux, "XMP ", &xmp_data, 1); - if (verbose) { - fprintf(stderr, "XMP size: %d\n", (int)xmp_data.size); - } - if (err != WEBP_MUX_OK) { - fprintf(stderr, "ERROR (%s): Could not set XMP chunk.\n", - ErrorString(err)); - goto End; - } - } - - err = WebPMuxAssemble(mux, &webp_data); - if (err != WEBP_MUX_OK) { - fprintf(stderr, "ERROR (%s): Could not assemble when re-muxing to add " - "loop count/metadata.\n", ErrorString(err)); - goto End; - } - } - - if (out_file != NULL) { - if (!ImgIoUtilWriteFile((const char*)out_file, webp_data.bytes, - webp_data.size)) { - WFPRINTF(stderr, "Error writing output file: %s\n", out_file); - goto End; - } - if (!quiet) { - if (!WSTRCMP(out_file, "-")) { - fprintf(stderr, "Saved %d bytes to STDIO\n", - (int)webp_data.size); - } else { - WFPRINTF(stderr, "Saved output file (%d bytes): %s\n", - (int)webp_data.size, out_file); - } - } - } else { - if (!quiet) { - fprintf(stderr, "Nothing written; use -o flag to save the result " - "(%d bytes).\n", (int)webp_data.size); - } - } - - // All OK. - ok = 1; - gif_error = GIF_OK; - - End: - WebPDataClear(&icc_data); - WebPDataClear(&xmp_data); - WebPMuxDelete(mux); - WebPDataClear(&webp_data); - WebPPictureFree(&frame); - WebPPictureFree(&curr_canvas); - WebPPictureFree(&prev_canvas); - WebPAnimEncoderDelete(enc); - - if (gif_error != GIF_OK) { - GIFDisplayError(gif, gif_error); - } - if (gif != NULL) { -#if LOCAL_GIF_PREREQ(5,1) - DGifCloseFile(gif, &gif_error); -#else - DGifCloseFile(gif); -#endif - } - - FREE_WARGV_AND_RETURN(!ok); -} - -#else // !WEBP_HAVE_GIF - -int main(int argc, const char* argv[]) { - fprintf(stderr, "GIF support not enabled in %s.\n", argv[0]); - (void)argc; - return 0; -} - -#endif - -//------------------------------------------------------------------------------ diff --git a/libwebp/examples/gifdec.c b/libwebp/examples/gifdec.c deleted file mode 100644 index 9b9a6947..00000000 --- a/libwebp/examples/gifdec.c +++ /dev/null @@ -1,416 +0,0 @@ -// Copyright 2012 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// GIF decode. - -#include "./gifdec.h" - -#include - -#ifdef WEBP_HAVE_GIF -#include -#include -#include - -#include "webp/encode.h" -#include "webp/mux_types.h" - -#define GIF_TRANSPARENT_COLOR 0x00000000u -#define GIF_WHITE_COLOR 0xffffffffu -#define GIF_TRANSPARENT_MASK 0x01 -#define GIF_DISPOSE_MASK 0x07 -#define GIF_DISPOSE_SHIFT 2 - -// from utils/utils.h -#ifdef __cplusplus -extern "C" { -#endif -extern void WebPCopyPlane(const uint8_t* src, int src_stride, - uint8_t* dst, int dst_stride, - int width, int height); -extern void WebPCopyPixels(const WebPPicture* const src, - WebPPicture* const dst); -#ifdef __cplusplus -} -#endif - -void GIFGetBackgroundColor(const ColorMapObject* const color_map, - int bgcolor_index, int transparent_index, - uint32_t* const bgcolor) { - if (transparent_index != GIF_INDEX_INVALID && - bgcolor_index == transparent_index) { - *bgcolor = GIF_TRANSPARENT_COLOR; // Special case. - } else if (color_map == NULL || color_map->Colors == NULL - || bgcolor_index >= color_map->ColorCount) { - *bgcolor = GIF_WHITE_COLOR; - fprintf(stderr, - "GIF decode warning: invalid background color index. Assuming " - "white background.\n"); - } else { - const GifColorType color = color_map->Colors[bgcolor_index]; - *bgcolor = (0xffu << 24) - | (color.Red << 16) - | (color.Green << 8) - | (color.Blue << 0); - } -} - -int GIFReadGraphicsExtension(const GifByteType* const buf, int* const duration, - GIFDisposeMethod* const dispose, - int* const transparent_index) { - const int flags = buf[1]; - const int dispose_raw = (flags >> GIF_DISPOSE_SHIFT) & GIF_DISPOSE_MASK; - const int duration_raw = buf[2] | (buf[3] << 8); // In 10 ms units. - if (buf[0] != 4) return 0; - *duration = duration_raw * 10; // Duration is in 1 ms units. - switch (dispose_raw) { - case 3: - *dispose = GIF_DISPOSE_RESTORE_PREVIOUS; - break; - case 2: - *dispose = GIF_DISPOSE_BACKGROUND; - break; - case 1: - case 0: - default: - *dispose = GIF_DISPOSE_NONE; - break; - } - *transparent_index = - (flags & GIF_TRANSPARENT_MASK) ? buf[4] : GIF_INDEX_INVALID; - return 1; -} - -static int Remap(const GifFileType* const gif, const uint8_t* const src, - int len, int transparent_index, uint32_t* dst) { - int i; - const GifColorType* colors; - const ColorMapObject* const cmap = - gif->Image.ColorMap ? gif->Image.ColorMap : gif->SColorMap; - if (cmap == NULL) return 1; - if (cmap->Colors == NULL || cmap->ColorCount <= 0) return 0; - colors = cmap->Colors; - - for (i = 0; i < len; ++i) { - if (src[i] == transparent_index) { - dst[i] = GIF_TRANSPARENT_COLOR; - } else if (src[i] < cmap->ColorCount) { - const GifColorType c = colors[src[i]]; - dst[i] = c.Blue | (c.Green << 8) | (c.Red << 16) | (0xffu << 24); - } else { - return 0; - } - } - return 1; -} - -int GIFReadFrame(GifFileType* const gif, int transparent_index, - GIFFrameRect* const gif_rect, WebPPicture* const picture) { - WebPPicture sub_image; - const GifImageDesc* const image_desc = &gif->Image; - uint32_t* dst = NULL; - uint8_t* tmp = NULL; - const GIFFrameRect rect = { - image_desc->Left, image_desc->Top, image_desc->Width, image_desc->Height - }; - const uint64_t memory_needed = 4 * rect.width * (uint64_t)rect.height; - int ok = 0; - *gif_rect = rect; - - if (memory_needed != (size_t)memory_needed || memory_needed > (4ULL << 32)) { - fprintf(stderr, "Image is too large (%d x %d).", rect.width, rect.height); - return 0; - } - - // Use a view for the sub-picture: - if (!WebPPictureView(picture, rect.x_offset, rect.y_offset, - rect.width, rect.height, &sub_image)) { - fprintf(stderr, "Sub-image %dx%d at position %d,%d is invalid!\n", - rect.width, rect.height, rect.x_offset, rect.y_offset); - return 0; - } - dst = sub_image.argb; - - tmp = (uint8_t*)WebPMalloc(rect.width * sizeof(*tmp)); - if (tmp == NULL) goto End; - - if (image_desc->Interlace) { // Interlaced image. - // We need 4 passes, with the following offsets and jumps. - const int interlace_offsets[] = { 0, 4, 2, 1 }; - const int interlace_jumps[] = { 8, 8, 4, 2 }; - int pass; - for (pass = 0; pass < 4; ++pass) { - const size_t stride = (size_t)sub_image.argb_stride; - int y = interlace_offsets[pass]; - uint32_t* row = dst + y * stride; - const size_t jump = interlace_jumps[pass] * stride; - for (; y < rect.height; y += interlace_jumps[pass], row += jump) { - if (DGifGetLine(gif, tmp, rect.width) == GIF_ERROR) goto End; - if (!Remap(gif, tmp, rect.width, transparent_index, row)) goto End; - } - } - } else { // Non-interlaced image. - int y; - uint32_t* ptr = dst; - for (y = 0; y < rect.height; ++y, ptr += sub_image.argb_stride) { - if (DGifGetLine(gif, tmp, rect.width) == GIF_ERROR) goto End; - if (!Remap(gif, tmp, rect.width, transparent_index, ptr)) goto End; - } - } - ok = 1; - - End: - if (!ok) picture->error_code = sub_image.error_code; - WebPPictureFree(&sub_image); - WebPFree(tmp); - return ok; -} - -int GIFReadLoopCount(GifFileType* const gif, GifByteType** const buf, - int* const loop_count) { - assert(!memcmp(*buf + 1, "NETSCAPE2.0", 11) || - !memcmp(*buf + 1, "ANIMEXTS1.0", 11)); - if (DGifGetExtensionNext(gif, buf) == GIF_ERROR) { - return 0; - } - if (*buf == NULL) { - return 0; // Loop count sub-block missing. - } - if ((*buf)[0] < 3 || (*buf)[1] != 1) { - return 0; // wrong size/marker - } - *loop_count = (*buf)[2] | ((*buf)[3] << 8); - return 1; -} - -int GIFReadMetadata(GifFileType* const gif, GifByteType** const buf, - WebPData* const metadata) { - const int is_xmp = !memcmp(*buf + 1, "XMP DataXMP", 11); - const int is_icc = !memcmp(*buf + 1, "ICCRGBG1012", 11); - assert(is_xmp || is_icc); - (void)is_icc; // silence unused warning. - // Construct metadata from sub-blocks. - // Usual case (including ICC profile): In each sub-block, the - // first byte specifies its size in bytes (0 to 255) and the - // rest of the bytes contain the data. - // Special case for XMP data: In each sub-block, the first byte - // is also part of the XMP payload. XMP in GIF also has a 257 - // byte padding data. See the XMP specification for details. - while (1) { - WebPData subblock; - const uint8_t* tmp; - if (DGifGetExtensionNext(gif, buf) == GIF_ERROR) { - return 0; - } - if (*buf == NULL) break; // Finished. - subblock.size = is_xmp ? (*buf)[0] + 1 : (*buf)[0]; - assert(subblock.size > 0); - subblock.bytes = is_xmp ? *buf : *buf + 1; - // Note: We store returned value in 'tmp' first, to avoid - // leaking old memory in metadata->bytes on error. - tmp = (uint8_t*)realloc((void*)metadata->bytes, - metadata->size + subblock.size); - if (tmp == NULL) { - return 0; - } - memcpy((void*)(tmp + metadata->size), - subblock.bytes, subblock.size); - metadata->bytes = tmp; - metadata->size += subblock.size; - } - if (is_xmp) { - // XMP padding data is 0x01, 0xff, 0xfe ... 0x01, 0x00. - const size_t xmp_pading_size = 257; - if (metadata->size > xmp_pading_size) { - metadata->size -= xmp_pading_size; - } - } - return 1; -} - -static void ClearRectangle(WebPPicture* const picture, - int left, int top, int width, int height) { - int i, j; - const size_t stride = picture->argb_stride; - uint32_t* dst = picture->argb + top * stride + left; - for (j = 0; j < height; ++j, dst += stride) { - for (i = 0; i < width; ++i) dst[i] = GIF_TRANSPARENT_COLOR; - } -} - -void GIFClearPic(WebPPicture* const pic, const GIFFrameRect* const rect) { - if (rect != NULL) { - ClearRectangle(pic, rect->x_offset, rect->y_offset, - rect->width, rect->height); - } else { - ClearRectangle(pic, 0, 0, pic->width, pic->height); - } -} - -void GIFCopyPixels(const WebPPicture* const src, WebPPicture* const dst) { - WebPCopyPixels(src, dst); -} - -void GIFDisposeFrame(GIFDisposeMethod dispose, const GIFFrameRect* const rect, - const WebPPicture* const prev_canvas, - WebPPicture* const curr_canvas) { - assert(rect != NULL); - if (dispose == GIF_DISPOSE_BACKGROUND) { - GIFClearPic(curr_canvas, rect); - } else if (dispose == GIF_DISPOSE_RESTORE_PREVIOUS) { - const size_t src_stride = prev_canvas->argb_stride; - const uint32_t* const src = prev_canvas->argb + rect->x_offset - + rect->y_offset * src_stride; - const size_t dst_stride = curr_canvas->argb_stride; - uint32_t* const dst = curr_canvas->argb + rect->x_offset - + rect->y_offset * dst_stride; - assert(prev_canvas != NULL); - WebPCopyPlane((uint8_t*)src, (int)(4 * src_stride), - (uint8_t*)dst, (int)(4 * dst_stride), - 4 * rect->width, rect->height); - } -} - -void GIFBlendFrames(const WebPPicture* const src, - const GIFFrameRect* const rect, WebPPicture* const dst) { - int i, j; - const size_t src_stride = src->argb_stride; - const size_t dst_stride = dst->argb_stride; - assert(src->width == dst->width && src->height == dst->height); - for (j = rect->y_offset; j < rect->y_offset + rect->height; ++j) { - for (i = rect->x_offset; i < rect->x_offset + rect->width; ++i) { - const uint32_t src_pixel = src->argb[j * src_stride + i]; - const int src_alpha = src_pixel >> 24; - if (src_alpha != 0) { - dst->argb[j * dst_stride + i] = src_pixel; - } - } - } -} - -void GIFDisplayError(const GifFileType* const gif, int gif_error) { - // libgif 4.2.0 has retired PrintGifError() and added GifErrorString(). -#if LOCAL_GIF_PREREQ(4,2) -#if LOCAL_GIF_PREREQ(5,0) - // Static string actually, hence the const char* cast. - const char* error_str = (const char*)GifErrorString( - (gif == NULL) ? gif_error : gif->Error); -#else - const char* error_str = (const char*)GifErrorString(); - (void)gif; -#endif - if (error_str == NULL) error_str = "Unknown error"; - fprintf(stderr, "GIFLib Error %d: %s\n", gif_error, error_str); -#else - (void)gif; - fprintf(stderr, "GIFLib Error %d: ", gif_error); - PrintGifError(); - fprintf(stderr, "\n"); -#endif -} - -#else // !WEBP_HAVE_GIF - -static void ErrorGIFNotAvailable(void) { - fprintf(stderr, "GIF support not compiled. Please install the libgif-dev " - "package before building.\n"); -} - -void GIFGetBackgroundColor(const struct ColorMapObject* const color_map, - int bgcolor_index, int transparent_index, - uint32_t* const bgcolor) { - (void)color_map; - (void)bgcolor_index; - (void)transparent_index; - (void)bgcolor; - ErrorGIFNotAvailable(); -} - -int GIFReadGraphicsExtension(const GifByteType* const data, int* const duration, - GIFDisposeMethod* const dispose, - int* const transparent_index) { - (void)data; - (void)duration; - (void)dispose; - (void)transparent_index; - ErrorGIFNotAvailable(); - return 0; -} - -int GIFReadFrame(struct GifFileType* const gif, int transparent_index, - GIFFrameRect* const gif_rect, - struct WebPPicture* const picture) { - (void)gif; - (void)transparent_index; - (void)gif_rect; - (void)picture; - ErrorGIFNotAvailable(); - return 0; -} - -int GIFReadLoopCount(struct GifFileType* const gif, GifByteType** const buf, - int* const loop_count) { - (void)gif; - (void)buf; - (void)loop_count; - ErrorGIFNotAvailable(); - return 0; -} - -int GIFReadMetadata(struct GifFileType* const gif, GifByteType** const buf, - struct WebPData* const metadata) { - (void)gif; - (void)buf; - (void)metadata; - ErrorGIFNotAvailable(); - return 0; -} - -void GIFDisposeFrame(GIFDisposeMethod dispose, const GIFFrameRect* const rect, - const struct WebPPicture* const prev_canvas, - struct WebPPicture* const curr_canvas) { - (void)dispose; - (void)rect; - (void)prev_canvas; - (void)curr_canvas; - ErrorGIFNotAvailable(); -} - -void GIFBlendFrames(const struct WebPPicture* const src, - const GIFFrameRect* const rect, - struct WebPPicture* const dst) { - (void)src; - (void)rect; - (void)dst; - ErrorGIFNotAvailable(); -} - -void GIFDisplayError(const struct GifFileType* const gif, int gif_error) { - (void)gif; - (void)gif_error; - ErrorGIFNotAvailable(); -} - -void GIFClearPic(struct WebPPicture* const pic, - const GIFFrameRect* const rect) { - (void)pic; - (void)rect; - ErrorGIFNotAvailable(); -} - -void GIFCopyPixels(const struct WebPPicture* const src, - struct WebPPicture* const dst) { - (void)src; - (void)dst; - ErrorGIFNotAvailable(); -} - -#endif // WEBP_HAVE_GIF - -// ----------------------------------------------------------------------------- diff --git a/libwebp/examples/gifdec.h b/libwebp/examples/gifdec.h deleted file mode 100644 index 5eba9dd3..00000000 --- a/libwebp/examples/gifdec.h +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2014 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// GIF decode. - -#ifndef WEBP_EXAMPLES_GIFDEC_H_ -#define WEBP_EXAMPLES_GIFDEC_H_ - -#include -#include "webp/types.h" - -#ifdef HAVE_CONFIG_H -#include "webp/config.h" -#endif - -#ifdef WEBP_HAVE_GIF -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -// GIFLIB_MAJOR is only defined in libgif >= 4.2.0. -#if defined(GIFLIB_MAJOR) && defined(GIFLIB_MINOR) -# define LOCAL_GIF_VERSION ((GIFLIB_MAJOR << 8) | GIFLIB_MINOR) -# define LOCAL_GIF_PREREQ(maj, min) \ - (LOCAL_GIF_VERSION >= (((maj) << 8) | (min))) -#else -# define LOCAL_GIF_VERSION 0 -# define LOCAL_GIF_PREREQ(maj, min) 0 -#endif - -#define GIF_INDEX_INVALID (-1) - -typedef enum GIFDisposeMethod { - GIF_DISPOSE_NONE, - GIF_DISPOSE_BACKGROUND, - GIF_DISPOSE_RESTORE_PREVIOUS -} GIFDisposeMethod; - -typedef struct { - int x_offset, y_offset, width, height; -} GIFFrameRect; - -struct WebPData; -struct WebPPicture; - -#ifndef WEBP_HAVE_GIF -struct ColorMapObject; -struct GifFileType; -typedef unsigned char GifByteType; -#endif - -// Given the index of background color and transparent color, returns the -// corresponding background color (in BGRA format) in 'bgcolor'. -void GIFGetBackgroundColor(const struct ColorMapObject* const color_map, - int bgcolor_index, int transparent_index, - uint32_t* const bgcolor); - -// Parses the given graphics extension data to get frame duration (in 1ms -// units), dispose method and transparent color index. -// Returns true on success. -int GIFReadGraphicsExtension(const GifByteType* const buf, int* const duration, - GIFDisposeMethod* const dispose, - int* const transparent_index); - -// Reads the next GIF frame from 'gif' into 'picture'. Also, returns the GIF -// frame dimensions and offsets in 'rect'. -// Returns true on success. -int GIFReadFrame(struct GifFileType* const gif, int transparent_index, - GIFFrameRect* const gif_rect, - struct WebPPicture* const picture); - -// Parses loop count from the given Netscape extension data. -int GIFReadLoopCount(struct GifFileType* const gif, GifByteType** const buf, - int* const loop_count); - -// Parses the given ICC or XMP extension data and stores it into 'metadata'. -// Returns true on success. -int GIFReadMetadata(struct GifFileType* const gif, GifByteType** const buf, - struct WebPData* const metadata); - -// Dispose the pixels within 'rect' of 'curr_canvas' based on 'dispose' method -// and 'prev_canvas'. -void GIFDisposeFrame(GIFDisposeMethod dispose, const GIFFrameRect* const rect, - const struct WebPPicture* const prev_canvas, - struct WebPPicture* const curr_canvas); - -// Given 'src' picture and its frame rectangle 'rect', blend it into 'dst'. -void GIFBlendFrames(const struct WebPPicture* const src, - const GIFFrameRect* const rect, - struct WebPPicture* const dst); - -// Prints an error string based on 'gif_error'. -void GIFDisplayError(const struct GifFileType* const gif, int gif_error); - -// In the given 'pic', clear the pixels in 'rect' to transparent color. -void GIFClearPic(struct WebPPicture* const pic, const GIFFrameRect* const rect); - -// Copy pixels from 'src' to 'dst' honoring strides. 'src' and 'dst' are assumed -// to be already allocated. -void GIFCopyPixels(const struct WebPPicture* const src, - struct WebPPicture* const dst); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // WEBP_EXAMPLES_GIFDEC_H_ diff --git a/libwebp/examples/img2webp.c b/libwebp/examples/img2webp.c deleted file mode 100644 index 3735030c..00000000 --- a/libwebp/examples/img2webp.c +++ /dev/null @@ -1,339 +0,0 @@ -// Copyright 2016 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// generate an animated WebP out of a sequence of images -// (PNG, JPEG, ...) -// -// Example usage: -// img2webp -o out.webp -q 40 -mixed -duration 40 input??.png -// -// Author: skal@google.com (Pascal Massimino) - -#include -#include -#include - -#ifdef HAVE_CONFIG_H -#include "webp/config.h" -#endif - -#include "../examples/example_util.h" -#include "../imageio/image_dec.h" -#include "../imageio/imageio_util.h" -#include "./stopwatch.h" -#include "./unicode.h" -#include "sharpyuv/sharpyuv.h" -#include "webp/encode.h" -#include "webp/mux.h" - -//------------------------------------------------------------------------------ - -static void Help(void) { - printf("Usage:\n\n"); - printf(" img2webp [file_options] [[frame_options] frame_file]..."); - printf(" [-o webp_file]\n\n"); - - printf("File-level options (only used at the start of compression):\n"); - printf(" -min_size ............ minimize size\n"); - printf(" -kmax .......... maximum number of frame between key-frames\n" - " (0=only keyframes)\n"); - printf(" -kmin .......... minimum number of frame between key-frames\n" - " (0=disable key-frames altogether)\n"); - printf(" -mixed ............... use mixed lossy/lossless automatic mode\n"); - printf(" -near_lossless . use near-lossless image preprocessing\n" - " (0..100=off), default=100\n"); - printf(" -sharp_yuv ........... use sharper (and slower) RGB->YUV " - "conversion\n " - "(lossy only)\n"); - printf(" -loop .......... loop count (default: 0, = infinite loop)\n"); - printf(" -v ................... verbose mode\n"); - printf(" -h ................... this help\n"); - printf(" -version ............. print version number and exit\n"); - printf("\n"); - - printf("Per-frame options (only used for subsequent images input):\n"); - printf(" -d ............. frame duration in ms (default: 100)\n"); - printf(" -lossless ........... use lossless mode (default)\n"); - printf(" -lossy ... ........... use lossy mode\n"); - printf(" -q ........... quality\n"); - printf(" -m ............. method to use\n"); - - printf("\n"); - printf("example: img2webp -loop 2 in0.png -lossy in1.jpg\n" - " -d 80 in2.tiff -o out.webp\n"); - printf("\nNote: if a single file name is passed as the argument, the " - "arguments will be\n"); - printf("tokenized from this file. The file name must not start with " - "the character '-'.\n"); - printf("\nSupported input formats:\n %s\n", - WebPGetEnabledInputFileFormats()); -} - -//------------------------------------------------------------------------------ - -static int ReadImage(const char filename[], WebPPicture* const pic) { - const uint8_t* data = NULL; - size_t data_size = 0; - WebPImageReader reader; - int ok; -#ifdef HAVE_WINCODEC_H - // Try to decode the file using WIC falling back to the other readers for - // e.g., WebP. - ok = ReadPictureWithWIC(filename, pic, 1, NULL); - if (ok) return 1; -#endif - if (!ImgIoUtilReadFile(filename, &data, &data_size)) return 0; - reader = WebPGuessImageReader(data, data_size); - ok = reader(data, data_size, pic, 1, NULL); - WebPFree((void*)data); - return ok; -} - -static int SetLoopCount(int loop_count, WebPData* const webp_data) { - int ok = 1; - WebPMuxError err; - uint32_t features; - WebPMuxAnimParams new_params; - WebPMux* const mux = WebPMuxCreate(webp_data, 1); - if (mux == NULL) return 0; - - err = WebPMuxGetFeatures(mux, &features); - ok = (err == WEBP_MUX_OK); - if (!ok || !(features & ANIMATION_FLAG)) goto End; - - err = WebPMuxGetAnimationParams(mux, &new_params); - ok = (err == WEBP_MUX_OK); - if (ok) { - new_params.loop_count = loop_count; - err = WebPMuxSetAnimationParams(mux, &new_params); - ok = (err == WEBP_MUX_OK); - } - if (ok) { - WebPDataClear(webp_data); - err = WebPMuxAssemble(mux, webp_data); - ok = (err == WEBP_MUX_OK); - } - - End: - WebPMuxDelete(mux); - if (!ok) { - fprintf(stderr, "Error during loop-count setting\n"); - } - return ok; -} - -//------------------------------------------------------------------------------ - -int main(int argc, const char* argv[]) { - const char* output = NULL; - WebPAnimEncoder* enc = NULL; - int verbose = 0; - int pic_num = 0; - int duration = 100; - int timestamp_ms = 0; - int loop_count = 0; - int width = 0, height = 0; - WebPAnimEncoderOptions anim_config; - WebPConfig config; - WebPPicture pic; - WebPData webp_data; - int c; - int have_input = 0; - CommandLineArguments cmd_args; - int ok; - - INIT_WARGV(argc, argv); - - ok = ExUtilInitCommandLineArguments(argc - 1, argv + 1, &cmd_args); - if (!ok) FREE_WARGV_AND_RETURN(1); - - argc = cmd_args.argc_; - argv = cmd_args.argv_; - - WebPDataInit(&webp_data); - if (!WebPAnimEncoderOptionsInit(&anim_config) || - !WebPConfigInit(&config) || - !WebPPictureInit(&pic)) { - fprintf(stderr, "Library version mismatch!\n"); - ok = 0; - goto End; - } - - // 1st pass of option parsing - for (c = 0; ok && c < argc; ++c) { - if (argv[c][0] == '-') { - int parse_error = 0; - if (!strcmp(argv[c], "-o") && c + 1 < argc) { - argv[c] = NULL; - output = (const char*)GET_WARGV_SHIFTED(argv, ++c); - } else if (!strcmp(argv[c], "-kmin") && c + 1 < argc) { - argv[c] = NULL; - anim_config.kmin = ExUtilGetInt(argv[++c], 0, &parse_error); - } else if (!strcmp(argv[c], "-kmax") && c + 1 < argc) { - argv[c] = NULL; - anim_config.kmax = ExUtilGetInt(argv[++c], 0, &parse_error); - } else if (!strcmp(argv[c], "-loop") && c + 1 < argc) { - argv[c] = NULL; - loop_count = ExUtilGetInt(argv[++c], 0, &parse_error); - if (loop_count < 0) { - fprintf(stderr, "Invalid non-positive loop-count (%d)\n", loop_count); - parse_error = 1; - } - } else if (!strcmp(argv[c], "-min_size")) { - anim_config.minimize_size = 1; - } else if (!strcmp(argv[c], "-mixed")) { - anim_config.allow_mixed = 1; - config.lossless = 0; - } else if (!strcmp(argv[c], "-near_lossless") && c + 1 < argc) { - argv[c] = NULL; - config.near_lossless = ExUtilGetInt(argv[++c], 0, &parse_error); - } else if (!strcmp(argv[c], "-sharp_yuv")) { - config.use_sharp_yuv = 1; - } else if (!strcmp(argv[c], "-v")) { - verbose = 1; - } else if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) { - Help(); - FREE_WARGV_AND_RETURN(0); - } else if (!strcmp(argv[c], "-version")) { - const int enc_version = WebPGetEncoderVersion(); - const int mux_version = WebPGetMuxVersion(); - const int sharpyuv_version = SharpYuvGetVersion(); - printf("WebP Encoder version: %d.%d.%d\nWebP Mux version: %d.%d.%d\n", - (enc_version >> 16) & 0xff, (enc_version >> 8) & 0xff, - enc_version & 0xff, (mux_version >> 16) & 0xff, - (mux_version >> 8) & 0xff, mux_version & 0xff); - printf("libsharpyuv: %d.%d.%d\n", (sharpyuv_version >> 24) & 0xff, - (sharpyuv_version >> 16) & 0xffff, sharpyuv_version & 0xff); - goto End; - } else { - continue; - } - ok = !parse_error; - if (!ok) goto End; - argv[c] = NULL; // mark option as 'parsed' during 1st pass - } else { - have_input |= 1; - } - } - if (!have_input) { - fprintf(stderr, "No input file(s) for generating animation!\n"); - goto End; - } - - // image-reading pass - pic_num = 0; - config.lossless = 1; - for (c = 0; ok && c < argc; ++c) { - if (argv[c] == NULL) continue; - if (argv[c][0] == '-') { // parse local options - int parse_error = 0; - if (!strcmp(argv[c], "-lossy")) { - if (!anim_config.allow_mixed) config.lossless = 0; - } else if (!strcmp(argv[c], "-lossless")) { - if (!anim_config.allow_mixed) config.lossless = 1; - } else if (!strcmp(argv[c], "-q") && c + 1 < argc) { - config.quality = ExUtilGetFloat(argv[++c], &parse_error); - } else if (!strcmp(argv[c], "-m") && c + 1 < argc) { - config.method = ExUtilGetInt(argv[++c], 0, &parse_error); - } else if (!strcmp(argv[c], "-d") && c + 1 < argc) { - duration = ExUtilGetInt(argv[++c], 0, &parse_error); - if (duration <= 0) { - fprintf(stderr, "Invalid negative duration (%d)\n", duration); - parse_error = 1; - } - } else { - parse_error = 1; // shouldn't be here. - fprintf(stderr, "Unknown option [%s]\n", argv[c]); - } - ok = !parse_error; - if (!ok) goto End; - continue; - } - - if (ok) { - ok = WebPValidateConfig(&config); - if (!ok) { - fprintf(stderr, "Invalid configuration.\n"); - goto End; - } - } - - // read next input image - pic.use_argb = 1; - ok = ReadImage((const char*)GET_WARGV_SHIFTED(argv, c), &pic); - if (!ok) goto End; - - if (enc == NULL) { - width = pic.width; - height = pic.height; - enc = WebPAnimEncoderNew(width, height, &anim_config); - ok = (enc != NULL); - if (!ok) { - fprintf(stderr, "Could not create WebPAnimEncoder object.\n"); - } - } - - if (ok) { - ok = (width == pic.width && height == pic.height); - if (!ok) { - fprintf(stderr, "Frame #%d dimension mismatched! " - "Got %d x %d. Was expecting %d x %d.\n", - pic_num, pic.width, pic.height, width, height); - } - } - - if (ok) { - ok = WebPAnimEncoderAdd(enc, &pic, timestamp_ms, &config); - if (!ok) { - fprintf(stderr, "Error while adding frame #%d\n", pic_num); - } - } - WebPPictureFree(&pic); - if (!ok) goto End; - - if (verbose) { - WFPRINTF(stderr, "Added frame #%3d at time %4d (file: %s)\n", - pic_num, timestamp_ms, GET_WARGV_SHIFTED(argv, c)); - } - timestamp_ms += duration; - ++pic_num; - } - - // add a last fake frame to signal the last duration - ok = ok && WebPAnimEncoderAdd(enc, NULL, timestamp_ms, NULL); - ok = ok && WebPAnimEncoderAssemble(enc, &webp_data); - if (!ok) { - fprintf(stderr, "Error during final animation assembly.\n"); - } - - End: - // free resources - WebPAnimEncoderDelete(enc); - - if (ok && loop_count > 0) { // Re-mux to add loop count. - ok = SetLoopCount(loop_count, &webp_data); - } - - if (ok) { - if (output != NULL) { - ok = ImgIoUtilWriteFile(output, webp_data.bytes, webp_data.size); - if (ok) WFPRINTF(stderr, "output file: %s ", (const W_CHAR*)output); - } else { - fprintf(stderr, "[no output file specified] "); - } - } - - if (ok) { - fprintf(stderr, "[%d frames, %u bytes].\n", - pic_num, (unsigned int)webp_data.size); - } - WebPDataClear(&webp_data); - ExUtilDeleteCommandLineArguments(&cmd_args); - FREE_WARGV_AND_RETURN(ok ? 0 : 1); -} diff --git a/libwebp/examples/stopwatch.h b/libwebp/examples/stopwatch.h deleted file mode 100644 index f1b0faca..00000000 --- a/libwebp/examples/stopwatch.h +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Helper functions to measure elapsed time. -// -// Author: Mikolaj Zalewski (mikolajz@google.com) - -#ifndef WEBP_EXAMPLES_STOPWATCH_H_ -#define WEBP_EXAMPLES_STOPWATCH_H_ - -#include "webp/types.h" - -#if defined _WIN32 && !defined __GNUC__ -#include - -typedef LARGE_INTEGER Stopwatch; - -static WEBP_INLINE void StopwatchReset(Stopwatch* watch) { - QueryPerformanceCounter(watch); -} - -static WEBP_INLINE double StopwatchReadAndReset(Stopwatch* watch) { - const LARGE_INTEGER old_value = *watch; - LARGE_INTEGER freq; - if (!QueryPerformanceCounter(watch)) - return 0.0; - if (!QueryPerformanceFrequency(&freq)) - return 0.0; - if (freq.QuadPart == 0) - return 0.0; - return (watch->QuadPart - old_value.QuadPart) / (double)freq.QuadPart; -} - - -#else /* !_WIN32 */ -#include // memcpy -#include - -typedef struct timeval Stopwatch; - -static WEBP_INLINE void StopwatchReset(Stopwatch* watch) { - gettimeofday(watch, NULL); -} - -static WEBP_INLINE double StopwatchReadAndReset(Stopwatch* watch) { - struct timeval old_value; - double delta_sec, delta_usec; - memcpy(&old_value, watch, sizeof(old_value)); - gettimeofday(watch, NULL); - delta_sec = (double)watch->tv_sec - old_value.tv_sec; - delta_usec = (double)watch->tv_usec - old_value.tv_usec; - return delta_sec + delta_usec / 1000000.0; -} - -#endif /* _WIN32 */ - -#endif // WEBP_EXAMPLES_STOPWATCH_H_ diff --git a/libwebp/examples/test.webp b/libwebp/examples/test.webp deleted file mode 100644 index 3e4bca1d..00000000 Binary files a/libwebp/examples/test.webp and /dev/null differ diff --git a/libwebp/examples/test_ref.ppm b/libwebp/examples/test_ref.ppm deleted file mode 100644 index 97719f01..00000000 --- a/libwebp/examples/test_ref.ppm +++ /dev/null @@ -1,4 +0,0 @@ -P6 -128 128 -255 -܇Οm{dqhtlvs{yƽlz\jmzhqmwŸ˕ځrWd~\i~jqzyM[vXfVc}[deoipfjxz}}~{qoڽ՘fwM]wLZtMZsOXq_fjq~rvrsssvs}NjXkIZsL\vP^yN[tbisx~ˁ}}qq~{[mGWqLZtIWrFQmoxyzss½ٲ̉lmz{vxڏk~JXvLWvLTqFNkQXtlqڣﷷąţyyƈViIXvN\yHPpLSpHOleiۂٰyyŪSc{FVpIWtS^}MUtLSpHOllpjlywyikxjlysvׅxzTd}IWqIWrQ]{P\zOWwLTqFMjcfzil~x{y}z~]_o~kmzikxehw^artw~sviit̕}qIZrJXrIWrO[yJVtPXxT\{FNkV]zv}osX\pqvfkwfj{sxy}hkei}X]ktycewbboȱӷġƶ^oHXqM[vDQlP\xNZxIUsLTsMUtHPm]ekrSZsSWoW[pfj{qttxjm]arZ^lmq^bv[^sdh}fj{dhyilehy~~Ǫ׶TdzEUmM[tAOjWcMXwJSrS[zIQqJSr[c^fNWrLSoPTqINhW\simX]tae}V\oX^qU[m]bwW\s]bykqflV[pTWkqp̹N^tIZpIWqHVqQ_zJXvLWvNZxEPoLWvQZyV^{W_}U\yOVsQUsTWt{\azSWqPUoPUlOTiV[pmrTXrOTmmrx}_d{X\qz}z~{wwեZhN[tN[tO]xQ_zM[vLZtL\vJZwBQoP^{Q]{W_W]~W[{UXwQUs\_}hlTXrLOmIMkDGdDH_EI^lqTXr~TWtaeqv~qpг}O_yNZvNVsLWsQ]yLWsN\wN\wHXrIZsHWtSa~S^}[abehiWXxW[yVZwZ^xTWtPTrOSqNQoBGaINc{^c}[_yX\yQVpjo}wvrp}˄wM]wDQlLWsLTqS[xV^{O[wS^zLWsBPkLZtO]xUa}Zbls_cop^bUXv\azW\vGJiHLjMPmFJbIObX^qZ^vy~w{UZq[_ttytyvv~HXrHXrIWrIUqMUrQZwNVsQZwPXvNVsJVrS_yO\vU^y^eVZw^bsvy}UZs]byX]wPTqPTqMQkNSjPViLQdSWo~jp]bw[_trvUZhZ\kkm}̩ffsxxhvHVqHVqHVqGUpHTpOWtU]zLTqLTqOVsLSpS\wOXqV]wU\v]b{ptjokmz}kpX]wLPhNSjTWtOSpW\vLPhMQfPUjV[rae}U[mU[mkpX]r^bv^bvehybdseerkm}fixtwdrFToIWrESmFToMXtS^zU]zHPmLSpJQoU\y\csw[_w\ax^czdichchdf_bzSWoNSjX]r\ax\azOTmPUlae}QVmHMdLPjINhMQfdj}y~ejVZojmy{z}}{wHTpMXtO[wLWsNZvT_{P\xLTqIQoLSpOSq\_~ilmpSVkdh}W[p[^sUZoNShV[r_h~^fzwqxPWqPXockDJdGNjNUqFMiXawt}V[rSUmtwxz}{}DOkIUqMXtJVrMXtP\xS^zLWvHPpGNkELiNQodhě[^r{ilSVkQUjMQfGLaJSf_h{ltW_vT[t^eJSiGNhNUqLSoFMjFMiIPjrzV^tLPhOQlxzxwtsm{LWsJSpJSpNVsT\yZbXa~NVvGOqFLoGMmIPlQXrbj~͈fkim\axNSjJOfQVmLPeV[p^cxchFIfMTqHOlFOjNUqZa}FIfQUrMPmTWtejMQkMQkWZt}xz[\rbasfev]\oa_rлǤp~TazNVsLTsLTsNVvV^~V^~NVvEMlGMpNTwLSpFMi[cypx^cx_d{\axW\sTXpNSjNSj\avioZ^sdiFIfGNkIOpGOlSZvfk^c}}[_yPTqeiOTmNSlbd]_x]^t{zzy]Zm[Zlkj}¾ĬIVpW_}PXxMUwMUwPXzU]NVxGOqDLmNTwIOpBIfJQmLTjmvpxW\schZ^vMQiSWoOTkPUjaez\btioae}AEbLSpLSpGOlJQkW\sswtwX[vikJMjQToprMOh\]syxsproa_r^]pɝPZtS\wLTqQZyNVxNVxQZ{OWyHPrFNpIQqQWxW^{LSoMTmHOiS[qz[cwX]wV[tHMf@E\INebf~PUjrxiodjzPUjHMfOVrHOlMUrFMiHMdX\qjmei~PSkikwyloTWl_av{zrqZXkmpԛ򕤯ȽzS\rV]wQXtV]zS[zT\{PXxLTsFNmIQqOWwT\{W^zQXtJQkELeELeNUoU]sGNhGLePTqNSlUZqMQipt[_tzjq{}X^oHMdT[wOVsNVvSZwUWrHI_TUkrswxhi~stUXmMPeUXmstqpmpeqzit~NZeOXhPXlX]tX]w[^{QXvS[xS[xPXvNVsQZwT\yT\yMTmMTmBIcAHbMTmELeBIc@GcIMjOSpOTmjorwhldj}MScPWaahrMScV[pT[tQXvOWtT[wVXqVWlijqsactqsvxSVjTWlW[ohj{Φ󀉔ybkxNTdV\oX\qW[p^aySZsU^yU^yQ[vS\wU^yS\wNWpFNdAI_BJa>E^GNhGNj7>Z;B_?Ba?B_BGaX]wINech}GM]DIWOUeafy_dyJSiMTmWawdl[]ofevsrhfwfevml}qt_cxadx[]o}yzw{zɲƴĜ󅌖t{ptlqhlzehyTVh_avZ^sXatU]sPXoQXrT[tNUoELeAHbDH_AF_@GaELh=Da=Da@Gd>A_>A^JNkHMfAF]PUjOTiOUhX^qsyejOTiS[qFNdLViT\pX\pZ\m^arihzdcvjiyrsy}~xzwy~{žǿ˽ȶ󏓝ԱsvhjypsVZmUZqPUoLOlFIhFIhGHhEFeAEc@Db@Dd>Dd>Eb>Eb?FbHOkFMiAHbAHbBIcNVlXatS[m]eydlU]sLSlJQkLSlTWtHJhOQj]^tcdyxzmp}~vvss¾ƤƲ󏐖Ϭķ[]obc{bdMNmIMkJLkLMlIJjFGi@Dd@Dd>Dd>Eb?Fb>EaGNjDJfBIeAHd?FbFMfDLb@H\IQeckQZpIPjFMfOVrMPoLOmPSm]_x]^spr~}~vxprvxss~~ۤƤɿĴ{zcd}hhVWyLMoILiJMjHJhEFe@Db@Db>Eb>Eb?Fb>EaELhAHdAHdAHd>Ea@GcELh>E^ELe]e{JSiGOcNVjV^rPUoNSlOQjX\qQShbdvom{z{}mpQTc[]jddqbboyyĘʹݸЪzxdd__NOoDFaDFaAD^?A^@Da@Db>Eb>Eb@Gc>EaDJf?Fb=D_@Gc>Ea@GcFMi@GcJQkXawPXoJSfXasPXlGLcQVm\_tQUjSTi\^ptsvtik}UWfikxx{^^kzz󩫪mpoz}{˲Ėde~OOkHLaGJ_HJcFHa@E^=@]:A]=D_>Ea?Fb>Ea;B^>Ea?Fb@GcAHdMTmSZsHPfFNdS[qOWmQZpLTjJOi_d{JNc_cw]_qjl{llyy{VXjWZirtlpzww}}Σ黻ǔ~dehθװwvWXmOSdNQeNQeLOd@E\>B\:A]>Ea?Fb>Ea;B^=D_@Gc?Fb>Ea=D]=E[FNdDLbMUkS[qQZpT[tU\vV[rejTWlX\pcewjlyyyy{\^plo~y{vx~{}deḭeisV[fTXfQUfOSfAF]>B\;B^?Fb>Ea;B^=D_=D_?Fb>Ea=D_;B\BJaEMa@H^MUkIQhJSiNUoV^tdi~{W[odhysvz}qpVXjxzrtvxfixdfvww˗ɥԽƞ{}efjmor_^c֗^blV[fSWePTeBF[?D[?B_>Ea;B^=D_=D_>Ea:A];B^=D_>EaFNdAI_;DZJQkHOiBIc;B\AHbV[pafy]arhlzy{jiywybdvjl{}fiv~oq~zz~~ǯ~}zy~tsxqptɍVU^WV_ljwyylpzTWbSVaUWfGJ^GIb@Da>Eb?Fc>Gb=Fa;E];E];E_;E_;E_?Ha?Ha?Ha?Hc@Id>Gb>GbAHdMQiNSh_ctqvvtsrzykjzvt~yy֪rqv{zwvz˜a^k_]jb_mdbpss\_hNQ\\^kNQeGIbDGd>A_?Fc>Fc=Fa;E];E];E_;Da;Da>Gb>G_>Gb>Gb=Fa=Fa?GdELhUZsOTi]arsvyxkjzom~dcs~~~}}ֽŤ͞}{wvzrqvvtya^lZWe^^j[^iZ]h]_lPTeJNcGLe@Db?Fc>Fc=Fa;E_;E_;E_;Da;Da=Fa=F^=Fa=Fa=Fa=Fa?GdELh\azOTicfxjly\^k{z_^oVUebaqqp~}}ssΨȱɾůȓ‰\[_edi[Zcɓcao]]iVZdkoy_boNQcNQfGLeGJh?Fb>Fc=Fa;E_;E_;E_;Da;E_=F^=F^=Fa=Fa@Id>Gb>FcAHdGLeX]rcfxdiw]_leht~baq\[ksrxw{zyyŽ͹¾ɾɍ򩨬edi~~}WUbhesbbmps~Z]ecfq_drMPdINeJOiAHd=Fa=Eb;Da;Da;Da;E_;E_;E];E];E_;E_>Gb;E_AIfJQmJOiW\qZ]olq_boz}ml}ihxrq~}vtttttǦƿڲžɟ򻺿ơ[Xe^\j]]iX\f_ck\_jlq}fj{DH]GLcDJd>Gb=Eb;Da;Da;Da;E_;E_;E];E];E_;E_=Fa;E_?GdGNjPUoQVkSVhlqvxy{edtedtxwxwsrqq~̽Ÿ{yƻĿ̰}ԯ^\ib_mqo}SS^Z]h[^fadohlx}FL^=AVFMf@Id=Eb=Eb;Da;Da;E_;E];E];E];E_;E_:D^:D^=EbAHdFJdNShMPb]bpxwyxttֻŦy̪{zljwVTbVVcNP]Z]hilwbepcfqimyrvFL^BJaDJd?Fb>Eb=Da;Da;E_;E];E];E_;E_;E_9B]:D^;Da=D_@Ga?D[FI]psxw~vvŲĭι˾̢¥rsyhhtNM]NP_SUdacrllxffrllxrt}fizAEZHJcJNkDGd>A_9@];B^@Ga?Fb?Fc>Eb>Eb=D_;B^;B^=D_;B\AF_DHb@B[LOcmpzzrr~xxttŲɾƴ˽ɫ[^fTVcPSbX[lVXjbdsoo{~~hhtkjz^_tHI_HJeMOlFIf?B_9@\;B^>Eb>Eb>Eb>Eb>Ea=D_;B^;B^;B\@Ga>A^@E^QUjNQcUWdiitffrllxŹ͹ǥԚz~jlyNP_QTewyhjyzz\\hllytsy{PQfEG_HJeGJhAEb=D_>Ea>Eb>Eb=Da=Da>Ea>Ea=D_;B^=D]9@Z@Da?D]PTi^bsdfswz]]immy{{jjvzz˺ϰƚxڳWZiTVhpr\^m~ffsZZetwEH]FHaLPjGJh?Fb;B^=Da=Da=Da=Da=D_>Ea>Ea=D_>E^:A[;?\@E^NQfcfxww{{Ͻ»ɘ϶yҸŬLN]IL]qslo~kjzNM]FFSOO\eeq~~y{_cw>@XOTmFIfAHd>Ea>Eb>Eb>Eb>Eb9@\:A]>Ea>Ea=D]=D];?\HMfHLa\_q˽Ȥۖ·;ɲGIXIL]SUdehwXWhML\^^k]]ipp{ILdINhHLiAHdAHd?Fc>Eb>Eb>Eb:A]:A]=D_>Ea>E^@Ga>A^AF_AEZ]arrt{}}ƫǺԏĺǾžLN]OQc\^macrji{TScbboZZejjs_ctVZo@E^>A^FMiBIeBIf?Fc>Eb>Eb:A];B^=D_=D_?F_>E^@Da@E^GJ_\_q{~z~ssԻ³ӭƿ³̽䚜ƽDzNM_IL]UWiik}PObqpedt^^kaaljjs}{}SUmFHcHLiGJhDJfAJe>Gb>Ea:A];B^>Ea=D_?F_9@Z@DaFJd=?WLOc~wzoozƌƦҴIJ˶Ƭ̴𑑑˾ЭPMaNMbHF]qo\[pzy\\illv}~NLeNLhJMjJTlGTkANe=F^=D]:A[;?\=@]?D]?D]?B_?B_AF_?DXfmx~swvv~~wwȱ̭͑xxxҶ̜OL_LH^VTkWUlMLahfyddpss}ihoډXToTTpDMeN[rDPh>G_:A[:A[>A^>A^?D]?D]?B_?B_BFc=AXZ_my~txppyzzĚĸɬȾշƿūlljͿ~~{HFTOM]XWjXWjSQb\\ittww{{fhmomtȽ˲[WmVWpBIcQ[vISmBIe=D_>A^?B_>A^?D]?D]?D]?D]?B_BG^MSasxxzzz{{zxͰȳĹ˽ɸŹϹaa^yywƅwwtVTaLIVNN[UUbPP\EEPaalMMVMNThiokjo£ϻwsQPeFJdMTpNUqHLiEHeAEb>A^=A[?D[?D[?D]?D]?B_DHbBHXqvsvqq~wvqo}ƻ𸸺ǽǺОVWSopkvwr}kjqddmTT]TT]OOXZ[aTU[NOSdeiomr˦qo}edtSVk?D]OTmOTmHLiBFc;?\>B\?DX?DX>BZ>B\AEb>B\?EWzsvoo{ml}rp}ƺθº߿½¸҇yTUPbc^}~ybc^stpklh~ijm]^bXZ]deiZ[^\]aTUXefjooqwwycewLOdPTiPSkOQlIMj?B_>B\?DX@EZ?D[?D]?B_?D]BH[jo}{{ddqxxxw̾ϸŻͨΟ{UVOef_lmfWXQ~mohde^stpjkfddbaa^eeeijljkm^_b]^aefiLMOijlrrtkkkjimfel}}fivUWiPQfPSkOTmDGd;B\@EZAGZ@E\?D]?B_@E^BH[SWey}yymmwww⻻ˬ׾{UVQ[\Wfhclmffha^_Xef_cd][\U^_[^_[Z[Viifccattrceddfe]_^TVUehf{}bcekmlsssiiilll}}}vvxxxz{zddpVXhTUjTVoINh@E^AGZAGZ@EZ?D[?B_@E^>BWBFWkmzllvxxjiyttzyƾĴ݌~OOM[[Xiifklhefbcd]cd]NOJTTQUUSQQOppmppmXXVddbjjhbb_[[XWWUffdjjjjjjffdhheddbaa^^^\iifxxxqqqttrmmmomr__iPO_LMbGIbAD\AEVLOaNQf?AZAD\?AZ?BWBFZacr}}kkxddqϾĭڷSSSNNNkkissqqrm]^Zbc\ijeQQOLLIZZWMMJbb_^^\ZZWiifbb_\\Z[[Xbb_hheaa^ddbeecVVTddbaa^__]eeceecmmksrojieiii__kTScTVhQUfLP\UZeUXjEH\AEZ?AZ?BWBDXIHXlly}}__kppyΝޜJJJMMM]][hhefhcbc^_aZfhcTTQOOM__]TTQUUS~~{SSPbc^]^Z[\W\]Xbc^efb^_[efbiifPPN]][eechhemmkjjhddbppmbb____{}^^hZZeX\dU[_\biZ^jFI[@DW@DXBF[HI^TSeiivzzww̉bboZZf˥Ϳ˛ԾǎAAALLLUUSccabc^Z[V^_Xab]WWUXXVUUSNNLXXVeecLLI[\WWXTWXTZ[V_a\\]X\]X_a\^^\ZZW]][eeceecmmkjjhZZWffd[]\^a_vxwklo]^bZ[]X]\]bcX\dDFS@BTDEZLMbTVhLJ[aam~~҅XWhbbo¶̎yy{Ŀ۫ݕHHHNNNVVTffd]^ZNOJQSL_a\WWU\\ZPPNPPN^^\cca}}zVVTXZU_aZWXQ_aZab[\]VZ[T_a\bb_]][ZZW^^\eeceecddbUUSX[ZX[Z^a_ceddddiiihheTVSTVQ[]Z^_cQQ[IIVEDTML\^]m]]jaaliir}~ۇQQ^qqz~}Ǭžȸί͸֓OOOGGGQQO]][VWSMNIUVOab]]][__]__][[XVVTaa^aa^]][TUPhibUVObc\bc\]^WWXQ^_[[[X]][VVT]][eecddbddbVXWSWXX]^[\^bdcbbbccalljWXTZ[Vbd_abdTU[JJTFFQJJVWWcaajijp\]cz{~}~ss^^jdzԪ뷷вȯZZZPPPQQOOOMPQMNOJWXQ^_[[[X^^\__]\\ZVVTcca^^\ZZW_a\de^XZSde^ab[_aZbc\TUPZZW]][\\Z__]cca__]aa^VXWUZ[PUWNSUcdfiik]]]cab[ZWVWSccaddd\[_WV]TSZSQVTSW]^bvwycdfqrttwvwyxι[[hxxߢԦۿտΣXXXaa^XXVTTQOPLOPLWXQZ[V[\Weec__]bb_[[X__]XXVUVQbc\de^STMXZSde^cd]]^WUVOWXTSSP]][XXV]][XXV[[XTVSNSTGLMEIJ_acaac]]]b_a_^\VVTcca^^^VVXTTVWWZZZ\WWWZ\[fih_ba_bafihqsr٥vveeq囚ǽUUS\]X_a\UVQQSNIJFOPL\]XZ[V]^Z^_[]^Z]^ZWXTZ[VXZUab[de^[\UMNG^_XWXQZ[TZ[TVWSWXT_a\XZUab]QSNXZU\\ZNPMVXWGIHXXXeee^^\aa^ccaUUSeecddbZZZSSS___[[[OOO[[[hhhXXVddbjjhyyw˶~}^]fvs·OPLUVQ]^ZZ[VHIEEFAMNIXZUTUP]^Z^_[WXT^_[XZUTUP]^Z\]V]^WXZSEF?WXQUVOZ[TZ[TXZU]^Z[\WZ[V^_[STOQSN]^ZSSP\\ZPPNVVTZZWQQOWWU\\ZPPNXXViif^^\LLIUUSWWUSSP^^^cca_a\cd_rsowxsttrqqs{zdbp}zٺǰIJFQSN^_[^_[JLGBD?GHDTUPSTO\]X]^ZVWS^_[XZUTUP]^ZZ[T[\U]^WGHAVWPVWP[\UXZSXZS^_XZ[TXZS\]VNOHOPI^_[]^ZZ[VQSNSTO^_[QSNSTOXZUQSNWXTjkfXZUMNIQSNZ[V[[X__]eec_a\de^fhadeappmlllihl~}rrp~ecpb_lljwƾHIETUPbc^^_[MNI>?:EFA[\WXZU\]X]^Z\]X]^ZWXTZ[VXZU^_X^_Xbc\STM[\U[\U]^WVWPZ[T]^WZ[TUVO[\UHIBQSL_aZUVQWXTWXTQSN\]XOPLSTO]^ZPQM\]XijeXZUVWSUVQbc^^_[ccaab]fhacd]bc\de^efb___aacqqsmmmhheqqo{{~{z\[d[Zcdcjjim̹̜IJFIJFZ[V\]XLMH9:6BD?]^ZVWSUVQXZU\]X[\WZ[V^_[WXTab[\]V]^WXZSNOHTUNXZSXZSZ[Q]^UbcZ\]T\]TTULWXOZ[TSTMXZS]^WLMFZ[T[\U_aZbc\OPI]^Wde^bc\^_XWXQab[]^Z[\W^_[hibde\abX_aZ]^Zbb_VVXjjljjh_a\jkfccahhjώzy~~bbdȝ̗Ӱ˺LMHLMH\]X^_[QSN?@;EFA[\WOPLQSNZ[VVWSZ[VZ[VZ[VUVQ\]V[\U]^W\]VJLEPQJUVOUVOWXO\]TabXZ[QQSITULXZP[\SOPIWXQbc\UVOTUNWXQ[\U[\UNOHde^ab[[\U\]VUVO]^WXZS\]Xcd]Z[Q]^Ucd[]^UZ[T__]ZZZfffbb_Z[V_a\bb____~~kkm̸ҿ¡׭ƝVWSQSN[\WZ[V[\WGHDHIEXZUNOJSTOZ[VXZUZ[VVWSXZUOPLWXQXZSWXQXZSGHAMNGPQJQSLSTJ[\S_aWUVMMNEQSIUVMZ[Q\]VQSLXZSXZSVWPZ[TXZSUVOOPIde^^_XWXQ\]VTUN[\UUVOZ[VZ[T]^U_bU^aTbcZUVOaa^\\\bbb\\ZXZUbc^iif^^^iiikkkjjlƔԚָ΍~z}WXTTUP]^Z\]Xab]MNIJLGWXTIJFPQMNOJ[\W[\WPQMZ[VIJFUVOVWPOPIPQMDE@IJFNOJNOJPQJZ[Q^_VSTJOPGOPGNOFXZP[\UNOHUVOVWPIJDSTMWXQUVOPQJ\]V_aZZ[T^_XUVO[\UTUP\]XZ[V_aWcd[WXO\]Tab]^^\]][aa^\]X^_[dealmieecbbbTTQddb}}}SSUyy{pprpppƎڻǽ͸Ϝ}{{yx}STOVWSWXTUVQUVQVWSPQMXZUGHDJLGOPLab]LMH[\WPQMIJFQSNMNISTOTTQIIGNNLLLLMMJSTOSTMUVOUVOQSLWXQSTMVWPVWPPQJOPISTMGHAQSLPQJSTMUVMUVM\]V^_XXZUUVQUVQMMJTTQZ[V]^W_aZab[[\UXZU^^\[[X\\Zdeade^ab[lmiffd__]UVQZ[Tjkf}~yooliifXXXlll~~~hhhddbԯǺӱt{JLGPQMVWSVWS[\WXZUNOJSTOGHDIJFUVQ_a\LMHWXTNOJEFAQSNLMHNNLUUSLLLLLLGGIJJJOPLPQJTUNTUNSTMMNGZ[T[\UVWPPQJOPISTMNOHLMFSTMOPIUVMUVMXZS]^WVWSTUPOOMHHFPPNXXV]^Zab[cd]^_[XXV]][^^\__]^_[^_XUVO^_[XXVTUPQSLVWNcd]mohbc^xytffd\\Z___qqqvvvmmm\\\^^\qrmԫ̷۽ھɬyFGBNOJTUPVWSVWSTUPJLGOPLPQMLMHZ[VTUPJLGVWSVWSNOJOPLMNIMMJSSPPPPGGG@@BGGGIJFQSLMNGUVONOHWXQ]^W^_XVWPPQJOPISTMUVOHIBOPINOHUVMUVMVWN[\UQSLUVQQSNPQMOOMVVTWXTZ[Tef_deaZZW^^\[[Xaa^XZU^_X[\U]^ZPPNJLGUVO\]Tab[bc\TUPefb[[XQQO\\Z__]eeeqqqxxxiiiqqsVVV\\Zffdlljyyw{{yrrpȬܖ{{wy~ɟ{@@>FFDJJHJJHVVTPPNBB@DE@QSNJLG[\WTUPJLGTUPUVQIJFIJFPQMNNLOOMSSSEEE::=EEEHIEHIEQSNQSNNOJQSNTUPZ[VVWSPQMOPLSTOXZUIJFJLGNOHJLBTULXZP]^WNOHSTOMNIJLGPPNPPNOPLPQJ]^Wbc^XXVVVT\\ZccaPQMVWPWXQWXTJJHGHDVWP]^U^_XXZSPQMcd_bb_]][TTQ\\Z___hhh[[[TTV^^aLLNNNNbb_ddbiifeecmmk]][{{{Ұٕwxxy}tw>>>AAAMMMFFFHHHJJJAAA@@>PQMPQMXZUMNI@A=HIENOJEFAGHDFGBFFDGGENNNAAA99;>>>DDA@@>LLIMMJLLIJJHNNLOOMUUSMMJIIGPPN]][SSPJJHMNISTJWXO^_X^_XPQMEFAHHFIIGLLIPPNVWSSTM^_X]^ZSSPTTQUUS]][UVQUVOZ[TUVQHHFMNIWXQ_aWab[]^WUVQ\]XZZWPPNUVQXXVQQO[[[UUUMMOONSGGIPPPZZZZZZ\\\TTT[[[\\\iii–sssŕ昚{}xyxz}r}s666;;;GGG>>>DDDAAA>>>AAAMMJJLGPQMNOJBD?HIELMHDE@DE@EFAEEBDDASSSFFF88:::=;;;@@>??=IIGGGELLIGGEFFDOOMLLIFFDQQOXXVSSPNNLHIELMFSTJ\]V^_XWXTGHDFFDDDAGGEJJHQSNMNG[\U]^ZSSPOOMVVTXXVUVQPQJVWPLMHIIGSTO^_Xfh^fhabc\VWSQSNSSPXXVNOJTUPWWUPPPQQTGGIHGLA@ENNP[[[UUU___WWWSSS]]]ZZZbbb~~~jjjllloooĪxy}xyrty{{~wzrzlwr}>>@::=FFHFFHJJMHHJBBE999MMJIJFGHDDE@BD?FGBLMHGHDBD?FGBFFDBB@TTTJJJ88:99;888777>>>BBBLLLEEEGGGGGGJJJFFFGGGQQQQQQUUUOOODDAMNGPQHVWPVWPWXTIJFLLILLINNLLLIMNIHIB^_Xfhc\\ZTTQWWU[[XZ[VUVOWXQOPLHHFTUPbc\ijahibab[XZUFGBJJHXXVOPLXZUUUSNNNSSUPPSQPUDBGJJMUUWPPS^^aJJMHHJPPSbbd^^acceXX[VVX[[]ddf~~motz~oq~qsps{{rvtxiqfos~???>>>IIIGGI??A;;>AADAAAEEBHIEEFA?@;?@;BD?LMHMNIDE@IJFIIGDDAQQQNNN:::;;;777666===AAAJJJNNNMMMNNNGGG>>>JJJPPPMMMVVVLLLFFDGHDMNGUVOVWP]^ZOPLQQOQQOJJHEEBHIEFGBUVQbc^VVTJJHOOMZ[VVWSXZUQSNXZULLI]][^_Xde\cd]\]Vab]NOJNNLSSP\]XXZUXXVJJHQQQPPSUTXLJOFEIIHMNMQZZ\PPSMMOOOQ[[][[]]]___bWWZTTViikooqyy{fhkz~kotfjrilwoq~vxrtfizwx~vzqypy480794BEALNM>?A236687FHE@@>FFDFFD>>;GGEAA?FFDHHFDDALLIJJHJJHVVT]][TTQFFD442997;;9@@>DDALLIJJHBB@BEAEGFILJEFHFGINPO@BAGIFDDAIIGUVQ[\WOPLLMH997???GGEBB@FFDEEB]][[[XQQONNLLMHSTONOJWWUSSPMMMIIIUUSef_de\ab[ef_cd_TUPMMJNNLWWU\\Z[[XTUPMMJNNLUUUSSUDEJEFLFGMVW[MNQIJNIJMUVX[[[QQQUUUVVVOOO]]]eeeeeeefi^_bijlabdcdhopshilefjdekqqzssjjwrqoqcfzw}{s{t{~AE:AE=EGBDFE9:=013687ILHEEBLLIGGE886663@@>GGEEEB??=MMJPPNQQOaa^bb_XXVTTQ??=@@>;;9DDAFFDLLIJJHAA?JMIEGFGHJFGIDEGIJMJMLFHEFFFGGGVVTXZUQSNTTQ???;;;FFD@@>FFDNNLiif__]SSPSSPMNIOPLOOMJJHQQQFFFDDFBBBVWPab[ab[TUP\]XVVTMMJMMJSSSWWWPPNXZUIJFNNLNNNOOQFGMDDMGHNTU[NOSEFIEFHVWZSSSMMMTTTXXXQQQVVV[[[WWW^_bUVX^_b]^a]^abcebce]^abcfdei{}ffpvvijadvsx{txt{BF;=@8>@;>@?78:-/1243BEAMMJOOMFFD220220??=EEBGGE@@>IIGJJHLLIUUSbb_ccaaa^OOMEEB997BB@DDALLIJJHBB@DFB>@??@B?@B:;>@ADNPOILHLLLNNNZZW\]XUVQOOMPPP@@@LLIMMJIIGJJHbb___]TTQLLIUVQMNIOOMNNLNNN===::=???PQMXZS[\WGHD\\ZLLIFFFIIIQQQWWWLLIXZUJLGOOMOOOJJMGHL@AGEFLNOSOPTFGIFGIWZXMMMHHHNNNTTTVVVUUUSSSWWWTUWUVX\]_VWZbce]^a]^abcebcfdeibci^^hhhsllyzyqrikzqsrwr{vTWMNQI?A=@BA@AD347243?A>NNLIIG??=774>>;;;9==:JJHGGEHHFHHFQQOJJHQQOSSPXXV]][HHF774AA???=IIGMMJGGE:=9;>=@AD=>@;=?;=?EGFDFBGGGOOOOOMXZUWXTJJHJJJ???LLIHHFAA?GGEZZWTTQJJHJJHHIEHIEHHFGGE@@@;;;88:AAA\]XXZUXZUUUSLLI???IIIGGGJJJQQQQQO_a\QSNQQOSSSFFH@AE;=BBDGGHLPQTMNPMONX[ZJJJEEEIIINNNIIITTTTTTVVVOPSNOQTUWVWZXZ\_acXZ\[\^^_cefjfhmQSXeeoddpxxz}_bomq{~txqww[^TOSJ8:68:9@AD124364>@=LLIJJHAA?::8HHF;;9??=QQOBB@??=QQOSSPNNLOOMOOMNNLZZWEEB::8EEBEEBFFDLLIPPN9;80219:=46801389;>@?@B?FFFQQQSSPNOJXZUSSP>>>BBBOOMLLIGGEFFDOOMHHFBB@BB@EFA?@;AA?DDADDD???::=EEEPPNPQM[[XAA?>>>:::FFHPPSFFFMMMNNLXZUSTOMMJSSSIIL?@D:;?GHLSTVIJMMONNPOUWTOOONNNFFFMMMHHHQQQOOOQQQLMONOQOPSMNPXZ\]^aVWZPQTVWZVW[^_c]^b[\b_afffpmmyz}acp[^feiqmp}{zoqlq{ipwTWMLOGDFA;>=@AD679132@B?LLIQQOGGE774MMJEEBAA?NNLEEBAA?PPNLLIWWULLIFFDIIGVVTAA?442??=BB@IIGJJHTTQ>@=79889;/02124>?A?A@GIFGGGEEEHHFQSN[\W^^\LLLLLLLLIIIGJJHEEBIIGIIGAA?GGE@A=DE@HHF@@>BBBHHHEEGBBBJJHMMJZZWBBB@@@NNPGGIMMODDDAAA>>;NOJXZUMMJPPPIIIBDFBDGNOQZ[]LNMLNMJMIQTPVVVQQQEEELLLHHHNNNSSSVVVPQTOPSPQTFGITUW[\^UVXTUWQSUTUW\]_^_cOPTVW[cdhklrdhpSV^W\^efjss}vtoo{eiqekpv~MPFMPHNPL=?>=>@78:8:9LNJGGENNLHHF>>;PPNNNL>>;JJHBB@@@>MMJFFDUUSTTQNNLHHFWWU@@>331;;9DDAQQOIIGUUSFHE;>=89;34789;@AD:=;>@=HHH>>>HHF]^Zab]\\ZZZZLLLLLIMMJHHF@@>DDAEEB774IIG@A=;=8FFDBB@DDDJJJNNPGGGGGELLI[[[EEENNPQQT@?DBBE;;;>>>??=QSN^_[LLIJJJIIIGHJHILMNPUWVNPOHJGEGDMOLSSSVVVLLLOOOMMMJJJWWWWWWVWZMNPIJMIJMPQTPQTZ[]WX[LMONOQ[\^_acUVXUVX^_bbceX]_TX[dehdehdcjvt~wtjirbfibhjjptЍIMBSVNPSN=?>=>@1249;:HJGMMJFFD??=@@>AA?UUS>>;TTQFFDGGEUUSMMJLLIOOMOOMLLI\\ZEEB663>>;FFD[[XFFDNNLBEA8:92364682369;:HJGILHDDDFFDIJFJLG[\WPQMJJH??=GGETTQJJH886>>;MMJ;;9HHFFGB?@;NNLIIGFFFSSSUUU???GGGMMM^^^JJMIILEDHDBG;:?88:>>>==:HIE^_[GGEFFFHHJBDFFGIGHJSUTOQPGIF@B?ILHGGEXXXWWWVVVSSSHHHXXXUUUQTSQSUGHJMNPMNPNOQXZ\\]_QSUPQTVXWX[Z[]\UWV^a_abd^cdPUVacbbdcbaehfmmlsbah^cdejkilrv{}GH?PQJWXTMMM@@B//1BBBBB@JMH:=8362798>@?TVSFHDTVQDE@MNIVWSOPLNOJJLGMNIHIEQQOOOM9:6FGBVWSab]GHDLMHJJJ>>@224224DDDIII??=DDALLIHHFMNINOJVWP^_XSTMHIEJJHMMJDDA442::8886886EEBNNL@@>EEBTTQAA?LLIXXVIIIOOOEEETTVPPSVUZFEIBAH:9>88:???@@>JJH]][AA????JJMABFFGJHIMFGIXZ\MONILJMOLIIGTTQ^^\MMJTTQPPNNNLTTQSUTQTSNPOLNMILJILJQTS\^][\^UVXUVXVWZ^_b[\^[\^]^a\]__ac\]_^_babd^_c^_c_ac^_bijlhioeiq_dp^co@A8MNGOPLIIIDDF113:::;;9PSNAD?3644768:9NPO@B>OSJNOJLMHOPLLMHPQMFGBLMHAB>UUS[[XGHD?@;HIBZ[THIBJLGFFH327224BBELLLPPPAA???=??=??=HHFNOJPQM\]VUVONOHJLGPPNNNL;;9442663774GGEPPNBB@AA?QQOIIGEEBPPNSSPWWWIIIGGI??AFEI@?D=;B98=779??ADDDZZWaa^LLL@@BJJM9:>?@DDEHFGJOPSGHJGIHJMLJJHOPLZ[VUVQXZUVWSQSNVVTPSQX[ZWZXLNMHJIFHGJMLUWV\]_TUWQSUTUWZ[]WX[STVXZ\[\^XZ\[\^Z[]^_bQSUVWZ\]_bbbcce_afadlX\fX]hsy}GH?LMFTUPFFFQQT113111;;9MOJAD@/10/02468JML=?;JMHNOJIJFOPLMNIGHD?@;IJFEFAFFDUUSWXTPQMNOHWXQJLEQSNLLL99;,,/;;;UUUUUSNNL@@>@@>>>>EEBGGELMHVWSNOHGHABD?MMJPPNHHF886220997@@>SSPDDA==:NNLJJHFFDPPNTTQWWUJJJNNNHHJ@@B;:??>BIHM@@B??AMMMZZWZZWQQQ;;>GGI:;?;=@?@DBDGMNPHILGIHHJIMMJNNLUUSZZWVVTUUSPPNTTQQTSWZXVXWOQPHJIGIHGIHOQPXZ\QSUNOQVWZXZ\Z[]PQTWX[XZ\VWZXZ\WX[]^aPQTQSU]^a_acWX[TU[[^fSV^LOW_ej_ejLMDQSLNOJ@@@SSU>>@777;;9LNJFHE236347679LMO>@=MOLPPNIIGOOMEEBBB@AA?FFDDDAMMJVVTVWSFGBFG@VWPQSLVWSFFF447;;;777LLITTQHIEEFADDDAAAGGGIIGFFDTUPQSNMNIMMJUUSMMJPPN==:++)997??=TTQDDA>>;LLILLIIIGNNLPPN\\ZIIGUUULLLWWZMMOFEI87;668==?HHHQQO\\ZJJJMMOHHJ89=9:>@AEHIMIJMEFHADB?A@OOOQQQSSSVVVNNNQQQNNNPPPSUTLNMMONSUTNPOILJHJIMONWX[TUWJLNMNPTUWTUWIJMTUWTUWWX[TUWVWZUVXSTVJLNXZ\WX[OTVIMSPTZQU]OSXZ^aW\^VWNUVOMNIDDDOOQTTVHHH::8>@==?>*+-&(+67:@AD@BAEGFFFF>>>FFFFFFMMMPPPPPPMMJAA?QQOWXTHIEIJDNOHTUNPQMJJHGGGTTTFFDIIGVWSSTO>?:888668>>>AAA>>;HHFPPNSSPSSPMMJNNLQQOIIG774442??=VVTOOMEEBFFDUUSMMJIIGMMJXZUXXVWWULLLTTTLLN--0336113>>@HHHUUS\\ZOOOLLN??A67::;?=>AGHLDEGFGI=?>EGFLLLTTVLLNOOQLLNNNPGGIQQQSUTOQPQTSOQPWZXPSQOQPZ\[VWZUVXGHJLMOPQTXZ\FGIHILPQTQSUTUWWX[STVZ[]MNPPQTMQSPUWJNTBFLLOUVZ_TXZTUWWXOLMFHIE???DDFGGI>>>11/79878:)*-*+/237469468:=;DDD======AAADDD@@@@@@DDDEEBUUSVWS?@;@A:FG@VWP[\WQQO[[[SSPEEBNOJQSNOPI894AAA>>@>>@======JJHPPNJJHIIGMMJHHFNNLOOM@@>AA?BB@UUSVVTNNLHHFSSPIIGMMJJJHUVQSTOLLIQQONNNOOO;;>IIL88:;;>QQQOOM[[X\\\BBEDDF?@D?@D;=@>?BDEGDEG9;:;>=EEGPPSJJMGGIGGIJJMFFHLLNJMLMONQTSPSQSUTSUTUWVTVUOPSNOQEFHIJMIJMPQTBDFFGILMOPQTSTVTUWMNPVWZTUWOTUFMMPVXPTZEHNIMSTUXQTSQTSUVMPQJEFABBB??AEEGBBB886243236(),/0634:67:78:=?>FFH::=::=??AAAD::=::=AAATTQVVTWXTMNIJLEFG@NOHOPLTTQ^^\]][GHDMNIQSLEF?9:6IILGFJ??A::=999HHHMMJGGEGGEJJHGGENNLSSPGGE??=;;9OOMWWUTTQGGEIIGJJHNNLFFDQSNLMHMNILLINNLNNNFFF@@@GGIMMOUUUGGEXXVNNNAAD88:78;9:>?@D@AE:;>>?A?A@@BAEEGNNPLLNFFHEEGGGIEEGEEGFHGMONOQPSUTTVUQTSVXWOQPTUWNOQEFHEFHBDFMNPHILNOQHILJLNPQTQSUHILPQTWX[MQSAGIMSUQW\IMSMQTTUWTTQVVTJLEIJDHIE??=BBBQQQIII444-/1236+,0/03-/29:>;=??A@JJM447@@B@@B>>@::=::=>>@@@@UUS[\WGHD?@;BD?OPLWXTPPN\\Z\\ZLMHGHDLMHDE@==:LLNMMOAAD==?777AAAJJHLLIHHFBB@>>;@@>@@>BB@>>>999HHHPPPMMJFFDJJHFFDFFDLLIMNINOJJJHIIGMMJ[[[XXXUUULLNPPSQQQDDAUUSPPP99;44778;=>AIJNIJM9:=?@BDEGBDFBBEEEGFFHBBBBBBEEGFFHAADEGFNPONPOSUTPSQILJVXWVXWUVXOPSJLNJLNEFHJLNFGIFGIFGIHILLMOPQTHILMNPWX[GLM=BEJPSOUWJOQLPQPSQNPMTTQNOJOPLPQMGHDDE@GGEBBE87;:;A01778;013124468:;>>?AEEG779779AADIIL99;336::=HHHZZWUUSEEB>>;FFDLLI[[XPPNZZZ\\\PPNBB@MMJBB@BBBDFEILJ;>=FHG=?>8:9MONFHGLNM@B?9;8=?;?A>;>=78:348=>AGHJHJIILHLNIJMIHJGFHGHJINPOFHGFHGFHGLMO?@B:;>ABEIJMEGF?A>TVSOQP@AD89;/039:>FGIUWV=?>;=?:;>?@D=>AEFHSUTOQNEGD=?>@AD?@BLNMNPOPSQQTSQTSJMLNPOX[ZTUWPQTIJMNOQJLNGHJGHJIJMDFEGIHGIHMONFHGLNMVXWMNPINOHMNMQSLPQHMNINOMQPQTSPPNMMJLMHDE>;=8AA?>>@32911:/06;=@6796879;:9:=:;>>>@224779??A==?224//1668===IIGVVTNNL>>;EEBPPNTTQZZZXXX\\\IIIAAAGGGFFF@@@?A@BEDDFEBED:=;8:9JMLEGFILJ>@?362362:=;89;46923967=@AEDFEEGDGIEFHEEGFDFEJLNNOQDEGABEFGIQSUDEG9:=BDFABEDFE@B?OQNTVUIJMABE2379:>EFHVXWEGF;=?78;:;?>?BIJMTVSTVQJMHBEADEG?@DGHJHJILNMQTSMONHJILNMTVUWX[OPSIJMMNPPQTJLNEFHABEGIHHJINPOLNMJMLSUTTVUMONFJLEIJINOHMNEIJGLMINOLPQIIGQQOTUPFG@9:6??===?329,,6-/4?@D?@B243=?>;=?>?A?@D12667:78;-/2+,0126;=?>>>HHFUUSQQOAA?AA?JJHUUSUUUZZZWWWPPP@@@JJJEEEEEEADB@BAHJIADB9;:9;:HJIEGFMONDFE9;8796=?>9:=46912889??@D=?>;>:?A=BEAFHGILJGHJJLN?@B?@B?@BQSUNOQLMO>?AEFHILJ?A>NPMSUTHIL@AD:;?ABFGHJVXWSUT>?A78;89=469GHJQTPWZUOQMILHEFH>?BJLNHILFGIGHJEFHBDFFGILMONOQIJMGHJEFHJLNJLNHILEFHEGFFHGJMLEGFBEDMONQTSNPOHMNGLMLPQJOPBGHDHIGLMINOQQOUUSUVQGHA=>9BB@AAD98?//8+,2>?BEFH687ADB:;>:;>>?B126:;?:;?237014348:;>???MMJLLIDDA>>;FFDHHFQQOWWWUUUZZZPPPEEEIIINNNGGG@BA8:9=?>:=;7989;:FHGDFEHJIDFE=?;9;8DFE>?A469/0667=>?B>@?=?;FHDFHEFHGFHG>?AFGI?@BBDF;=?EFH;=?9:=78:?@B=?>=?>PSQLNM=>@67:67:ABFDEGJML\^]GHJ>?B89=:;?MNPPSOTVQOQMILHGHJABFHILGHJEFHEFH?@B?@BBDFFGIHILMNPNOQ?@BIJMJLNIJMEFHFHGNPOJMLFHGILJMONVXWLNMEIJDHIHMNGLM?DEAFGDHIFJLSSPWWUWXTPQJ=>9??=DDFA@GEEN12878;347798@BA@AD4687;>&*037=14:-17*-3*-3-/2:::NNLQQOIIG??=AA?GGELLINNNUUUWWWNNNAAAHHHQQQGGGEGF?A@9;:ADB8:99;:DFE@BAEGFBED@B?=?;GIH9:=126-/478>;=@ADB>@=BE@?A>:=;798>?A;=?67978:67989;78:3479:>:;?9:=>?AGHJPQTFGJ46989=?@DEFHEGF\^]LMO=>A12667:FGIQTPX[V^a\JMIHIL;=@?@D>?B?@D?@D;=@:;?@AEHIMGHJ?@BJLN9:=ABELMODEG=>@HJIOQPJMLFHGFHGEGFNPOHJIAFG@EFDHIAFG>BD;@ABGHGLMOOMUUSUVQOPI894886==?>=D88A/0689=6799;:ADB>?A12637=$(-,06(+1*-3(+1*-3014;;;LLINNLHHF@@>==:??=HHFJJJUUUTTTQQQ===GGGMMMIII@BA=?>9;:HJI?A@>@?DFEBEDADBBEDEGDGIFILJ;=?46912834:78;>@?>@=GIEEGDBEDADB>?A9:=12434767989;89;67:78>;=B89=89;DEGNOSDEJ12878;=>AABEDFE[]\PQTBDG9:>FGJMNPSUQWZU]_[PSOLMO?@D;=@:;??@D>?B78;9:>ABFIJNMNPGHJPQT@ADGHJIJMGHJGHJPSQOQPNPOEGFGIHEGFMONMONFJLDHIFJLDHI;@A;@ABGHEIJSSPUUSPQMGHA340997;;>218++4,-378;679364>@?>?A469-17&*2/2:,08%)1%)1*-6239PPPQQOBB@442==:??=;;9==:IIIOOOUUUSSS;;;AAAIIIDDD@BA=?>>@?JMLEGF?A@?A@?A@9;:?A@GIFLNJILJ;=?469128/060149;::=9FHDBEA=?>8:99:=67901334746878:78:46934:89?46967:HIMIJN?@F67=34889=?@BDFESUTPQTDEH>?BGHLIJMOQNSUPZ\WUWTOPS?@D9:@9:@>?E:;A78>89?=>D@AEABEABENOQEFHEFHFGIJLNLMOGIHGIHMONJMLGIHADBFHGHJIBGH?DE@EF=AB9>?;@ABGHBGHNNLQSNOPIFG@:;7::8779,+2%&,,-3469124687>?A;=?014),4#&/&*2"%-"%-#&,*-3348DFELLIFFD??=886DDALLIGGEBBBNNNPPNTTQ;;9IIG@@@>>>9;:@BAGIHPSQOQPEGFDFE?A@=?>BEDLNJQTPGIH9:=126-/467=237:=;=?;@B?=?;9;:78:89=67:01434812634834812622;33=12878;IJNNOSDEJ78>12889==>@ABESTVVWZJLNFGJNOSHILILHJMHQTOTVSMON;=?9:>67=:;A9:@12878>>?EABH>?B?@BHILABE89;?@BJLNIJMFHGJMLLNMQTSNPOADBFHGIJMDHI?DE?DE;@A7;=;@ABGH@EFPQMMNGOPISTMMNIBBB=;@43:)*0()/78;3474689:=78;/06**6%%1$$-%%/()/126236013>@?BED@BA9;:;>=ADBFHGLNMPPPHHFQSNQSNHIELMHHHFBBB78:@ADFHEMOLLNJJMIIJM@AD>?ADFEOQNNPMADB78:34:,,612812689;9;::=;89;78;78>14:14=03;/2=-1;69A26>03;009009/0678;GHJJLO@AG34:1289:@?@D=>AFGJVWZEFHEFH@@BLLNFFFIIGUUSUUSNNLGGGEFH89=34:67=11:88A66?88A?@DEFHHILBDF=>@=>@GHJEFHEFHBDFIJMNOQGHJGHJEFHHIL:;?=>A>?B:;?9:>9:>=>A:;?PQJIJDZ[TMNIDDA===76:218*+1,-3:;?236-/1348128((1))4%%2%%1&&0&(--/2468687?A@:=;798798?A@?A@BEDADB???GGGJLGOPI892>?:???;;>89=ABEFHENPLQTOGIFFGIFGJBDFABEGIHNPMJML=>@239,,634:67=9:>236?@B?@D;=B46;37?,0:+-:02?13@79F14?,08--922;017237:;>QSVFGM67=34:78>EFL=>DBDGNOSGHJ>?A??ALLNHHHFFFSSPWWUPQMEEBNOQ?@D34:239//866?11=>>G?@DDEGGHJ@AD:;>=>@DEGDEG>?A=>@HILNOQMNPFGIABEGHJDEH@AE;=@78;=>A=>A>?B=>AQSLGHAWXQOPLBB@III649107+,2128>?B013+,/126/06%%/&&2$$1%%1))2%&,*+/9:=>@?>@?9;:364243:=;BED>@?>@?GGIGGGNNLLMHAB>IIG;;;==?9:>>?A>@=DFASUP@B?;=?@AE@AD9:=:=;GIFNPO?@B017//834:89?=>A89;>?A89=34:34:26>+/9*,9/1>13@79F14?,0822>//8,-3348?@BOPT@AG23923967=DEJ;=BABFMNQHIL;=?JJMIILFFFHHHVVTTTQMNIHHFX[ZWX\89=67=34:66?11:88A=>A@AEABF:;?78;;=@?@DABF?@B>?AHILNOQMNPFGIABEGHJ?@D9:>67:469BDGEFIBDGDEHLMFQSLTUNNOJMMJ@@@327/-4()/128=>A)*,*+-/03,-3$$-%%1$$1&&2**3#$*&(+;=?BEDEGF679/02679679:;>ABE@ADDDFDDFNNLPPNOOMMMJJJMAAD>?BDEG>@=>@;NPL:=9124014@AD>?A:=;BEALNM=>@-/400967=23934812478:78;67=34:/2:-1;,/;+-:-0=68E26@03;11=11:,-3014FGISTWIJP67=-/467==>D9:@ABFQSVIJM=>@>>@@@BEEEFFFTTQVVTOPLFFDZ\[abdABF237/0612899B67=BDIEFIEFI=>A469:;?;=@@AE?@B=>@DEGHILGHJGHJEFHHILGHL=>A469126>?BBDG@AE?@DSTMIJDQSLVWSEEB@@@98=/-4()/128;=@+,/*+-)*-#$*$$-%%1##0$$0&&0&(-)*-BDFILJ236/03,-1348;=@67:78;34898===?GGGLLLAAA???336-,1+,0236AD@HJFTVQGIF124/03=>@>?AADBEGDBED89;,-3++412846;78;01378:89=89?78>,08(+6-0=02?+-:+-:+/9+/7--9,,6,-3469LMOLMPNOU:;A/0646;89?9:@@AEIJN@AD9:=AAD==?:::AAATTQ[[XLMHLLIZ\[TUWMNP=>A126/06*+19:@;=B;=B>?E46;67==>D?@F>?B;=?;=?BDFEFHIJMIJMHILFGIDEGEFH679124?@BHILHILDEG?@9@A:PQJUVQTTQFFF438(&-()/78>BDG/02)*,)*-#$*%%/##/""/$$0**3()/014GHJTUW89=/03+,0-/2/03014:;?237,+0;:?BBEHHHEEE@@B76:0/34699:=:=9?A=OQMLNJ:;>78;89;;=?>@?=?;>@?78:-/4,,646;46;469,-089;67:128-/4+/7),7,/;,/;*,9*,9*-8*-6--9,,6&(-9:>JLNJLOQSXLMS0172399:@46;BDGDEH>?A;=?HHJ99;888>>>MMJOOMIJFMNIPSOTVUUVXNOQ:;?014/0646;89?67=78>34:01789?;=B:;A9:>468=>@EFHGHJGHJEFHBDFDEGABE9:=89;=>@DEGEFH>?A:;4>?8PQJWXTMMJBBB327%$+*+1?@FJLO347,-0,-1)*0++4((3$$1**666?$%+126BDFSTV:;?-/4,-3+,2239-/4017)*00/698=HHJHHHEEE??A98=/-4:;?;=?8:79;7NPLJMI9:=67:89;@AD@BA9;88:9679/06--746;128126,-078:4699:@ABH+/7),7,/;(*7)+8)+8),7),4))4009+,278;BDFFGJFGM:;A9:@01723934:>?B@AE;=?:;>>>@::=>>>===IIGOOMSTOQSNLNJQTSNPOIJM469-/2126;=B:;A66?33=22;11:77@;;E;=B@AE9:=;=?@AD?@BDEGGHJIJMHJI=?>687798=?>ADBFHGADB>?8:;4IJDTUPIIGHHH:9>&%,+,2DEJQSV78:124237/0622;%%1""/**699B()/78;?@BQSU9:>+,2/06,-3,-39:@89?67=43::9>AADHHHBBB::=76:+*189=78:;>::=8QTOEGD-/1+,0236>?A>@?241364468017--7017,-3014/0223678;78>34:*-6*-8+-:$&3(*7(*7(+6(+3++7))2,-39:>GHJIJNOPVQSX@AG017*+146;;=@?@D89;89;??A==?777;;;FFDOOMTUPPQMLNJSUQLNMGHJ/03-/2+,0;=B??H66?22;33=33=22;33=67=78;4689:=9:=@ADEFHHILIJMDFE4763648:9@BA@BAFHGHJI \ No newline at end of file diff --git a/libwebp/examples/unicode.h b/libwebp/examples/unicode.h deleted file mode 100644 index 0831e23c..00000000 --- a/libwebp/examples/unicode.h +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2018 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Unicode support for Windows. The main idea is to maintain an array of Unicode -// arguments (wargv) and use it only for file paths. The regular argv is used -// for everything else. -// -// Author: Yannis Guyon (yguyon@google.com) - -#ifndef WEBP_EXAMPLES_UNICODE_H_ -#define WEBP_EXAMPLES_UNICODE_H_ - -#include - -#if defined(_WIN32) && defined(_UNICODE) - -// wchar_t is used instead of TCHAR because we only perform additional work when -// Unicode is enabled and because the output of CommandLineToArgvW() is wchar_t. - -#include -#include -#include -#include -#include - -// Create a wchar_t array containing Unicode parameters. -#define INIT_WARGV(ARGC, ARGV) \ - int wargc; \ - const W_CHAR** const wargv = \ - (const W_CHAR**)CommandLineToArgvW(GetCommandLineW(), &wargc); \ - do { \ - if (wargv == NULL || wargc != (ARGC)) { \ - fprintf(stderr, "Error: Unable to get Unicode arguments.\n"); \ - FREE_WARGV_AND_RETURN(-1); \ - } \ - } while (0) - -// Use this to get a Unicode argument (e.g. file path). -#define GET_WARGV(UNUSED, C) wargv[C] -// For cases where argv is shifted by one compared to wargv. -#define GET_WARGV_SHIFTED(UNUSED, C) wargv[(C) + 1] -#define GET_WARGV_OR_NULL() wargv - -// Release resources. LocalFree() is needed after CommandLineToArgvW(). -#define FREE_WARGV() LOCAL_FREE((W_CHAR** const)wargv) -#define LOCAL_FREE(WARGV) \ - do { \ - if ((WARGV) != NULL) LocalFree(WARGV); \ - } while (0) - -#define W_CHAR wchar_t // WCHAR without underscore might already be defined. -#define TO_W_CHAR(STR) (L##STR) - -#define WFOPEN(ARG, OPT) _wfopen((const W_CHAR*)ARG, TO_W_CHAR(OPT)) - -#define WFPRINTF(STREAM, STR, ...) \ - do { \ - int prev_mode; \ - fflush(STREAM); \ - prev_mode = _setmode(_fileno(STREAM), _O_U8TEXT); \ - fwprintf(STREAM, TO_W_CHAR(STR), __VA_ARGS__); \ - fflush(STREAM); \ - (void)_setmode(_fileno(STREAM), prev_mode); \ - } while (0) -#define WPRINTF(STR, ...) WFPRINTF(stdout, STR, __VA_ARGS__) - -#define WSTRLEN(FILENAME) wcslen((const W_CHAR*)FILENAME) -#define WSTRCMP(FILENAME, STR) wcscmp((const W_CHAR*)FILENAME, TO_W_CHAR(STR)) -#define WSTRRCHR(FILENAME, STR) wcsrchr((const W_CHAR*)FILENAME, TO_W_CHAR(STR)) -#define WSNPRINTF(A, B, STR, ...) _snwprintf(A, B, TO_W_CHAR(STR), __VA_ARGS__) - -#else - -#include - -// Unicode file paths work as is on Unix platforms, and no extra work is done on -// Windows either if Unicode is disabled. - -#define INIT_WARGV(ARGC, ARGV) - -#define GET_WARGV(ARGV, C) (ARGV)[C] -#define GET_WARGV_SHIFTED(ARGV, C) (ARGV)[C] -#define GET_WARGV_OR_NULL() NULL - -#define FREE_WARGV() -#define LOCAL_FREE(WARGV) - -#define W_CHAR char -#define TO_W_CHAR(STR) (STR) - -#define WFOPEN(ARG, OPT) fopen(ARG, OPT) - -#define WPRINTF(STR, ...) printf(STR, __VA_ARGS__) -#define WFPRINTF(STREAM, STR, ...) fprintf(STREAM, STR, __VA_ARGS__) - -#define WSTRLEN(FILENAME) strlen(FILENAME) -#define WSTRCMP(FILENAME, STR) strcmp(FILENAME, STR) -#define WSTRRCHR(FILENAME, STR) strrchr(FILENAME, STR) -#define WSNPRINTF(A, B, STR, ...) snprintf(A, B, STR, __VA_ARGS__) - -#endif // defined(_WIN32) && defined(_UNICODE) - -// Don't forget to free wargv before returning (e.g. from main). -#define FREE_WARGV_AND_RETURN(VALUE) \ - do { \ - FREE_WARGV(); \ - return (VALUE); \ - } while (0) - -#endif // WEBP_EXAMPLES_UNICODE_H_ diff --git a/libwebp/examples/unicode_gif.h b/libwebp/examples/unicode_gif.h deleted file mode 100644 index 626c6e72..00000000 --- a/libwebp/examples/unicode_gif.h +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2018 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// giflib doesn't have a Unicode DGifOpenFileName(). Let's make one. -// -// Author: Yannis Guyon (yguyon@google.com) - -#ifndef WEBP_EXAMPLES_UNICODE_GIF_H_ -#define WEBP_EXAMPLES_UNICODE_GIF_H_ - -#include "./unicode.h" -#ifdef HAVE_CONFIG_H -#include "webp/config.h" // For WEBP_HAVE_GIF -#endif - -#if defined(WEBP_HAVE_GIF) - -#ifdef _WIN32 -#include // Not standard, needed for _topen and flags. -#include -#endif - -#include -#include -#include "./gifdec.h" - -#if !defined(STDIN_FILENO) -#define STDIN_FILENO 0 -#endif - -static GifFileType* DGifOpenFileUnicode(const W_CHAR* file_name, int* error) { - if (!WSTRCMP(file_name, "-")) { -#if LOCAL_GIF_PREREQ(5, 0) - return DGifOpenFileHandle(STDIN_FILENO, error); -#else - (void)error; - return DGifOpenFileHandle(STDIN_FILENO); -#endif - } - -#if defined(_WIN32) && defined(_UNICODE) - { - int file_handle = _wopen(file_name, _O_RDONLY | _O_BINARY); - if (file_handle == -1) { - if (error != NULL) *error = D_GIF_ERR_OPEN_FAILED; - return NULL; - } - -#if LOCAL_GIF_PREREQ(5, 0) - return DGifOpenFileHandle(file_handle, error); -#else - return DGifOpenFileHandle(file_handle); -#endif - } - -#else - -#if LOCAL_GIF_PREREQ(5, 0) - return DGifOpenFileName(file_name, error); -#else - return DGifOpenFileName(file_name); -#endif - -#endif // defined(_WIN32) && defined(_UNICODE) - // DGifCloseFile() is called later. -} - -#endif // defined(WEBP_HAVE_GIF) - -#endif // WEBP_EXAMPLES_UNICODE_GIF_H_ diff --git a/libwebp/examples/vwebp.c b/libwebp/examples/vwebp.c deleted file mode 100644 index 45331edf..00000000 --- a/libwebp/examples/vwebp.c +++ /dev/null @@ -1,654 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Simple OpenGL-based WebP file viewer. -// -// Author: Skal (pascal.massimino@gmail.com) -#ifdef HAVE_CONFIG_H -#include "webp/config.h" -#endif - -#if defined(__unix__) || defined(__CYGWIN__) -#define _POSIX_C_SOURCE 200112L // for setenv -#endif - -#include -#include -#include - -#if defined(WEBP_HAVE_GL) - -#if defined(HAVE_GLUT_GLUT_H) -#include -#else -#include -#ifdef FREEGLUT -#include -#endif -#endif - -#ifdef WEBP_HAVE_QCMS -#include -#endif - -#include "webp/decode.h" -#include "webp/demux.h" - -#include "../examples/example_util.h" -#include "../imageio/imageio_util.h" -#include "./unicode.h" - -#if defined(_MSC_VER) && _MSC_VER < 1900 -#define snprintf _snprintf -#endif - -// Unfortunate global variables. Gathered into a struct for comfort. -static struct { - int has_animation; - int has_color_profile; - int done; - int decoding_error; - int print_info; - int only_deltas; - int use_color_profile; - int draw_anim_background_color; - - int canvas_width, canvas_height; - int loop_count; - uint32_t bg_color; - - const char* file_name; - WebPData data; - WebPDecoderConfig config; - const WebPDecBuffer* pic; - WebPDemuxer* dmux; - WebPIterator curr_frame; - WebPIterator prev_frame; - WebPChunkIterator iccp; - int viewport_width, viewport_height; -} kParams; - -static void ClearPreviousPic(void) { - WebPFreeDecBuffer((WebPDecBuffer*)kParams.pic); - kParams.pic = NULL; -} - -static void ClearParams(void) { - ClearPreviousPic(); - WebPDataClear(&kParams.data); - WebPDemuxReleaseIterator(&kParams.curr_frame); - WebPDemuxReleaseIterator(&kParams.prev_frame); - WebPDemuxReleaseChunkIterator(&kParams.iccp); - WebPDemuxDelete(kParams.dmux); - kParams.dmux = NULL; -} - -// Sets the previous frame to the dimensions of the canvas and has it dispose -// to background to cause the canvas to be cleared. -static void ClearPreviousFrame(void) { - WebPIterator* const prev = &kParams.prev_frame; - prev->width = kParams.canvas_width; - prev->height = kParams.canvas_height; - prev->x_offset = prev->y_offset = 0; - prev->dispose_method = WEBP_MUX_DISPOSE_BACKGROUND; -} - -// ----------------------------------------------------------------------------- -// Color profile handling -static int ApplyColorProfile(const WebPData* const profile, - WebPDecBuffer* const rgba) { -#ifdef WEBP_HAVE_QCMS - int i, ok = 0; - uint8_t* line; - uint8_t major_revision; - qcms_profile* input_profile = NULL; - qcms_profile* output_profile = NULL; - qcms_transform* transform = NULL; - const qcms_data_type input_type = QCMS_DATA_RGBA_8; - const qcms_data_type output_type = QCMS_DATA_RGBA_8; - const qcms_intent intent = QCMS_INTENT_DEFAULT; - - if (profile == NULL || rgba == NULL) return 0; - if (profile->bytes == NULL || profile->size < 10) return 1; - major_revision = profile->bytes[8]; - - qcms_enable_iccv4(); - input_profile = qcms_profile_from_memory(profile->bytes, profile->size); - // qcms_profile_is_bogus() is broken with ICCv4. - if (input_profile == NULL || - (major_revision < 4 && qcms_profile_is_bogus(input_profile))) { - fprintf(stderr, "Color profile is bogus!\n"); - goto Error; - } - - output_profile = qcms_profile_sRGB(); - if (output_profile == NULL) { - fprintf(stderr, "Error creating output color profile!\n"); - goto Error; - } - - qcms_profile_precache_output_transform(output_profile); - transform = qcms_transform_create(input_profile, input_type, - output_profile, output_type, - intent); - if (transform == NULL) { - fprintf(stderr, "Error creating color transform!\n"); - goto Error; - } - - line = rgba->u.RGBA.rgba; - for (i = 0; i < rgba->height; ++i, line += rgba->u.RGBA.stride) { - qcms_transform_data(transform, line, line, rgba->width); - } - ok = 1; - - Error: - if (input_profile != NULL) qcms_profile_release(input_profile); - if (output_profile != NULL) qcms_profile_release(output_profile); - if (transform != NULL) qcms_transform_release(transform); - return ok; -#else - (void)profile; - (void)rgba; - return 1; -#endif // WEBP_HAVE_QCMS -} - -//------------------------------------------------------------------------------ -// File decoding - -static int Decode(void) { // Fills kParams.curr_frame - const WebPIterator* const curr = &kParams.curr_frame; - WebPDecoderConfig* const config = &kParams.config; - WebPDecBuffer* const output_buffer = &config->output; - int ok = 0; - - ClearPreviousPic(); - output_buffer->colorspace = MODE_RGBA; - ok = (WebPDecode(curr->fragment.bytes, curr->fragment.size, - config) == VP8_STATUS_OK); - if (!ok) { - fprintf(stderr, "Decoding of frame #%d failed!\n", curr->frame_num); - } else { - kParams.pic = output_buffer; - if (kParams.use_color_profile) { - ok = ApplyColorProfile(&kParams.iccp.chunk, output_buffer); - if (!ok) { - fprintf(stderr, "Applying color profile to frame #%d failed!\n", - curr->frame_num); - } - } - } - return ok; -} - -static void decode_callback(int what) { - if (what == 0 && !kParams.done) { - int duration = 0; - if (kParams.dmux != NULL) { - WebPIterator* const curr = &kParams.curr_frame; - if (!WebPDemuxNextFrame(curr)) { - WebPDemuxReleaseIterator(curr); - if (WebPDemuxGetFrame(kParams.dmux, 1, curr)) { - --kParams.loop_count; - kParams.done = (kParams.loop_count == 0); - if (kParams.done) return; - ClearPreviousFrame(); - } else { - kParams.decoding_error = 1; - kParams.done = 1; - return; - } - } - duration = curr->duration; - // Behavior copied from Chrome, cf: - // https://cs.chromium.org/chromium/src/third_party/WebKit/Source/ - // platform/graphics/DeferredImageDecoder.cpp? - // rcl=b4c33049f096cd283f32be9a58b9a9e768227c26&l=246 - if (duration <= 10) duration = 100; - } - if (!Decode()) { - kParams.decoding_error = 1; - kParams.done = 1; - } else { - glutPostRedisplay(); - glutTimerFunc(duration, decode_callback, what); - } - } -} - -//------------------------------------------------------------------------------ -// Callbacks - -static void HandleKey(unsigned char key, int pos_x, int pos_y) { - // Note: rescaling the window or toggling some features during an animation - // generates visual artifacts. This is not fixed because refreshing the frame - // may require rendering the whole animation from start till current frame. - (void)pos_x; - (void)pos_y; - if (key == 'q' || key == 'Q' || key == 27 /* Esc */) { -#ifdef FREEGLUT - glutLeaveMainLoop(); -#else - ClearParams(); - exit(0); -#endif - } else if (key == 'c') { - if (kParams.has_color_profile && !kParams.decoding_error) { - kParams.use_color_profile = 1 - kParams.use_color_profile; - - if (kParams.has_animation) { - // Restart the completed animation to pickup the color profile change. - if (kParams.done && kParams.loop_count == 0) { - kParams.loop_count = - (int)WebPDemuxGetI(kParams.dmux, WEBP_FF_LOOP_COUNT) + 1; - kParams.done = 0; - // Start the decode loop immediately. - glutTimerFunc(0, decode_callback, 0); - } - } else { - Decode(); - glutPostRedisplay(); - } - } - } else if (key == 'b') { - kParams.draw_anim_background_color = 1 - kParams.draw_anim_background_color; - if (!kParams.has_animation) ClearPreviousFrame(); - glutPostRedisplay(); - } else if (key == 'i') { - kParams.print_info = 1 - kParams.print_info; - if (!kParams.has_animation) ClearPreviousFrame(); - glutPostRedisplay(); - } else if (key == 'd') { - kParams.only_deltas = 1 - kParams.only_deltas; - glutPostRedisplay(); - } -} - -static void HandleReshape(int width, int height) { - // Note: reshape doesn't preserve aspect ratio, and might - // be handling larger-than-screen pictures incorrectly. - glViewport(0, 0, width, height); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - kParams.viewport_width = width; - kParams.viewport_height = height; - if (!kParams.has_animation) ClearPreviousFrame(); -} - -static void PrintString(const char* const text) { - void* const font = GLUT_BITMAP_9_BY_15; - int i; - for (i = 0; text[i]; ++i) { - glutBitmapCharacter(font, text[i]); - } -} - -static void PrintStringW(const char* const text) { -#if defined(_WIN32) && defined(_UNICODE) - void* const font = GLUT_BITMAP_9_BY_15; - const W_CHAR* const wtext = (const W_CHAR*)text; - int i; - for (i = 0; wtext[i]; ++i) { - glutBitmapCharacter(font, wtext[i]); - } -#else - PrintString(text); -#endif -} - -static float GetColorf(uint32_t color, int shift) { - return ((color >> shift) & 0xff) / 255.f; -} - -static void DrawCheckerBoard(void) { - const int square_size = 8; // must be a power of 2 - int x, y; - GLint viewport[4]; // x, y, width, height - - glPushMatrix(); - - glGetIntegerv(GL_VIEWPORT, viewport); - // shift to integer coordinates with (0,0) being top-left. - glOrtho(0, viewport[2], viewport[3], 0, -1, 1); - for (y = 0; y < viewport[3]; y += square_size) { - for (x = 0; x < viewport[2]; x += square_size) { - const GLubyte color = 128 + 64 * (!((x + y) & square_size)); - glColor3ub(color, color, color); - glRecti(x, y, x + square_size, y + square_size); - } - } - glPopMatrix(); -} - -static void DrawBackground(void) { - // Whole window cleared with clear color, checkerboard rendered on top of it. - glClear(GL_COLOR_BUFFER_BIT); - DrawCheckerBoard(); - - // ANIM background color rendered (blend) on top. Default is white for still - // images (without ANIM chunk). glClear() can't be used for that (no blend). - if (kParams.draw_anim_background_color) { - glPushMatrix(); - glLoadIdentity(); - glColor4f(GetColorf(kParams.bg_color, 16), // BGRA from spec - GetColorf(kParams.bg_color, 8), - GetColorf(kParams.bg_color, 0), - GetColorf(kParams.bg_color, 24)); - glRecti(-1, -1, +1, +1); - glPopMatrix(); - } -} - -// Draw background in a scissored rectangle. -static void DrawBackgroundScissored(int window_x, int window_y, int frame_w, - int frame_h) { - // Only update the requested area, not the whole canvas. - window_x = window_x * kParams.viewport_width / kParams.canvas_width; - window_y = window_y * kParams.viewport_height / kParams.canvas_height; - frame_w = frame_w * kParams.viewport_width / kParams.canvas_width; - frame_h = frame_h * kParams.viewport_height / kParams.canvas_height; - - // glScissor() takes window coordinates (0,0 at bottom left). - window_y = kParams.viewport_height - window_y - frame_h; - - glEnable(GL_SCISSOR_TEST); - glScissor(window_x, window_y, frame_w, frame_h); - DrawBackground(); - glDisable(GL_SCISSOR_TEST); -} - -static void HandleDisplay(void) { - const WebPDecBuffer* const pic = kParams.pic; - const WebPIterator* const curr = &kParams.curr_frame; - WebPIterator* const prev = &kParams.prev_frame; - GLfloat xoff, yoff; - if (pic == NULL) return; - glPushMatrix(); - glPixelZoom((GLfloat)(+1. / kParams.canvas_width * kParams.viewport_width), - (GLfloat)(-1. / kParams.canvas_height * kParams.viewport_height)); - xoff = (GLfloat)(2. * curr->x_offset / kParams.canvas_width); - yoff = (GLfloat)(2. * curr->y_offset / kParams.canvas_height); - glRasterPos2f(-1.f + xoff, 1.f - yoff); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glPixelStorei(GL_UNPACK_ROW_LENGTH, pic->u.RGBA.stride / 4); - - if (kParams.only_deltas) { - DrawBackground(); - } else { - // The rectangle of the previous frame might be different than the current - // frame, so we may need to DrawBackgroundScissored for both. - if (prev->dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) { - // Clear the previous frame rectangle. - DrawBackgroundScissored(prev->x_offset, prev->y_offset, prev->width, - prev->height); - } - if (curr->blend_method == WEBP_MUX_NO_BLEND) { - // We simulate no-blending behavior by first clearing the current frame - // rectangle and then alpha-blending against it. - DrawBackgroundScissored(curr->x_offset, curr->y_offset, curr->width, - curr->height); - } - } - - *prev = *curr; - - glDrawPixels(pic->width, pic->height, - GL_RGBA, GL_UNSIGNED_BYTE, - (GLvoid*)pic->u.RGBA.rgba); - if (kParams.print_info) { - char tmp[32]; - - glColor4f(0.90f, 0.0f, 0.90f, 1.0f); - glRasterPos2f(-0.95f, 0.90f); - PrintStringW(kParams.file_name); - - snprintf(tmp, sizeof(tmp), "Dimension:%d x %d", pic->width, pic->height); - glColor4f(0.90f, 0.0f, 0.90f, 1.0f); - glRasterPos2f(-0.95f, 0.80f); - PrintString(tmp); - if (curr->x_offset != 0 || curr->y_offset != 0) { - snprintf(tmp, sizeof(tmp), " (offset:%d,%d)", - curr->x_offset, curr->y_offset); - glRasterPos2f(-0.95f, 0.70f); - PrintString(tmp); - } - } - glPopMatrix(); -#if defined(__APPLE__) || defined(_WIN32) - glFlush(); -#else - glutSwapBuffers(); -#endif -} - -static void StartDisplay(void) { - int width = kParams.canvas_width; - int height = kParams.canvas_height; - int screen_width, screen_height; - // TODO(webp:365) GLUT_DOUBLE results in flickering / old frames to be - // partially displayed with animated webp + alpha. -#if defined(__APPLE__) || defined(_WIN32) - glutInitDisplayMode(GLUT_RGBA); -#else - glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA); -#endif - screen_width = glutGet(GLUT_SCREEN_WIDTH); - screen_height = glutGet(GLUT_SCREEN_HEIGHT); - if (width > screen_width || height > screen_height) { - if (width > screen_width) { - height = (height * screen_width + width - 1) / width; - width = screen_width; - } - if (height > screen_height) { - width = (width * screen_height + height - 1) / height; - height = screen_height; - } - } - glutInitWindowSize(width, height); - glutCreateWindow("WebP viewer"); - glutDisplayFunc(HandleDisplay); - glutReshapeFunc(HandleReshape); - glutIdleFunc(NULL); - glutKeyboardFunc(HandleKey); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_BLEND); - glClearColor(0, 0, 0, 0); // window will be cleared to black (no blend) - DrawBackground(); -} - -//------------------------------------------------------------------------------ -// Main - -static void Help(void) { - printf( - "Usage: vwebp in_file [options]\n\n" - "Decodes the WebP image file and visualize it using OpenGL\n" - "Options are:\n" - " -version ..... print version number and exit\n" - " -noicc ....... don't use the icc profile if present\n" - " -nofancy ..... don't use the fancy YUV420 upscaler\n" - " -nofilter .... disable in-loop filtering\n" - " -dither dithering strength (0..100), default=50\n" - " -noalphadither disable alpha plane dithering\n" - " -usebgcolor .. display background color\n" - " -mt .......... use multi-threading\n" - " -info ........ print info\n" - " -h ........... this help message\n" - "\n" - "Keyboard shortcuts:\n" - " 'c' ................ toggle use of color profile\n" - " 'b' ................ toggle background color display\n" - " 'i' ................ overlay file information\n" - " 'd' ................ disable blending & disposal (debug)\n" - " 'q' / 'Q' / ESC .... quit\n"); -} - -int main(int argc, char* argv[]) { - int c; - WebPDecoderConfig* const config = &kParams.config; - WebPIterator* const curr = &kParams.curr_frame; - - INIT_WARGV(argc, argv); - - if (!WebPInitDecoderConfig(config)) { - fprintf(stderr, "Library version mismatch!\n"); - FREE_WARGV_AND_RETURN(-1); - } - config->options.dithering_strength = 50; - config->options.alpha_dithering_strength = 100; - kParams.use_color_profile = 1; - // Background color hidden by default to see transparent areas. - kParams.draw_anim_background_color = 0; - - for (c = 1; c < argc; ++c) { - int parse_error = 0; - if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) { - Help(); - FREE_WARGV_AND_RETURN(0); - } else if (!strcmp(argv[c], "-noicc")) { - kParams.use_color_profile = 0; - } else if (!strcmp(argv[c], "-nofancy")) { - config->options.no_fancy_upsampling = 1; - } else if (!strcmp(argv[c], "-nofilter")) { - config->options.bypass_filtering = 1; - } else if (!strcmp(argv[c], "-noalphadither")) { - config->options.alpha_dithering_strength = 0; - } else if (!strcmp(argv[c], "-usebgcolor")) { - kParams.draw_anim_background_color = 1; - } else if (!strcmp(argv[c], "-dither") && c + 1 < argc) { - config->options.dithering_strength = - ExUtilGetInt(argv[++c], 0, &parse_error); - } else if (!strcmp(argv[c], "-info")) { - kParams.print_info = 1; - } else if (!strcmp(argv[c], "-version")) { - const int dec_version = WebPGetDecoderVersion(); - const int dmux_version = WebPGetDemuxVersion(); - printf("WebP Decoder version: %d.%d.%d\nWebP Demux version: %d.%d.%d\n", - (dec_version >> 16) & 0xff, (dec_version >> 8) & 0xff, - dec_version & 0xff, (dmux_version >> 16) & 0xff, - (dmux_version >> 8) & 0xff, dmux_version & 0xff); - FREE_WARGV_AND_RETURN(0); - } else if (!strcmp(argv[c], "-mt")) { - config->options.use_threads = 1; - } else if (!strcmp(argv[c], "--")) { - if (c < argc - 1) kParams.file_name = (const char*)GET_WARGV(argv, ++c); - break; - } else if (argv[c][0] == '-') { - printf("Unknown option '%s'\n", argv[c]); - Help(); - FREE_WARGV_AND_RETURN(-1); - } else { - kParams.file_name = (const char*)GET_WARGV(argv, c); - } - - if (parse_error) { - Help(); - FREE_WARGV_AND_RETURN(-1); - } - } - - if (kParams.file_name == NULL) { - printf("missing input file!!\n"); - Help(); - FREE_WARGV_AND_RETURN(0); - } - - if (!ImgIoUtilReadFile(kParams.file_name, - &kParams.data.bytes, &kParams.data.size)) { - goto Error; - } - - if (!WebPGetInfo(kParams.data.bytes, kParams.data.size, NULL, NULL)) { - fprintf(stderr, "Input file doesn't appear to be WebP format.\n"); - goto Error; - } - - kParams.dmux = WebPDemux(&kParams.data); - if (kParams.dmux == NULL) { - fprintf(stderr, "Could not create demuxing object!\n"); - goto Error; - } - - kParams.canvas_width = WebPDemuxGetI(kParams.dmux, WEBP_FF_CANVAS_WIDTH); - kParams.canvas_height = WebPDemuxGetI(kParams.dmux, WEBP_FF_CANVAS_HEIGHT); - if (kParams.print_info) { - printf("Canvas: %d x %d\n", kParams.canvas_width, kParams.canvas_height); - } - - ClearPreviousFrame(); - - memset(&kParams.iccp, 0, sizeof(kParams.iccp)); - kParams.has_color_profile = - !!(WebPDemuxGetI(kParams.dmux, WEBP_FF_FORMAT_FLAGS) & ICCP_FLAG); - if (kParams.has_color_profile) { -#ifdef WEBP_HAVE_QCMS - if (!WebPDemuxGetChunk(kParams.dmux, "ICCP", 1, &kParams.iccp)) goto Error; - printf("VP8X: Found color profile\n"); -#else - fprintf(stderr, "Warning: color profile present, but qcms is unavailable!\n" - "Build libqcms from Mozilla or Chromium and define WEBP_HAVE_QCMS " - "before building.\n"); -#endif - } - - if (!WebPDemuxGetFrame(kParams.dmux, 1, curr)) goto Error; - - kParams.has_animation = (curr->num_frames > 1); - kParams.loop_count = (int)WebPDemuxGetI(kParams.dmux, WEBP_FF_LOOP_COUNT); - kParams.bg_color = WebPDemuxGetI(kParams.dmux, WEBP_FF_BACKGROUND_COLOR); - printf("VP8X: Found %d images in file (loop count = %d)\n", - curr->num_frames, kParams.loop_count); - - // Decode first frame - if (!Decode()) goto Error; - - // Position iterator to last frame. Next call to HandleDisplay will wrap over. - // We take this into account by bumping up loop_count. - if (!WebPDemuxGetFrame(kParams.dmux, 0, curr)) goto Error; - if (kParams.loop_count) ++kParams.loop_count; - -#if defined(__unix__) || defined(__CYGWIN__) - // Work around GLUT compositor bug. - // https://bugs.launchpad.net/ubuntu/+source/freeglut/+bug/369891 - setenv("XLIB_SKIP_ARGB_VISUALS", "1", 1); -#endif - - // Start display (and timer) - glutInit(&argc, argv); -#ifdef FREEGLUT - glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION); -#endif - StartDisplay(); - - if (kParams.has_animation) glutTimerFunc(0, decode_callback, 0); - glutMainLoop(); - - // Should only be reached when using FREEGLUT: - ClearParams(); - FREE_WARGV_AND_RETURN(0); - - Error: - ClearParams(); - FREE_WARGV_AND_RETURN(-1); -} - -#else // !WEBP_HAVE_GL - -int main(int argc, const char* argv[]) { - fprintf(stderr, "OpenGL support not enabled in %s.\n", argv[0]); - (void)argc; - return 0; -} - -#endif - -//------------------------------------------------------------------------------ diff --git a/libwebp/examples/webpinfo.c b/libwebp/examples/webpinfo.c deleted file mode 100644 index 1d2278ee..00000000 --- a/libwebp/examples/webpinfo.c +++ /dev/null @@ -1,1186 +0,0 @@ -// Copyright 2017 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Command-line tool to print out the chunk level structure of WebP files -// along with basic integrity checks. -// -// Author: Hui Su (huisu@google.com) - -#include -#include - -#ifdef HAVE_CONFIG_H -#include "webp/config.h" -#endif - -#include "../imageio/imageio_util.h" -#include "./unicode.h" -#include "webp/decode.h" -#include "webp/format_constants.h" -#include "webp/mux_types.h" - -#if defined(_MSC_VER) && _MSC_VER < 1900 -#define snprintf _snprintf -#endif - -#define LOG_ERROR(MESSAGE) \ - do { \ - if (webp_info->show_diagnosis_) { \ - fprintf(stderr, "Error: %s\n", MESSAGE); \ - } \ - } while (0) - -#define LOG_WARN(MESSAGE) \ - do { \ - if (webp_info->show_diagnosis_) { \ - fprintf(stderr, "Warning: %s\n", MESSAGE); \ - } \ - ++webp_info->num_warnings_; \ - } while (0) - -static const char* const kFormats[3] = { - "Unknown", - "Lossy", - "Lossless" -}; - -static const char* const kLosslessTransforms[4] = { - "Predictor", - "Cross Color", - "Subtract Green", - "Color Indexing" -}; - -static const char* const kAlphaFilterMethods[4] = { - "None", - "Horizontal", - "Vertical", - "Gradient" -}; - -typedef enum { - WEBP_INFO_OK = 0, - WEBP_INFO_TRUNCATED_DATA, - WEBP_INFO_PARSE_ERROR, - WEBP_INFO_INVALID_PARAM, - WEBP_INFO_BITSTREAM_ERROR, - WEBP_INFO_MISSING_DATA, - WEBP_INFO_INVALID_COMMAND -} WebPInfoStatus; - -typedef enum ChunkID { - CHUNK_VP8, - CHUNK_VP8L, - CHUNK_VP8X, - CHUNK_ALPHA, - CHUNK_ANIM, - CHUNK_ANMF, - CHUNK_ICCP, - CHUNK_EXIF, - CHUNK_XMP, - CHUNK_UNKNOWN, - CHUNK_TYPES = CHUNK_UNKNOWN -} ChunkID; - -typedef struct { - size_t start_; - size_t end_; - const uint8_t* buf_; -} MemBuffer; - -typedef struct { - size_t offset_; - size_t size_; - const uint8_t* payload_; - ChunkID id_; -} ChunkData; - -typedef struct WebPInfo { - int canvas_width_; - int canvas_height_; - int loop_count_; - int num_frames_; - int chunk_counts_[CHUNK_TYPES]; - int anmf_subchunk_counts_[3]; // 0 VP8; 1 VP8L; 2 ALPH. - uint32_t bgcolor_; - int feature_flags_; - int has_alpha_; - // Used for parsing ANMF chunks. - int frame_width_, frame_height_; - size_t anim_frame_data_size_; - int is_processing_anim_frame_, seen_alpha_subchunk_, seen_image_subchunk_; - // Print output control. - int quiet_, show_diagnosis_, show_summary_; - int num_warnings_; - int parse_bitstream_; -} WebPInfo; - -static void WebPInfoInit(WebPInfo* const webp_info) { - memset(webp_info, 0, sizeof(*webp_info)); -} - -static const uint32_t kWebPChunkTags[CHUNK_TYPES] = { - MKFOURCC('V', 'P', '8', ' '), - MKFOURCC('V', 'P', '8', 'L'), - MKFOURCC('V', 'P', '8', 'X'), - MKFOURCC('A', 'L', 'P', 'H'), - MKFOURCC('A', 'N', 'I', 'M'), - MKFOURCC('A', 'N', 'M', 'F'), - MKFOURCC('I', 'C', 'C', 'P'), - MKFOURCC('E', 'X', 'I', 'F'), - MKFOURCC('X', 'M', 'P', ' '), -}; - -// ----------------------------------------------------------------------------- -// Data reading. - -static int GetLE16(const uint8_t* const data) { - return (data[0] << 0) | (data[1] << 8); -} - -static int GetLE24(const uint8_t* const data) { - return GetLE16(data) | (data[2] << 16); -} - -static uint32_t GetLE32(const uint8_t* const data) { - return GetLE16(data) | ((uint32_t)GetLE16(data + 2) << 16); -} - -static int ReadLE16(const uint8_t** data) { - const int val = GetLE16(*data); - *data += 2; - return val; -} - -static int ReadLE24(const uint8_t** data) { - const int val = GetLE24(*data); - *data += 3; - return val; -} - -static uint32_t ReadLE32(const uint8_t** data) { - const uint32_t val = GetLE32(*data); - *data += 4; - return val; -} - -static int ReadFileToWebPData(const char* const filename, - WebPData* const webp_data) { - const uint8_t* data; - size_t size; - if (!ImgIoUtilReadFile(filename, &data, &size)) return 0; - webp_data->bytes = data; - webp_data->size = size; - return 1; -} - -// ----------------------------------------------------------------------------- -// MemBuffer object. - -static void InitMemBuffer(MemBuffer* const mem, const WebPData* webp_data) { - mem->buf_ = webp_data->bytes; - mem->start_ = 0; - mem->end_ = webp_data->size; -} - -static size_t MemDataSize(const MemBuffer* const mem) { - return (mem->end_ - mem->start_); -} - -static const uint8_t* GetBuffer(MemBuffer* const mem) { - return mem->buf_ + mem->start_; -} - -static void Skip(MemBuffer* const mem, size_t size) { - mem->start_ += size; -} - -static uint32_t ReadMemBufLE32(MemBuffer* const mem) { - const uint8_t* const data = mem->buf_ + mem->start_; - const uint32_t val = GetLE32(data); - assert(MemDataSize(mem) >= 4); - Skip(mem, 4); - return val; -} - -// ----------------------------------------------------------------------------- -// Lossy bitstream analysis. - -static int GetBits(const uint8_t* const data, size_t data_size, size_t nb, - int* val, uint64_t* const bit_pos) { - *val = 0; - while (nb-- > 0) { - const uint64_t p = (*bit_pos)++; - if ((p >> 3) >= data_size) { - return 0; - } else { - const int bit = !!(data[p >> 3] & (128 >> ((p & 7)))); - *val = (*val << 1) | bit; - } - } - return 1; -} - -static int GetSignedBits(const uint8_t* const data, size_t data_size, size_t nb, - int* val, uint64_t* const bit_pos) { - int sign; - if (!GetBits(data, data_size, nb, val, bit_pos)) return 0; - if (!GetBits(data, data_size, 1, &sign, bit_pos)) return 0; - if (sign) *val = -(*val); - return 1; -} - -#define GET_BITS(v, n) \ - do { \ - if (!GetBits(data, data_size, n, &(v), bit_pos)) { \ - LOG_ERROR("Truncated lossy bitstream."); \ - return WEBP_INFO_TRUNCATED_DATA; \ - } \ - } while (0) - -#define GET_SIGNED_BITS(v, n) \ - do { \ - if (!GetSignedBits(data, data_size, n, &(v), bit_pos)) { \ - LOG_ERROR("Truncated lossy bitstream."); \ - return WEBP_INFO_TRUNCATED_DATA; \ - } \ - } while (0) - -static WebPInfoStatus ParseLossySegmentHeader(const WebPInfo* const webp_info, - const uint8_t* const data, - size_t data_size, - uint64_t* const bit_pos) { - int use_segment; - GET_BITS(use_segment, 1); - printf(" Use segment: %d\n", use_segment); - if (use_segment) { - int update_map, update_data; - GET_BITS(update_map, 1); - GET_BITS(update_data, 1); - printf(" Update map: %d\n" - " Update data: %d\n", - update_map, update_data); - if (update_data) { - int i, a_delta; - int quantizer[4] = {0, 0, 0, 0}; - int filter_strength[4] = {0, 0, 0, 0}; - GET_BITS(a_delta, 1); - printf(" Absolute delta: %d\n", a_delta); - for (i = 0; i < 4; ++i) { - int bit; - GET_BITS(bit, 1); - if (bit) GET_SIGNED_BITS(quantizer[i], 7); - } - for (i = 0; i < 4; ++i) { - int bit; - GET_BITS(bit, 1); - if (bit) GET_SIGNED_BITS(filter_strength[i], 6); - } - printf(" Quantizer: %d %d %d %d\n", quantizer[0], quantizer[1], - quantizer[2], quantizer[3]); - printf(" Filter strength: %d %d %d %d\n", filter_strength[0], - filter_strength[1], filter_strength[2], filter_strength[3]); - } - if (update_map) { - int i; - int prob_segment[3] = {255, 255, 255}; - for (i = 0; i < 3; ++i) { - int bit; - GET_BITS(bit, 1); - if (bit) GET_BITS(prob_segment[i], 8); - } - printf(" Prob segment: %d %d %d\n", - prob_segment[0], prob_segment[1], prob_segment[2]); - } - } - return WEBP_INFO_OK; -} - -static WebPInfoStatus ParseLossyFilterHeader(const WebPInfo* const webp_info, - const uint8_t* const data, - size_t data_size, - uint64_t* const bit_pos) { - int simple_filter, level, sharpness, use_lf_delta; - GET_BITS(simple_filter, 1); - GET_BITS(level, 6); - GET_BITS(sharpness, 3); - GET_BITS(use_lf_delta, 1); - printf(" Simple filter: %d\n", simple_filter); - printf(" Level: %d\n", level); - printf(" Sharpness: %d\n", sharpness); - printf(" Use lf delta: %d\n", use_lf_delta); - if (use_lf_delta) { - int update; - GET_BITS(update, 1); - printf(" Update lf delta: %d\n", update); - if (update) { - int i; - for (i = 0; i < 4 + 4; ++i) { - int temp; - GET_BITS(temp, 1); - if (temp) GET_BITS(temp, 7); - } - } - } - return WEBP_INFO_OK; -} - -static WebPInfoStatus ParseLossyHeader(const ChunkData* const chunk_data, - const WebPInfo* const webp_info) { - const uint8_t* data = chunk_data->payload_; - size_t data_size = chunk_data->size_ - CHUNK_HEADER_SIZE; - const uint32_t bits = (uint32_t)data[0] | (data[1] << 8) | (data[2] << 16); - const int key_frame = !(bits & 1); - const int profile = (bits >> 1) & 7; - const int display = (bits >> 4) & 1; - const uint32_t partition0_length = (bits >> 5); - WebPInfoStatus status = WEBP_INFO_OK; - uint64_t bit_position = 0; - uint64_t* const bit_pos = &bit_position; - int colorspace, clamp_type; - printf(" Parsing lossy bitstream...\n"); - // Calling WebPGetFeatures() in ProcessImageChunk() should ensure this. - assert(chunk_data->size_ >= CHUNK_HEADER_SIZE + 10); - if (profile > 3) { - LOG_ERROR("Unknown profile."); - return WEBP_INFO_BITSTREAM_ERROR; - } - if (!display) { - LOG_ERROR("Frame is not displayable."); - return WEBP_INFO_BITSTREAM_ERROR; - } - data += 3; - data_size -= 3; - printf( - " Key frame: %s\n" - " Profile: %d\n" - " Display: Yes\n" - " Part. 0 length: %d\n", - key_frame ? "Yes" : "No", profile, partition0_length); - if (key_frame) { - if (!(data[0] == 0x9d && data[1] == 0x01 && data[2] == 0x2a)) { - LOG_ERROR("Invalid lossy bitstream signature."); - return WEBP_INFO_BITSTREAM_ERROR; - } - printf(" Width: %d\n" - " X scale: %d\n" - " Height: %d\n" - " Y scale: %d\n", - ((data[4] << 8) | data[3]) & 0x3fff, data[4] >> 6, - ((data[6] << 8) | data[5]) & 0x3fff, data[6] >> 6); - data += 7; - data_size -= 7; - } else { - LOG_ERROR("Non-keyframe detected in lossy bitstream."); - return WEBP_INFO_BITSTREAM_ERROR; - } - if (partition0_length >= data_size) { - LOG_ERROR("Bad partition length."); - return WEBP_INFO_BITSTREAM_ERROR; - } - GET_BITS(colorspace, 1); - GET_BITS(clamp_type, 1); - printf(" Color space: %d\n", colorspace); - printf(" Clamp type: %d\n", clamp_type); - status = ParseLossySegmentHeader(webp_info, data, data_size, bit_pos); - if (status != WEBP_INFO_OK) return status; - status = ParseLossyFilterHeader(webp_info, data, data_size, bit_pos); - if (status != WEBP_INFO_OK) return status; - { // Partition number and size. - const uint8_t* part_size = data + partition0_length; - int num_parts, i; - size_t part_data_size; - GET_BITS(num_parts, 2); - num_parts = 1 << num_parts; - if ((int)(data_size - partition0_length) < (num_parts - 1) * 3) { - LOG_ERROR("Truncated lossy bitstream."); - return WEBP_INFO_TRUNCATED_DATA; - } - part_data_size = data_size - partition0_length - (num_parts - 1) * 3; - printf(" Total partitions: %d\n", num_parts); - for (i = 1; i < num_parts; ++i) { - const size_t psize = - part_size[0] | (part_size[1] << 8) | (part_size[2] << 16); - if (psize > part_data_size) { - LOG_ERROR("Truncated partition."); - return WEBP_INFO_TRUNCATED_DATA; - } - printf(" Part. %d length: %d\n", i, (int)psize); - part_data_size -= psize; - part_size += 3; - } - } - // Quantizer. - { - int base_q, bit; - int dq_y1_dc = 0, dq_y2_dc = 0, dq_y2_ac = 0, dq_uv_dc = 0, dq_uv_ac = 0; - GET_BITS(base_q, 7); - GET_BITS(bit, 1); - if (bit) GET_SIGNED_BITS(dq_y1_dc, 4); - GET_BITS(bit, 1); - if (bit) GET_SIGNED_BITS(dq_y2_dc, 4); - GET_BITS(bit, 1); - if (bit) GET_SIGNED_BITS(dq_y2_ac, 4); - GET_BITS(bit, 1); - if (bit) GET_SIGNED_BITS(dq_uv_dc, 4); - GET_BITS(bit, 1); - if (bit) GET_SIGNED_BITS(dq_uv_ac, 4); - printf(" Base Q: %d\n", base_q); - printf(" DQ Y1 DC: %d\n", dq_y1_dc); - printf(" DQ Y2 DC: %d\n", dq_y2_dc); - printf(" DQ Y2 AC: %d\n", dq_y2_ac); - printf(" DQ UV DC: %d\n", dq_uv_dc); - printf(" DQ UV AC: %d\n", dq_uv_ac); - } - if ((*bit_pos >> 3) >= partition0_length) { - LOG_ERROR("Truncated lossy bitstream."); - return WEBP_INFO_TRUNCATED_DATA; - } - return WEBP_INFO_OK; -} - -// ----------------------------------------------------------------------------- -// Lossless bitstream analysis. - -static int LLGetBits(const uint8_t* const data, size_t data_size, size_t nb, - int* val, uint64_t* const bit_pos) { - uint32_t i = 0; - *val = 0; - while (i < nb) { - const uint64_t p = (*bit_pos)++; - if ((p >> 3) >= data_size) { - return 0; - } else { - const int bit = !!(data[p >> 3] & (1 << ((p & 7)))); - *val = *val | (bit << i); - ++i; - } - } - return 1; -} - -#define LL_GET_BITS(v, n) \ - do { \ - if (!LLGetBits(data, data_size, n, &(v), bit_pos)) { \ - LOG_ERROR("Truncated lossless bitstream."); \ - return WEBP_INFO_TRUNCATED_DATA; \ - } \ - } while (0) - -static WebPInfoStatus ParseLosslessTransform(WebPInfo* const webp_info, - const uint8_t* const data, - size_t data_size, - uint64_t* const bit_pos) { - int use_transform, block_size, n_colors; - LL_GET_BITS(use_transform, 1); - printf(" Use transform: %s\n", use_transform ? "Yes" : "No"); - if (use_transform) { - int type; - LL_GET_BITS(type, 2); - printf(" 1st transform: %s (%d)\n", kLosslessTransforms[type], type); - switch (type) { - case PREDICTOR_TRANSFORM: - case CROSS_COLOR_TRANSFORM: - LL_GET_BITS(block_size, 3); - block_size = 1 << (block_size + 2); - printf(" Tran. block size: %d\n", block_size); - break; - case COLOR_INDEXING_TRANSFORM: - LL_GET_BITS(n_colors, 8); - n_colors += 1; - printf(" No. of colors: %d\n", n_colors); - break; - default: break; - } - } - return WEBP_INFO_OK; -} - -static WebPInfoStatus ParseLosslessHeader(const ChunkData* const chunk_data, - WebPInfo* const webp_info) { - const uint8_t* data = chunk_data->payload_; - size_t data_size = chunk_data->size_ - CHUNK_HEADER_SIZE; - uint64_t bit_position = 0; - uint64_t* const bit_pos = &bit_position; - WebPInfoStatus status; - printf(" Parsing lossless bitstream...\n"); - if (data_size < VP8L_FRAME_HEADER_SIZE) { - LOG_ERROR("Truncated lossless bitstream."); - return WEBP_INFO_TRUNCATED_DATA; - } - if (data[0] != VP8L_MAGIC_BYTE) { - LOG_ERROR("Invalid lossless bitstream signature."); - return WEBP_INFO_BITSTREAM_ERROR; - } - data += 1; - data_size -= 1; - { - int width, height, has_alpha, version; - LL_GET_BITS(width, 14); - LL_GET_BITS(height, 14); - LL_GET_BITS(has_alpha, 1); - LL_GET_BITS(version, 3); - width += 1; - height += 1; - printf(" Width: %d\n", width); - printf(" Height: %d\n", height); - printf(" Alpha: %d\n", has_alpha); - printf(" Version: %d\n", version); - } - status = ParseLosslessTransform(webp_info, data, data_size, bit_pos); - if (status != WEBP_INFO_OK) return status; - return WEBP_INFO_OK; -} - -static WebPInfoStatus ParseAlphaHeader(const ChunkData* const chunk_data, - WebPInfo* const webp_info) { - const uint8_t* data = chunk_data->payload_; - size_t data_size = chunk_data->size_ - CHUNK_HEADER_SIZE; - if (data_size <= ALPHA_HEADER_LEN) { - LOG_ERROR("Truncated ALPH chunk."); - return WEBP_INFO_TRUNCATED_DATA; - } - printf(" Parsing ALPH chunk...\n"); - { - const int compression_method = (data[0] >> 0) & 0x03; - const int filter = (data[0] >> 2) & 0x03; - const int pre_processing = (data[0] >> 4) & 0x03; - const int reserved_bits = (data[0] >> 6) & 0x03; - printf(" Compression: %d\n", compression_method); - printf(" Filter: %s (%d)\n", - kAlphaFilterMethods[filter], filter); - printf(" Pre-processing: %d\n", pre_processing); - if (compression_method > ALPHA_LOSSLESS_COMPRESSION) { - LOG_ERROR("Invalid Alpha compression method."); - return WEBP_INFO_BITSTREAM_ERROR; - } - if (pre_processing > ALPHA_PREPROCESSED_LEVELS) { - LOG_ERROR("Invalid Alpha pre-processing method."); - return WEBP_INFO_BITSTREAM_ERROR; - } - if (reserved_bits != 0) { - LOG_WARN("Reserved bits in ALPH chunk header are not all 0."); - } - data += ALPHA_HEADER_LEN; - data_size -= ALPHA_HEADER_LEN; - if (compression_method == ALPHA_LOSSLESS_COMPRESSION) { - uint64_t bit_pos = 0; - WebPInfoStatus status = - ParseLosslessTransform(webp_info, data, data_size, &bit_pos); - if (status != WEBP_INFO_OK) return status; - } - } - return WEBP_INFO_OK; -} - -// ----------------------------------------------------------------------------- -// Chunk parsing. - -static WebPInfoStatus ParseRIFFHeader(WebPInfo* const webp_info, - MemBuffer* const mem) { - const size_t min_size = RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE; - size_t riff_size; - - if (MemDataSize(mem) < min_size) { - LOG_ERROR("Truncated data detected when parsing RIFF header."); - return WEBP_INFO_TRUNCATED_DATA; - } - if (memcmp(GetBuffer(mem), "RIFF", CHUNK_SIZE_BYTES) || - memcmp(GetBuffer(mem) + CHUNK_HEADER_SIZE, "WEBP", CHUNK_SIZE_BYTES)) { - LOG_ERROR("Corrupted RIFF header."); - return WEBP_INFO_PARSE_ERROR; - } - riff_size = GetLE32(GetBuffer(mem) + TAG_SIZE); - if (riff_size < CHUNK_HEADER_SIZE) { - LOG_ERROR("RIFF size is too small."); - return WEBP_INFO_PARSE_ERROR; - } - if (riff_size > MAX_CHUNK_PAYLOAD) { - LOG_ERROR("RIFF size is over limit."); - return WEBP_INFO_PARSE_ERROR; - } - riff_size += CHUNK_HEADER_SIZE; - if (!webp_info->quiet_) { - printf("RIFF HEADER:\n"); - printf(" File size: %6d\n", (int)riff_size); - } - if (riff_size < mem->end_) { - LOG_WARN("RIFF size is smaller than the file size."); - mem->end_ = riff_size; - } else if (riff_size > mem->end_) { - LOG_ERROR("Truncated data detected when parsing RIFF payload."); - return WEBP_INFO_TRUNCATED_DATA; - } - Skip(mem, RIFF_HEADER_SIZE); - return WEBP_INFO_OK; -} - -static WebPInfoStatus ParseChunk(const WebPInfo* const webp_info, - MemBuffer* const mem, - ChunkData* const chunk_data) { - memset(chunk_data, 0, sizeof(*chunk_data)); - if (MemDataSize(mem) < CHUNK_HEADER_SIZE) { - LOG_ERROR("Truncated data detected when parsing chunk header."); - return WEBP_INFO_TRUNCATED_DATA; - } else { - const size_t chunk_start_offset = mem->start_; - const uint32_t fourcc = ReadMemBufLE32(mem); - const uint32_t payload_size = ReadMemBufLE32(mem); - const uint32_t payload_size_padded = payload_size + (payload_size & 1); - const size_t chunk_size = CHUNK_HEADER_SIZE + payload_size_padded; - int i; - if (payload_size > MAX_CHUNK_PAYLOAD) { - LOG_ERROR("Size of chunk payload is over limit."); - return WEBP_INFO_INVALID_PARAM; - } - if (payload_size_padded > MemDataSize(mem)){ - LOG_ERROR("Truncated data detected when parsing chunk payload."); - return WEBP_INFO_TRUNCATED_DATA; - } - for (i = 0; i < CHUNK_TYPES; ++i) { - if (kWebPChunkTags[i] == fourcc) break; - } - chunk_data->offset_ = chunk_start_offset; - chunk_data->size_ = chunk_size; - chunk_data->id_ = (ChunkID)i; - chunk_data->payload_ = GetBuffer(mem); - if (chunk_data->id_ == CHUNK_ANMF) { - if (payload_size != payload_size_padded) { - LOG_ERROR("ANMF chunk size should always be even."); - return WEBP_INFO_PARSE_ERROR; - } - // There are sub-chunks to be parsed in an ANMF chunk. - Skip(mem, ANMF_CHUNK_SIZE); - } else { - Skip(mem, payload_size_padded); - } - return WEBP_INFO_OK; - } -} - -// ----------------------------------------------------------------------------- -// Chunk analysis. - -static WebPInfoStatus ProcessVP8XChunk(const ChunkData* const chunk_data, - WebPInfo* const webp_info) { - const uint8_t* data = chunk_data->payload_; - if (webp_info->chunk_counts_[CHUNK_VP8] || - webp_info->chunk_counts_[CHUNK_VP8L] || - webp_info->chunk_counts_[CHUNK_VP8X]) { - LOG_ERROR("Already seen a VP8/VP8L/VP8X chunk when parsing VP8X chunk."); - return WEBP_INFO_PARSE_ERROR; - } - if (chunk_data->size_ != VP8X_CHUNK_SIZE + CHUNK_HEADER_SIZE) { - LOG_ERROR("Corrupted VP8X chunk."); - return WEBP_INFO_PARSE_ERROR; - } - ++webp_info->chunk_counts_[CHUNK_VP8X]; - webp_info->feature_flags_ = *data; - data += 4; - webp_info->canvas_width_ = 1 + ReadLE24(&data); - webp_info->canvas_height_ = 1 + ReadLE24(&data); - if (!webp_info->quiet_) { - printf(" ICCP: %d\n Alpha: %d\n EXIF: %d\n XMP: %d\n Animation: %d\n", - (webp_info->feature_flags_ & ICCP_FLAG) != 0, - (webp_info->feature_flags_ & ALPHA_FLAG) != 0, - (webp_info->feature_flags_ & EXIF_FLAG) != 0, - (webp_info->feature_flags_ & XMP_FLAG) != 0, - (webp_info->feature_flags_ & ANIMATION_FLAG) != 0); - printf(" Canvas size %d x %d\n", - webp_info->canvas_width_, webp_info->canvas_height_); - } - if (webp_info->canvas_width_ > MAX_CANVAS_SIZE) { - LOG_WARN("Canvas width is out of range in VP8X chunk."); - } - if (webp_info->canvas_height_ > MAX_CANVAS_SIZE) { - LOG_WARN("Canvas height is out of range in VP8X chunk."); - } - if ((uint64_t)webp_info->canvas_width_ * webp_info->canvas_height_ > - MAX_IMAGE_AREA) { - LOG_WARN("Canvas area is out of range in VP8X chunk."); - } - return WEBP_INFO_OK; -} - -static WebPInfoStatus ProcessANIMChunk(const ChunkData* const chunk_data, - WebPInfo* const webp_info) { - const uint8_t* data = chunk_data->payload_; - if (!webp_info->chunk_counts_[CHUNK_VP8X]) { - LOG_ERROR("ANIM chunk detected before VP8X chunk."); - return WEBP_INFO_PARSE_ERROR; - } - if (chunk_data->size_ != ANIM_CHUNK_SIZE + CHUNK_HEADER_SIZE) { - LOG_ERROR("Corrupted ANIM chunk."); - return WEBP_INFO_PARSE_ERROR; - } - webp_info->bgcolor_ = ReadLE32(&data); - webp_info->loop_count_ = ReadLE16(&data); - ++webp_info->chunk_counts_[CHUNK_ANIM]; - if (!webp_info->quiet_) { - printf(" Background color:(ARGB) %02x %02x %02x %02x\n", - (webp_info->bgcolor_ >> 24) & 0xff, - (webp_info->bgcolor_ >> 16) & 0xff, - (webp_info->bgcolor_ >> 8) & 0xff, - webp_info->bgcolor_ & 0xff); - printf(" Loop count : %d\n", webp_info->loop_count_); - } - if (webp_info->loop_count_ > MAX_LOOP_COUNT) { - LOG_WARN("Loop count is out of range in ANIM chunk."); - } - return WEBP_INFO_OK; -} - -static WebPInfoStatus ProcessANMFChunk(const ChunkData* const chunk_data, - WebPInfo* const webp_info) { - const uint8_t* data = chunk_data->payload_; - int offset_x, offset_y, width, height, duration, blend, dispose, temp; - if (webp_info->is_processing_anim_frame_) { - LOG_ERROR("ANMF chunk detected within another ANMF chunk."); - return WEBP_INFO_PARSE_ERROR; - } - if (!webp_info->chunk_counts_[CHUNK_ANIM]) { - LOG_ERROR("ANMF chunk detected before ANIM chunk."); - return WEBP_INFO_PARSE_ERROR; - } - if (chunk_data->size_ <= CHUNK_HEADER_SIZE + ANMF_CHUNK_SIZE) { - LOG_ERROR("Truncated data detected when parsing ANMF chunk."); - return WEBP_INFO_TRUNCATED_DATA; - } - offset_x = 2 * ReadLE24(&data); - offset_y = 2 * ReadLE24(&data); - width = 1 + ReadLE24(&data); - height = 1 + ReadLE24(&data); - duration = ReadLE24(&data); - temp = *data; - dispose = temp & 1; - blend = (temp >> 1) & 1; - ++webp_info->chunk_counts_[CHUNK_ANMF]; - if (!webp_info->quiet_) { - printf(" Offset_X: %d\n Offset_Y: %d\n Width: %d\n Height: %d\n" - " Duration: %d\n Dispose: %d\n Blend: %d\n", - offset_x, offset_y, width, height, duration, dispose, blend); - } - if (duration > MAX_DURATION) { - LOG_ERROR("Invalid duration parameter in ANMF chunk."); - return WEBP_INFO_INVALID_PARAM; - } - if (offset_x > MAX_POSITION_OFFSET || offset_y > MAX_POSITION_OFFSET) { - LOG_ERROR("Invalid offset parameters in ANMF chunk."); - return WEBP_INFO_INVALID_PARAM; - } - if ((uint64_t)offset_x + width > (uint64_t)webp_info->canvas_width_ || - (uint64_t)offset_y + height > (uint64_t)webp_info->canvas_height_) { - LOG_ERROR("Frame exceeds canvas in ANMF chunk."); - return WEBP_INFO_INVALID_PARAM; - } - webp_info->is_processing_anim_frame_ = 1; - webp_info->seen_alpha_subchunk_ = 0; - webp_info->seen_image_subchunk_ = 0; - webp_info->frame_width_ = width; - webp_info->frame_height_ = height; - webp_info->anim_frame_data_size_ = - chunk_data->size_ - CHUNK_HEADER_SIZE - ANMF_CHUNK_SIZE; - return WEBP_INFO_OK; -} - -static WebPInfoStatus ProcessImageChunk(const ChunkData* const chunk_data, - WebPInfo* const webp_info) { - const uint8_t* data = chunk_data->payload_ - CHUNK_HEADER_SIZE; - WebPBitstreamFeatures features; - const VP8StatusCode vp8_status = - WebPGetFeatures(data, chunk_data->size_, &features); - if (vp8_status != VP8_STATUS_OK) { - LOG_ERROR("VP8/VP8L bitstream error."); - return WEBP_INFO_BITSTREAM_ERROR; - } - if (!webp_info->quiet_) { - assert(features.format >= 0 && features.format <= 2); - printf(" Width: %d\n Height: %d\n Alpha: %d\n Animation: %d\n" - " Format: %s (%d)\n", - features.width, features.height, features.has_alpha, - features.has_animation, kFormats[features.format], features.format); - } - if (webp_info->is_processing_anim_frame_) { - ++webp_info->anmf_subchunk_counts_[chunk_data->id_ == CHUNK_VP8 ? 0 : 1]; - if (chunk_data->id_ == CHUNK_VP8L && webp_info->seen_alpha_subchunk_) { - LOG_ERROR("Both VP8L and ALPH sub-chunks are present in an ANMF chunk."); - return WEBP_INFO_PARSE_ERROR; - } - if (webp_info->frame_width_ != features.width || - webp_info->frame_height_ != features.height) { - LOG_ERROR("Frame size in VP8/VP8L sub-chunk differs from ANMF header."); - return WEBP_INFO_PARSE_ERROR; - } - if (webp_info->seen_image_subchunk_) { - LOG_ERROR("Consecutive VP8/VP8L sub-chunks in an ANMF chunk."); - return WEBP_INFO_PARSE_ERROR; - } - webp_info->seen_image_subchunk_ = 1; - } else { - if (webp_info->chunk_counts_[CHUNK_VP8] || - webp_info->chunk_counts_[CHUNK_VP8L]) { - LOG_ERROR("Multiple VP8/VP8L chunks detected."); - return WEBP_INFO_PARSE_ERROR; - } - if (chunk_data->id_ == CHUNK_VP8L && - webp_info->chunk_counts_[CHUNK_ALPHA]) { - LOG_WARN("Both VP8L and ALPH chunks are detected."); - } - if (webp_info->chunk_counts_[CHUNK_ANIM] || - webp_info->chunk_counts_[CHUNK_ANMF]) { - LOG_ERROR("VP8/VP8L chunk and ANIM/ANMF chunk are both detected."); - return WEBP_INFO_PARSE_ERROR; - } - if (webp_info->chunk_counts_[CHUNK_VP8X]) { - if (webp_info->canvas_width_ != features.width || - webp_info->canvas_height_ != features.height) { - LOG_ERROR("Image size in VP8/VP8L chunk differs from VP8X chunk."); - return WEBP_INFO_PARSE_ERROR; - } - } else { - webp_info->canvas_width_ = features.width; - webp_info->canvas_height_ = features.height; - if (webp_info->canvas_width_ < 1 || webp_info->canvas_height_ < 1 || - webp_info->canvas_width_ > MAX_CANVAS_SIZE || - webp_info->canvas_height_ > MAX_CANVAS_SIZE || - (uint64_t)webp_info->canvas_width_ * webp_info->canvas_height_ > - MAX_IMAGE_AREA) { - LOG_WARN("Invalid parameters in VP8/VP8L chunk."); - } - } - ++webp_info->chunk_counts_[chunk_data->id_]; - } - ++webp_info->num_frames_; - webp_info->has_alpha_ |= features.has_alpha; - if (webp_info->parse_bitstream_) { - const int is_lossy = (chunk_data->id_ == CHUNK_VP8); - const WebPInfoStatus status = - is_lossy ? ParseLossyHeader(chunk_data, webp_info) - : ParseLosslessHeader(chunk_data, webp_info); - if (status != WEBP_INFO_OK) return status; - } - return WEBP_INFO_OK; -} - -static WebPInfoStatus ProcessALPHChunk(const ChunkData* const chunk_data, - WebPInfo* const webp_info) { - if (webp_info->is_processing_anim_frame_) { - ++webp_info->anmf_subchunk_counts_[2]; - if (webp_info->seen_alpha_subchunk_) { - LOG_ERROR("Consecutive ALPH sub-chunks in an ANMF chunk."); - return WEBP_INFO_PARSE_ERROR; - } - webp_info->seen_alpha_subchunk_ = 1; - - if (webp_info->seen_image_subchunk_) { - LOG_ERROR("ALPHA sub-chunk detected after VP8 sub-chunk " - "in an ANMF chunk."); - return WEBP_INFO_PARSE_ERROR; - } - } else { - if (webp_info->chunk_counts_[CHUNK_ANIM] || - webp_info->chunk_counts_[CHUNK_ANMF]) { - LOG_ERROR("ALPHA chunk and ANIM/ANMF chunk are both detected."); - return WEBP_INFO_PARSE_ERROR; - } - if (!webp_info->chunk_counts_[CHUNK_VP8X]) { - LOG_ERROR("ALPHA chunk detected before VP8X chunk."); - return WEBP_INFO_PARSE_ERROR; - } - if (webp_info->chunk_counts_[CHUNK_VP8]) { - LOG_ERROR("ALPHA chunk detected after VP8 chunk."); - return WEBP_INFO_PARSE_ERROR; - } - if (webp_info->chunk_counts_[CHUNK_ALPHA]) { - LOG_ERROR("Multiple ALPHA chunks detected."); - return WEBP_INFO_PARSE_ERROR; - } - ++webp_info->chunk_counts_[CHUNK_ALPHA]; - } - webp_info->has_alpha_ = 1; - if (webp_info->parse_bitstream_) { - const WebPInfoStatus status = ParseAlphaHeader(chunk_data, webp_info); - if (status != WEBP_INFO_OK) return status; - } - return WEBP_INFO_OK; -} - -static WebPInfoStatus ProcessICCPChunk(const ChunkData* const chunk_data, - WebPInfo* const webp_info) { - (void)chunk_data; - if (!webp_info->chunk_counts_[CHUNK_VP8X]) { - LOG_ERROR("ICCP chunk detected before VP8X chunk."); - return WEBP_INFO_PARSE_ERROR; - } - if (webp_info->chunk_counts_[CHUNK_VP8] || - webp_info->chunk_counts_[CHUNK_VP8L] || - webp_info->chunk_counts_[CHUNK_ANIM]) { - LOG_ERROR("ICCP chunk detected after image data."); - return WEBP_INFO_PARSE_ERROR; - } - ++webp_info->chunk_counts_[CHUNK_ICCP]; - return WEBP_INFO_OK; -} - -static WebPInfoStatus ProcessChunk(const ChunkData* const chunk_data, - WebPInfo* const webp_info) { - WebPInfoStatus status = WEBP_INFO_OK; - ChunkID id = chunk_data->id_; - if (chunk_data->id_ == CHUNK_UNKNOWN) { - char error_message[50]; - snprintf(error_message, 50, "Unknown chunk at offset %6d, length %6d", - (int)chunk_data->offset_, (int)chunk_data->size_); - LOG_WARN(error_message); - } else { - if (!webp_info->quiet_) { - char tag[4]; - uint32_t fourcc = kWebPChunkTags[chunk_data->id_]; -#ifdef WORDS_BIGENDIAN - fourcc = (fourcc >> 24) | ((fourcc >> 8) & 0xff00) | - ((fourcc << 8) & 0xff0000) | (fourcc << 24); -#endif - memcpy(tag, &fourcc, sizeof(tag)); - printf("Chunk %c%c%c%c at offset %6d, length %6d\n", - tag[0], tag[1], tag[2], tag[3], (int)chunk_data->offset_, - (int)chunk_data->size_); - } - } - switch (id) { - case CHUNK_VP8: - case CHUNK_VP8L: - status = ProcessImageChunk(chunk_data, webp_info); - break; - case CHUNK_VP8X: - status = ProcessVP8XChunk(chunk_data, webp_info); - break; - case CHUNK_ALPHA: - status = ProcessALPHChunk(chunk_data, webp_info); - break; - case CHUNK_ANIM: - status = ProcessANIMChunk(chunk_data, webp_info); - break; - case CHUNK_ANMF: - status = ProcessANMFChunk(chunk_data, webp_info); - break; - case CHUNK_ICCP: - status = ProcessICCPChunk(chunk_data, webp_info); - break; - case CHUNK_EXIF: - case CHUNK_XMP: - ++webp_info->chunk_counts_[id]; - break; - case CHUNK_UNKNOWN: - default: - break; - } - if (webp_info->is_processing_anim_frame_ && id != CHUNK_ANMF) { - if (webp_info->anim_frame_data_size_ == chunk_data->size_) { - if (!webp_info->seen_image_subchunk_) { - LOG_ERROR("No VP8/VP8L chunk detected in an ANMF chunk."); - return WEBP_INFO_PARSE_ERROR; - } - webp_info->is_processing_anim_frame_ = 0; - } else if (webp_info->anim_frame_data_size_ > chunk_data->size_) { - webp_info->anim_frame_data_size_ -= chunk_data->size_; - } else { - LOG_ERROR("Truncated data detected when parsing ANMF chunk."); - return WEBP_INFO_TRUNCATED_DATA; - } - } - return status; -} - -static WebPInfoStatus Validate(WebPInfo* const webp_info) { - if (webp_info->num_frames_ < 1) { - LOG_ERROR("No image/frame detected."); - return WEBP_INFO_MISSING_DATA; - } - if (webp_info->chunk_counts_[CHUNK_VP8X]) { - const int iccp = !!(webp_info->feature_flags_ & ICCP_FLAG); - const int exif = !!(webp_info->feature_flags_ & EXIF_FLAG); - const int xmp = !!(webp_info->feature_flags_ & XMP_FLAG); - const int animation = !!(webp_info->feature_flags_ & ANIMATION_FLAG); - const int alpha = !!(webp_info->feature_flags_ & ALPHA_FLAG); - if (!alpha && webp_info->has_alpha_) { - LOG_ERROR("Unexpected alpha data detected."); - return WEBP_INFO_PARSE_ERROR; - } - if (alpha && !webp_info->has_alpha_) { - LOG_WARN("Alpha flag is set with no alpha data present."); - } - if (iccp && !webp_info->chunk_counts_[CHUNK_ICCP]) { - LOG_ERROR("Missing ICCP chunk."); - return WEBP_INFO_MISSING_DATA; - } - if (exif && !webp_info->chunk_counts_[CHUNK_EXIF]) { - LOG_ERROR("Missing EXIF chunk."); - return WEBP_INFO_MISSING_DATA; - } - if (xmp && !webp_info->chunk_counts_[CHUNK_XMP]) { - LOG_ERROR("Missing XMP chunk."); - return WEBP_INFO_MISSING_DATA; - } - if (!iccp && webp_info->chunk_counts_[CHUNK_ICCP]) { - LOG_ERROR("Unexpected ICCP chunk detected."); - return WEBP_INFO_PARSE_ERROR; - } - if (!exif && webp_info->chunk_counts_[CHUNK_EXIF]) { - LOG_ERROR("Unexpected EXIF chunk detected."); - return WEBP_INFO_PARSE_ERROR; - } - if (!xmp && webp_info->chunk_counts_[CHUNK_XMP]) { - LOG_ERROR("Unexpected XMP chunk detected."); - return WEBP_INFO_PARSE_ERROR; - } - // Incomplete animation frame. - if (webp_info->is_processing_anim_frame_) return WEBP_INFO_MISSING_DATA; - if (!animation && webp_info->num_frames_ > 1) { - LOG_ERROR("More than 1 frame detected in non-animation file."); - return WEBP_INFO_PARSE_ERROR; - } - if (animation && (!webp_info->chunk_counts_[CHUNK_ANIM] || - !webp_info->chunk_counts_[CHUNK_ANMF])) { - LOG_ERROR("No ANIM/ANMF chunk detected in animation file."); - return WEBP_INFO_PARSE_ERROR; - } - } - return WEBP_INFO_OK; -} - -static void ShowSummary(const WebPInfo* const webp_info) { - int i; - printf("Summary:\n"); - printf("Number of frames: %d\n", webp_info->num_frames_); - printf("Chunk type : VP8 VP8L VP8X ALPH ANIM ANMF(VP8 /VP8L/ALPH) ICCP " - "EXIF XMP\n"); - printf("Chunk counts: "); - for (i = 0; i < CHUNK_TYPES; ++i) { - printf("%4d ", webp_info->chunk_counts_[i]); - if (i == CHUNK_ANMF) { - printf("%4d %4d %4d ", - webp_info->anmf_subchunk_counts_[0], - webp_info->anmf_subchunk_counts_[1], - webp_info->anmf_subchunk_counts_[2]); - } - } - printf("\n"); -} - -static WebPInfoStatus AnalyzeWebP(WebPInfo* const webp_info, - const WebPData* webp_data) { - ChunkData chunk_data; - MemBuffer mem_buffer; - WebPInfoStatus webp_info_status = WEBP_INFO_OK; - - InitMemBuffer(&mem_buffer, webp_data); - webp_info_status = ParseRIFFHeader(webp_info, &mem_buffer); - if (webp_info_status != WEBP_INFO_OK) goto Error; - - // Loop through all the chunks. Terminate immediately in case of error. - while (webp_info_status == WEBP_INFO_OK && MemDataSize(&mem_buffer) > 0) { - webp_info_status = ParseChunk(webp_info, &mem_buffer, &chunk_data); - if (webp_info_status != WEBP_INFO_OK) goto Error; - webp_info_status = ProcessChunk(&chunk_data, webp_info); - } - if (webp_info_status != WEBP_INFO_OK) goto Error; - if (webp_info->show_summary_) ShowSummary(webp_info); - - // Final check. - webp_info_status = Validate(webp_info); - - Error: - if (!webp_info->quiet_) { - if (webp_info_status == WEBP_INFO_OK) { - printf("No error detected.\n"); - } else { - printf("Errors detected.\n"); - } - if (webp_info->num_warnings_ > 0) { - printf("There were %d warning(s).\n", webp_info->num_warnings_); - } - } - return webp_info_status; -} - -static void Help(void) { - printf("Usage: webpinfo [options] in_files\n" - "Note: there could be multiple input files;\n" - " options must come before input files.\n" - "Options:\n" - " -version ........... Print version number and exit.\n" - " -quiet ............. Do not show chunk parsing information.\n" - " -diag .............. Show parsing error diagnosis.\n" - " -summary ........... Show chunk stats summary.\n" - " -bitstream_info .... Parse bitstream header.\n"); -} - -int main(int argc, const char* argv[]) { - int c, quiet = 0, show_diag = 0, show_summary = 0; - int parse_bitstream = 0; - WebPInfoStatus webp_info_status = WEBP_INFO_OK; - WebPInfo webp_info; - - INIT_WARGV(argc, argv); - - if (argc == 1) { - Help(); - FREE_WARGV_AND_RETURN(WEBP_INFO_OK); - } - - // Parse command-line input. - for (c = 1; c < argc; ++c) { - if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help") || - !strcmp(argv[c], "-H") || !strcmp(argv[c], "-longhelp")) { - Help(); - FREE_WARGV_AND_RETURN(WEBP_INFO_OK); - } else if (!strcmp(argv[c], "-quiet")) { - quiet = 1; - } else if (!strcmp(argv[c], "-diag")) { - show_diag = 1; - } else if (!strcmp(argv[c], "-summary")) { - show_summary = 1; - } else if (!strcmp(argv[c], "-bitstream_info")) { - parse_bitstream = 1; - } else if (!strcmp(argv[c], "-version")) { - const int version = WebPGetDecoderVersion(); - printf("WebP Decoder version: %d.%d.%d\n", - (version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff); - FREE_WARGV_AND_RETURN(0); - } else { // Assume the remaining are all input files. - break; - } - } - - if (c == argc) { - Help(); - FREE_WARGV_AND_RETURN(WEBP_INFO_INVALID_COMMAND); - } - - // Process input files one by one. - for (; c < argc; ++c) { - WebPData webp_data; - const W_CHAR* in_file = NULL; - WebPInfoInit(&webp_info); - webp_info.quiet_ = quiet; - webp_info.show_diagnosis_ = show_diag; - webp_info.show_summary_ = show_summary; - webp_info.parse_bitstream_ = parse_bitstream; - in_file = GET_WARGV(argv, c); - if (in_file == NULL || - !ReadFileToWebPData((const char*)in_file, &webp_data)) { - webp_info_status = WEBP_INFO_INVALID_COMMAND; - WFPRINTF(stderr, "Failed to open input file %s.\n", in_file); - continue; - } - if (!webp_info.quiet_) WPRINTF("File: %s\n", in_file); - webp_info_status = AnalyzeWebP(&webp_info, &webp_data); - WebPDataClear(&webp_data); - } - FREE_WARGV_AND_RETURN(webp_info_status); -} diff --git a/libwebp/examples/webpmux.c b/libwebp/examples/webpmux.c deleted file mode 100644 index 9bf45103..00000000 --- a/libwebp/examples/webpmux.c +++ /dev/null @@ -1,1244 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Simple command-line to create a WebP container file and to extract or strip -// relevant data from the container file. -// -// Authors: Vikas (vikaas.arora@gmail.com), -// Urvang (urvang@google.com) - -/* Usage examples: - - Create container WebP file: - webpmux -frame anim_1.webp +100+10+10 \ - -frame anim_2.webp +100+25+25+1 \ - -frame anim_3.webp +100+50+50+1 \ - -frame anim_4.webp +100 \ - -loop 10 -bgcolor 128,255,255,255 \ - -o out_animation_container.webp - - webpmux -set icc image_profile.icc in.webp -o out_icc_container.webp - webpmux -set exif image_metadata.exif in.webp -o out_exif_container.webp - webpmux -set xmp image_metadata.xmp in.webp -o out_xmp_container.webp - webpmux -set loop 1 in.webp -o out_looped.webp - - Extract relevant data from WebP container file: - webpmux -get frame n in.webp -o out_frame.webp - webpmux -get icc in.webp -o image_profile.icc - webpmux -get exif in.webp -o image_metadata.exif - webpmux -get xmp in.webp -o image_metadata.xmp - - Strip data from WebP Container file: - webpmux -strip icc in.webp -o out.webp - webpmux -strip exif in.webp -o out.webp - webpmux -strip xmp in.webp -o out.webp - - Change duration of frame intervals: - webpmux -duration 150 in.webp -o out.webp - webpmux -duration 33,2 in.webp -o out.webp - webpmux -duration 200,10,0 -duration 150,6,50 in.webp -o out.webp - - Misc: - webpmux -info in.webp - webpmux [ -h | -help ] - webpmux -version - webpmux argument_file_name -*/ - -#ifdef HAVE_CONFIG_H -#include "webp/config.h" -#endif - -#include -#include -#include -#include -#include "webp/decode.h" -#include "webp/mux.h" -#include "../examples/example_util.h" -#include "../imageio/imageio_util.h" -#include "./unicode.h" - -//------------------------------------------------------------------------------ -// Config object to parse command-line arguments. - -typedef enum { - NIL_ACTION = 0, - ACTION_GET, - ACTION_SET, - ACTION_STRIP, - ACTION_INFO, - ACTION_HELP, - ACTION_DURATION -} ActionType; - -typedef enum { - NIL_SUBTYPE = 0, - SUBTYPE_ANMF, - SUBTYPE_LOOP, - SUBTYPE_BGCOLOR -} FeatureSubType; - -typedef struct { - FeatureSubType subtype_; - const char* filename_; - const char* params_; -} FeatureArg; - -typedef enum { - NIL_FEATURE = 0, - FEATURE_EXIF, - FEATURE_XMP, - FEATURE_ICCP, - FEATURE_ANMF, - FEATURE_DURATION, - FEATURE_LOOP, - FEATURE_BGCOLOR, - LAST_FEATURE -} FeatureType; - -static const char* const kFourccList[LAST_FEATURE] = { - NULL, "EXIF", "XMP ", "ICCP", "ANMF" -}; - -static const char* const kDescriptions[LAST_FEATURE] = { - NULL, "EXIF metadata", "XMP metadata", "ICC profile", - "Animation frame" -}; - -typedef struct { - CommandLineArguments cmd_args_; - - ActionType action_type_; - const char* input_; - const char* output_; - FeatureType type_; - FeatureArg* args_; - int arg_count_; -} Config; - -//------------------------------------------------------------------------------ -// Helper functions. - -static int CountOccurrences(const CommandLineArguments* const args, - const char* const arg) { - int i; - int num_occurences = 0; - - for (i = 0; i < args->argc_; ++i) { - if (!strcmp(args->argv_[i], arg)) { - ++num_occurences; - } - } - return num_occurences; -} - -static const char* const kErrorMessages[-WEBP_MUX_NOT_ENOUGH_DATA + 1] = { - "WEBP_MUX_NOT_FOUND", "WEBP_MUX_INVALID_ARGUMENT", "WEBP_MUX_BAD_DATA", - "WEBP_MUX_MEMORY_ERROR", "WEBP_MUX_NOT_ENOUGH_DATA" -}; - -static const char* ErrorString(WebPMuxError err) { - assert(err <= WEBP_MUX_NOT_FOUND && err >= WEBP_MUX_NOT_ENOUGH_DATA); - return kErrorMessages[-err]; -} - -#define RETURN_IF_ERROR(ERR_MSG) \ - do { \ - if (err != WEBP_MUX_OK) { \ - fprintf(stderr, ERR_MSG); \ - return err; \ - } \ - } while (0) - -#define RETURN_IF_ERROR3(ERR_MSG, FORMAT_STR1, FORMAT_STR2) \ - do { \ - if (err != WEBP_MUX_OK) { \ - fprintf(stderr, ERR_MSG, FORMAT_STR1, FORMAT_STR2); \ - return err; \ - } \ - } while (0) - -#define ERROR_GOTO1(ERR_MSG, LABEL) \ - do { \ - fprintf(stderr, ERR_MSG); \ - ok = 0; \ - goto LABEL; \ - } while (0) - -#define ERROR_GOTO2(ERR_MSG, FORMAT_STR, LABEL) \ - do { \ - fprintf(stderr, ERR_MSG, FORMAT_STR); \ - ok = 0; \ - goto LABEL; \ - } while (0) - -#define ERROR_GOTO3(ERR_MSG, FORMAT_STR1, FORMAT_STR2, LABEL) \ - do { \ - fprintf(stderr, ERR_MSG, FORMAT_STR1, FORMAT_STR2); \ - ok = 0; \ - goto LABEL; \ - } while (0) - -static WebPMuxError DisplayInfo(const WebPMux* mux) { - int width, height; - uint32_t flag; - - WebPMuxError err = WebPMuxGetCanvasSize(mux, &width, &height); - assert(err == WEBP_MUX_OK); // As WebPMuxCreate() was successful earlier. - printf("Canvas size: %d x %d\n", width, height); - - err = WebPMuxGetFeatures(mux, &flag); - RETURN_IF_ERROR("Failed to retrieve features\n"); - - if (flag == 0) { - printf("No features present.\n"); - return err; - } - - // Print the features present. - printf("Features present:"); - if (flag & ANIMATION_FLAG) printf(" animation"); - if (flag & ICCP_FLAG) printf(" ICC profile"); - if (flag & EXIF_FLAG) printf(" EXIF metadata"); - if (flag & XMP_FLAG) printf(" XMP metadata"); - if (flag & ALPHA_FLAG) printf(" transparency"); - printf("\n"); - - if (flag & ANIMATION_FLAG) { - const WebPChunkId id = WEBP_CHUNK_ANMF; - const char* const type_str = "frame"; - int nFrames; - - WebPMuxAnimParams params; - err = WebPMuxGetAnimationParams(mux, ¶ms); - assert(err == WEBP_MUX_OK); - printf("Background color : 0x%.8X Loop Count : %d\n", - params.bgcolor, params.loop_count); - - err = WebPMuxNumChunks(mux, id, &nFrames); - assert(err == WEBP_MUX_OK); - - printf("Number of %ss: %d\n", type_str, nFrames); - if (nFrames > 0) { - int i; - printf("No.: width height alpha x_offset y_offset "); - printf("duration dispose blend "); - printf("image_size compression\n"); - for (i = 1; i <= nFrames; i++) { - WebPMuxFrameInfo frame; - err = WebPMuxGetFrame(mux, i, &frame); - if (err == WEBP_MUX_OK) { - WebPBitstreamFeatures features; - const VP8StatusCode status = WebPGetFeatures( - frame.bitstream.bytes, frame.bitstream.size, &features); - assert(status == VP8_STATUS_OK); // Checked by WebPMuxCreate(). - (void)status; - printf("%3d: %5d %5d %5s %8d %8d ", i, features.width, - features.height, features.has_alpha ? "yes" : "no", - frame.x_offset, frame.y_offset); - { - const char* const dispose = - (frame.dispose_method == WEBP_MUX_DISPOSE_NONE) ? "none" - : "background"; - const char* const blend = - (frame.blend_method == WEBP_MUX_BLEND) ? "yes" : "no"; - printf("%8d %10s %5s ", frame.duration, dispose, blend); - } - printf("%10d %11s\n", (int)frame.bitstream.size, - (features.format == 1) ? "lossy" : - (features.format == 2) ? "lossless" : - "undefined"); - } - WebPDataClear(&frame.bitstream); - RETURN_IF_ERROR3("Failed to retrieve %s#%d\n", type_str, i); - } - } - } - - if (flag & ICCP_FLAG) { - WebPData icc_profile; - err = WebPMuxGetChunk(mux, "ICCP", &icc_profile); - assert(err == WEBP_MUX_OK); - printf("Size of the ICC profile data: %d\n", (int)icc_profile.size); - } - - if (flag & EXIF_FLAG) { - WebPData exif; - err = WebPMuxGetChunk(mux, "EXIF", &exif); - assert(err == WEBP_MUX_OK); - printf("Size of the EXIF metadata: %d\n", (int)exif.size); - } - - if (flag & XMP_FLAG) { - WebPData xmp; - err = WebPMuxGetChunk(mux, "XMP ", &xmp); - assert(err == WEBP_MUX_OK); - printf("Size of the XMP metadata: %d\n", (int)xmp.size); - } - - if ((flag & ALPHA_FLAG) && !(flag & ANIMATION_FLAG)) { - WebPMuxFrameInfo image; - err = WebPMuxGetFrame(mux, 1, &image); - if (err == WEBP_MUX_OK) { - printf("Size of the image (with alpha): %d\n", (int)image.bitstream.size); - } - WebPDataClear(&image.bitstream); - RETURN_IF_ERROR("Failed to retrieve the image\n"); - } - - return WEBP_MUX_OK; -} - -static void PrintHelp(void) { - printf("Usage: webpmux -get GET_OPTIONS INPUT -o OUTPUT\n"); - printf(" webpmux -set SET_OPTIONS INPUT -o OUTPUT\n"); - printf(" webpmux -duration DURATION_OPTIONS [-duration ...]\n"); - printf(" INPUT -o OUTPUT\n"); - printf(" webpmux -strip STRIP_OPTIONS INPUT -o OUTPUT\n"); - printf(" webpmux -frame FRAME_OPTIONS [-frame...] [-loop LOOP_COUNT]" - "\n"); - printf(" [-bgcolor BACKGROUND_COLOR] -o OUTPUT\n"); - printf(" webpmux -info INPUT\n"); - printf(" webpmux [-h|-help]\n"); - printf(" webpmux -version\n"); - printf(" webpmux argument_file_name\n"); - - printf("\n"); - printf("GET_OPTIONS:\n"); - printf(" Extract relevant data:\n"); - printf(" icc get ICC profile\n"); - printf(" exif get EXIF metadata\n"); - printf(" xmp get XMP metadata\n"); - printf(" frame n get nth frame\n"); - - printf("\n"); - printf("SET_OPTIONS:\n"); - printf(" Set color profile/metadata/parameters:\n"); - printf(" loop LOOP_COUNT set the loop count\n"); - printf(" bgcolor BACKGROUND_COLOR set the animation background color\n"); - printf(" icc file.icc set ICC profile\n"); - printf(" exif file.exif set EXIF metadata\n"); - printf(" xmp file.xmp set XMP metadata\n"); - printf(" where: 'file.icc' contains the ICC profile to be set,\n"); - printf(" 'file.exif' contains the EXIF metadata to be set\n"); - printf(" 'file.xmp' contains the XMP metadata to be set\n"); - - printf("\n"); - printf("DURATION_OPTIONS:\n"); - printf(" Set duration of selected frames:\n"); - printf(" duration set duration for all frames\n"); - printf(" duration,frame set duration of a particular frame\n"); - printf(" duration,start,end set duration of frames in the\n"); - printf(" interval [start,end])\n"); - printf(" where: 'duration' is the duration in milliseconds\n"); - printf(" 'start' is the start frame index\n"); - printf(" 'end' is the inclusive end frame index\n"); - printf(" The special 'end' value '0' means: last frame.\n"); - - printf("\n"); - printf("STRIP_OPTIONS:\n"); - printf(" Strip color profile/metadata:\n"); - printf(" icc strip ICC profile\n"); - printf(" exif strip EXIF metadata\n"); - printf(" xmp strip XMP metadata\n"); - - printf("\n"); - printf("FRAME_OPTIONS(i):\n"); - printf(" Create animation:\n"); - printf(" file_i +di[+xi+yi[+mi[bi]]]\n"); - printf(" where: 'file_i' is the i'th animation frame (WebP format),\n"); - printf(" 'di' is the pause duration before next frame,\n"); - printf(" 'xi','yi' specify the image offset for this frame,\n"); - printf(" 'mi' is the dispose method for this frame (0 or 1),\n"); - printf(" 'bi' is the blending method for this frame (+b or -b)" - "\n"); - - printf("\n"); - printf("LOOP_COUNT:\n"); - printf(" Number of times to repeat the animation.\n"); - printf(" Valid range is 0 to 65535 [Default: 0 (infinite)].\n"); - - printf("\n"); - printf("BACKGROUND_COLOR:\n"); - printf(" Background color of the canvas.\n"); - printf(" A,R,G,B\n"); - printf(" where: 'A', 'R', 'G' and 'B' are integers in the range 0 to 255 " - "specifying\n"); - printf(" the Alpha, Red, Green and Blue component values " - "respectively\n"); - printf(" [Default: 255,255,255,255]\n"); - - printf("\nINPUT & OUTPUT are in WebP format.\n"); - - printf("\nNote: The nature of EXIF, XMP and ICC data is not checked"); - printf(" and is assumed to be\nvalid.\n"); - printf("\nNote: if a single file name is passed as the argument, the " - "arguments will be\n"); - printf("tokenized from this file. The file name must not start with " - "the character '-'.\n"); -} - -static void WarnAboutOddOffset(const WebPMuxFrameInfo* const info) { - if ((info->x_offset | info->y_offset) & 1) { - fprintf(stderr, "Warning: odd offsets will be snapped to even values" - " (%d, %d) -> (%d, %d)\n", info->x_offset, info->y_offset, - info->x_offset & ~1, info->y_offset & ~1); - } -} - -static int CreateMux(const char* const filename, WebPMux** mux) { - WebPData bitstream; - assert(mux != NULL); - if (!ExUtilReadFileToWebPData(filename, &bitstream)) return 0; - *mux = WebPMuxCreate(&bitstream, 1); - WebPDataClear(&bitstream); - if (*mux != NULL) return 1; - WFPRINTF(stderr, "Failed to create mux object from file %s.\n", - (const W_CHAR*)filename); - return 0; -} - -static int WriteData(const char* filename, const WebPData* const webpdata) { - int ok = 0; - FILE* fout = WSTRCMP(filename, "-") ? WFOPEN(filename, "wb") - : ImgIoUtilSetBinaryMode(stdout); - if (fout == NULL) { - WFPRINTF(stderr, "Error opening output WebP file %s!\n", - (const W_CHAR*)filename); - return 0; - } - if (fwrite(webpdata->bytes, webpdata->size, 1, fout) != 1) { - WFPRINTF(stderr, "Error writing file %s!\n", (const W_CHAR*)filename); - } else { - WFPRINTF(stderr, "Saved file %s (%d bytes)\n", - (const W_CHAR*)filename, (int)webpdata->size); - ok = 1; - } - if (fout != stdout) fclose(fout); - return ok; -} - -static int WriteWebP(WebPMux* const mux, const char* filename) { - int ok; - WebPData webp_data; - const WebPMuxError err = WebPMuxAssemble(mux, &webp_data); - if (err != WEBP_MUX_OK) { - fprintf(stderr, "Error (%s) assembling the WebP file.\n", ErrorString(err)); - return 0; - } - ok = WriteData(filename, &webp_data); - WebPDataClear(&webp_data); - return ok; -} - -static WebPMux* DuplicateMuxHeader(const WebPMux* const mux) { - WebPMux* new_mux = WebPMuxNew(); - WebPMuxAnimParams p; - WebPMuxError err; - int i; - int ok = 1; - - if (new_mux == NULL) return NULL; - - err = WebPMuxGetAnimationParams(mux, &p); - if (err == WEBP_MUX_OK) { - err = WebPMuxSetAnimationParams(new_mux, &p); - if (err != WEBP_MUX_OK) { - ERROR_GOTO2("Error (%s) handling animation params.\n", - ErrorString(err), End); - } - } else { - /* it might not be an animation. Just keep moving. */ - } - - for (i = 1; i <= 3; ++i) { - WebPData metadata; - err = WebPMuxGetChunk(mux, kFourccList[i], &metadata); - if (err == WEBP_MUX_OK && metadata.size > 0) { - err = WebPMuxSetChunk(new_mux, kFourccList[i], &metadata, 1); - if (err != WEBP_MUX_OK) { - ERROR_GOTO1("Error transferring metadata in DuplicateMuxHeader().", - End); - } - } - } - - End: - if (!ok) { - WebPMuxDelete(new_mux); - new_mux = NULL; - } - return new_mux; -} - -static int ParseFrameArgs(const char* args, WebPMuxFrameInfo* const info) { - int dispose_method, unused; - char plus_minus, blend_method; - const int num_args = sscanf(args, "+%d+%d+%d+%d%c%c+%d", &info->duration, - &info->x_offset, &info->y_offset, &dispose_method, - &plus_minus, &blend_method, &unused); - switch (num_args) { - case 1: - info->x_offset = info->y_offset = 0; // fall through - case 3: - dispose_method = 0; // fall through - case 4: - plus_minus = '+'; - blend_method = 'b'; // fall through - case 6: - break; - case 2: - case 5: - default: - return 0; - } - - WarnAboutOddOffset(info); - - // Note: The validity of the following conversion is checked by - // WebPMuxPushFrame(). - info->dispose_method = (WebPMuxAnimDispose)dispose_method; - - if (blend_method != 'b') return 0; - if (plus_minus != '-' && plus_minus != '+') return 0; - info->blend_method = - (plus_minus == '+') ? WEBP_MUX_BLEND : WEBP_MUX_NO_BLEND; - return 1; -} - -static int ParseBgcolorArgs(const char* args, uint32_t* const bgcolor) { - uint32_t a, r, g, b; - if (sscanf(args, "%u,%u,%u,%u", &a, &r, &g, &b) != 4) return 0; - if (a >= 256 || r >= 256 || g >= 256 || b >= 256) return 0; - *bgcolor = (a << 24) | (r << 16) | (g << 8) | (b << 0); - return 1; -} - -//------------------------------------------------------------------------------ -// Clean-up. - -static void DeleteConfig(Config* const config) { - if (config != NULL) { - free(config->args_); - ExUtilDeleteCommandLineArguments(&config->cmd_args_); - memset(config, 0, sizeof(*config)); - } -} - -//------------------------------------------------------------------------------ -// Parsing. - -// Basic syntactic checks on the command-line arguments. -// Returns 1 on valid, 0 otherwise. -// Also fills up num_feature_args to be number of feature arguments given. -// (e.g. if there are 4 '-frame's and 1 '-loop', then num_feature_args = 5). -static int ValidateCommandLine(const CommandLineArguments* const cmd_args, - int* num_feature_args) { - int num_frame_args; - int num_loop_args; - int num_bgcolor_args; - int num_durations_args; - int ok = 1; - - assert(num_feature_args != NULL); - *num_feature_args = 0; - - // Simple checks. - if (CountOccurrences(cmd_args, "-get") > 1) { - ERROR_GOTO1("ERROR: Multiple '-get' arguments specified.\n", ErrValidate); - } - if (CountOccurrences(cmd_args, "-set") > 1) { - ERROR_GOTO1("ERROR: Multiple '-set' arguments specified.\n", ErrValidate); - } - if (CountOccurrences(cmd_args, "-strip") > 1) { - ERROR_GOTO1("ERROR: Multiple '-strip' arguments specified.\n", ErrValidate); - } - if (CountOccurrences(cmd_args, "-info") > 1) { - ERROR_GOTO1("ERROR: Multiple '-info' arguments specified.\n", ErrValidate); - } - if (CountOccurrences(cmd_args, "-o") > 1) { - ERROR_GOTO1("ERROR: Multiple output files specified.\n", ErrValidate); - } - - // Compound checks. - num_frame_args = CountOccurrences(cmd_args, "-frame"); - num_loop_args = CountOccurrences(cmd_args, "-loop"); - num_bgcolor_args = CountOccurrences(cmd_args, "-bgcolor"); - num_durations_args = CountOccurrences(cmd_args, "-duration"); - - if (num_loop_args > 1) { - ERROR_GOTO1("ERROR: Multiple loop counts specified.\n", ErrValidate); - } - if (num_bgcolor_args > 1) { - ERROR_GOTO1("ERROR: Multiple background colors specified.\n", ErrValidate); - } - - if ((num_frame_args == 0) && (num_loop_args + num_bgcolor_args > 0)) { - ERROR_GOTO1("ERROR: Loop count and background color are relevant only in " - "case of animation.\n", ErrValidate); - } - if (num_durations_args > 0 && num_frame_args != 0) { - ERROR_GOTO1("ERROR: Can not combine -duration and -frame commands.\n", - ErrValidate); - } - - assert(ok == 1); - if (num_durations_args > 0) { - *num_feature_args = num_durations_args; - } else if (num_frame_args == 0) { - // Single argument ('set' action for ICCP/EXIF/XMP, OR a 'get' action). - *num_feature_args = 1; - } else { - // Multiple arguments ('set' action for animation) - *num_feature_args = num_frame_args + num_loop_args + num_bgcolor_args; - } - - ErrValidate: - return ok; -} - -#define ACTION_IS_NIL (config->action_type_ == NIL_ACTION) - -#define FEATURETYPE_IS_NIL (config->type_ == NIL_FEATURE) - -#define CHECK_NUM_ARGS_AT_LEAST(NUM, LABEL) \ - do { \ - if (argc < i + (NUM)) { \ - fprintf(stderr, "ERROR: Too few arguments for '%s'.\n", argv[i]); \ - goto LABEL; \ - } \ - } while (0) - -#define CHECK_NUM_ARGS_AT_MOST(NUM, LABEL) \ - do { \ - if (argc > i + (NUM)) { \ - fprintf(stderr, "ERROR: Too many arguments for '%s'.\n", argv[i]); \ - goto LABEL; \ - } \ - } while (0) - -#define CHECK_NUM_ARGS_EXACTLY(NUM, LABEL) \ - do { \ - CHECK_NUM_ARGS_AT_LEAST(NUM, LABEL); \ - CHECK_NUM_ARGS_AT_MOST(NUM, LABEL); \ - } while (0) - -// Parses command-line arguments to fill up config object. Also performs some -// semantic checks. unicode_argv contains wchar_t arguments or is null. -static int ParseCommandLine(Config* config, const W_CHAR** const unicode_argv) { - int i = 0; - int feature_arg_index = 0; - int ok = 1; - int argc = config->cmd_args_.argc_; - const char* const* argv = config->cmd_args_.argv_; - // Unicode file paths will be used if available. - const char* const* wargv = - (unicode_argv != NULL) ? (const char**)(unicode_argv + 1) : argv; - - while (i < argc) { - FeatureArg* const arg = &config->args_[feature_arg_index]; - if (argv[i][0] == '-') { // One of the action types or output. - if (!strcmp(argv[i], "-set")) { - if (ACTION_IS_NIL) { - config->action_type_ = ACTION_SET; - } else { - ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse); - } - ++i; - } else if (!strcmp(argv[i], "-duration")) { - CHECK_NUM_ARGS_AT_LEAST(2, ErrParse); - if (ACTION_IS_NIL || config->action_type_ == ACTION_DURATION) { - config->action_type_ = ACTION_DURATION; - } else { - ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse); - } - if (FEATURETYPE_IS_NIL || config->type_ == FEATURE_DURATION) { - config->type_ = FEATURE_DURATION; - } else { - ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse); - } - arg->params_ = argv[i + 1]; - ++feature_arg_index; - i += 2; - } else if (!strcmp(argv[i], "-get")) { - if (ACTION_IS_NIL) { - config->action_type_ = ACTION_GET; - } else { - ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse); - } - ++i; - } else if (!strcmp(argv[i], "-strip")) { - if (ACTION_IS_NIL) { - config->action_type_ = ACTION_STRIP; - config->arg_count_ = 0; - } else { - ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse); - } - ++i; - } else if (!strcmp(argv[i], "-frame")) { - CHECK_NUM_ARGS_AT_LEAST(3, ErrParse); - if (ACTION_IS_NIL || config->action_type_ == ACTION_SET) { - config->action_type_ = ACTION_SET; - } else { - ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse); - } - if (FEATURETYPE_IS_NIL || config->type_ == FEATURE_ANMF) { - config->type_ = FEATURE_ANMF; - } else { - ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse); - } - arg->subtype_ = SUBTYPE_ANMF; - arg->filename_ = wargv[i + 1]; - arg->params_ = argv[i + 2]; - ++feature_arg_index; - i += 3; - } else if (!strcmp(argv[i], "-loop") || !strcmp(argv[i], "-bgcolor")) { - CHECK_NUM_ARGS_AT_LEAST(2, ErrParse); - if (ACTION_IS_NIL || config->action_type_ == ACTION_SET) { - config->action_type_ = ACTION_SET; - } else { - ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse); - } - if (FEATURETYPE_IS_NIL || config->type_ == FEATURE_ANMF) { - config->type_ = FEATURE_ANMF; - } else { - ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse); - } - arg->subtype_ = - !strcmp(argv[i], "-loop") ? SUBTYPE_LOOP : SUBTYPE_BGCOLOR; - arg->params_ = argv[i + 1]; - ++feature_arg_index; - i += 2; - } else if (!strcmp(argv[i], "-o")) { - CHECK_NUM_ARGS_AT_LEAST(2, ErrParse); - config->output_ = wargv[i + 1]; - i += 2; - } else if (!strcmp(argv[i], "-info")) { - CHECK_NUM_ARGS_EXACTLY(2, ErrParse); - if (config->action_type_ != NIL_ACTION) { - ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse); - } else { - config->action_type_ = ACTION_INFO; - config->arg_count_ = 0; - config->input_ = wargv[i + 1]; - } - i += 2; - } else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "-help")) { - PrintHelp(); - DeleteConfig(config); - LOCAL_FREE((W_CHAR** const)unicode_argv); - exit(0); - } else if (!strcmp(argv[i], "-version")) { - const int version = WebPGetMuxVersion(); - printf("%d.%d.%d\n", - (version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff); - DeleteConfig(config); - LOCAL_FREE((W_CHAR** const)unicode_argv); - exit(0); - } else if (!strcmp(argv[i], "--")) { - if (i < argc - 1) { - ++i; - if (config->input_ == NULL) { - config->input_ = wargv[i]; - } else { - ERROR_GOTO2("ERROR at '%s': Multiple input files specified.\n", - argv[i], ErrParse); - } - } - break; - } else { - ERROR_GOTO2("ERROR: Unknown option: '%s'.\n", argv[i], ErrParse); - } - } else { // One of the feature types or input. - if (ACTION_IS_NIL) { - ERROR_GOTO1("ERROR: Action must be specified before other arguments.\n", - ErrParse); - } - if (!strcmp(argv[i], "icc") || !strcmp(argv[i], "exif") || - !strcmp(argv[i], "xmp")) { - if (FEATURETYPE_IS_NIL) { - config->type_ = (!strcmp(argv[i], "icc")) ? FEATURE_ICCP : - (!strcmp(argv[i], "exif")) ? FEATURE_EXIF : FEATURE_XMP; - } else { - ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse); - } - if (config->action_type_ == ACTION_SET) { - CHECK_NUM_ARGS_AT_LEAST(2, ErrParse); - arg->filename_ = wargv[i + 1]; - ++feature_arg_index; - i += 2; - } else { - ++i; - } - } else if (!strcmp(argv[i], "frame") && - (config->action_type_ == ACTION_GET)) { - CHECK_NUM_ARGS_AT_LEAST(2, ErrParse); - config->type_ = FEATURE_ANMF; - arg->params_ = argv[i + 1]; - ++feature_arg_index; - i += 2; - } else if (!strcmp(argv[i], "loop") && - (config->action_type_ == ACTION_SET)) { - CHECK_NUM_ARGS_AT_LEAST(2, ErrParse); - config->type_ = FEATURE_LOOP; - arg->params_ = argv[i + 1]; - ++feature_arg_index; - i += 2; - } else if (!strcmp(argv[i], "bgcolor") && - (config->action_type_ == ACTION_SET)) { - CHECK_NUM_ARGS_AT_LEAST(2, ErrParse); - config->type_ = FEATURE_BGCOLOR; - arg->params_ = argv[i + 1]; - ++feature_arg_index; - i += 2; - } else { // Assume input file. - if (config->input_ == NULL) { - config->input_ = wargv[i]; - } else { - ERROR_GOTO2("ERROR at '%s': Multiple input files specified.\n", - argv[i], ErrParse); - } - ++i; - } - } - } - ErrParse: - return ok; -} - -// Additional checks after config is filled. -static int ValidateConfig(Config* const config) { - int ok = 1; - - // Action. - if (ACTION_IS_NIL) { - ERROR_GOTO1("ERROR: No action specified.\n", ErrValidate2); - } - - // Feature type. - if (FEATURETYPE_IS_NIL && config->action_type_ != ACTION_INFO) { - ERROR_GOTO1("ERROR: No feature specified.\n", ErrValidate2); - } - - // Input file. - if (config->input_ == NULL) { - if (config->action_type_ != ACTION_SET) { - ERROR_GOTO1("ERROR: No input file specified.\n", ErrValidate2); - } else if (config->type_ != FEATURE_ANMF) { - ERROR_GOTO1("ERROR: No input file specified.\n", ErrValidate2); - } - } - - // Output file. - if (config->output_ == NULL && config->action_type_ != ACTION_INFO) { - ERROR_GOTO1("ERROR: No output file specified.\n", ErrValidate2); - } - - ErrValidate2: - return ok; -} - -// Create config object from command-line arguments. -static int InitializeConfig(int argc, const char* argv[], Config* const config, - const W_CHAR** const unicode_argv) { - int num_feature_args = 0; - int ok; - - memset(config, 0, sizeof(*config)); - - ok = ExUtilInitCommandLineArguments(argc, argv, &config->cmd_args_); - if (!ok) return 0; - - // Validate command-line arguments. - if (!ValidateCommandLine(&config->cmd_args_, &num_feature_args)) { - ERROR_GOTO1("Exiting due to command-line parsing error.\n", Err1); - } - - config->arg_count_ = num_feature_args; - config->args_ = (FeatureArg*)calloc(num_feature_args, sizeof(*config->args_)); - if (config->args_ == NULL) { - ERROR_GOTO1("ERROR: Memory allocation error.\n", Err1); - } - - // Parse command-line. - if (!ParseCommandLine(config, unicode_argv) || !ValidateConfig(config)) { - ERROR_GOTO1("Exiting due to command-line parsing error.\n", Err1); - } - - Err1: - return ok; -} - -#undef ACTION_IS_NIL -#undef FEATURETYPE_IS_NIL -#undef CHECK_NUM_ARGS_AT_LEAST -#undef CHECK_NUM_ARGS_AT_MOST -#undef CHECK_NUM_ARGS_EXACTLY - -//------------------------------------------------------------------------------ -// Processing. - -static int GetFrame(const WebPMux* mux, const Config* config) { - WebPMuxError err = WEBP_MUX_OK; - WebPMux* mux_single = NULL; - int num = 0; - int ok = 1; - int parse_error = 0; - const WebPChunkId id = WEBP_CHUNK_ANMF; - WebPMuxFrameInfo info; - WebPDataInit(&info.bitstream); - - num = ExUtilGetInt(config->args_[0].params_, 10, &parse_error); - if (num < 0) { - ERROR_GOTO1("ERROR: Frame/Fragment index must be non-negative.\n", ErrGet); - } - if (parse_error) goto ErrGet; - - err = WebPMuxGetFrame(mux, num, &info); - if (err == WEBP_MUX_OK && info.id != id) err = WEBP_MUX_NOT_FOUND; - if (err != WEBP_MUX_OK) { - ERROR_GOTO3("ERROR (%s): Could not get frame %d.\n", - ErrorString(err), num, ErrGet); - } - - mux_single = WebPMuxNew(); - if (mux_single == NULL) { - err = WEBP_MUX_MEMORY_ERROR; - ERROR_GOTO2("ERROR (%s): Could not allocate a mux object.\n", - ErrorString(err), ErrGet); - } - err = WebPMuxSetImage(mux_single, &info.bitstream, 1); - if (err != WEBP_MUX_OK) { - ERROR_GOTO2("ERROR (%s): Could not create single image mux object.\n", - ErrorString(err), ErrGet); - } - - ok = WriteWebP(mux_single, config->output_); - - ErrGet: - WebPDataClear(&info.bitstream); - WebPMuxDelete(mux_single); - return ok && !parse_error; -} - -// Read and process config. -static int Process(const Config* config) { - WebPMux* mux = NULL; - WebPData chunk; - WebPMuxError err = WEBP_MUX_OK; - int ok = 1; - - switch (config->action_type_) { - case ACTION_GET: { - ok = CreateMux(config->input_, &mux); - if (!ok) goto Err2; - switch (config->type_) { - case FEATURE_ANMF: - ok = GetFrame(mux, config); - break; - - case FEATURE_ICCP: - case FEATURE_EXIF: - case FEATURE_XMP: - err = WebPMuxGetChunk(mux, kFourccList[config->type_], &chunk); - if (err != WEBP_MUX_OK) { - ERROR_GOTO3("ERROR (%s): Could not get the %s.\n", - ErrorString(err), kDescriptions[config->type_], Err2); - } - ok = WriteData(config->output_, &chunk); - break; - - default: - ERROR_GOTO1("ERROR: Invalid feature for action 'get'.\n", Err2); - break; - } - break; - } - case ACTION_SET: { - switch (config->type_) { - case FEATURE_ANMF: { - int i; - WebPMuxAnimParams params = { 0xFFFFFFFF, 0 }; - mux = WebPMuxNew(); - if (mux == NULL) { - ERROR_GOTO2("ERROR (%s): Could not allocate a mux object.\n", - ErrorString(WEBP_MUX_MEMORY_ERROR), Err2); - } - for (i = 0; i < config->arg_count_; ++i) { - switch (config->args_[i].subtype_) { - case SUBTYPE_BGCOLOR: { - uint32_t bgcolor; - ok = ParseBgcolorArgs(config->args_[i].params_, &bgcolor); - if (!ok) { - ERROR_GOTO1("ERROR: Could not parse the background color \n", - Err2); - } - params.bgcolor = bgcolor; - break; - } - case SUBTYPE_LOOP: { - int parse_error = 0; - const int loop_count = - ExUtilGetInt(config->args_[i].params_, 10, &parse_error); - if (loop_count < 0 || loop_count > 65535) { - // Note: This is only a 'necessary' condition for loop_count - // to be valid. The 'sufficient' conditioned in checked in - // WebPMuxSetAnimationParams() method called later. - ERROR_GOTO1("ERROR: Loop count must be in the range 0 to " - "65535.\n", Err2); - } - ok = !parse_error; - if (!ok) goto Err2; - params.loop_count = loop_count; - break; - } - case SUBTYPE_ANMF: { - WebPMuxFrameInfo frame; - frame.id = WEBP_CHUNK_ANMF; - ok = ExUtilReadFileToWebPData(config->args_[i].filename_, - &frame.bitstream); - if (!ok) goto Err2; - ok = ParseFrameArgs(config->args_[i].params_, &frame); - if (!ok) { - WebPDataClear(&frame.bitstream); - ERROR_GOTO1("ERROR: Could not parse frame properties.\n", - Err2); - } - err = WebPMuxPushFrame(mux, &frame, 1); - WebPDataClear(&frame.bitstream); - if (err != WEBP_MUX_OK) { - ERROR_GOTO3("ERROR (%s): Could not add a frame at index %d." - "\n", ErrorString(err), i, Err2); - } - break; - } - default: { - ERROR_GOTO1("ERROR: Invalid subtype for 'frame'", Err2); - break; - } - } - } - err = WebPMuxSetAnimationParams(mux, ¶ms); - if (err != WEBP_MUX_OK) { - ERROR_GOTO2("ERROR (%s): Could not set animation parameters.\n", - ErrorString(err), Err2); - } - break; - } - - case FEATURE_ICCP: - case FEATURE_EXIF: - case FEATURE_XMP: { - ok = CreateMux(config->input_, &mux); - if (!ok) goto Err2; - ok = ExUtilReadFileToWebPData(config->args_[0].filename_, &chunk); - if (!ok) goto Err2; - err = WebPMuxSetChunk(mux, kFourccList[config->type_], &chunk, 1); - WebPDataClear(&chunk); - if (err != WEBP_MUX_OK) { - ERROR_GOTO3("ERROR (%s): Could not set the %s.\n", - ErrorString(err), kDescriptions[config->type_], Err2); - } - break; - } - case FEATURE_LOOP: { - WebPMuxAnimParams params = { 0xFFFFFFFF, 0 }; - int parse_error = 0; - const int loop_count = - ExUtilGetInt(config->args_[0].params_, 10, &parse_error); - if (loop_count < 0 || loop_count > 65535 || parse_error) { - ERROR_GOTO1("ERROR: Loop count must be in the range 0 to 65535.\n", - Err2); - } - ok = CreateMux(config->input_, &mux); - if (!ok) goto Err2; - ok = (WebPMuxGetAnimationParams(mux, ¶ms) == WEBP_MUX_OK); - if (!ok) { - ERROR_GOTO1("ERROR: input file does not seem to be an animation.\n", - Err2); - } - params.loop_count = loop_count; - err = WebPMuxSetAnimationParams(mux, ¶ms); - ok = (err == WEBP_MUX_OK); - if (!ok) { - ERROR_GOTO2("ERROR (%s): Could not set animation parameters.\n", - ErrorString(err), Err2); - } - break; - } - case FEATURE_BGCOLOR: { - WebPMuxAnimParams params = { 0xFFFFFFFF, 0 }; - uint32_t bgcolor; - ok = ParseBgcolorArgs(config->args_[0].params_, &bgcolor); - if (!ok) { - ERROR_GOTO1("ERROR: Could not parse the background color.\n", - Err2); - } - ok = CreateMux(config->input_, &mux); - if (!ok) goto Err2; - ok = (WebPMuxGetAnimationParams(mux, ¶ms) == WEBP_MUX_OK); - if (!ok) { - ERROR_GOTO1("ERROR: input file does not seem to be an animation.\n", - Err2); - } - params.bgcolor = bgcolor; - err = WebPMuxSetAnimationParams(mux, ¶ms); - ok = (err == WEBP_MUX_OK); - if (!ok) { - ERROR_GOTO2("ERROR (%s): Could not set animation parameters.\n", - ErrorString(err), Err2); - } - break; - } - default: { - ERROR_GOTO1("ERROR: Invalid feature for action 'set'.\n", Err2); - break; - } - } - ok = WriteWebP(mux, config->output_); - break; - } - case ACTION_DURATION: { - int num_frames; - ok = CreateMux(config->input_, &mux); - if (!ok) goto Err2; - err = WebPMuxNumChunks(mux, WEBP_CHUNK_ANMF, &num_frames); - ok = (err == WEBP_MUX_OK); - if (!ok) { - ERROR_GOTO1("ERROR: can not parse the number of frames.\n", Err2); - } - if (num_frames == 0) { - fprintf(stderr, "Doesn't look like the source is animated. " - "Skipping duration setting.\n"); - ok = WriteWebP(mux, config->output_); - if (!ok) goto Err2; - } else { - int i; - int* durations = NULL; - WebPMux* new_mux = DuplicateMuxHeader(mux); - if (new_mux == NULL) goto Err2; - durations = (int*)WebPMalloc((size_t)num_frames * sizeof(*durations)); - if (durations == NULL) goto Err2; - for (i = 0; i < num_frames; ++i) durations[i] = -1; - - // Parse intervals to process. - for (i = 0; i < config->arg_count_; ++i) { - int k; - int args[3]; - int duration, start, end; - const int nb_args = ExUtilGetInts(config->args_[i].params_, - 10, 3, args); - ok = (nb_args >= 1); - if (!ok) goto Err3; - duration = args[0]; - if (duration < 0) { - ERROR_GOTO1("ERROR: duration must be strictly positive.\n", Err3); - } - - if (nb_args == 1) { // only duration is present -> use full interval - start = 1; - end = num_frames; - } else { - start = args[1]; - if (start <= 0) { - start = 1; - } else if (start > num_frames) { - start = num_frames; - } - end = (nb_args >= 3) ? args[2] : start; - if (end == 0 || end > num_frames) end = num_frames; - } - - for (k = start; k <= end; ++k) { - assert(k >= 1 && k <= num_frames); - durations[k - 1] = duration; - } - } - - // Apply non-negative durations to their destination frames. - for (i = 1; i <= num_frames; ++i) { - WebPMuxFrameInfo frame; - err = WebPMuxGetFrame(mux, i, &frame); - if (err != WEBP_MUX_OK || frame.id != WEBP_CHUNK_ANMF) { - ERROR_GOTO2("ERROR: can not retrieve frame #%d.\n", i, Err3); - } - if (durations[i - 1] >= 0) frame.duration = durations[i - 1]; - err = WebPMuxPushFrame(new_mux, &frame, 1); - if (err != WEBP_MUX_OK) { - ERROR_GOTO2("ERROR: error push frame data #%d\n", i, Err3); - } - WebPDataClear(&frame.bitstream); - } - WebPMuxDelete(mux); - ok = WriteWebP(new_mux, config->output_); - mux = new_mux; // transfer for the WebPMuxDelete() call - new_mux = NULL; - - Err3: - WebPFree(durations); - WebPMuxDelete(new_mux); - if (!ok) goto Err2; - } - break; - } - case ACTION_STRIP: { - ok = CreateMux(config->input_, &mux); - if (!ok) goto Err2; - if (config->type_ == FEATURE_ICCP || config->type_ == FEATURE_EXIF || - config->type_ == FEATURE_XMP) { - err = WebPMuxDeleteChunk(mux, kFourccList[config->type_]); - if (err != WEBP_MUX_OK) { - ERROR_GOTO3("ERROR (%s): Could not strip the %s.\n", - ErrorString(err), kDescriptions[config->type_], Err2); - } - } else { - ERROR_GOTO1("ERROR: Invalid feature for action 'strip'.\n", Err2); - break; - } - ok = WriteWebP(mux, config->output_); - break; - } - case ACTION_INFO: { - ok = CreateMux(config->input_, &mux); - if (!ok) goto Err2; - ok = (DisplayInfo(mux) == WEBP_MUX_OK); - break; - } - default: { - assert(0); // Invalid action. - break; - } - } - - Err2: - WebPMuxDelete(mux); - return ok; -} - -//------------------------------------------------------------------------------ -// Main. - -int main(int argc, const char* argv[]) { - Config config; - int ok; - - INIT_WARGV(argc, argv); - - ok = InitializeConfig(argc - 1, argv + 1, &config, GET_WARGV_OR_NULL()); - if (ok) { - ok = Process(&config); - } else { - PrintHelp(); - } - DeleteConfig(&config); - FREE_WARGV_AND_RETURN(!ok); -} - -//------------------------------------------------------------------------------ diff --git a/libwebp/extras/Makefile.am b/libwebp/extras/Makefile.am deleted file mode 100644 index d5a9af49..00000000 --- a/libwebp/extras/Makefile.am +++ /dev/null @@ -1,45 +0,0 @@ -AM_CPPFLAGS += -I$(top_builddir) -I$(top_srcdir) -AM_CPPFLAGS += -I$(top_builddir)/src -I$(top_srcdir)/src -noinst_LTLIBRARIES = libwebpextras.la - -noinst_HEADERS = -noinst_HEADERS += ../src/webp/types.h - -libwebpextras_la_SOURCES = -libwebpextras_la_SOURCES += extras.c extras.h quality_estimate.c -libwebpextras_la_SOURCES += sharpyuv_risk_table.c sharpyuv_risk_table.h - -libwebpextras_la_CPPFLAGS = $(AM_CPPFLAGS) -libwebpextras_la_LDFLAGS = -lm -libwebpextras_la_LIBADD = ../src/libwebp.la - -noinst_PROGRAMS = -noinst_PROGRAMS += webp_quality -if BUILD_DEMUX - noinst_PROGRAMS += get_disto -endif -if BUILD_VWEBP_SDL - noinst_PROGRAMS += vwebp_sdl -endif - -get_disto_SOURCES = get_disto.c -get_disto_CPPFLAGS = $(AM_CPPFLAGS) -get_disto_LDADD = -get_disto_LDADD += ../imageio/libimageio_util.la -get_disto_LDADD += ../imageio/libimagedec.la -get_disto_LDADD += ../src/libwebp.la -get_disto_LDADD += $(PNG_LIBS) $(JPEG_LIBS) $(TIFF_LIBS) - -webp_quality_SOURCES = webp_quality.c -webp_quality_CPPFLAGS = $(AM_CPPFLAGS) -webp_quality_LDADD = -webp_quality_LDADD += ../imageio/libimageio_util.la -webp_quality_LDADD += libwebpextras.la -webp_quality_LDADD += ../src/libwebp.la - -vwebp_sdl_SOURCES = vwebp_sdl.c webp_to_sdl.c webp_to_sdl.h -vwebp_sdl_CPPFLAGS = $(AM_CPPFLAGS) $(SDL_INCLUDES) -vwebp_sdl_LDADD = -vwebp_sdl_LDADD += ../imageio/libimageio_util.la -vwebp_sdl_LDADD += ../src/libwebp.la -vwebp_sdl_LDADD += $(SDL_LIBS) diff --git a/libwebp/extras/extras.c b/libwebp/extras/extras.c deleted file mode 100644 index ba9f4bc9..00000000 --- a/libwebp/extras/extras.c +++ /dev/null @@ -1,324 +0,0 @@ -// Copyright 2015 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Additional WebP utilities. -// - -#include "extras/extras.h" - -#include -#include -#include - -#include "extras/sharpyuv_risk_table.h" -#include "sharpyuv/sharpyuv.h" -#include "src/dsp/dsp.h" -#include "src/utils/utils.h" -#include "webp/format_constants.h" -#include "webp/types.h" - -#define XTRA_MAJ_VERSION 1 -#define XTRA_MIN_VERSION 3 -#define XTRA_REV_VERSION 2 - -//------------------------------------------------------------------------------ - -int WebPGetExtrasVersion(void) { - return (XTRA_MAJ_VERSION << 16) | (XTRA_MIN_VERSION << 8) | XTRA_REV_VERSION; -} - -//------------------------------------------------------------------------------ - -int WebPImportGray(const uint8_t* gray_data, WebPPicture* pic) { - int y, width, uv_width; - if (pic == NULL || gray_data == NULL) return 0; - pic->colorspace = WEBP_YUV420; - if (!WebPPictureAlloc(pic)) return 0; - width = pic->width; - uv_width = (width + 1) >> 1; - for (y = 0; y < pic->height; ++y) { - memcpy(pic->y + y * pic->y_stride, gray_data, width); - gray_data += width; // <- we could use some 'data_stride' here if needed - if ((y & 1) == 0) { - memset(pic->u + (y >> 1) * pic->uv_stride, 128, uv_width); - memset(pic->v + (y >> 1) * pic->uv_stride, 128, uv_width); - } - } - return 1; -} - -int WebPImportRGB565(const uint8_t* rgb565, WebPPicture* pic) { - int x, y; - uint32_t* dst; - if (pic == NULL || rgb565 == NULL) return 0; - pic->colorspace = WEBP_YUV420; - pic->use_argb = 1; - if (!WebPPictureAlloc(pic)) return 0; - dst = pic->argb; - for (y = 0; y < pic->height; ++y) { - const int width = pic->width; - for (x = 0; x < width; ++x) { -#if defined(WEBP_SWAP_16BIT_CSP) && (WEBP_SWAP_16BIT_CSP == 1) - const uint32_t rg = rgb565[2 * x + 1]; - const uint32_t gb = rgb565[2 * x + 0]; -#else - const uint32_t rg = rgb565[2 * x + 0]; - const uint32_t gb = rgb565[2 * x + 1]; -#endif - uint32_t r = rg & 0xf8; - uint32_t g = ((rg << 5) | (gb >> 3)) & 0xfc; - uint32_t b = (gb << 5); - // dithering - r = r | (r >> 5); - g = g | (g >> 6); - b = b | (b >> 5); - dst[x] = (0xffu << 24) | (r << 16) | (g << 8) | b; - } - rgb565 += 2 * width; - dst += pic->argb_stride; - } - return 1; -} - -int WebPImportRGB4444(const uint8_t* rgb4444, WebPPicture* pic) { - int x, y; - uint32_t* dst; - if (pic == NULL || rgb4444 == NULL) return 0; - pic->colorspace = WEBP_YUV420; - pic->use_argb = 1; - if (!WebPPictureAlloc(pic)) return 0; - dst = pic->argb; - for (y = 0; y < pic->height; ++y) { - const int width = pic->width; - for (x = 0; x < width; ++x) { -#if defined(WEBP_SWAP_16BIT_CSP) && (WEBP_SWAP_16BIT_CSP == 1) - const uint32_t rg = rgb4444[2 * x + 1]; - const uint32_t ba = rgb4444[2 * x + 0]; -#else - const uint32_t rg = rgb4444[2 * x + 0]; - const uint32_t ba = rgb4444[2 * x + 1]; -#endif - uint32_t r = rg & 0xf0; - uint32_t g = (rg << 4); - uint32_t b = (ba & 0xf0); - uint32_t a = (ba << 4); - // dithering - r = r | (r >> 4); - g = g | (g >> 4); - b = b | (b >> 4); - a = a | (a >> 4); - dst[x] = (a << 24) | (r << 16) | (g << 8) | b; - } - rgb4444 += 2 * width; - dst += pic->argb_stride; - } - return 1; -} - -int WebPImportColorMappedARGB(const uint8_t* indexed, int indexed_stride, - const uint32_t palette[], int palette_size, - WebPPicture* pic) { - int x, y; - uint32_t* dst; - // 256 as the input buffer is uint8_t. - assert(MAX_PALETTE_SIZE <= 256); - if (pic == NULL || indexed == NULL || indexed_stride < pic->width || - palette == NULL || palette_size > MAX_PALETTE_SIZE || palette_size <= 0) { - return 0; - } - pic->use_argb = 1; - if (!WebPPictureAlloc(pic)) return 0; - dst = pic->argb; - for (y = 0; y < pic->height; ++y) { - for (x = 0; x < pic->width; ++x) { - // Make sure we are within the palette. - if (indexed[x] >= palette_size) { - WebPPictureFree(pic); - return 0; - } - dst[x] = palette[indexed[x]]; - } - indexed += indexed_stride; - dst += pic->argb_stride; - } - return 1; -} - -//------------------------------------------------------------------------------ - -int WebPUnmultiplyARGB(WebPPicture* pic) { - int y; - uint32_t* dst; - if (pic == NULL || pic->use_argb != 1 || pic->argb == NULL) return 0; - WebPInitAlphaProcessing(); - dst = pic->argb; - for (y = 0; y < pic->height; ++y) { - WebPMultARGBRow(dst, pic->width, /*inverse=*/1); - dst += pic->argb_stride; - } - return 1; -} - -//------------------------------------------------------------------------------ -// 420 risk metric - -#define YUV_FIX 16 // fixed-point precision for RGB->YUV -static const int kYuvHalf = 1 << (YUV_FIX - 1); - -// Maps a value in [0, (256 << YUV_FIX) - 1] to [0, -// precomputed_scores_table_sampling - 1]. It is important that the extremal -// values are preserved and 1:1 mapped: -// ConvertValue(0) = 0 -// ConvertValue((256 << 16) - 1) = rgb_sampling_size - 1 -static int SharpYuvConvertValueToSampledIdx(int v, int rgb_sampling_size) { - v = (v + kYuvHalf) >> YUV_FIX; - v = (v < 0) ? 0 : (v > 255) ? 255 : v; - return (v * (rgb_sampling_size - 1)) / 255; -} - -#undef YUV_FIX - -// For each pixel, computes the index to look up that color in a precomputed -// risk score table where the YUV space is subsampled to a size of -// precomputed_scores_table_sampling^3 (see sharpyuv_risk_table.h) -static int SharpYuvConvertToYuvSharpnessIndex( - int r, int g, int b, const SharpYuvConversionMatrix* matrix, - int precomputed_scores_table_sampling) { - const int y = SharpYuvConvertValueToSampledIdx( - matrix->rgb_to_y[0] * r + matrix->rgb_to_y[1] * g + - matrix->rgb_to_y[2] * b + matrix->rgb_to_y[3], - precomputed_scores_table_sampling); - const int u = SharpYuvConvertValueToSampledIdx( - matrix->rgb_to_u[0] * r + matrix->rgb_to_u[1] * g + - matrix->rgb_to_u[2] * b + matrix->rgb_to_u[3], - precomputed_scores_table_sampling); - const int v = SharpYuvConvertValueToSampledIdx( - matrix->rgb_to_v[0] * r + matrix->rgb_to_v[1] * g + - matrix->rgb_to_v[2] * b + matrix->rgb_to_v[3], - precomputed_scores_table_sampling); - return y + u * precomputed_scores_table_sampling + - v * precomputed_scores_table_sampling * - precomputed_scores_table_sampling; -} - -static void SharpYuvRowToYuvSharpnessIndex( - const uint8_t* r_ptr, const uint8_t* g_ptr, const uint8_t* b_ptr, - int rgb_step, int rgb_bit_depth, int width, uint16_t* dst, - const SharpYuvConversionMatrix* matrix, - int precomputed_scores_table_sampling) { - int i; - assert(rgb_bit_depth == 8); - (void)rgb_bit_depth; // Unused for now. - for (i = 0; i < width; - ++i, r_ptr += rgb_step, g_ptr += rgb_step, b_ptr += rgb_step) { - dst[i] = - SharpYuvConvertToYuvSharpnessIndex(r_ptr[0], g_ptr[0], b_ptr[0], matrix, - precomputed_scores_table_sampling); - } -} - -#define SAFE_ALLOC(W, H, T) ((T*)WebPSafeMalloc((uint64_t)(W) * (H), sizeof(T))) - -static int DoEstimateRisk(const uint8_t* r_ptr, const uint8_t* g_ptr, - const uint8_t* b_ptr, int rgb_step, int rgb_stride, - int rgb_bit_depth, int width, int height, - const SharpYuvOptions* options, - const uint8_t precomputed_scores_table[], - int precomputed_scores_table_sampling, - float* score_out) { - const int sampling3 = precomputed_scores_table_sampling * - precomputed_scores_table_sampling * - precomputed_scores_table_sampling; - const int kNoiseLevel = 4; - double total_score = 0; - double count = 0; - // Rows of indices in - uint16_t* row1 = SAFE_ALLOC(width, 1, uint16_t); - uint16_t* row2 = SAFE_ALLOC(width, 1, uint16_t); - uint16_t* tmp; - int i, j; - - if (row1 == NULL || row2 == NULL) { - WebPFree(row1); - WebPFree(row2); - return 0; - } - - // Convert the first row ahead. - SharpYuvRowToYuvSharpnessIndex(r_ptr, g_ptr, b_ptr, rgb_step, rgb_bit_depth, - width, row2, options->yuv_matrix, - precomputed_scores_table_sampling); - - for (j = 1; j < height; ++j) { - r_ptr += rgb_stride; - g_ptr += rgb_stride; - b_ptr += rgb_stride; - // Swap row 1 and row 2. - tmp = row1; - row1 = row2; - row2 = tmp; - // Convert the row below. - SharpYuvRowToYuvSharpnessIndex(r_ptr, g_ptr, b_ptr, rgb_step, rgb_bit_depth, - width, row2, options->yuv_matrix, - precomputed_scores_table_sampling); - for (i = 0; i < width - 1; ++i) { - const int idx0 = row1[i + 0]; - const int idx1 = row1[i + 1]; - const int idx2 = row2[i + 0]; - const int score = precomputed_scores_table[idx0 + sampling3 * idx1] + - precomputed_scores_table[idx0 + sampling3 * idx2] + - precomputed_scores_table[idx1 + sampling3 * idx2]; - if (score > kNoiseLevel) { - total_score += score; - count += 1.0; - } - } - } - if (count > 0.) total_score /= count; - - // If less than 1% of pixels were evaluated -> below noise level. - if (100. * count / (width * height) < 1.) total_score = 0.; - - // Rescale to [0:100] - total_score = (total_score > 25.) ? 100. : total_score * 100. / 25.; - - WebPFree(row1); - WebPFree(row2); - - *score_out = (float)total_score; - return 1; -} - -#undef SAFE_ALLOC - -int SharpYuvEstimate420Risk(const void* r_ptr, const void* g_ptr, - const void* b_ptr, int rgb_step, int rgb_stride, - int rgb_bit_depth, int width, int height, - const SharpYuvOptions* options, float* score) { - if (width < 1 || height < 1 || width == INT_MAX || height == INT_MAX || - r_ptr == NULL || g_ptr == NULL || b_ptr == NULL || options == NULL || - score == NULL) { - return 0; - } - if (rgb_bit_depth != 8) { - return 0; - } - - if (width <= 4 || height <= 4) { - *score = 0.0f; // too small, no real risk. - return 1; - } - - return DoEstimateRisk( - (const uint8_t*)r_ptr, (const uint8_t*)g_ptr, (const uint8_t*)b_ptr, - rgb_step, rgb_stride, rgb_bit_depth, width, height, options, - kSharpYuvPrecomputedRisk, kSharpYuvPrecomputedRiskYuvSampling, score); -} - -//------------------------------------------------------------------------------ diff --git a/libwebp/extras/extras.h b/libwebp/extras/extras.h deleted file mode 100644 index 3cc9d700..00000000 --- a/libwebp/extras/extras.h +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2015 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// - -#ifndef WEBP_EXTRAS_EXTRAS_H_ -#define WEBP_EXTRAS_EXTRAS_H_ - -#include "webp/types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#include "sharpyuv/sharpyuv.h" -#include "webp/encode.h" - -#define WEBP_EXTRAS_ABI_VERSION 0x0003 // MAJOR(8b) + MINOR(8b) - -//------------------------------------------------------------------------------ - -// Returns the version number of the extras library, packed in hexadecimal using -// 8bits for each of major/minor/revision. E.g: v2.5.7 is 0x020507. -WEBP_EXTERN int WebPGetExtrasVersion(void); - -//------------------------------------------------------------------------------ -// Ad-hoc colorspace importers. - -// Import luma sample (gray scale image) into 'picture'. The 'picture' -// width and height must be set prior to calling this function. -WEBP_EXTERN int WebPImportGray(const uint8_t* gray, WebPPicture* picture); - -// Import rgb sample in RGB565 packed format into 'picture'. The 'picture' -// width and height must be set prior to calling this function. -WEBP_EXTERN int WebPImportRGB565(const uint8_t* rgb565, WebPPicture* pic); - -// Import rgb sample in RGB4444 packed format into 'picture'. The 'picture' -// width and height must be set prior to calling this function. -WEBP_EXTERN int WebPImportRGB4444(const uint8_t* rgb4444, WebPPicture* pic); - -// Import a color mapped image. The number of colors is less or equal to -// MAX_PALETTE_SIZE. 'pic' must have been initialized. Its content, if any, -// will be discarded. Returns 'false' in case of error, or if indexed[] contains -// invalid indices. -WEBP_EXTERN int -WebPImportColorMappedARGB(const uint8_t* indexed, int indexed_stride, - const uint32_t palette[], int palette_size, - WebPPicture* pic); - -// Convert the ARGB content of 'pic' from associated to unassociated. -// 'pic' can be for instance the result of calling of some WebPPictureImportXXX -// functions, with pic->use_argb set to 'true'. It is assumed (and not checked) -// that the pre-multiplied r/g/b values as less or equal than the alpha value. -// Return false in case of error (invalid parameter, ...). -WEBP_EXTERN int WebPUnmultiplyARGB(WebPPicture* pic); - -//------------------------------------------------------------------------------ - -// Parse a bitstream, search for VP8 (lossy) header and report a -// rough estimation of the quality factor used for compressing the bitstream. -// If the bitstream is in lossless format, the special value '101' is returned. -// Otherwise (lossy bitstream), the returned value is in the range [0..100]. -// Any error (invalid bitstream, animated WebP, incomplete header, etc.) -// will return a value of -1. -WEBP_EXTERN int VP8EstimateQuality(const uint8_t* const data, size_t size); - -//------------------------------------------------------------------------------ - -// Computes a score between 0 and 100 which represents the risk of having visual -// quality loss from converting an RGB image to YUV420. -// A low score, typically < 40, means there is a low risk of artifacts from -// chroma subsampling and a simple averaging algorithm can be used instead of -// the more expensive SharpYuvConvert function. -// A medium score, typically >= 40 and < 70, means that simple chroma -// subsampling will produce artifacts and it may be advisable to use the more -// costly SharpYuvConvert for YUV420 conversion. -// A high score, typically >= 70, means there is a very high risk of artifacts -// from chroma subsampling even with SharpYuvConvert, and best results might be -// achieved by using YUV444. -// If not using SharpYuvConvert, a threshold of about 50 can be used to decide -// between (simple averaging) 420 and 444. -// r_ptr, g_ptr, b_ptr: pointers to the source r, g and b channels. Should point -// to uint8_t buffers if rgb_bit_depth is 8, or uint16_t buffers otherwise. -// rgb_step: distance in bytes between two horizontally adjacent pixels on the -// r, g and b channels. If rgb_bit_depth is > 8, it should be a -// multiple of 2. -// rgb_stride: distance in bytes between two vertically adjacent pixels on the -// r, g, and b channels. If rgb_bit_depth is > 8, it should be a -// multiple of 2. -// rgb_bit_depth: number of bits for each r/g/b value. Only a value of 8 is -// currently supported. -// width, height: width and height of the image in pixels -// Returns 0 on failure. -WEBP_EXTERN int SharpYuvEstimate420Risk( - const void* r_ptr, const void* g_ptr, const void* b_ptr, int rgb_step, - int rgb_stride, int rgb_bit_depth, int width, int height, - const SharpYuvOptions* options, float* score); - -//------------------------------------------------------------------------------ - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // WEBP_EXTRAS_EXTRAS_H_ diff --git a/libwebp/extras/get_disto.c b/libwebp/extras/get_disto.c deleted file mode 100644 index 3aa345bb..00000000 --- a/libwebp/extras/get_disto.c +++ /dev/null @@ -1,356 +0,0 @@ -// Copyright 2016 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Simple tool to load two webp/png/jpg/tiff files and compute PSNR/SSIM. -// This is mostly a wrapper around WebPPictureDistortion(). -// -/* - gcc -o get_disto get_disto.c -O3 -I../ -L../examples -L../imageio \ - -lexample_util -limageio_util -limagedec -lwebp -L/opt/local/lib \ - -lpng -lz -ljpeg -ltiff -lm -lpthread -*/ -// -// Author: Skal (pascal.massimino@gmail.com) - -#include -#include -#include -#include - -#include "webp/encode.h" -#include "imageio/image_dec.h" -#include "imageio/imageio_util.h" -#include "../examples/unicode.h" - -static size_t ReadPicture(const char* const filename, WebPPicture* const pic, - int keep_alpha) { - const uint8_t* data = NULL; - size_t data_size = 0; - WebPImageReader reader = NULL; - int ok = ImgIoUtilReadFile(filename, &data, &data_size); - if (!ok) goto End; - - pic->use_argb = 1; // force ARGB - -#ifdef HAVE_WINCODEC_H - // Try to decode the file using WIC falling back to the other readers for - // e.g., WebP. - ok = ReadPictureWithWIC(filename, pic, keep_alpha, NULL); - if (ok) goto End; -#endif - reader = WebPGuessImageReader(data, data_size); - ok = reader(data, data_size, pic, keep_alpha, NULL); - - End: - if (!ok) { - WFPRINTF(stderr, "Error! Could not process file %s\n", - (const W_CHAR*)filename); - } - free((void*)data); - return ok ? data_size : 0; -} - -static void RescalePlane(uint8_t* plane, int width, int height, - int x_stride, int y_stride, int max) { - const uint32_t factor = (max > 0) ? (255u << 16) / max : 0; - int x, y; - for (y = 0; y < height; ++y) { - uint8_t* const ptr = plane + y * y_stride; - for (x = 0; x < width * x_stride; x += x_stride) { - const uint32_t diff = (ptr[x] * factor + (1 << 15)) >> 16; - ptr[x] = diff; - } - } -} - -// Return the max absolute difference. -static int DiffScaleChannel(uint8_t* src1, int stride1, - const uint8_t* src2, int stride2, - int x_stride, int w, int h, int do_scaling) { - int x, y; - int max = 0; - for (y = 0; y < h; ++y) { - uint8_t* const ptr1 = src1 + y * stride1; - const uint8_t* const ptr2 = src2 + y * stride2; - for (x = 0; x < w * x_stride; x += x_stride) { - const int diff = abs(ptr1[x] - ptr2[x]); - if (diff > max) max = diff; - ptr1[x] = diff; - } - } - - if (do_scaling) RescalePlane(src1, w, h, x_stride, stride1, max); - return max; -} - -//------------------------------------------------------------------------------ -// SSIM calculation. We re-implement these functions here, out of dsp/, to avoid -// breaking the library's hidden visibility. This code duplication avoids the -// bigger annoyance of having to open up internal details of libdsp... - -#define SSIM_KERNEL 3 // total size of the kernel: 2 * SSIM_KERNEL + 1 - -// struct for accumulating statistical moments -typedef struct { - uint32_t w; // sum(w_i) : sum of weights - uint32_t xm, ym; // sum(w_i * x_i), sum(w_i * y_i) - uint32_t xxm, xym, yym; // sum(w_i * x_i * x_i), etc. -} DistoStats; - -// hat-shaped filter. Sum of coefficients is equal to 16. -static const uint32_t kWeight[2 * SSIM_KERNEL + 1] = { 1, 2, 3, 4, 3, 2, 1 }; - -static WEBP_INLINE double SSIMCalculation(const DistoStats* const stats) { - const uint32_t N = stats->w; - const uint32_t w2 = N * N; - const uint32_t C1 = 20 * w2; - const uint32_t C2 = 60 * w2; - const uint32_t C3 = 8 * 8 * w2; // 'dark' limit ~= 6 - const uint64_t xmxm = (uint64_t)stats->xm * stats->xm; - const uint64_t ymym = (uint64_t)stats->ym * stats->ym; - if (xmxm + ymym >= C3) { - const int64_t xmym = (int64_t)stats->xm * stats->ym; - const int64_t sxy = (int64_t)stats->xym * N - xmym; // can be negative - const uint64_t sxx = (uint64_t)stats->xxm * N - xmxm; - const uint64_t syy = (uint64_t)stats->yym * N - ymym; - // we descale by 8 to prevent overflow during the fnum/fden multiply. - const uint64_t num_S = (2 * (uint64_t)(sxy < 0 ? 0 : sxy) + C2) >> 8; - const uint64_t den_S = (sxx + syy + C2) >> 8; - const uint64_t fnum = (2 * xmym + C1) * num_S; - const uint64_t fden = (xmxm + ymym + C1) * den_S; - const double r = (double)fnum / fden; - assert(r >= 0. && r <= 1.0); - return r; - } - return 1.; // area is too dark to contribute meaningfully -} - -static double SSIMGetClipped(const uint8_t* src1, int stride1, - const uint8_t* src2, int stride2, - int xo, int yo, int W, int H) { - DistoStats stats = { 0, 0, 0, 0, 0, 0 }; - const int ymin = (yo - SSIM_KERNEL < 0) ? 0 : yo - SSIM_KERNEL; - const int ymax = (yo + SSIM_KERNEL > H - 1) ? H - 1 : yo + SSIM_KERNEL; - const int xmin = (xo - SSIM_KERNEL < 0) ? 0 : xo - SSIM_KERNEL; - const int xmax = (xo + SSIM_KERNEL > W - 1) ? W - 1 : xo + SSIM_KERNEL; - int x, y; - src1 += ymin * stride1; - src2 += ymin * stride2; - for (y = ymin; y <= ymax; ++y, src1 += stride1, src2 += stride2) { - for (x = xmin; x <= xmax; ++x) { - const uint32_t w = kWeight[SSIM_KERNEL + x - xo] - * kWeight[SSIM_KERNEL + y - yo]; - const uint32_t s1 = src1[x]; - const uint32_t s2 = src2[x]; - stats.w += w; - stats.xm += w * s1; - stats.ym += w * s2; - stats.xxm += w * s1 * s1; - stats.xym += w * s1 * s2; - stats.yym += w * s2 * s2; - } - } - return SSIMCalculation(&stats); -} - -// Compute SSIM-score map. Return -1 in case of error, max diff otherwise. -static int SSIMScaleChannel(uint8_t* src1, int stride1, - const uint8_t* src2, int stride2, - int x_stride, int w, int h, int do_scaling) { - int x, y; - int max = 0; - uint8_t* const plane1 = (uint8_t*)malloc(2 * w * h * sizeof(*plane1)); - uint8_t* const plane2 = plane1 + w * h; - if (plane1 == NULL) return -1; - - // extract plane - for (y = 0; y < h; ++y) { - for (x = 0; x < w; ++x) { - plane1[x + y * w] = src1[x * x_stride + y * stride1]; - plane2[x + y * w] = src2[x * x_stride + y * stride2]; - } - } - for (y = 0; y < h; ++y) { - for (x = 0; x < w; ++x) { - const double ssim = SSIMGetClipped(plane1, w, plane2, w, x, y, w, h); - int diff = (int)(255 * (1. - ssim)); - if (diff < 0) { - diff = 0; - } else if (diff > max) { - max = diff; - } - src1[x * x_stride + y * stride1] = (diff > 255) ? 255u : (uint8_t)diff; - } - } - free(plane1); - - if (do_scaling) RescalePlane(src1, w, h, x_stride, stride1, max); - return max; -} - -// Convert an argb picture to luminance. -static void ConvertToGray(WebPPicture* const pic) { - int x, y; - assert(pic != NULL); - assert(pic->use_argb); - for (y = 0; y < pic->height; ++y) { - uint32_t* const row = &pic->argb[y * pic->argb_stride]; - for (x = 0; x < pic->width; ++x) { - const uint32_t argb = row[x]; - const uint32_t r = (argb >> 16) & 0xff; - const uint32_t g = (argb >> 8) & 0xff; - const uint32_t b = (argb >> 0) & 0xff; - // We use BT.709 for converting to luminance. - const uint32_t Y = (uint32_t)(0.2126 * r + 0.7152 * g + 0.0722 * b + .5); - row[x] = (argb & 0xff000000u) | (Y * 0x010101u); - } - } -} - -static void Help(void) { - fprintf(stderr, - "Usage: get_disto [-ssim][-psnr][-alpha] compressed.webp orig.webp\n" - " -ssim ..... print SSIM distortion\n" - " -psnr ..... print PSNR distortion (default)\n" - " -alpha .... preserve alpha plane\n" - " -h ........ this message\n" - " -o . save the diff map as a WebP lossless file\n" - " -scale .... scale the difference map to fit [0..255] range\n" - " -gray ..... use grayscale for difference map (-scale)\n" - "\nSupported input formats:\n %s\n", - WebPGetEnabledInputFileFormats()); -} - -int main(int argc, const char* argv[]) { - WebPPicture pic1, pic2; - size_t size1 = 0, size2 = 0; - int ret = 1; - float disto[5]; - int type = 0; - int c; - int help = 0; - int keep_alpha = 0; - int scale = 0; - int use_gray = 0; - const char* name1 = NULL; - const char* name2 = NULL; - const char* output = NULL; - - INIT_WARGV(argc, argv); - - if (!WebPPictureInit(&pic1) || !WebPPictureInit(&pic2)) { - fprintf(stderr, "Can't init pictures\n"); - FREE_WARGV_AND_RETURN(1); - } - - for (c = 1; c < argc; ++c) { - if (!strcmp(argv[c], "-ssim")) { - type = 1; - } else if (!strcmp(argv[c], "-psnr")) { - type = 0; - } else if (!strcmp(argv[c], "-alpha")) { - keep_alpha = 1; - } else if (!strcmp(argv[c], "-scale")) { - scale = 1; - } else if (!strcmp(argv[c], "-gray")) { - use_gray = 1; - } else if (!strcmp(argv[c], "-h")) { - help = 1; - ret = 0; - } else if (!strcmp(argv[c], "-o")) { - if (++c == argc) { - fprintf(stderr, "missing file name after %s option.\n", argv[c - 1]); - goto End; - } - output = (const char*)GET_WARGV(argv, c); - } else if (name1 == NULL) { - name1 = (const char*)GET_WARGV(argv, c); - } else { - name2 = (const char*)GET_WARGV(argv, c); - } - } - if (help || name1 == NULL || name2 == NULL) { - if (!help) { - fprintf(stderr, "Error: missing arguments.\n"); - } - Help(); - goto End; - } - size1 = ReadPicture(name1, &pic1, 1); - size2 = ReadPicture(name2, &pic2, 1); - if (size1 == 0 || size2 == 0) goto End; - - if (!keep_alpha) { - WebPBlendAlpha(&pic1, 0x00000000); - WebPBlendAlpha(&pic2, 0x00000000); - } - - if (!WebPPictureDistortion(&pic1, &pic2, type, disto)) { - fprintf(stderr, "Error while computing the distortion.\n"); - goto End; - } - printf("%u %.2f %.2f %.2f %.2f %.2f [ %.2f bpp ]\n", - (unsigned int)size1, - disto[4], disto[0], disto[1], disto[2], disto[3], - 8.f * size1 / pic1.width / pic1.height); - - if (output != NULL) { - uint8_t* data = NULL; - size_t data_size = 0; - if (pic1.use_argb != pic2.use_argb) { - fprintf(stderr, "Pictures are not in the same argb format. " - "Can't save the difference map.\n"); - goto End; - } - if (pic1.use_argb) { - int n; - fprintf(stderr, "max differences per channel: "); - for (n = 0; n < 3; ++n) { // skip the alpha channel - const int range = (type == 1) ? - SSIMScaleChannel((uint8_t*)pic1.argb + n, pic1.argb_stride * 4, - (const uint8_t*)pic2.argb + n, pic2.argb_stride * 4, - 4, pic1.width, pic1.height, scale) : - DiffScaleChannel((uint8_t*)pic1.argb + n, pic1.argb_stride * 4, - (const uint8_t*)pic2.argb + n, pic2.argb_stride * 4, - 4, pic1.width, pic1.height, scale); - if (range < 0) fprintf(stderr, "\nError computing diff map\n"); - fprintf(stderr, "[%d]", range); - } - fprintf(stderr, "\n"); - if (use_gray) ConvertToGray(&pic1); - } else { - fprintf(stderr, "Can only compute the difference map in ARGB format.\n"); - goto End; - } -#if !defined(WEBP_REDUCE_CSP) - data_size = WebPEncodeLosslessBGRA((const uint8_t*)pic1.argb, - pic1.width, pic1.height, - pic1.argb_stride * 4, - &data); - if (data_size == 0) { - fprintf(stderr, "Error during lossless encoding.\n"); - goto End; - } - ret = ImgIoUtilWriteFile(output, data, data_size) ? 0 : 1; - WebPFree(data); - if (ret) goto End; -#else - (void)data; - (void)data_size; - fprintf(stderr, "Cannot save the difference map. Please recompile " - "without the WEBP_REDUCE_CSP flag.\n"); -#endif // WEBP_REDUCE_CSP - } - ret = 0; - - End: - WebPPictureFree(&pic1); - WebPPictureFree(&pic2); - FREE_WARGV_AND_RETURN(ret); -} diff --git a/libwebp/extras/quality_estimate.c b/libwebp/extras/quality_estimate.c deleted file mode 100644 index 17e98d96..00000000 --- a/libwebp/extras/quality_estimate.c +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright 2016 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// VP8EstimateQuality(): rough encoding quality estimate -// -// Author: Skal (pascal.massimino@gmail.com) - -#include "extras/extras.h" -#include "webp/decode.h" - -#include - -//------------------------------------------------------------------------------ - -#define INVALID_BIT_POS (1ull << 63) - -// In most cases, we don't need to use a full arithmetic decoder, since -// all the header's bits are written using a uniform probability of 128. -// We can just parse the header as if it was bits (works in 99.999% cases). -static WEBP_INLINE uint32_t GetBit(const uint8_t* const data, size_t nb, - uint64_t max_size, uint64_t* const bit_pos) { - uint32_t val = 0; - if (*bit_pos + nb <= 8 * max_size) { - while (nb-- > 0) { - const uint64_t p = (*bit_pos)++; - const int bit = !!(data[p >> 3] & (128 >> ((p & 7)))); - val = (val << 1) | bit; - } - } else { - *bit_pos = INVALID_BIT_POS; - } - return val; -} - -#define GET_BIT(n) GetBit(data, (n), size, &bit_pos) -#define CONDITIONAL_SKIP(n) (GET_BIT(1) ? GET_BIT((n)) : 0) - -int VP8EstimateQuality(const uint8_t* const data, size_t size) { - size_t pos = 0; - uint64_t bit_pos; - uint64_t sig = 0x00; - int ok = 0; - int Q = -1; - WebPBitstreamFeatures features; - - if (data == NULL) return -1; - - if (WebPGetFeatures(data, size, &features) != VP8_STATUS_OK) { - return -1; // invalid file - } - if (features.format == 2) return 101; // lossless - if (features.format == 0 || features.has_animation) return -1; // mixed - - while (pos < size) { - sig = (sig >> 8) | ((uint64_t)data[pos++] << 40); - if ((sig >> 24) == 0x2a019dull) { - ok = 1; - break; - } - } - if (!ok) return -1; - if (pos + 4 > size) return -1; - - // Skip main Header - // width = (data[pos + 0] | (data[pos + 1] << 8)) & 0x3fff; - // height = (data[pos + 2] | (data[pos + 3] << 8)) & 0x3fff; - pos += 4; - bit_pos = pos * 8; - - GET_BIT(2); // colorspace + clamp type - - // Segment header - if (GET_BIT(1)) { // use_segment_ - int s; - const int update_map = GET_BIT(1); - if (GET_BIT(1)) { // update data - const int absolute_delta = GET_BIT(1); - int q[4] = { 0, 0, 0, 0 }; - for (s = 0; s < 4; ++s) { - if (GET_BIT(1)) { - q[s] = GET_BIT(7); - if (GET_BIT(1)) q[s] = -q[s]; // sign - } - } - if (absolute_delta) Q = q[0]; // just use the first segment's quantizer - for (s = 0; s < 4; ++s) CONDITIONAL_SKIP(7); // filter strength - } - if (update_map) { - for (s = 0; s < 3; ++s) CONDITIONAL_SKIP(8); - } - } - // Filter header - GET_BIT(1 + 6 + 3); // simple + level + sharpness - if (GET_BIT(1)) { // use_lf_delta - if (GET_BIT(1)) { // update lf_delta? - int n; - for (n = 0; n < 4 + 4; ++n) CONDITIONAL_SKIP(6); - } - } - // num partitions - GET_BIT(2); - - // ParseQuant - { - const int base_q = GET_BIT(7); - /* dqy1_dc = */ CONDITIONAL_SKIP(5); - /* dqy2_dc = */ CONDITIONAL_SKIP(5); - /* dqy2_ac = */ CONDITIONAL_SKIP(5); - /* dquv_dc = */ CONDITIONAL_SKIP(5); - /* dquv_ac = */ CONDITIONAL_SKIP(5); - - if (Q < 0) Q = base_q; - } - if (bit_pos == INVALID_BIT_POS) return -1; - - // base mapping - Q = (127 - Q) * 100 / 127; - // correction for power-law behavior in low range - if (Q < 80) { - Q = (int)(pow(Q / 80., 1. / 0.38) * 80); - } - return Q; -} diff --git a/libwebp/extras/sharpyuv_risk_table.c b/libwebp/extras/sharpyuv_risk_table.c deleted file mode 100644 index ab3e7fdd..00000000 --- a/libwebp/extras/sharpyuv_risk_table.c +++ /dev/null @@ -1,6210 +0,0 @@ -// Copyright 2023 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Precomputed data for 420 risk estimation. - -#include "src/webp/types.h" - -const int kSharpYuvPrecomputedRiskYuvSampling = 7; - -const uint8_t kSharpYuvPrecomputedRisk[] = { - 0, 2, 2, 3, 3, 2, 2, 1, 2, 2, 3, 2, 2, 1, 2, 1, 2, 2, 2, - 1, 2, 2, 1, 1, 2, 2, 3, 4, 4, 4, 4, 4, 5, 4, 4, 8, 8, 8, - 7, 5, 4, 4, 14, 12, 9, 8, 6, 4, 4, 2, 1, 2, 2, 2, 2, 1, 2, - 0, 2, 2, 2, 1, 1, 2, 1, 1, 2, 2, 1, 3, 2, 2, 2, 2, 2, 3, - 4, 5, 5, 5, 5, 5, 4, 4, 11, 9, 9, 8, 6, 5, 4, 18, 14, 11, 9, - 7, 5, 4, 2, 1, 1, 1, 1, 3, 6, 2, 2, 1, 1, 1, 3, 6, 3, 2, - 2, 2, 3, 3, 7, 6, 3, 5, 6, 6, 6, 8, 9, 7, 9, 9, 9, 8, 8, - 14, 12, 13, 12, 11, 10, 8, 20, 18, 16, 14, 13, 11, 10, 3, 6, 6, 7, 7, - 7, 10, 6, 7, 7, 8, 8, 8, 10, 10, 7, 9, 9, 10, 10, 10, 13, 10, 12, - 13, 13, 13, 12, 13, 15, 17, 17, 17, 16, 15, 14, 22, 21, 20, 19, 18, 17, 20, - 27, 25, 23, 20, 19, 19, 14, 15, 14, 14, 15, 14, 9, 16, 16, 16, 16, 16, 15, - 9, 16, 17, 18, 18, 18, 17, 14, 16, 21, 21, 22, 22, 20, 17, 19, 26, 27, 26, - 25, 24, 18, 23, 30, 32, 29, 28, 25, 20, 27, 33, 35, 32, 30, 28, 22, 24, 25, - 24, 24, 21, 17, 12, 23, 27, 25, 26, 22, 17, 14, 24, 30, 29, 28, 24, 20, 17, - 24, 31, 32, 32, 28, 24, 20, 27, 34, 37, 36, 32, 27, 22, 30, 36, 42, 41, 34, - 29, 23, 33, 39, 44, 44, 38, 31, 26, 32, 37, 36, 29, 23, 19, 15, 31, 38, 39, - 31, 25, 20, 16, 31, 38, 41, 34, 28, 24, 20, 31, 38, 44, 38, 33, 27, 24, 34, - 41, 46, 45, 37, 31, 25, 36, 43, 47, 49, 40, 33, 27, 39, 44, 49, 49, 42, 36, - 29, 2, 0, 2, 2, 2, 2, 1, 2, 1, 2, 2, 2, 1, 1, 2, 2, 1, 2, - 1, 2, 3, 2, 2, 2, 2, 3, 4, 5, 5, 5, 5, 5, 6, 5, 5, 9, 9, - 9, 8, 6, 5, 5, 15, 14, 10, 8, 7, 5, 5, 2, 2, 1, 2, 1, 1, 4, - 2, 2, 0, 2, 1, 1, 4, 2, 2, 1, 1, 1, 3, 5, 3, 3, 3, 3, 3, - 4, 6, 7, 6, 7, 6, 6, 5, 6, 12, 11, 10, 9, 8, 7, 6, 19, 16, 12, - 10, 9, 8, 6, 2, 2, 3, 3, 3, 5, 7, 3, 2, 3, 4, 4, 5, 7, 7, - 2, 4, 6, 6, 6, 9, 10, 4, 8, 9, 9, 9, 11, 13, 8, 11, 13, 13, 12, - 11, 17, 14, 15, 16, 15, 14, 10, 21, 20, 18, 18, 16, 15, 13, 7, 7, 9, 9, - 10, 8, 11, 11, 8, 10, 11, 11, 11, 11, 13, 8, 11, 13, 13, 14, 13, 16, 11, - 16, 17, 17, 17, 15, 17, 17, 20, 21, 21, 20, 18, 18, 23, 25, 24, 23, 21, 20, - 21, 29, 28, 26, 25, 23, 22, 16, 17, 17, 17, 18, 17, 11, 20, 18, 19, 19, 19, - 18, 11, 19, 20, 20, 22, 21, 20, 16, 19, 24, 26, 25, 26, 24, 22, 21, 29, 31, - 30, 31, 27, 22, 26, 33, 35, 33, 31, 30, 25, 30, 36, 39, 36, 35, 31, 26, 27, - 28, 28, 27, 23, 20, 15, 26, 30, 29, 29, 25, 21, 17, 27, 32, 32, 32, 28, 24, - 21, 26, 35, 38, 37, 32, 29, 25, 30, 38, 41, 41, 36, 31, 25, 34, 40, 47, 45, - 39, 33, 27, 37, 44, 48, 49, 41, 35, 29, 35, 42, 40, 33, 27, 22, 18, 36, 41, - 42, 34, 29, 24, 21, 36, 41, 46, 38, 32, 28, 24, 35, 43, 49, 42, 37, 32, 28, - 38, 45, 51, 48, 42, 36, 30, 40, 47, 53, 51, 44, 38, 32, 44, 49, 54, 55, 47, - 39, 34, 2, 2, 0, 2, 2, 1, 2, 3, 2, 1, 2, 2, 1, 3, 3, 2, 1, - 1, 2, 3, 5, 3, 3, 3, 3, 3, 4, 5, 6, 6, 7, 6, 6, 5, 6, 11, - 10, 10, 9, 7, 5, 5, 17, 15, 12, 10, 8, 5, 6, 3, 2, 2, 1, 1, 3, - 6, 3, 2, 2, 1, 1, 3, 6, 4, 3, 2, 2, 3, 5, 7, 7, 4, 4, 5, - 6, 6, 8, 11, 7, 8, 9, 9, 6, 9, 14, 12, 12, 11, 11, 10, 8, 20, 17, - 14, 12, 13, 11, 9, 4, 3, 4, 5, 6, 6, 8, 8, 3, 4, 6, 7, 6, 9, - 11, 3, 5, 9, 10, 8, 11, 14, 5, 9, 12, 13, 12, 13, 17, 10, 12, 16, 17, - 16, 13, 21, 15, 17, 20, 19, 17, 12, 23, 20, 20, 21, 20, 19, 16, 11, 8, 12, - 13, 12, 10, 13, 15, 9, 12, 14, 14, 14, 14, 18, 10, 13, 16, 17, 17, 16, 20, - 14, 18, 20, 21, 21, 18, 21, 20, 22, 24, 25, 24, 21, 21, 25, 27, 28, 27, 26, - 25, 23, 31, 30, 30, 28, 27, 26, 19, 19, 20, 21, 21, 20, 13, 23, 21, 21, 22, - 23, 21, 14, 23, 22, 23, 25, 25, 25, 19, 23, 26, 28, 29, 29, 28, 25, 24, 31, - 34, 34, 34, 32, 26, 28, 36, 40, 38, 37, 34, 28, 32, 40, 43, 40, 39, 35, 29, - 29, 32, 31, 30, 26, 22, 17, 29, 33, 32, 32, 29, 25, 21, 29, 36, 36, 36, 32, - 28, 24, 29, 38, 42, 40, 36, 32, 28, 32, 42, 45, 44, 40, 35, 30, 37, 45, 50, - 49, 42, 37, 31, 40, 47, 52, 52, 46, 39, 33, 38, 45, 42, 36, 30, 25, 21, 39, - 45, 45, 38, 32, 28, 24, 39, 45, 49, 42, 37, 32, 28, 38, 46, 52, 46, 41, 35, - 31, 42, 49, 55, 52, 45, 40, 34, 45, 51, 57, 57, 48, 42, 36, 48, 53, 58, 57, - 51, 44, 38, 3, 2, 2, 0, 0, 2, 4, 3, 2, 2, 0, 1, 3, 6, 3, 3, - 2, 2, 2, 4, 7, 4, 4, 4, 5, 4, 5, 7, 8, 7, 8, 8, 7, 6, 7, - 12, 11, 12, 10, 8, 6, 7, 18, 16, 13, 11, 9, 6, 8, 3, 2, 2, 2, 3, - 5, 7, 4, 3, 2, 2, 3, 6, 8, 8, 3, 2, 3, 6, 7, 9, 11, 4, 5, - 6, 9, 8, 11, 14, 8, 9, 10, 12, 8, 11, 17, 13, 13, 13, 14, 12, 11, 22, - 18, 15, 13, 16, 15, 11, 8, 3, 5, 8, 8, 8, 10, 12, 3, 5, 8, 10, 8, - 11, 15, 5, 6, 11, 13, 9, 13, 18, 9, 10, 15, 16, 16, 16, 21, 12, 14, 19, - 19, 19, 16, 24, 17, 18, 21, 22, 21, 16, 26, 22, 20, 23, 23, 22, 19, 15, 9, - 13, 15, 16, 12, 15, 18, 11, 14, 16, 17, 17, 17, 22, 13, 15, 19, 21, 21, 19, - 26, 17, 20, 24, 23, 25, 21, 26, 22, 24, 27, 28, 27, 24, 25, 27, 30, 31, 31, - 29, 27, 25, 33, 33, 33, 32, 31, 30, 23, 20, 22, 24, 24, 23, 16, 26, 22, 25, - 25, 26, 25, 17, 26, 25, 26, 28, 30, 28, 22, 26, 29, 31, 33, 33, 32, 27, 28, - 34, 37, 36, 38, 36, 30, 30, 39, 42, 42, 41, 37, 32, 34, 43, 46, 44, 42, 39, - 33, 31, 34, 33, 33, 30, 26, 20, 31, 36, 35, 35, 32, 28, 24, 32, 37, 39, 39, - 36, 31, 28, 32, 40, 45, 42, 40, 37, 32, 34, 44, 50, 48, 44, 40, 34, 39, 47, - 54, 52, 47, 40, 35, 43, 48, 56, 56, 49, 43, 37, 43, 46, 45, 39, 32, 29, 25, - 42, 47, 47, 40, 35, 31, 28, 41, 47, 49, 44, 39, 36, 31, 42, 48, 55, 50, 44, - 40, 34, 45, 52, 57, 55, 49, 43, 38, 48, 54, 59, 60, 53, 44, 39, 51, 57, 61, - 60, 54, 47, 41, 3, 2, 2, 0, 0, 2, 4, 3, 2, 2, 1, 0, 3, 6, 3, - 2, 2, 2, 2, 4, 6, 4, 4, 4, 4, 4, 5, 7, 8, 7, 8, 8, 7, 6, - 8, 12, 12, 11, 11, 8, 6, 8, 18, 16, 13, 11, 9, 6, 8, 3, 2, 2, 2, - 3, 5, 7, 4, 3, 2, 2, 3, 6, 8, 8, 3, 2, 3, 6, 7, 9, 12, 5, - 5, 6, 9, 8, 11, 14, 8, 9, 10, 12, 8, 10, 17, 13, 13, 13, 14, 13, 11, - 22, 18, 15, 13, 15, 15, 11, 8, 3, 5, 8, 8, 8, 10, 12, 3, 5, 9, 10, - 8, 11, 16, 5, 6, 11, 13, 9, 13, 17, 8, 9, 15, 16, 15, 15, 22, 12, 14, - 19, 20, 20, 16, 24, 17, 18, 21, 22, 21, 16, 26, 22, 20, 23, 24, 22, 19, 15, - 9, 13, 15, 15, 12, 16, 18, 11, 14, 16, 17, 17, 17, 21, 13, 15, 19, 21, 21, - 19, 26, 17, 20, 23, 24, 25, 20, 25, 21, 24, 27, 27, 27, 24, 24, 27, 29, 30, - 30, 29, 27, 26, 33, 32, 33, 32, 31, 30, 23, 21, 23, 24, 23, 22, 15, 26, 22, - 24, 24, 26, 25, 17, 26, 24, 25, 28, 30, 27, 22, 26, 29, 30, 33, 33, 32, 27, - 28, 34, 36, 38, 37, 35, 30, 30, 38, 43, 42, 41, 37, 32, 33, 42, 46, 44, 42, - 39, 34, 32, 34, 33, 33, 29, 26, 20, 32, 37, 35, 35, 32, 28, 24, 31, 38, 38, - 39, 36, 32, 28, 31, 40, 44, 44, 39, 36, 32, 35, 42, 49, 48, 44, 40, 33, 39, - 47, 54, 53, 46, 40, 36, 44, 50, 54, 55, 48, 43, 37, 40, 47, 44, 37, 33, 28, - 25, 41, 48, 47, 40, 35, 31, 28, 40, 47, 50, 44, 40, 35, 31, 41, 49, 55, 50, - 44, 39, 35, 44, 52, 58, 55, 47, 43, 38, 48, 55, 60, 59, 50, 45, 39, 50, 57, - 62, 62, 53, 47, 42, 2, 2, 1, 2, 2, 0, 3, 2, 2, 1, 2, 2, 1, 4, - 2, 2, 1, 2, 4, 3, 5, 3, 3, 4, 4, 6, 6, 6, 6, 7, 7, 7, 9, - 8, 6, 11, 11, 11, 10, 9, 8, 6, 18, 15, 13, 11, 10, 7, 6, 2, 2, 2, - 1, 1, 3, 5, 3, 2, 2, 1, 1, 4, 6, 6, 2, 2, 3, 4, 5, 7, 10, - 4, 5, 6, 7, 6, 9, 11, 8, 9, 9, 10, 7, 8, 16, 13, 13, 12, 12, 11, - 9, 21, 18, 15, 13, 14, 13, 9, 6, 2, 4, 6, 6, 6, 8, 10, 2, 4, 7, - 8, 6, 9, 14, 3, 5, 9, 10, 7, 11, 16, 6, 9, 13, 14, 13, 13, 18, 11, - 12, 17, 18, 17, 13, 22, 16, 17, 20, 20, 18, 13, 25, 22, 20, 22, 22, 20, 17, - 14, 7, 12, 13, 13, 9, 13, 17, 9, 12, 14, 15, 14, 14, 20, 12, 13, 17, 18, - 19, 16, 22, 15, 18, 22, 22, 22, 18, 22, 20, 22, 25, 26, 25, 21, 23, 25, 28, - 28, 28, 27, 24, 24, 31, 31, 30, 30, 29, 27, 22, 19, 21, 21, 21, 20, 13, 24, - 20, 22, 22, 23, 22, 14, 24, 22, 23, 26, 26, 25, 19, 25, 26, 28, 29, 32, 29, - 25, 25, 32, 34, 35, 35, 32, 27, 28, 36, 41, 39, 37, 34, 30, 32, 40, 43, 43, - 39, 36, 30, 29, 32, 32, 30, 26, 22, 17, 29, 35, 32, 32, 29, 25, 22, 29, 35, - 35, 36, 33, 29, 25, 29, 38, 41, 41, 37, 33, 29, 33, 41, 47, 45, 42, 37, 30, - 38, 44, 52, 52, 44, 38, 32, 41, 47, 53, 53, 47, 40, 34, 39, 46, 42, 36, 30, - 26, 22, 39, 45, 45, 38, 33, 29, 25, 39, 44, 48, 42, 36, 33, 28, 39, 46, 52, - 47, 41, 37, 33, 42, 50, 54, 52, 45, 39, 36, 45, 52, 58, 56, 49, 43, 35, 49, - 54, 58, 59, 52, 44, 37, 1, 1, 2, 4, 4, 3, 0, 2, 1, 2, 4, 4, 3, - 2, 2, 1, 1, 4, 5, 4, 4, 2, 3, 3, 5, 7, 7, 6, 5, 6, 7, 8, - 10, 8, 7, 10, 10, 11, 11, 10, 8, 7, 17, 15, 12, 11, 11, 8, 7, 2, 1, - 1, 3, 2, 2, 3, 2, 2, 1, 2, 2, 2, 4, 2, 2, 1, 3, 3, 3, 5, - 6, 3, 4, 5, 5, 4, 6, 9, 7, 8, 8, 8, 6, 6, 13, 12, 12, 11, 9, - 8, 6, 20, 18, 13, 12, 11, 9, 6, 2, 2, 3, 3, 3, 5, 6, 6, 2, 3, - 4, 4, 4, 6, 11, 2, 4, 7, 7, 5, 8, 15, 4, 8, 10, 10, 10, 10, 16, - 9, 11, 14, 14, 14, 10, 19, 14, 16, 18, 16, 15, 10, 23, 21, 19, 19, 18, 16, - 14, 11, 7, 9, 10, 10, 7, 11, 15, 7, 10, 11, 12, 11, 11, 17, 9, 12, 14, - 15, 15, 12, 19, 13, 16, 18, 18, 18, 14, 19, 17, 20, 22, 23, 22, 18, 20, 23, - 26, 26, 25, 23, 21, 22, 29, 29, 27, 26, 25, 23, 19, 17, 18, 18, 18, 17, 11, - 22, 18, 20, 19, 20, 19, 11, 22, 20, 21, 23, 23, 22, 17, 22, 24, 26, 27, 27, - 26, 22, 23, 30, 31, 32, 32, 28, 24, 25, 34, 37, 36, 34, 30, 26, 30, 37, 41, - 37, 36, 33, 27, 27, 29, 27, 27, 24, 20, 15, 26, 31, 30, 29, 26, 22, 18, 27, - 33, 32, 33, 30, 26, 22, 26, 35, 39, 36, 34, 29, 25, 31, 37, 43, 42, 38, 33, - 28, 35, 44, 48, 47, 40, 34, 30, 38, 45, 49, 49, 42, 37, 31, 35, 41, 38, 32, - 26, 23, 18, 36, 42, 41, 35, 29, 25, 22, 36, 40, 43, 38, 33, 29, 25, 36, 42, - 50, 43, 37, 34, 29, 39, 45, 52, 47, 42, 37, 31, 42, 47, 53, 54, 45, 39, 33, - 46, 51, 54, 54, 46, 40, 35, 1, 2, 3, 3, 3, 2, 2, 0, 2, 2, 3, 3, - 2, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 3, 4, - 4, 5, 4, 4, 7, 7, 7, 7, 5, 4, 4, 13, 12, 9, 7, 6, 4, 4, 1, - 2, 2, 3, 2, 2, 1, 2, 1, 2, 2, 2, 1, 0, 2, 0, 2, 2, 2, 1, - 2, 2, 2, 2, 2, 2, 3, 4, 5, 5, 5, 5, 5, 4, 4, 10, 9, 9, 8, - 6, 4, 4, 17, 14, 11, 8, 6, 5, 4, 2, 1, 1, 2, 2, 2, 5, 2, 1, - 1, 1, 1, 2, 6, 2, 2, 1, 2, 2, 2, 6, 5, 3, 4, 4, 5, 5, 7, - 8, 7, 8, 8, 8, 7, 7, 13, 12, 12, 11, 10, 9, 7, 20, 17, 15, 13, 11, - 10, 9, 2, 5, 6, 6, 6, 6, 9, 5, 6, 6, 7, 7, 7, 9, 8, 7, 8, - 8, 9, 9, 9, 11, 9, 11, 12, 12, 12, 11, 12, 15, 15, 16, 15, 15, 14, 14, - 20, 20, 20, 18, 17, 16, 19, 27, 24, 21, 20, 18, 17, 13, 14, 13, 14, 14, 13, - 9, 15, 15, 14, 15, 15, 14, 9, 15, 17, 17, 17, 17, 16, 12, 15, 21, 20, 20, - 21, 19, 16, 18, 25, 25, 24, 24, 23, 17, 22, 29, 30, 29, 26, 24, 19, 26, 32, - 33, 31, 29, 26, 21, 23, 24, 23, 22, 20, 15, 12, 23, 27, 25, 25, 21, 16, 13, - 23, 28, 28, 26, 23, 19, 15, 23, 30, 32, 31, 28, 22, 19, 26, 32, 36, 36, 31, - 26, 20, 29, 34, 41, 39, 34, 28, 23, 31, 38, 41, 42, 35, 30, 25, 31, 37, 35, - 29, 23, 18, 14, 31, 37, 38, 30, 25, 19, 15, 30, 36, 40, 33, 27, 23, 18, 30, - 37, 44, 37, 31, 26, 23, 33, 39, 45, 43, 36, 30, 24, 36, 42, 48, 47, 39, 31, - 27, 38, 43, 48, 49, 42, 34, 28, 2, 1, 2, 2, 2, 2, 1, 2, 0, 2, 3, - 2, 2, 1, 2, 1, 1, 2, 2, 1, 3, 2, 2, 2, 2, 3, 3, 5, 5, 5, - 5, 5, 5, 5, 4, 9, 8, 8, 8, 6, 5, 4, 15, 13, 10, 8, 7, 5, 4, - 2, 1, 2, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 3, 2, 2, 1, 1, 1, - 2, 5, 2, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 4, 6, 11, 10, 10, - 9, 7, 5, 6, 19, 15, 12, 9, 8, 7, 6, 2, 2, 2, 2, 2, 4, 7, 3, - 2, 3, 3, 3, 5, 7, 5, 2, 4, 5, 5, 5, 8, 9, 3, 7, 8, 8, 8, - 9, 12, 8, 11, 11, 12, 11, 10, 16, 13, 15, 15, 14, 12, 10, 21, 19, 18, 17, - 15, 14, 13, 5, 7, 8, 8, 9, 8, 11, 9, 7, 9, 10, 10, 10, 11, 12, 8, - 11, 11, 12, 12, 12, 16, 11, 15, 16, 16, 15, 14, 16, 17, 19, 19, 20, 19, 17, - 16, 23, 24, 23, 22, 20, 19, 21, 29, 27, 25, 23, 22, 20, 16, 16, 17, 16, 17, - 16, 10, 18, 18, 18, 18, 18, 17, 11, 18, 19, 20, 20, 21, 19, 16, 18, 24, 24, - 25, 25, 23, 20, 21, 29, 29, 28, 28, 26, 21, 24, 32, 34, 33, 31, 28, 24, 29, - 36, 38, 34, 33, 30, 25, 26, 28, 26, 26, 22, 18, 14, 25, 31, 28, 28, 23, 19, - 16, 26, 32, 31, 31, 27, 23, 19, 26, 33, 36, 33, 32, 26, 22, 29, 36, 40, 38, - 35, 30, 25, 33, 39, 45, 44, 36, 31, 27, 35, 42, 45, 46, 41, 33, 29, 35, 41, - 38, 31, 26, 21, 17, 35, 40, 41, 34, 27, 23, 19, 35, 41, 44, 37, 30, 26, 22, - 34, 41, 47, 41, 35, 31, 26, 37, 43, 50, 47, 40, 34, 29, 39, 46, 52, 51, 42, - 37, 30, 42, 49, 53, 53, 44, 39, 32, 2, 1, 1, 2, 2, 1, 2, 2, 2, 0, - 2, 2, 1, 3, 3, 2, 1, 1, 2, 2, 4, 3, 3, 3, 3, 3, 4, 5, 5, - 6, 6, 6, 6, 5, 5, 10, 10, 9, 8, 7, 5, 5, 17, 15, 11, 9, 7, 5, - 5, 3, 2, 1, 1, 1, 3, 5, 3, 2, 2, 1, 1, 3, 6, 3, 2, 2, 2, - 2, 4, 7, 6, 4, 4, 4, 5, 5, 8, 9, 7, 7, 8, 8, 5, 8, 13, 12, - 11, 11, 10, 9, 8, 20, 17, 13, 11, 11, 10, 8, 3, 2, 4, 5, 5, 6, 8, - 6, 3, 4, 6, 6, 6, 8, 10, 3, 5, 8, 8, 7, 10, 13, 4, 9, 11, 12, - 11, 12, 16, 9, 12, 15, 15, 15, 12, 20, 14, 16, 18, 17, 16, 12, 22, 20, 19, - 20, 19, 17, 16, 10, 7, 11, 11, 11, 9, 12, 13, 8, 11, 12, 13, 13, 13, 16, - 10, 13, 16, 16, 16, 15, 18, 13, 17, 19, 19, 19, 17, 20, 18, 22, 23, 24, 22, - 19, 20, 24, 27, 27, 25, 25, 22, 23, 30, 30, 28, 27, 26, 25, 19, 18, 19, 19, - 20, 18, 12, 21, 19, 20, 21, 21, 20, 13, 22, 21, 23, 24, 25, 23, 18, 21, 26, - 27, 28, 28, 27, 23, 24, 31, 33, 32, 33, 30, 25, 27, 36, 38, 36, 34, 31, 26, - 31, 39, 41, 38, 37, 34, 28, 28, 31, 30, 29, 25, 21, 17, 28, 33, 32, 31, 28, - 23, 19, 27, 35, 35, 34, 31, 26, 23, 28, 36, 40, 38, 35, 30, 27, 32, 41, 45, - 44, 39, 34, 29, 35, 43, 51, 48, 42, 36, 30, 39, 46, 51, 50, 44, 38, 32, 37, - 44, 41, 34, 29, 24, 20, 39, 44, 44, 37, 32, 26, 23, 38, 43, 47, 40, 36, 31, - 26, 38, 45, 50, 45, 39, 35, 30, 40, 48, 54, 50, 43, 37, 32, 44, 51, 56, 53, - 46, 40, 34, 46, 52, 57, 57, 49, 42, 37, 3, 2, 2, 0, 0, 2, 4, 3, 3, - 2, 0, 1, 2, 5, 3, 3, 2, 2, 2, 3, 6, 4, 4, 4, 4, 4, 5, 7, - 7, 7, 7, 7, 7, 6, 7, 12, 11, 11, 10, 8, 6, 7, 17, 15, 12, 10, 9, - 6, 7, 3, 3, 2, 2, 2, 5, 7, 3, 3, 2, 2, 2, 5, 8, 7, 3, 2, - 3, 5, 6, 9, 10, 4, 5, 6, 8, 7, 10, 13, 8, 9, 9, 12, 8, 10, 16, - 13, 13, 12, 13, 12, 10, 22, 18, 14, 13, 15, 14, 10, 7, 3, 5, 7, 7, 8, - 10, 11, 3, 5, 8, 9, 8, 11, 14, 4, 6, 11, 12, 9, 12, 17, 7, 9, 14, - 15, 15, 15, 19, 11, 13, 18, 19, 18, 15, 24, 16, 18, 20, 21, 20, 15, 25, 21, - 20, 22, 22, 21, 18, 14, 8, 13, 14, 14, 11, 15, 17, 10, 13, 15, 17, 16, 16, - 20, 12, 14, 18, 20, 20, 18, 22, 16, 19, 22, 23, 23, 19, 23, 21, 24, 26, 27, - 27, 23, 24, 26, 29, 30, 30, 28, 27, 25, 32, 32, 31, 31, 29, 29, 22, 20, 22, - 23, 23, 22, 15, 27, 21, 24, 24, 25, 24, 16, 25, 23, 26, 28, 28, 27, 21, 25, - 29, 30, 32, 33, 31, 27, 27, 34, 36, 37, 37, 34, 29, 30, 38, 42, 41, 38, 35, - 31, 32, 41, 45, 42, 42, 38, 33, 32, 33, 34, 32, 29, 25, 19, 31, 36, 35, 34, - 32, 27, 24, 31, 38, 37, 38, 34, 30, 27, 31, 39, 43, 42, 39, 35, 31, 35, 43, - 50, 47, 44, 39, 33, 39, 47, 55, 52, 46, 39, 34, 43, 50, 54, 55, 49, 42, 36, - 41, 46, 44, 38, 32, 27, 24, 41, 46, 46, 40, 34, 31, 27, 40, 48, 50, 44, 40, - 35, 30, 41, 47, 55, 48, 43, 39, 34, 44, 50, 58, 54, 48, 42, 37, 47, 54, 60, - 58, 52, 45, 37, 50, 55, 61, 60, 54, 47, 39, 2, 2, 2, 1, 1, 2, 4, 3, - 2, 2, 1, 0, 2, 5, 3, 2, 2, 2, 2, 4, 6, 4, 4, 4, 4, 4, 5, - 7, 8, 7, 7, 7, 7, 6, 7, 12, 11, 11, 10, 8, 6, 7, 17, 15, 13, 10, - 9, 6, 7, 3, 2, 2, 1, 3, 5, 8, 4, 2, 2, 2, 3, 5, 8, 7, 3, - 2, 3, 6, 6, 9, 11, 4, 5, 6, 9, 7, 10, 14, 8, 8, 9, 12, 8, 10, - 17, 13, 13, 12, 14, 12, 10, 22, 18, 14, 13, 15, 14, 10, 7, 3, 5, 8, 8, - 9, 11, 12, 3, 5, 8, 9, 8, 11, 15, 5, 5, 11, 12, 9, 13, 18, 8, 9, - 15, 16, 15, 15, 21, 12, 13, 18, 19, 19, 15, 25, 16, 18, 21, 21, 21, 15, 25, - 22, 20, 23, 23, 22, 19, 15, 8, 13, 15, 15, 12, 16, 18, 10, 14, 16, 17, 17, - 17, 21, 13, 14, 19, 20, 21, 18, 25, 17, 19, 23, 23, 24, 20, 25, 21, 24, 27, - 28, 27, 23, 25, 26, 29, 31, 30, 28, 26, 25, 32, 32, 32, 31, 31, 29, 23, 21, - 22, 24, 24, 23, 16, 26, 22, 23, 24, 26, 25, 17, 26, 24, 26, 28, 30, 28, 21, - 26, 28, 31, 33, 33, 32, 27, 27, 35, 36, 36, 38, 35, 30, 29, 38, 41, 42, 39, - 36, 31, 34, 41, 45, 43, 42, 38, 33, 32, 34, 34, 32, 30, 25, 20, 31, 35, 35, - 35, 32, 28, 23, 31, 38, 38, 38, 35, 31, 28, 31, 40, 44, 43, 39, 35, 32, 34, - 43, 49, 47, 43, 40, 32, 40, 46, 54, 52, 46, 39, 35, 43, 50, 55, 55, 48, 42, - 36, 42, 47, 45, 39, 33, 28, 24, 41, 47, 48, 40, 35, 31, 27, 41, 47, 50, 45, - 40, 35, 31, 42, 48, 56, 49, 44, 39, 35, 45, 51, 57, 55, 48, 42, 37, 48, 53, - 61, 59, 51, 44, 39, 50, 57, 61, 61, 54, 48, 40, 2, 1, 1, 3, 3, 1, 3, - 2, 1, 1, 2, 2, 0, 3, 2, 2, 1, 1, 2, 2, 4, 2, 3, 3, 3, 4, - 4, 5, 5, 6, 6, 6, 7, 6, 5, 10, 10, 9, 9, 8, 6, 5, 16, 14, 11, - 9, 8, 6, 5, 2, 2, 1, 1, 2, 4, 6, 2, 2, 1, 1, 2, 3, 5, 4, - 2, 1, 2, 3, 4, 6, 9, 3, 4, 4, 6, 5, 7, 11, 7, 7, 8, 9, 5, - 7, 14, 11, 11, 11, 11, 9, 7, 19, 16, 13, 11, 12, 11, 7, 5, 2, 4, 6, - 7, 7, 9, 9, 2, 4, 7, 7, 6, 8, 13, 2, 5, 9, 9, 6, 10, 15, 5, - 8, 12, 12, 12, 12, 18, 9, 11, 16, 16, 15, 12, 21, 14, 16, 19, 18, 17, 12, - 23, 20, 18, 20, 19, 18, 16, 13, 7, 11, 12, 13, 11, 14, 16, 8, 12, 14, 15, - 14, 13, 19, 10, 13, 16, 17, 18, 15, 21, 14, 17, 20, 20, 20, 16, 22, 19, 21, - 24, 24, 24, 20, 21, 24, 26, 27, 26, 26, 23, 22, 30, 29, 28, 28, 27, 26, 20, - 19, 20, 20, 22, 21, 14, 23, 20, 22, 23, 23, 21, 13, 23, 22, 24, 25, 26, 24, - 19, 24, 26, 28, 29, 29, 28, 23, 25, 31, 34, 33, 34, 32, 25, 28, 36, 39, 37, - 36, 33, 28, 30, 39, 41, 39, 38, 34, 30, 29, 32, 31, 31, 28, 23, 19, 28, 33, - 33, 32, 29, 24, 20, 28, 37, 35, 37, 32, 28, 24, 28, 37, 41, 40, 37, 33, 28, - 31, 39, 46, 43, 40, 35, 29, 37, 43, 51, 48, 42, 36, 31, 39, 46, 51, 51, 44, - 39, 33, 39, 44, 42, 36, 30, 26, 22, 39, 44, 45, 38, 32, 28, 24, 39, 44, 47, - 41, 35, 31, 27, 38, 47, 51, 45, 40, 35, 31, 41, 48, 54, 51, 44, 39, 33, 46, - 51, 56, 57, 47, 40, 35, 47, 53, 58, 58, 49, 43, 37, 1, 1, 3, 6, 6, 4, - 2, 1, 1, 3, 5, 5, 3, 0, 2, 1, 2, 3, 4, 3, 2, 2, 2, 2, 3, - 5, 5, 4, 4, 5, 5, 6, 8, 6, 4, 9, 8, 8, 8, 8, 6, 4, 14, 12, - 10, 8, 9, 6, 4, 2, 1, 2, 4, 3, 3, 5, 2, 1, 1, 3, 3, 2, 3, - 2, 1, 1, 1, 1, 2, 4, 3, 3, 3, 3, 3, 3, 4, 8, 6, 6, 6, 6, - 4, 4, 12, 10, 10, 9, 7, 6, 5, 18, 14, 11, 10, 8, 7, 5, 2, 1, 3, - 4, 5, 6, 8, 4, 2, 3, 5, 5, 5, 6, 9, 2, 4, 6, 6, 4, 6, 12, - 3, 7, 9, 9, 9, 8, 16, 8, 10, 12, 13, 12, 8, 18, 13, 14, 15, 14, 13, - 8, 20, 18, 16, 17, 16, 15, 13, 8, 6, 9, 10, 11, 9, 11, 13, 7, 10, 11, - 12, 12, 11, 15, 8, 11, 13, 13, 13, 11, 17, 11, 15, 16, 16, 16, 13, 19, 16, - 19, 21, 21, 20, 16, 18, 21, 23, 24, 23, 22, 19, 20, 27, 26, 25, 24, 23, 21, - 17, 17, 18, 18, 19, 18, 12, 21, 18, 19, 19, 20, 18, 11, 20, 20, 21, 22, 22, - 21, 15, 20, 24, 25, 25, 26, 24, 19, 22, 28, 29, 29, 30, 28, 22, 24, 33, 36, - 35, 32, 29, 24, 28, 36, 39, 36, 35, 31, 26, 27, 29, 27, 27, 24, 21, 17, 26, - 32, 30, 29, 25, 21, 16, 26, 33, 33, 31, 27, 23, 20, 25, 36, 36, 34, 32, 28, - 23, 29, 37, 42, 41, 34, 31, 26, 32, 40, 46, 44, 38, 33, 27, 37, 41, 47, 46, - 40, 34, 29, 36, 41, 39, 32, 27, 24, 19, 36, 41, 41, 35, 29, 24, 20, 35, 40, - 44, 37, 32, 27, 24, 36, 43, 47, 42, 37, 32, 27, 38, 44, 50, 47, 40, 34, 29, - 41, 47, 52, 49, 42, 37, 31, 43, 49, 52, 52, 46, 39, 33, 2, 2, 3, 3, 3, - 2, 2, 1, 2, 3, 3, 3, 2, 2, 0, 2, 2, 3, 2, 2, 1, 1, 1, 1, - 2, 2, 2, 3, 3, 3, 3, 4, 4, 3, 3, 7, 7, 7, 6, 5, 3, 3, 13, - 11, 9, 7, 5, 3, 3, 0, 2, 2, 3, 2, 2, 2, 1, 2, 2, 3, 2, 2, - 1, 2, 1, 2, 2, 2, 2, 1, 2, 1, 2, 2, 2, 2, 3, 4, 4, 4, 4, - 4, 3, 4, 9, 8, 8, 7, 5, 4, 4, 16, 13, 10, 8, 6, 4, 3, 2, 1, - 2, 2, 2, 1, 4, 2, 1, 1, 1, 1, 1, 4, 2, 1, 1, 0, 0, 1, 5, - 3, 2, 3, 3, 3, 3, 6, 7, 6, 6, 6, 7, 6, 6, 12, 11, 11, 10, 8, - 7, 6, 19, 17, 13, 12, 10, 9, 8, 2, 4, 4, 5, 5, 5, 8, 3, 5, 5, - 6, 6, 6, 8, 7, 6, 6, 7, 7, 7, 8, 10, 9, 10, 10, 10, 11, 10, 10, - 14, 14, 14, 14, 13, 13, 13, 19, 19, 18, 16, 15, 14, 18, 25, 22, 20, 18, 16, - 16, 12, 12, 12, 12, 12, 12, 8, 14, 14, 14, 13, 14, 13, 8, 14, 16, 15, 15, - 15, 14, 11, 14, 19, 19, 19, 19, 18, 14, 17, 23, 23, 23, 23, 20, 16, 21, 27, - 28, 27, 26, 23, 18, 25, 31, 32, 29, 28, 25, 20, 21, 23, 22, 21, 18, 14, 10, - 21, 25, 23, 23, 20, 16, 11, 21, 27, 26, 25, 22, 18, 14, 21, 27, 30, 29, 25, - 21, 18, 24, 30, 34, 34, 30, 25, 19, 27, 33, 39, 37, 32, 26, 21, 30, 36, 40, - 40, 35, 28, 23, 29, 34, 33, 27, 22, 17, 13, 29, 35, 37, 29, 23, 19, 14, 29, - 35, 39, 32, 25, 22, 17, 30, 35, 42, 35, 30, 25, 21, 31, 37, 44, 40, 35, 29, - 23, 33, 41, 46, 46, 36, 31, 25, 36, 43, 47, 46, 39, 32, 26, 1, 2, 2, 2, - 2, 2, 1, 2, 1, 2, 3, 2, 2, 1, 2, 0, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 3, 4, 4, 4, 4, 4, 5, 4, 4, 8, 8, 8, 7, 5, 4, 4, - 14, 12, 9, 8, 6, 4, 4, 2, 0, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, - 1, 2, 2, 2, 1, 2, 2, 1, 4, 2, 2, 2, 3, 2, 3, 5, 6, 5, 5, - 5, 5, 4, 5, 11, 10, 9, 8, 6, 5, 5, 18, 15, 11, 9, 7, 5, 5, 2, - 2, 1, 2, 1, 3, 6, 2, 2, 2, 2, 2, 4, 6, 4, 2, 3, 3, 4, 4, - 7, 7, 3, 6, 6, 6, 7, 9, 11, 7, 9, 10, 10, 10, 8, 15, 12, 14, 13, - 12, 11, 8, 20, 18, 17, 15, 14, 12, 11, 4, 6, 7, 7, 8, 7, 10, 8, 7, - 8, 8, 9, 9, 10, 11, 8, 10, 10, 11, 11, 11, 14, 10, 14, 14, 14, 14, 13, - 14, 16, 18, 18, 18, 17, 16, 15, 21, 22, 21, 20, 18, 18, 20, 28, 26, 24, 22, - 20, 19, 14, 15, 15, 15, 16, 15, 10, 17, 17, 16, 16, 17, 15, 10, 16, 18, 19, - 19, 19, 18, 14, 17, 22, 23, 23, 23, 21, 18, 19, 27, 27, 27, 27, 24, 20, 24, - 31, 34, 32, 29, 27, 21, 28, 34, 36, 33, 31, 28, 23, 24, 26, 24, 24, 21, 17, - 13, 24, 29, 27, 26, 23, 18, 14, 24, 30, 29, 28, 25, 21, 17, 24, 31, 34, 32, - 29, 25, 22, 29, 35, 38, 37, 34, 29, 23, 32, 37, 44, 42, 36, 31, 25, 34, 40, - 45, 44, 39, 33, 26, 33, 38, 37, 30, 24, 20, 16, 32, 39, 40, 32, 26, 21, 18, - 32, 38, 42, 35, 30, 25, 21, 33, 40, 46, 39, 33, 28, 24, 34, 41, 48, 43, 38, - 32, 27, 37, 43, 49, 49, 41, 35, 28, 40, 46, 49, 50, 44, 36, 30, 2, 1, 1, - 2, 2, 1, 1, 2, 1, 1, 2, 2, 1, 2, 2, 2, 0, 2, 1, 2, 3, 2, - 3, 2, 3, 3, 4, 5, 5, 5, 6, 5, 6, 5, 5, 10, 9, 9, 8, 6, 5, - 5, 16, 14, 11, 8, 7, 5, 4, 2, 2, 1, 2, 1, 2, 5, 2, 2, 1, 1, - 1, 2, 5, 3, 2, 1, 1, 1, 3, 6, 4, 3, 3, 3, 4, 4, 7, 8, 6, - 7, 7, 7, 5, 7, 12, 11, 10, 10, 9, 7, 7, 19, 16, 13, 11, 10, 9, 7, - 2, 2, 4, 4, 5, 6, 8, 4, 2, 4, 5, 5, 6, 8, 8, 2, 5, 7, 7, - 6, 9, 11, 4, 8, 10, 10, 10, 11, 14, 8, 11, 14, 14, 14, 11, 18, 14, 16, - 17, 16, 15, 11, 21, 20, 18, 19, 18, 16, 14, 8, 7, 10, 11, 11, 9, 12, 11, - 8, 11, 11, 12, 12, 12, 14, 8, 12, 14, 14, 15, 14, 17, 12, 17, 18, 18, 17, - 15, 18, 17, 21, 21, 22, 21, 19, 18, 23, 26, 25, 24, 23, 21, 22, 30, 29, 27, - 26, 24, 23, 17, 18, 18, 18, 19, 18, 12, 19, 19, 19, 20, 20, 19, 12, 20, 20, - 21, 23, 23, 22, 17, 20, 25, 27, 26, 27, 26, 21, 22, 30, 32, 31, 31, 29, 23, - 26, 35, 37, 35, 33, 30, 25, 30, 37, 40, 37, 36, 32, 27, 28, 29, 28, 28, 25, - 20, 17, 27, 32, 31, 30, 26, 22, 18, 27, 34, 34, 34, 29, 25, 21, 27, 35, 38, - 37, 34, 30, 25, 31, 38, 43, 41, 38, 33, 27, 34, 41, 49, 47, 39, 33, 29, 38, - 44, 49, 49, 43, 36, 30, 36, 43, 41, 34, 28, 24, 20, 37, 43, 44, 36, 30, 25, - 21, 36, 43, 46, 38, 34, 29, 24, 37, 44, 49, 44, 38, 34, 29, 40, 46, 53, 49, - 42, 36, 30, 42, 49, 55, 54, 45, 38, 33, 45, 51, 55, 55, 48, 41, 34, 2, 2, - 1, 2, 2, 2, 4, 2, 2, 1, 2, 2, 1, 3, 3, 2, 2, 0, 1, 2, 4, - 3, 3, 3, 3, 2, 3, 5, 6, 6, 6, 6, 5, 4, 5, 10, 10, 9, 8, 6, - 4, 5, 16, 14, 11, 9, 7, 4, 5, 2, 2, 1, 2, 3, 5, 7, 3, 2, 2, - 2, 3, 4, 6, 4, 2, 2, 2, 3, 5, 7, 7, 3, 4, 4, 6, 6, 8, 10, - 7, 7, 8, 9, 6, 8, 14, 11, 11, 10, 11, 10, 8, 19, 16, 13, 11, 13, 11, - 8, 4, 2, 5, 7, 8, 9, 11, 8, 3, 4, 7, 8, 8, 10, 11, 3, 5, 9, - 10, 8, 11, 14, 5, 8, 12, 13, 13, 13, 18, 9, 12, 16, 17, 16, 13, 21, 14, - 16, 19, 19, 18, 13, 22, 20, 18, 21, 20, 19, 17, 11, 8, 12, 14, 14, 12, 16, - 15, 8, 13, 14, 15, 16, 15, 18, 10, 14, 17, 18, 17, 16, 20, 14, 18, 20, 21, - 21, 18, 21, 19, 23, 24, 25, 24, 21, 21, 24, 27, 28, 27, 27, 24, 23, 30, 31, - 29, 29, 27, 27, 20, 19, 21, 22, 23, 22, 16, 23, 21, 23, 23, 24, 22, 15, 23, - 23, 24, 26, 26, 25, 20, 23, 27, 29, 30, 31, 29, 25, 25, 32, 33, 34, 34, 32, - 27, 27, 36, 39, 38, 36, 34, 29, 31, 39, 43, 41, 39, 37, 30, 30, 33, 33, 32, - 29, 25, 20, 29, 34, 34, 34, 30, 25, 21, 29, 37, 37, 37, 33, 28, 25, 30, 39, - 41, 40, 37, 33, 29, 33, 42, 47, 45, 41, 38, 30, 36, 44, 51, 49, 44, 38, 33, - 40, 47, 52, 53, 46, 38, 34, 41, 46, 44, 37, 32, 28, 23, 40, 45, 46, 40, 33, - 29, 25, 40, 46, 49, 42, 37, 33, 28, 40, 47, 53, 47, 41, 36, 32, 43, 50, 55, - 52, 46, 40, 35, 45, 52, 57, 56, 49, 43, 36, 48, 54, 57, 58, 52, 44, 38, 2, - 1, 2, 2, 2, 4, 5, 2, 2, 2, 2, 2, 2, 4, 3, 2, 2, 1, 0, 2, - 5, 3, 3, 3, 2, 2, 3, 6, 7, 6, 6, 5, 5, 4, 6, 11, 9, 9, 8, - 6, 4, 6, 16, 13, 10, 8, 7, 4, 6, 3, 2, 2, 3, 4, 7, 9, 3, 2, - 2, 3, 4, 6, 8, 5, 2, 2, 2, 4, 5, 8, 9, 4, 4, 4, 7, 6, 9, - 13, 7, 7, 7, 10, 6, 9, 16, 11, 11, 10, 12, 11, 9, 20, 16, 12, 11, 13, - 12, 9, 5, 2, 5, 9, 9, 10, 13, 9, 3, 5, 9, 10, 9, 11, 13, 3, 5, - 10, 11, 8, 11, 15, 6, 8, 13, 14, 14, 14, 20, 11, 12, 16, 18, 18, 13, 23, - 15, 16, 19, 20, 18, 14, 23, 19, 18, 20, 21, 20, 18, 13, 8, 13, 15, 16, 14, - 18, 16, 9, 14, 16, 17, 17, 17, 19, 11, 14, 18, 18, 19, 17, 23, 15, 18, 21, - 22, 22, 19, 24, 20, 23, 25, 26, 25, 22, 24, 24, 27, 28, 28, 28, 25, 23, 30, - 31, 30, 30, 29, 27, 21, 20, 23, 23, 25, 24, 18, 25, 22, 24, 25, 26, 24, 17, - 24, 24, 27, 28, 28, 26, 21, 24, 28, 30, 31, 31, 29, 26, 26, 32, 35, 36, 36, - 33, 28, 28, 37, 40, 39, 39, 35, 29, 30, 40, 45, 42, 40, 37, 32, 31, 34, 33, - 34, 31, 27, 22, 31, 36, 35, 36, 32, 28, 23, 30, 38, 38, 38, 34, 30, 26, 30, - 41, 42, 42, 39, 33, 29, 34, 43, 48, 47, 42, 37, 31, 36, 45, 53, 51, 44, 40, - 34, 41, 47, 53, 54, 47, 40, 35, 41, 47, 45, 39, 34, 30, 26, 41, 47, 47, 41, - 35, 30, 26, 42, 48, 50, 44, 37, 34, 30, 42, 48, 54, 47, 42, 38, 33, 43, 51, - 56, 52, 47, 40, 35, 47, 53, 59, 57, 49, 42, 37, 50, 55, 59, 59, 52, 46, 39, - 1, 2, 2, 4, 4, 3, 4, 2, 1, 2, 4, 4, 2, 3, 2, 2, 2, 2, 3, - 0, 3, 2, 2, 1, 1, 2, 2, 3, 4, 4, 4, 4, 5, 4, 4, 8, 8, 7, - 7, 6, 4, 4, 13, 11, 9, 7, 6, 4, 4, 2, 1, 2, 3, 4, 6, 7, 2, - 1, 2, 3, 4, 5, 6, 3, 2, 1, 1, 2, 3, 5, 6, 3, 2, 3, 4, 4, - 6, 10, 5, 5, 6, 7, 4, 6, 12, 9, 9, 8, 9, 7, 6, 17, 14, 10, 9, - 10, 9, 6, 2, 2, 5, 7, 8, 9, 11, 7, 2, 4, 8, 8, 8, 9, 11, 2, - 4, 7, 8, 6, 8, 14, 4, 7, 10, 10, 11, 10, 17, 8, 10, 14, 15, 14, 10, - 19, 12, 14, 16, 16, 15, 10, 20, 17, 15, 17, 18, 17, 15, 11, 7, 12, 14, 14, - 12, 15, 14, 8, 12, 15, 16, 15, 15, 17, 9, 12, 15, 16, 16, 14, 19, 12, 16, - 18, 19, 18, 15, 21, 17, 20, 22, 23, 22, 18, 20, 22, 24, 25, 25, 23, 22, 20, - 26, 26, 27, 26, 25, 24, 18, 18, 21, 22, 23, 22, 16, 21, 20, 22, 23, 24, 23, - 15, 22, 21, 24, 25, 24, 23, 18, 22, 26, 26, 28, 28, 27, 23, 23, 30, 31, 32, - 33, 29, 24, 26, 34, 38, 36, 34, 31, 26, 27, 36, 39, 37, 37, 34, 27, 28, 31, - 32, 32, 29, 25, 20, 29, 33, 33, 33, 29, 25, 21, 27, 36, 35, 34, 30, 27, 23, - 28, 38, 39, 37, 34, 29, 26, 31, 39, 43, 42, 38, 32, 28, 34, 41, 48, 46, 41, - 34, 30, 37, 44, 49, 49, 42, 37, 31, 39, 44, 42, 36, 31, 27, 23, 39, 45, 45, - 38, 33, 28, 23, 39, 45, 47, 40, 34, 30, 26, 40, 45, 52, 44, 38, 34, 30, 41, - 47, 52, 49, 42, 37, 33, 43, 48, 55, 53, 45, 39, 33, 46, 51, 56, 55, 48, 40, - 35, 2, 3, 5, 6, 6, 5, 4, 1, 2, 4, 6, 6, 4, 2, 1, 2, 3, 4, - 5, 3, 0, 1, 1, 1, 3, 4, 3, 2, 3, 3, 3, 4, 6, 4, 2, 7, 6, - 6, 6, 6, 4, 2, 11, 9, 7, 6, 6, 4, 2, 1, 2, 3, 5, 4, 5, 6, - 1, 2, 3, 4, 4, 4, 5, 2, 1, 2, 3, 2, 2, 3, 2, 1, 1, 1, 1, - 2, 4, 5, 4, 4, 4, 3, 2, 3, 9, 8, 7, 7, 5, 4, 4, 14, 11, 8, - 7, 7, 6, 4, 2, 1, 5, 5, 6, 8, 9, 2, 1, 4, 6, 6, 6, 8, 5, - 1, 4, 6, 6, 5, 6, 10, 2, 5, 7, 7, 7, 7, 13, 6, 8, 10, 11, 10, - 7, 15, 11, 11, 13, 13, 11, 7, 16, 14, 13, 14, 14, 13, 12, 6, 6, 11, 11, - 12, 11, 13, 11, 7, 11, 12, 13, 13, 12, 13, 7, 11, 13, 13, 13, 11, 16, 10, - 14, 15, 14, 15, 12, 17, 15, 17, 19, 19, 18, 15, 16, 19, 20, 21, 21, 20, 18, - 16, 22, 23, 23, 23, 21, 20, 15, 17, 18, 19, 20, 19, 13, 18, 18, 20, 20, 21, - 20, 12, 18, 19, 21, 21, 21, 19, 15, 18, 22, 24, 24, 24, 22, 18, 20, 27, 28, - 28, 28, 26, 20, 21, 30, 33, 31, 29, 28, 22, 24, 33, 34, 33, 32, 28, 24, 27, - 30, 29, 29, 26, 22, 17, 26, 31, 30, 31, 27, 22, 18, 26, 34, 33, 31, 27, 23, - 19, 26, 34, 35, 33, 31, 27, 22, 28, 36, 40, 38, 34, 29, 24, 31, 37, 43, 42, - 36, 30, 26, 33, 39, 45, 44, 39, 33, 27, 37, 41, 39, 34, 29, 25, 21, 36, 41, - 42, 36, 30, 25, 21, 37, 41, 45, 37, 31, 26, 22, 36, 42, 46, 41, 35, 31, 26, - 37, 43, 48, 44, 38, 31, 28, 39, 45, 50, 48, 41, 34, 29, 41, 46, 51, 51, 45, - 36, 29, 2, 2, 3, 4, 4, 3, 2, 2, 2, 3, 4, 4, 3, 2, 1, 2, 2, - 3, 3, 2, 1, 0, 2, 2, 2, 3, 2, 3, 3, 3, 3, 3, 4, 3, 3, 7, - 6, 7, 6, 4, 3, 3, 12, 11, 8, 7, 5, 3, 3, 1, 2, 3, 3, 2, 2, - 2, 0, 2, 2, 3, 2, 2, 1, 1, 2, 2, 2, 2, 2, 1, 2, 1, 2, 2, - 2, 1, 3, 4, 3, 4, 4, 4, 3, 3, 9, 8, 8, 7, 5, 3, 3, 16, 13, - 10, 8, 6, 4, 3, 1, 2, 2, 2, 2, 2, 3, 2, 1, 1, 2, 2, 2, 3, - 2, 0, 1, 1, 1, 1, 3, 2, 2, 2, 2, 2, 2, 5, 6, 5, 5, 5, 5, - 4, 5, 12, 10, 10, 9, 7, 6, 5, 18, 17, 13, 10, 9, 7, 6, 2, 3, 3, - 4, 4, 4, 7, 2, 4, 4, 5, 5, 5, 8, 5, 5, 5, 6, 6, 6, 7, 8, - 8, 8, 9, 9, 9, 9, 9, 13, 13, 12, 13, 12, 11, 12, 19, 17, 16, 15, 14, - 13, 18, 24, 21, 18, 17, 15, 15, 11, 11, 11, 11, 11, 11, 8, 13, 13, 12, 13, - 13, 12, 8, 12, 15, 15, 14, 14, 13, 10, 13, 18, 18, 17, 18, 16, 13, 16, 23, - 22, 22, 22, 20, 15, 20, 26, 28, 26, 25, 21, 17, 24, 29, 30, 27, 27, 23, 18, - 20, 23, 21, 21, 17, 13, 10, 21, 24, 23, 22, 19, 15, 10, 21, 25, 26, 24, 21, - 17, 12, 21, 27, 28, 27, 25, 20, 17, 23, 29, 33, 33, 29, 23, 19, 25, 32, 38, - 36, 30, 26, 20, 29, 35, 39, 39, 34, 27, 21, 28, 34, 33, 25, 21, 17, 12, 28, - 34, 34, 29, 22, 17, 13, 28, 34, 38, 30, 25, 20, 16, 29, 34, 40, 33, 29, 24, - 20, 30, 37, 42, 38, 33, 26, 22, 33, 39, 44, 43, 36, 29, 24, 35, 41, 44, 44, - 38, 32, 26, 1, 2, 3, 4, 4, 3, 3, 2, 2, 3, 4, 4, 3, 2, 1, 2, - 3, 3, 3, 2, 1, 2, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, - 7, 6, 6, 6, 4, 3, 3, 13, 11, 8, 6, 5, 3, 3, 2, 2, 3, 3, 3, - 3, 3, 2, 1, 2, 3, 3, 2, 3, 2, 1, 2, 2, 2, 1, 1, 2, 1, 1, - 2, 1, 1, 3, 4, 4, 4, 4, 4, 3, 3, 9, 8, 8, 7, 5, 3, 3, 16, - 13, 10, 7, 5, 4, 3, 2, 1, 2, 2, 3, 4, 6, 2, 2, 2, 3, 3, 4, - 6, 2, 2, 2, 2, 3, 3, 6, 5, 2, 4, 4, 4, 5, 7, 8, 6, 8, 8, - 8, 7, 6, 13, 11, 12, 11, 10, 9, 7, 19, 16, 15, 13, 11, 10, 9, 2, 6, - 7, 8, 8, 7, 10, 5, 6, 8, 8, 9, 9, 10, 9, 7, 8, 9, 9, 9, 10, - 12, 9, 12, 12, 12, 12, 11, 12, 14, 15, 15, 16, 15, 14, 13, 20, 20, 19, 18, - 16, 15, 18, 26, 24, 21, 19, 18, 18, 13, 14, 15, 15, 16, 15, 10, 14, 16, 15, - 16, 17, 16, 10, 15, 18, 17, 17, 17, 16, 12, 15, 21, 21, 21, 21, 19, 16, 18, - 25, 25, 25, 25, 22, 17, 21, 28, 30, 28, 26, 24, 19, 25, 32, 34, 31, 30, 26, - 21, 24, 24, 25, 25, 21, 17, 13, 23, 27, 26, 25, 23, 18, 14, 23, 29, 28, 27, - 23, 19, 15, 23, 30, 31, 31, 27, 23, 19, 26, 32, 36, 35, 31, 26, 21, 29, 35, - 41, 41, 34, 28, 23, 31, 38, 42, 43, 35, 30, 24, 32, 38, 36, 30, 25, 20, 16, - 31, 38, 39, 32, 26, 21, 17, 31, 38, 41, 33, 27, 23, 19, 32, 37, 44, 36, 31, - 26, 23, 34, 39, 45, 42, 36, 30, 25, 35, 41, 47, 46, 39, 33, 26, 38, 44, 48, - 49, 42, 34, 29, 1, 2, 3, 4, 4, 4, 3, 2, 2, 3, 4, 4, 3, 2, 1, - 2, 2, 3, 3, 1, 1, 2, 2, 0, 2, 2, 2, 3, 4, 3, 3, 3, 3, 3, - 3, 7, 7, 7, 6, 4, 3, 3, 13, 11, 8, 6, 5, 3, 3, 2, 2, 2, 3, - 4, 4, 6, 2, 2, 2, 3, 3, 3, 5, 2, 1, 2, 2, 2, 2, 4, 2, 2, - 2, 1, 1, 2, 5, 5, 5, 4, 4, 4, 3, 5, 10, 9, 8, 7, 6, 4, 5, - 17, 14, 10, 8, 7, 6, 5, 2, 2, 4, 5, 5, 7, 9, 2, 2, 4, 5, 6, - 7, 8, 5, 2, 4, 5, 5, 6, 7, 8, 3, 6, 7, 7, 7, 9, 12, 6, 9, - 10, 11, 10, 9, 15, 11, 13, 14, 13, 12, 9, 19, 17, 16, 16, 14, 13, 12, 4, - 7, 10, 11, 12, 10, 13, 9, 7, 11, 12, 12, 12, 13, 12, 8, 11, 12, 12, 12, - 12, 14, 10, 14, 15, 15, 15, 13, 16, 15, 18, 18, 20, 18, 16, 15, 21, 23, 22, - 21, 20, 19, 19, 27, 26, 24, 22, 21, 20, 15, 17, 18, 19, 19, 18, 13, 17, 18, - 19, 20, 21, 19, 13, 18, 20, 21, 21, 20, 19, 15, 17, 24, 24, 24, 24, 23, 18, - 20, 27, 28, 29, 28, 26, 21, 23, 32, 34, 32, 30, 27, 22, 27, 35, 37, 35, 32, - 29, 23, 26, 29, 28, 28, 25, 21, 17, 27, 31, 30, 30, 26, 21, 17, 27, 33, 33, - 31, 27, 22, 19, 27, 34, 36, 34, 31, 26, 22, 28, 36, 41, 40, 36, 28, 24, 33, - 38, 45, 43, 37, 32, 26, 35, 41, 45, 45, 40, 34, 28, 35, 41, 40, 33, 29, 24, - 20, 35, 42, 43, 35, 29, 25, 20, 36, 41, 45, 37, 31, 26, 22, 36, 41, 47, 40, - 35, 30, 25, 37, 43, 48, 46, 40, 33, 27, 39, 44, 51, 51, 42, 35, 30, 43, 47, - 52, 52, 46, 38, 31, 2, 2, 3, 5, 5, 4, 5, 2, 2, 3, 4, 4, 3, 3, - 2, 2, 3, 3, 2, 1, 3, 2, 2, 2, 0, 2, 1, 3, 4, 4, 3, 3, 3, - 2, 3, 8, 7, 7, 6, 4, 2, 4, 13, 11, 8, 6, 5, 2, 3, 2, 2, 3, - 3, 5, 6, 8, 2, 2, 2, 3, 4, 5, 7, 2, 2, 2, 2, 3, 4, 6, 4, - 2, 2, 2, 3, 4, 6, 8, 5, 5, 5, 6, 4, 7, 11, 9, 9, 8, 8, 7, - 7, 17, 13, 10, 8, 10, 8, 7, 2, 2, 5, 7, 8, 10, 12, 4, 2, 5, 8, - 9, 9, 11, 8, 2, 5, 8, 8, 7, 9, 11, 3, 6, 10, 10, 10, 10, 15, 7, - 9, 13, 14, 13, 11, 18, 12, 13, 16, 15, 15, 11, 19, 17, 16, 17, 17, 16, 15, - 8, 8, 12, 14, 15, 13, 16, 12, 8, 13, 14, 16, 15, 15, 15, 8, 13, 15, 16, - 15, 15, 17, 12, 16, 17, 18, 18, 16, 19, 16, 20, 22, 22, 22, 18, 18, 22, 24, - 25, 24, 23, 22, 19, 26, 27, 26, 26, 24, 24, 17, 19, 21, 21, 23, 22, 16, 20, - 20, 22, 24, 24, 23, 16, 20, 22, 23, 24, 24, 22, 18, 20, 25, 27, 27, 27, 26, - 22, 22, 30, 31, 32, 31, 29, 24, 25, 34, 36, 36, 34, 30, 26, 29, 37, 40, 37, - 36, 33, 27, 28, 32, 32, 31, 29, 25, 20, 28, 34, 33, 33, 29, 25, 21, 28, 36, - 36, 35, 30, 25, 22, 29, 37, 39, 37, 33, 30, 25, 31, 39, 44, 43, 38, 33, 27, - 34, 41, 49, 46, 41, 35, 29, 39, 43, 49, 49, 42, 37, 31, 39, 46, 43, 37, 31, - 27, 23, 39, 45, 46, 39, 33, 28, 23, 39, 46, 49, 41, 34, 29, 25, 39, 45, 50, - 44, 37, 34, 29, 40, 47, 52, 49, 42, 37, 31, 43, 49, 54, 53, 46, 39, 32, 45, - 51, 54, 55, 49, 42, 34, 2, 3, 3, 4, 4, 6, 7, 2, 2, 3, 4, 3, 4, - 5, 2, 2, 3, 2, 2, 2, 4, 3, 2, 2, 2, 0, 2, 5, 5, 4, 4, 3, - 3, 3, 5, 9, 8, 7, 6, 4, 3, 5, 13, 10, 8, 6, 5, 3, 5, 2, 2, - 3, 4, 6, 9, 10, 3, 2, 3, 4, 6, 7, 9, 3, 2, 2, 3, 4, 6, 8, - 6, 3, 2, 2, 5, 5, 8, 10, 5, 5, 5, 8, 6, 8, 13, 9, 8, 8, 10, - 9, 8, 16, 13, 9, 8, 11, 11, 8, 3, 2, 6, 9, 11, 12, 14, 7, 2, 6, - 10, 11, 11, 13, 10, 3, 5, 9, 11, 10, 12, 13, 4, 7, 11, 12, 13, 12, 18, - 9, 10, 14, 16, 15, 13, 21, 12, 13, 17, 18, 17, 12, 20, 16, 15, 18, 19, 19, - 17, 10, 8, 14, 16, 17, 15, 18, 13, 8, 14, 17, 18, 18, 18, 16, 10, 14, 17, - 19, 19, 17, 20, 13, 17, 20, 21, 21, 18, 21, 18, 21, 23, 25, 24, 21, 21, 22, - 25, 26, 27, 25, 24, 20, 26, 27, 28, 28, 27, 26, 19, 20, 23, 25, 26, 25, 19, - 22, 22, 25, 26, 27, 25, 18, 23, 23, 26, 27, 27, 26, 21, 22, 26, 29, 30, 31, - 29, 24, 24, 31, 34, 34, 34, 31, 27, 26, 34, 38, 37, 36, 34, 28, 28, 36, 41, - 38, 38, 35, 30, 31, 35, 35, 35, 31, 28, 23, 31, 37, 36, 36, 33, 28, 24, 30, - 39, 38, 37, 33, 29, 25, 31, 38, 41, 40, 36, 32, 28, 32, 41, 46, 44, 40, 35, - 29, 35, 43, 52, 49, 42, 37, 32, 37, 45, 51, 51, 45, 39, 33, 40, 48, 45, 39, - 34, 31, 26, 42, 48, 48, 41, 36, 30, 26, 42, 48, 50, 43, 37, 32, 28, 41, 48, - 53, 46, 39, 35, 31, 43, 49, 54, 52, 45, 39, 33, 44, 52, 57, 56, 47, 42, 36, - 46, 53, 57, 58, 50, 43, 37, 3, 4, 4, 5, 5, 6, 7, 2, 3, 4, 5, 5, - 4, 5, 2, 3, 4, 3, 3, 2, 3, 2, 2, 2, 2, 2, 0, 3, 3, 2, 2, - 2, 3, 2, 3, 6, 5, 5, 4, 3, 2, 3, 9, 7, 5, 4, 3, 2, 3, 2, - 3, 4, 5, 6, 8, 9, 2, 3, 3, 5, 6, 6, 7, 2, 2, 3, 3, 4, 5, - 6, 4, 2, 1, 1, 3, 3, 5, 8, 3, 3, 4, 5, 3, 5, 10, 6, 6, 5, - 7, 6, 5, 12, 9, 6, 5, 8, 7, 5, 2, 2, 6, 8, 9, 11, 12, 5, 2, - 5, 9, 9, 9, 11, 9, 2, 5, 8, 9, 8, 10, 13, 2, 5, 8, 9, 9, 9, - 15, 6, 8, 11, 12, 12, 9, 16, 8, 10, 13, 14, 13, 9, 15, 12, 11, 15, 15, - 15, 13, 9, 7, 13, 15, 15, 14, 17, 14, 8, 13, 15, 16, 16, 16, 16, 8, 13, - 15, 16, 16, 15, 18, 10, 14, 17, 17, 17, 14, 19, 15, 18, 20, 20, 20, 17, 16, - 18, 21, 22, 22, 22, 20, 15, 21, 22, 24, 24, 23, 22, 17, 19, 22, 23, 24, 23, - 16, 20, 20, 23, 24, 25, 23, 16, 20, 21, 24, 25, 24, 23, 19, 20, 24, 25, 26, - 27, 25, 21, 21, 29, 30, 29, 30, 28, 23, 22, 30, 33, 33, 31, 29, 24, 22, 31, - 36, 35, 33, 31, 26, 28, 32, 32, 32, 30, 26, 21, 28, 34, 34, 34, 30, 25, 21, - 29, 36, 35, 35, 31, 26, 22, 28, 36, 38, 36, 32, 28, 24, 29, 38, 44, 40, 36, - 32, 26, 32, 40, 46, 43, 38, 33, 28, 33, 42, 46, 46, 41, 35, 30, 39, 46, 44, - 37, 32, 28, 24, 40, 45, 46, 40, 33, 29, 24, 40, 46, 48, 40, 33, 29, 24, 40, - 45, 50, 43, 37, 33, 28, 40, 45, 51, 47, 40, 34, 29, 41, 47, 52, 51, 43, 37, - 31, 43, 48, 53, 53, 46, 39, 32, 4, 5, 6, 7, 8, 6, 7, 4, 4, 5, 7, - 7, 5, 4, 3, 4, 4, 5, 6, 3, 2, 3, 3, 3, 3, 5, 3, 0, 2, 1, - 1, 2, 4, 2, 0, 3, 2, 2, 2, 3, 2, 0, 5, 3, 2, 2, 3, 2, 0, - 4, 4, 5, 6, 7, 8, 8, 3, 4, 4, 5, 6, 6, 6, 2, 4, 4, 4, 4, - 4, 4, 2, 2, 2, 2, 2, 2, 3, 2, 1, 1, 2, 2, 1, 3, 4, 3, 2, - 2, 2, 2, 3, 8, 5, 3, 2, 4, 3, 3, 3, 4, 6, 7, 9, 10, 11, 2, - 3, 6, 8, 8, 8, 9, 5, 3, 6, 7, 7, 6, 8, 9, 2, 4, 7, 6, 7, - 6, 12, 3, 5, 7, 8, 8, 6, 13, 4, 6, 9, 9, 9, 6, 11, 8, 6, 9, - 10, 10, 10, 5, 7, 11, 12, 13, 13, 14, 10, 8, 12, 13, 14, 14, 13, 13, 8, - 12, 13, 14, 14, 12, 15, 8, 12, 14, 14, 14, 11, 15, 10, 13, 15, 16, 15, 14, - 13, 12, 15, 17, 17, 17, 16, 11, 15, 17, 18, 19, 18, 18, 15, 17, 20, 20, 21, - 21, 14, 18, 18, 21, 21, 21, 20, 13, 18, 20, 22, 22, 22, 20, 16, 18, 20, 22, - 22, 23, 21, 17, 16, 23, 26, 24, 24, 22, 18, 16, 24, 27, 28, 26, 24, 20, 17, - 25, 30, 28, 28, 26, 21, 27, 29, 30, 29, 26, 23, 18, 27, 32, 31, 31, 27, 22, - 18, 27, 33, 33, 32, 27, 23, 19, 27, 33, 35, 32, 29, 24, 19, 26, 33, 37, 35, - 31, 26, 22, 27, 34, 39, 37, 32, 28, 23, 27, 34, 40, 40, 35, 29, 24, 37, 42, - 41, 34, 29, 25, 21, 37, 42, 43, 35, 30, 25, 21, 37, 43, 44, 36, 31, 27, 22, - 37, 42, 46, 40, 32, 27, 23, 36, 41, 46, 41, 35, 28, 24, 36, 42, 46, 45, 37, - 31, 26, 36, 41, 46, 46, 39, 33, 27, 4, 5, 6, 8, 8, 6, 5, 4, 5, 6, - 7, 8, 6, 4, 3, 4, 5, 6, 7, 4, 3, 3, 3, 4, 4, 4, 3, 2, 0, - 2, 2, 2, 3, 2, 2, 4, 4, 4, 3, 3, 2, 2, 10, 8, 6, 4, 3, 2, - 2, 3, 4, 5, 6, 5, 5, 5, 3, 4, 5, 6, 6, 5, 4, 2, 4, 4, 5, - 4, 4, 3, 2, 2, 3, 3, 3, 2, 1, 2, 2, 2, 2, 2, 2, 1, 6, 5, - 6, 5, 2, 1, 1, 13, 11, 7, 5, 3, 1, 1, 2, 3, 4, 4, 5, 5, 5, - 2, 3, 4, 4, 5, 4, 5, 2, 2, 4, 3, 4, 4, 4, 2, 1, 1, 1, 1, - 1, 2, 3, 3, 2, 2, 3, 1, 2, 9, 8, 7, 6, 4, 3, 2, 15, 14, 10, - 7, 6, 4, 3, 2, 3, 5, 5, 6, 6, 8, 1, 4, 5, 6, 6, 6, 8, 3, - 5, 6, 6, 6, 6, 8, 6, 6, 6, 6, 6, 7, 7, 6, 10, 9, 10, 10, 9, - 8, 9, 15, 14, 13, 12, 11, 10, 15, 21, 18, 15, 14, 12, 12, 11, 11, 11, 12, - 13, 11, 8, 12, 13, 13, 13, 14, 12, 8, 12, 14, 14, 14, 15, 13, 9, 12, 16, - 15, 15, 15, 14, 10, 14, 19, 19, 19, 19, 17, 12, 17, 23, 24, 23, 21, 19, 13, - 21, 26, 28, 25, 23, 21, 15, 20, 22, 21, 22, 19, 14, 10, 20, 24, 23, 24, 20, - 16, 11, 20, 26, 25, 25, 21, 16, 12, 20, 25, 26, 25, 22, 18, 14, 20, 26, 30, - 29, 25, 20, 15, 22, 29, 36, 33, 28, 23, 17, 25, 31, 35, 36, 30, 25, 19, 28, - 35, 32, 26, 22, 17, 13, 28, 35, 36, 29, 24, 18, 14, 28, 34, 38, 30, 25, 19, - 14, 28, 35, 38, 31, 26, 21, 17, 26, 33, 38, 36, 30, 26, 19, 29, 36, 40, 39, - 33, 28, 20, 32, 37, 40, 40, 33, 29, 23, 4, 5, 6, 7, 7, 7, 6, 3, 5, - 6, 7, 7, 6, 5, 3, 4, 5, 6, 6, 4, 3, 3, 3, 3, 4, 4, 2, 1, - 2, 0, 1, 2, 3, 2, 2, 4, 4, 4, 3, 2, 2, 1, 10, 8, 5, 4, 2, - 2, 1, 3, 4, 5, 7, 7, 7, 6, 3, 4, 5, 6, 6, 5, 5, 2, 3, 5, - 5, 5, 4, 3, 2, 2, 2, 2, 2, 2, 0, 2, 2, 1, 2, 1, 1, 0, 7, - 6, 5, 4, 2, 1, 0, 13, 11, 7, 5, 3, 1, 0, 3, 3, 4, 5, 6, 7, - 8, 2, 3, 4, 5, 6, 6, 7, 2, 2, 4, 4, 4, 4, 6, 2, 2, 2, 2, - 3, 3, 5, 5, 3, 5, 5, 5, 4, 5, 10, 8, 9, 8, 7, 6, 5, 15, 13, - 12, 10, 8, 7, 6, 2, 6, 7, 8, 9, 9, 11, 2, 7, 8, 8, 9, 9, 10, - 6, 7, 8, 9, 9, 9, 10, 9, 7, 9, 9, 9, 9, 9, 9, 11, 12, 12, 13, - 12, 11, 10, 17, 17, 16, 14, 13, 13, 16, 23, 20, 18, 16, 15, 14, 13, 14, 14, - 15, 16, 15, 11, 13, 16, 16, 16, 17, 16, 11, 14, 17, 17, 17, 17, 16, 12, 14, - 18, 17, 18, 18, 16, 13, 15, 22, 22, 21, 22, 19, 14, 19, 26, 27, 26, 24, 21, - 16, 23, 30, 31, 28, 26, 23, 18, 23, 25, 24, 24, 22, 17, 13, 23, 27, 26, 25, - 23, 18, 14, 23, 29, 29, 26, 23, 18, 14, 23, 28, 29, 28, 24, 20, 16, 23, 29, - 33, 32, 28, 23, 18, 26, 32, 39, 37, 31, 25, 19, 29, 33, 38, 39, 34, 27, 21, - 31, 37, 37, 29, 24, 20, 16, 32, 38, 39, 31, 26, 21, 17, 31, 37, 41, 33, 27, - 21, 17, 31, 36, 43, 34, 28, 24, 20, 30, 37, 42, 40, 32, 26, 21, 31, 38, 44, - 44, 35, 29, 23, 35, 40, 46, 46, 39, 31, 24, 4, 5, 6, 8, 8, 7, 6, 4, - 5, 6, 7, 7, 6, 5, 3, 4, 5, 6, 6, 4, 3, 3, 3, 3, 3, 4, 2, - 1, 2, 1, 0, 2, 2, 1, 1, 4, 4, 4, 3, 2, 1, 1, 10, 8, 5, 3, - 2, 1, 1, 4, 4, 5, 7, 7, 8, 8, 3, 4, 5, 6, 7, 6, 7, 3, 4, - 5, 5, 5, 4, 5, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 1, 0, 3, - 7, 6, 5, 4, 2, 1, 3, 13, 10, 7, 5, 4, 2, 3, 3, 4, 6, 7, 8, - 10, 10, 2, 3, 6, 7, 8, 8, 9, 3, 3, 6, 6, 6, 7, 8, 6, 2, 4, - 5, 5, 6, 7, 8, 4, 6, 7, 7, 7, 7, 12, 8, 10, 10, 9, 8, 7, 15, - 13, 13, 12, 10, 10, 8, 2, 7, 10, 11, 11, 12, 13, 6, 8, 10, 11, 12, 12, - 13, 10, 8, 11, 11, 12, 12, 12, 12, 8, 11, 12, 12, 12, 11, 12, 12, 14, 15, - 16, 14, 14, 12, 18, 20, 19, 17, 17, 15, 15, 23, 22, 21, 19, 18, 16, 14, 17, - 18, 18, 19, 18, 14, 15, 19, 19, 19, 19, 19, 13, 16, 19, 20, 20, 20, 19, 15, - 16, 21, 22, 21, 21, 20, 16, 16, 24, 25, 24, 24, 22, 17, 19, 27, 30, 29, 27, - 24, 19, 24, 32, 34, 31, 29, 26, 20, 26, 29, 28, 28, 25, 21, 16, 26, 31, 29, - 30, 26, 21, 16, 25, 32, 32, 30, 26, 21, 17, 26, 31, 33, 32, 27, 23, 19, 25, - 32, 37, 35, 31, 26, 20, 28, 34, 41, 39, 34, 27, 23, 32, 36, 42, 42, 36, 30, - 24, 35, 41, 39, 33, 28, 24, 19, 35, 41, 42, 35, 29, 24, 19, 35, 42, 45, 36, - 30, 24, 19, 35, 40, 46, 38, 31, 26, 22, 33, 40, 46, 43, 37, 29, 24, 35, 43, - 47, 47, 39, 32, 26, 39, 45, 49, 48, 41, 34, 29, 4, 5, 6, 8, 8, 7, 8, - 4, 5, 6, 7, 7, 6, 6, 3, 5, 6, 6, 5, 4, 4, 3, 3, 3, 3, 3, - 2, 2, 2, 2, 2, 0, 2, 1, 2, 5, 4, 4, 3, 2, 1, 2, 9, 7, 5, - 3, 2, 1, 2, 4, 5, 5, 7, 8, 10, 10, 3, 4, 5, 6, 7, 8, 8, 3, - 4, 5, 5, 5, 6, 6, 3, 2, 3, 3, 3, 4, 5, 4, 2, 2, 2, 3, 3, - 5, 8, 6, 5, 5, 5, 4, 5, 12, 9, 6, 5, 6, 5, 5, 3, 4, 7, 9, - 10, 12, 13, 3, 3, 7, 9, 9, 10, 11, 6, 3, 6, 8, 8, 8, 10, 9, 2, - 5, 7, 8, 8, 9, 11, 4, 7, 10, 10, 10, 9, 14, 8, 10, 12, 12, 11, 9, - 14, 11, 11, 14, 13, 12, 11, 6, 8, 12, 13, 14, 14, 16, 10, 9, 13, 14, 15, - 15, 16, 13, 9, 13, 14, 15, 15, 15, 15, 9, 13, 15, 15, 16, 14, 15, 13, 16, - 18, 18, 18, 17, 14, 18, 21, 21, 20, 19, 18, 14, 21, 23, 23, 22, 21, 20, 16, - 19, 20, 21, 22, 22, 16, 18, 20, 22, 23, 23, 22, 16, 18, 21, 23, 23, 24, 22, - 18, 18, 23, 24, 24, 25, 23, 19, 18, 27, 28, 27, 27, 25, 20, 21, 30, 33, 31, - 30, 27, 22, 24, 31, 35, 33, 32, 29, 23, 27, 32, 31, 31, 28, 24, 20, 28, 34, - 32, 33, 29, 24, 20, 27, 35, 36, 34, 29, 25, 20, 28, 35, 37, 36, 31, 27, 22, - 27, 34, 40, 39, 35, 29, 23, 31, 38, 44, 43, 37, 31, 25, 34, 39, 45, 46, 40, - 33, 27, 38, 45, 43, 37, 31, 26, 22, 39, 44, 46, 39, 33, 27, 23, 39, 45, 47, - 40, 33, 28, 23, 39, 45, 49, 41, 35, 30, 26, 37, 43, 49, 46, 39, 33, 27, 38, - 45, 51, 50, 43, 35, 29, 41, 46, 51, 51, 44, 38, 31, 5, 5, 6, 7, 7, 9, - 10, 5, 5, 6, 7, 7, 7, 8, 4, 5, 6, 5, 5, 5, 6, 4, 3, 3, 3, - 3, 3, 4, 3, 3, 2, 2, 0, 1, 4, 4, 3, 3, 2, 1, 1, 4, 6, 5, - 3, 2, 2, 2, 4, 4, 5, 6, 7, 9, 11, 12, 4, 5, 5, 7, 9, 10, 10, - 4, 4, 5, 5, 7, 8, 9, 5, 3, 3, 3, 5, 6, 7, 6, 3, 2, 3, 6, - 5, 7, 8, 4, 4, 4, 7, 7, 7, 10, 7, 4, 4, 8, 8, 7, 3, 5, 8, - 11, 12, 14, 15, 5, 4, 7, 11, 12, 12, 14, 8, 4, 7, 10, 11, 11, 13, 12, - 3, 5, 10, 11, 12, 11, 13, 4, 7, 12, 13, 13, 12, 14, 6, 8, 12, 14, 14, - 12, 14, 9, 9, 13, 16, 16, 15, 8, 9, 14, 17, 18, 17, 20, 12, 10, 15, 17, - 19, 19, 19, 15, 10, 16, 18, 19, 19, 18, 17, 10, 15, 18, 18, 19, 17, 16, 14, - 17, 20, 21, 21, 20, 15, 16, 20, 22, 23, 23, 22, 14, 18, 21, 23, 24, 24, 24, - 19, 21, 24, 25, 26, 26, 19, 21, 22, 25, 26, 28, 26, 19, 21, 24, 26, 28, 27, - 25, 21, 21, 25, 26, 27, 28, 27, 22, 20, 28, 30, 30, 31, 29, 24, 21, 29, 34, - 33, 32, 30, 25, 21, 30, 37, 35, 34, 33, 27, 30, 34, 35, 34, 32, 28, 24, 30, - 37, 37, 37, 33, 28, 24, 30, 39, 39, 37, 33, 29, 25, 31, 38, 40, 39, 35, 30, - 25, 30, 39, 43, 41, 36, 32, 27, 31, 40, 47, 44, 39, 33, 29, 32, 41, 45, 47, - 41, 36, 31, 42, 48, 47, 40, 35, 31, 26, 43, 49, 49, 42, 36, 32, 27, 42, 48, - 51, 44, 37, 32, 27, 43, 48, 53, 44, 39, 33, 29, 41, 47, 53, 49, 41, 35, 31, - 42, 48, 52, 50, 44, 38, 32, 43, 48, 53, 53, 46, 40, 33, 4, 5, 5, 6, 6, - 8, 8, 4, 5, 5, 6, 6, 6, 6, 3, 4, 5, 4, 4, 4, 4, 3, 3, 3, - 2, 3, 2, 3, 2, 2, 1, 1, 1, 0, 2, 3, 2, 2, 2, 1, 0, 2, 5, - 3, 2, 1, 1, 0, 2, 4, 4, 5, 6, 8, 10, 10, 3, 4, 5, 6, 7, 8, - 9, 3, 3, 4, 4, 5, 6, 7, 4, 2, 2, 2, 3, 4, 5, 6, 2, 2, 2, - 4, 3, 5, 7, 3, 2, 2, 5, 5, 5, 9, 5, 3, 2, 6, 6, 5, 3, 4, - 7, 9, 11, 12, 14, 5, 3, 7, 10, 10, 10, 12, 9, 3, 6, 9, 9, 9, 10, - 13, 2, 5, 8, 9, 10, 9, 13, 3, 5, 9, 10, 11, 9, 16, 5, 6, 10, 12, - 12, 9, 14, 8, 7, 11, 13, 13, 13, 9, 8, 13, 15, 16, 15, 17, 13, 8, 13, - 16, 16, 17, 17, 16, 8, 13, 16, 17, 16, 16, 18, 9, 14, 16, 17, 17, 14, 18, - 12, 15, 18, 19, 18, 17, 15, 13, 17, 19, 20, 20, 20, 14, 16, 19, 21, 21, 21, - 21, 16, 19, 22, 23, 24, 24, 18, 20, 20, 22, 24, 25, 23, 17, 20, 21, 25, 25, - 25, 24, 19, 20, 24, 25, 26, 26, 24, 20, 18, 25, 27, 28, 28, 25, 21, 18, 26, - 30, 30, 29, 27, 23, 18, 27, 32, 32, 31, 30, 25, 29, 33, 33, 32, 30, 26, 21, - 28, 35, 34, 34, 31, 26, 21, 29, 38, 37, 35, 31, 27, 22, 28, 36, 38, 37, 32, - 28, 23, 28, 36, 41, 39, 34, 29, 25, 29, 36, 42, 42, 35, 30, 26, 30, 37, 43, - 43, 38, 33, 27, 40, 47, 45, 37, 33, 28, 24, 40, 45, 46, 40, 34, 29, 25, 41, - 46, 49, 41, 34, 29, 25, 40, 45, 50, 42, 36, 31, 26, 39, 44, 49, 46, 38, 33, - 28, 39, 45, 50, 47, 40, 34, 30, 39, 46, 50, 49, 43, 36, 30, 4, 5, 6, 8, - 8, 6, 6, 4, 4, 5, 7, 7, 5, 4, 3, 4, 5, 5, 6, 4, 2, 3, 3, - 3, 3, 5, 3, 0, 2, 1, 1, 2, 4, 2, 0, 2, 2, 2, 2, 3, 2, 0, - 4, 3, 2, 2, 3, 2, 0, 4, 4, 5, 6, 6, 8, 8, 3, 4, 5, 5, 6, - 6, 6, 3, 4, 4, 4, 4, 4, 5, 2, 2, 2, 2, 2, 2, 3, 2, 2, 1, - 1, 1, 1, 3, 4, 2, 2, 2, 2, 2, 3, 7, 5, 2, 2, 3, 3, 3, 3, - 4, 6, 8, 9, 10, 11, 2, 3, 6, 8, 8, 8, 9, 5, 3, 6, 7, 7, 7, - 8, 9, 2, 4, 7, 6, 7, 6, 11, 2, 4, 7, 8, 8, 6, 13, 4, 5, 8, - 9, 9, 6, 10, 8, 6, 9, 10, 10, 10, 5, 7, 11, 12, 13, 13, 14, 10, 7, - 11, 13, 14, 14, 13, 13, 8, 12, 13, 14, 13, 12, 15, 7, 12, 14, 14, 14, 11, - 16, 10, 13, 15, 15, 15, 14, 12, 12, 15, 16, 17, 17, 16, 10, 15, 17, 18, 18, - 18, 18, 15, 17, 20, 20, 21, 20, 14, 18, 18, 21, 21, 22, 20, 13, 18, 19, 21, - 22, 22, 20, 17, 17, 21, 23, 23, 23, 21, 16, 16, 22, 25, 25, 25, 23, 18, 16, - 24, 27, 27, 25, 24, 20, 17, 25, 30, 28, 28, 26, 21, 25, 29, 30, 30, 26, 23, - 18, 27, 32, 32, 30, 27, 23, 18, 27, 34, 34, 33, 28, 23, 19, 27, 33, 34, 32, - 29, 25, 20, 26, 33, 37, 34, 30, 26, 21, 27, 33, 41, 38, 32, 28, 23, 27, 34, - 39, 41, 35, 29, 24, 36, 42, 39, 34, 29, 25, 21, 37, 43, 42, 36, 31, 26, 22, - 37, 43, 45, 38, 31, 26, 22, 38, 42, 47, 39, 32, 28, 23, 37, 40, 45, 42, 34, - 29, 24, 35, 41, 46, 44, 36, 30, 26, 36, 42, 46, 45, 40, 33, 27, 8, 9, 10, - 12, 12, 11, 10, 8, 9, 10, 12, 12, 10, 9, 7, 8, 9, 10, 11, 8, 7, 7, - 7, 7, 8, 8, 6, 3, 4, 4, 4, 5, 4, 3, 2, 0, 2, 2, 2, 3, 3, - 2, 6, 5, 2, 2, 2, 3, 2, 7, 8, 10, 11, 11, 11, 10, 7, 8, 9, 10, - 10, 10, 9, 6, 7, 9, 9, 9, 8, 7, 6, 6, 6, 7, 6, 5, 2, 3, 3, - 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 9, 7, 4, 2, 1, 2, 2, - 6, 8, 9, 9, 10, 11, 10, 6, 7, 8, 9, 9, 9, 9, 5, 6, 7, 7, 8, - 8, 7, 5, 5, 5, 5, 5, 5, 3, 2, 1, 1, 2, 2, 2, 3, 5, 4, 3, - 2, 0, 2, 3, 11, 10, 6, 4, 2, 2, 3, 6, 7, 8, 9, 11, 12, 11, 5, - 7, 8, 10, 10, 10, 10, 4, 7, 8, 8, 8, 9, 8, 5, 6, 5, 6, 6, 6, - 6, 3, 6, 6, 6, 7, 7, 7, 5, 11, 10, 9, 8, 8, 8, 11, 16, 13, 12, - 10, 9, 10, 9, 10, 11, 11, 12, 12, 12, 11, 12, 12, 12, 13, 12, 10, 11, 13, - 14, 13, 13, 12, 8, 11, 15, 14, 14, 14, 13, 9, 11, 16, 16, 15, 15, 15, 10, - 12, 18, 21, 20, 18, 16, 11, 17, 21, 24, 21, 20, 18, 13, 18, 20, 20, 21, 18, - 14, 11, 19, 23, 23, 22, 19, 14, 10, 19, 24, 25, 24, 20, 15, 10, 18, 24, 25, - 26, 22, 16, 11, 18, 24, 27, 27, 23, 17, 13, 19, 24, 30, 29, 24, 20, 15, 21, - 27, 31, 31, 27, 21, 16, 27, 33, 33, 26, 21, 16, 12, 27, 33, 35, 27, 22, 17, - 13, 27, 33, 36, 29, 23, 18, 13, 28, 33, 37, 30, 25, 19, 15, 26, 33, 36, 33, - 26, 22, 16, 27, 32, 35, 34, 28, 23, 19, 28, 31, 36, 36, 31, 25, 20, 8, 9, - 10, 11, 11, 11, 10, 7, 8, 10, 11, 11, 10, 8, 7, 8, 9, 10, 9, 8, 6, - 6, 6, 7, 7, 7, 5, 2, 4, 4, 4, 4, 4, 2, 2, 2, 0, 2, 2, 2, - 2, 2, 6, 4, 2, 2, 2, 2, 2, 7, 8, 9, 11, 11, 11, 11, 6, 8, 9, - 10, 11, 9, 9, 6, 7, 8, 9, 8, 7, 6, 6, 5, 6, 6, 6, 5, 2, 3, - 3, 3, 3, 2, 2, 2, 3, 2, 2, 2, 1, 2, 2, 9, 7, 3, 2, 1, 2, - 2, 6, 7, 8, 9, 11, 11, 12, 6, 6, 8, 9, 10, 10, 10, 6, 6, 8, 8, - 8, 8, 8, 5, 5, 6, 6, 5, 5, 5, 3, 2, 3, 3, 3, 3, 4, 5, 5, - 5, 4, 3, 4, 5, 11, 9, 8, 6, 5, 5, 5, 6, 9, 9, 11, 12, 14, 13, - 5, 8, 10, 11, 12, 12, 11, 5, 8, 9, 9, 9, 10, 9, 8, 7, 8, 8, 8, - 9, 8, 6, 8, 9, 9, 10, 10, 10, 6, 13, 13, 12, 11, 11, 11, 11, 18, 16, - 14, 12, 12, 13, 12, 13, 14, 14, 15, 15, 13, 12, 15, 15, 16, 16, 14, 11, 13, - 16, 17, 16, 16, 15, 11, 13, 17, 17, 16, 17, 16, 12, 12, 19, 19, 18, 18, 17, - 13, 14, 22, 23, 21, 20, 18, 14, 19, 24, 26, 24, 22, 20, 16, 22, 24, 24, 24, - 21, 17, 13, 22, 26, 25, 25, 22, 17, 12, 22, 28, 28, 27, 22, 17, 13, 22, 27, - 29, 27, 24, 19, 14, 22, 27, 30, 30, 25, 20, 16, 21, 28, 34, 33, 27, 21, 17, - 25, 30, 34, 35, 30, 24, 18, 31, 37, 36, 29, 23, 19, 15, 30, 36, 39, 32, 25, - 20, 16, 30, 37, 40, 32, 26, 21, 17, 31, 35, 41, 33, 27, 22, 17, 29, 35, 41, - 36, 29, 23, 19, 29, 35, 41, 38, 32, 26, 20, 30, 37, 40, 42, 34, 27, 22, 8, - 9, 10, 12, 11, 11, 10, 7, 8, 10, 11, 11, 9, 8, 7, 8, 9, 9, 9, 7, - 6, 6, 6, 7, 7, 7, 5, 2, 4, 4, 3, 4, 3, 2, 2, 2, 2, 0, 2, - 2, 2, 2, 5, 3, 2, 1, 2, 2, 2, 7, 8, 9, 10, 11, 11, 12, 7, 8, - 9, 10, 11, 10, 10, 6, 7, 8, 8, 8, 7, 7, 6, 6, 6, 6, 5, 4, 4, - 3, 3, 3, 3, 2, 2, 4, 3, 2, 2, 1, 2, 2, 3, 7, 5, 3, 1, 1, - 2, 3, 6, 7, 9, 11, 12, 14, 14, 6, 7, 10, 11, 12, 12, 12, 6, 7, 9, - 10, 9, 9, 9, 5, 5, 7, 7, 7, 7, 6, 6, 2, 4, 5, 5, 5, 6, 8, - 4, 7, 7, 6, 6, 6, 8, 7, 8, 9, 7, 7, 8, 6, 10, 11, 12, 14, 15, - 15, 5, 9, 11, 12, 13, 13, 13, 8, 9, 11, 11, 12, 11, 11, 10, 8, 11, 11, - 11, 12, 10, 9, 9, 11, 12, 12, 12, 13, 8, 13, 15, 15, 14, 14, 14, 8, 16, - 17, 16, 15, 15, 15, 13, 16, 17, 17, 18, 18, 15, 15, 17, 18, 18, 19, 17, 13, - 15, 18, 20, 19, 19, 18, 14, 15, 20, 20, 20, 20, 19, 14, 13, 22, 22, 21, 21, - 20, 15, 16, 24, 26, 24, 23, 21, 17, 18, 25, 28, 27, 25, 23, 19, 24, 27, 27, - 27, 24, 20, 16, 26, 29, 29, 29, 25, 21, 16, 25, 31, 31, 30, 25, 21, 17, 24, - 31, 32, 30, 26, 22, 17, 24, 30, 34, 32, 28, 23, 18, 24, 31, 36, 36, 30, 24, - 20, 27, 33, 38, 39, 33, 27, 21, 35, 39, 39, 32, 27, 22, 18, 34, 41, 42, 34, - 28, 23, 19, 35, 41, 44, 36, 29, 24, 19, 34, 40, 44, 37, 30, 25, 21, 33, 39, - 44, 39, 32, 26, 22, 32, 39, 43, 43, 34, 29, 23, 34, 40, 45, 45, 39, 30, 25, - 7, 8, 9, 10, 10, 10, 11, 7, 7, 8, 10, 10, 9, 8, 6, 7, 8, 9, 8, - 7, 6, 6, 6, 6, 6, 6, 4, 3, 3, 3, 3, 3, 2, 1, 2, 2, 2, 2, - 0, 2, 2, 2, 4, 3, 2, 1, 1, 1, 2, 7, 7, 8, 9, 10, 12, 13, 6, - 7, 8, 9, 10, 10, 11, 6, 7, 7, 7, 8, 8, 8, 5, 5, 5, 5, 5, 5, - 5, 3, 2, 2, 2, 2, 3, 5, 3, 2, 2, 2, 2, 3, 4, 6, 4, 2, 2, - 3, 3, 4, 6, 7, 10, 11, 13, 14, 15, 5, 6, 9, 12, 12, 12, 12, 4, 6, - 9, 10, 10, 10, 10, 8, 4, 6, 8, 8, 8, 8, 10, 2, 4, 7, 8, 8, 8, - 11, 3, 5, 8, 9, 9, 8, 10, 7, 6, 10, 10, 10, 11, 5, 10, 13, 13, 15, - 15, 17, 8, 9, 12, 14, 14, 14, 15, 11, 9, 13, 13, 14, 14, 14, 13, 8, 13, - 14, 14, 15, 13, 13, 10, 14, 15, 16, 16, 16, 11, 12, 16, 16, 17, 16, 17, 10, - 15, 17, 18, 18, 18, 18, 15, 18, 20, 20, 22, 21, 17, 17, 20, 22, 22, 22, 21, - 15, 17, 20, 23, 22, 22, 22, 17, 17, 22, 23, 23, 23, 22, 17, 16, 24, 25, 25, - 25, 23, 19, 16, 25, 28, 27, 26, 24, 20, 17, 26, 30, 28, 29, 26, 22, 27, 31, - 31, 31, 27, 24, 19, 27, 32, 33, 33, 28, 24, 19, 27, 35, 35, 34, 29, 24, 20, - 27, 33, 35, 34, 29, 25, 21, 26, 33, 38, 36, 31, 26, 22, 27, 32, 39, 39, 33, - 27, 23, 28, 34, 39, 40, 35, 30, 25, 38, 44, 42, 36, 31, 26, 21, 38, 45, 45, - 38, 31, 27, 22, 37, 44, 47, 39, 32, 27, 22, 38, 43, 48, 40, 34, 28, 23, 37, - 42, 48, 43, 35, 30, 25, 36, 43, 47, 45, 37, 32, 27, 37, 42, 47, 47, 41, 33, - 28, 6, 6, 7, 8, 8, 9, 10, 5, 6, 7, 8, 8, 8, 8, 5, 6, 6, 6, - 6, 6, 6, 4, 4, 4, 4, 4, 3, 3, 2, 2, 2, 2, 1, 1, 3, 3, 2, - 2, 2, 0, 1, 3, 5, 4, 2, 2, 1, 1, 3, 5, 6, 7, 8, 10, 12, 13, - 5, 5, 6, 8, 10, 10, 10, 4, 5, 6, 6, 7, 8, 8, 4, 3, 3, 4, 5, - 6, 7, 5, 3, 2, 2, 4, 4, 7, 6, 3, 3, 2, 5, 5, 7, 8, 5, 3, - 3, 6, 6, 7, 4, 5, 8, 11, 13, 14, 15, 4, 4, 8, 11, 12, 12, 14, 8, - 4, 8, 10, 10, 11, 12, 11, 3, 5, 9, 10, 11, 11, 12, 3, 5, 10, 11, 12, - 11, 13, 4, 7, 11, 13, 13, 11, 12, 8, 7, 12, 13, 14, 14, 8, 9, 14, 16, - 17, 17, 19, 11, 9, 14, 17, 18, 17, 18, 14, 9, 15, 17, 18, 18, 17, 16, 10, - 14, 17, 18, 19, 16, 16, 12, 16, 18, 20, 19, 19, 14, 14, 18, 20, 21, 21, 21, - 12, 16, 20, 22, 22, 22, 22, 17, 21, 23, 24, 25, 25, 19, 20, 21, 24, 25, 26, - 25, 18, 20, 22, 26, 26, 27, 25, 21, 20, 25, 26, 27, 27, 26, 21, 18, 26, 28, - 29, 29, 27, 22, 18, 27, 31, 32, 30, 29, 24, 19, 29, 33, 33, 33, 30, 25, 30, - 33, 34, 34, 31, 27, 23, 30, 37, 36, 35, 32, 27, 23, 30, 38, 38, 37, 33, 28, - 23, 30, 38, 39, 37, 33, 29, 24, 28, 37, 42, 39, 35, 30, 25, 30, 37, 44, 42, - 36, 32, 27, 31, 38, 43, 44, 38, 33, 29, 42, 48, 45, 40, 34, 30, 26, 41, 48, - 48, 41, 35, 30, 26, 42, 47, 50, 42, 36, 31, 27, 41, 47, 51, 44, 37, 32, 27, - 40, 45, 51, 46, 39, 34, 29, 40, 46, 50, 49, 42, 36, 30, 40, 46, 51, 51, 44, - 37, 32, 4, 5, 5, 6, 6, 8, 8, 4, 5, 5, 6, 6, 6, 6, 3, 4, 5, - 4, 4, 4, 4, 3, 3, 3, 2, 3, 2, 2, 2, 2, 1, 1, 2, 0, 2, 3, - 2, 2, 1, 2, 0, 2, 5, 3, 2, 1, 1, 0, 2, 4, 4, 5, 6, 8, 9, - 10, 3, 4, 5, 6, 8, 8, 8, 3, 4, 4, 4, 6, 6, 7, 4, 2, 2, 2, - 4, 4, 5, 6, 2, 2, 2, 4, 3, 5, 7, 3, 2, 2, 5, 5, 5, 9, 5, - 3, 2, 6, 6, 5, 3, 4, 7, 9, 10, 12, 14, 5, 3, 7, 10, 10, 10, 12, - 9, 3, 6, 8, 9, 9, 10, 13, 2, 5, 8, 9, 10, 9, 13, 3, 5, 9, 11, - 11, 9, 17, 5, 6, 10, 11, 12, 9, 14, 9, 7, 11, 13, 13, 13, 9, 8, 13, - 15, 15, 15, 17, 15, 8, 13, 16, 17, 17, 16, 16, 8, 14, 15, 16, 17, 16, 19, - 9, 13, 17, 17, 17, 14, 18, 12, 15, 18, 18, 19, 17, 15, 13, 17, 19, 20, 20, - 20, 15, 16, 19, 21, 21, 21, 22, 17, 19, 22, 23, 25, 23, 18, 20, 20, 23, 24, - 26, 23, 17, 20, 21, 25, 25, 26, 24, 19, 20, 23, 25, 25, 26, 24, 20, 19, 25, - 27, 28, 28, 26, 22, 18, 26, 30, 30, 29, 27, 23, 19, 27, 32, 32, 31, 28, 25, - 28, 32, 32, 33, 30, 26, 21, 29, 35, 35, 34, 31, 26, 22, 29, 37, 36, 36, 31, - 26, 22, 28, 36, 39, 37, 33, 28, 23, 29, 35, 40, 40, 33, 29, 24, 28, 36, 42, - 41, 36, 30, 26, 30, 37, 43, 44, 38, 33, 28, 40, 46, 44, 38, 32, 29, 25, 40, - 46, 47, 39, 33, 29, 24, 42, 45, 49, 41, 35, 30, 25, 39, 46, 50, 42, 36, 30, - 26, 39, 44, 49, 46, 39, 32, 28, 39, 45, 50, 48, 40, 34, 29, 39, 45, 50, 50, - 43, 37, 31, 4, 5, 6, 7, 7, 6, 6, 4, 4, 5, 7, 7, 5, 4, 3, 4, - 5, 5, 6, 4, 2, 3, 3, 3, 3, 5, 3, 0, 2, 1, 1, 2, 4, 2, 0, - 2, 2, 2, 2, 3, 2, 0, 4, 3, 2, 2, 3, 2, 0, 4, 4, 5, 6, 7, - 8, 8, 3, 4, 4, 5, 6, 6, 7, 3, 4, 4, 4, 4, 4, 4, 2, 2, 2, - 2, 2, 2, 3, 2, 2, 1, 1, 1, 1, 3, 4, 2, 2, 2, 2, 2, 3, 7, - 5, 2, 2, 4, 3, 3, 3, 4, 6, 8, 9, 10, 11, 2, 3, 7, 8, 8, 8, - 9, 5, 3, 6, 7, 6, 6, 8, 9, 2, 4, 7, 6, 6, 6, 11, 2, 4, 7, - 8, 8, 6, 12, 4, 5, 8, 9, 9, 6, 10, 8, 6, 9, 10, 10, 10, 5, 7, - 11, 13, 13, 13, 14, 10, 7, 11, 13, 14, 14, 13, 13, 8, 12, 13, 14, 13, 12, - 15, 8, 12, 14, 14, 14, 11, 15, 10, 13, 15, 15, 15, 14, 13, 12, 15, 16, 17, - 16, 17, 10, 15, 17, 18, 18, 18, 18, 15, 17, 19, 20, 21, 20, 15, 18, 19, 20, - 21, 22, 21, 13, 18, 20, 22, 22, 22, 20, 16, 18, 22, 22, 22, 23, 22, 17, 16, - 23, 24, 24, 25, 23, 18, 16, 24, 27, 27, 26, 23, 20, 17, 25, 30, 28, 28, 25, - 21, 27, 30, 29, 30, 27, 23, 19, 27, 32, 32, 31, 27, 23, 18, 26, 34, 34, 32, - 27, 23, 19, 27, 33, 34, 33, 29, 24, 19, 25, 33, 37, 35, 31, 26, 21, 27, 33, - 40, 38, 32, 26, 22, 27, 34, 40, 40, 34, 29, 24, 37, 43, 40, 34, 29, 26, 21, - 37, 42, 44, 36, 31, 25, 22, 36, 41, 46, 37, 30, 26, 22, 37, 42, 47, 39, 32, - 28, 23, 36, 41, 46, 42, 36, 29, 24, 36, 40, 45, 44, 36, 31, 25, 35, 41, 45, - 46, 40, 33, 28, 14, 15, 16, 18, 18, 17, 16, 13, 15, 16, 18, 17, 16, 14, 13, - 14, 16, 16, 16, 13, 11, 12, 13, 13, 13, 13, 9, 5, 10, 10, 10, 9, 6, 5, - 5, 6, 6, 5, 4, 5, 5, 4, 0, 2, 2, 3, 4, 5, 4, 13, 14, 16, 17, - 17, 17, 16, 12, 14, 15, 16, 17, 16, 14, 12, 13, 15, 15, 14, 13, 11, 11, 12, - 12, 12, 11, 9, 4, 9, 8, 8, 8, 5, 4, 4, 5, 4, 4, 3, 3, 4, 4, - 3, 2, 2, 2, 3, 4, 4, 12, 13, 15, 16, 17, 17, 17, 11, 13, 14, 15, 16, - 15, 15, 12, 12, 13, 13, 13, 12, 11, 11, 11, 10, 10, 10, 8, 4, 7, 7, 7, - 7, 3, 4, 4, 2, 2, 2, 2, 3, 3, 4, 5, 4, 1, 2, 3, 4, 5, 11, - 13, 14, 16, 17, 18, 18, 11, 13, 14, 16, 17, 16, 16, 10, 13, 14, 14, 14, 14, - 12, 7, 12, 11, 11, 11, 9, 9, 4, 8, 7, 7, 5, 5, 6, 3, 6, 6, 6, - 7, 6, 7, 5, 11, 8, 8, 8, 8, 8, 12, 12, 14, 15, 17, 18, 19, 10, 12, - 14, 15, 16, 16, 16, 10, 12, 13, 13, 13, 13, 12, 10, 12, 12, 12, 12, 10, 7, - 8, 13, 13, 13, 14, 13, 8, 8, 14, 16, 16, 16, 15, 10, 11, 17, 19, 18, 18, - 17, 11, 16, 18, 18, 19, 16, 17, 18, 16, 20, 20, 21, 17, 15, 15, 16, 22, 22, - 21, 17, 12, 11, 16, 21, 23, 23, 19, 14, 10, 15, 20, 25, 24, 20, 17, 11, 15, - 22, 27, 25, 23, 18, 13, 17, 23, 27, 28, 24, 20, 15, 25, 31, 30, 24, 18, 16, - 17, 25, 31, 32, 26, 20, 15, 14, 25, 31, 33, 27, 21, 16, 11, 25, 30, 35, 28, - 23, 18, 13, 24, 30, 32, 28, 24, 21, 15, 24, 28, 31, 30, 25, 21, 17, 24, 28, - 31, 31, 27, 23, 19, 12, 13, 15, 16, 16, 16, 15, 12, 13, 14, 15, 15, 14, 12, - 11, 12, 14, 14, 13, 11, 9, 11, 11, 11, 11, 10, 7, 3, 8, 8, 8, 7, 5, - 3, 3, 5, 4, 3, 3, 3, 3, 3, 2, 0, 2, 2, 3, 3, 3, 11, 12, 14, - 15, 16, 16, 15, 11, 12, 13, 15, 15, 14, 12, 11, 12, 13, 13, 12, 11, 9, 11, - 10, 10, 10, 9, 7, 3, 8, 7, 7, 7, 3, 3, 3, 4, 3, 3, 2, 2, 3, - 3, 3, 2, 2, 2, 2, 2, 3, 10, 12, 13, 14, 15, 16, 17, 10, 11, 13, 14, - 14, 14, 14, 11, 11, 12, 12, 12, 11, 10, 10, 10, 10, 10, 9, 7, 5, 5, 6, - 7, 6, 4, 4, 5, 3, 2, 3, 3, 3, 4, 5, 3, 2, 3, 3, 3, 4, 4, - 11, 13, 14, 15, 17, 18, 18, 9, 13, 14, 15, 16, 16, 15, 7, 13, 14, 13, 13, - 13, 11, 8, 11, 11, 11, 10, 9, 9, 6, 7, 8, 8, 8, 8, 8, 3, 8, 9, - 9, 9, 9, 10, 3, 11, 11, 11, 10, 11, 11, 12, 13, 14, 15, 17, 18, 17, 11, - 13, 14, 15, 16, 16, 15, 11, 14, 15, 15, 15, 14, 11, 11, 15, 15, 15, 15, 14, - 10, 10, 17, 17, 16, 17, 15, 12, 11, 17, 20, 19, 18, 17, 13, 13, 18, 22, 20, - 21, 19, 14, 20, 22, 22, 22, 19, 18, 17, 20, 24, 23, 24, 20, 16, 15, 20, 26, - 26, 25, 20, 16, 12, 20, 26, 27, 25, 22, 17, 13, 19, 24, 28, 28, 24, 19, 14, - 19, 25, 31, 30, 25, 20, 16, 20, 25, 31, 33, 27, 22, 17, 28, 34, 33, 27, 22, - 18, 17, 29, 36, 36, 29, 23, 18, 14, 28, 35, 39, 30, 25, 19, 14, 29, 34, 39, - 31, 25, 20, 16, 27, 33, 38, 34, 28, 22, 18, 28, 33, 37, 36, 30, 25, 19, 27, - 34, 38, 39, 33, 26, 21, 9, 11, 12, 13, 13, 13, 12, 9, 10, 11, 13, 12, 11, - 9, 9, 9, 11, 11, 10, 9, 7, 8, 8, 8, 8, 8, 5, 2, 6, 6, 5, 5, - 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 9, 9, - 11, 12, 12, 13, 13, 9, 9, 10, 12, 12, 11, 11, 8, 9, 10, 10, 9, 9, 8, - 8, 7, 7, 7, 7, 5, 3, 5, 5, 4, 4, 2, 2, 3, 2, 2, 1, 1, 2, - 2, 3, 4, 2, 2, 1, 2, 2, 3, 8, 9, 11, 12, 13, 15, 15, 8, 8, 11, - 12, 13, 13, 13, 8, 8, 11, 11, 10, 10, 10, 6, 7, 8, 8, 8, 7, 6, 5, - 3, 5, 6, 4, 5, 6, 6, 2, 4, 5, 5, 5, 6, 5, 4, 5, 6, 6, 6, - 7, 8, 11, 12, 13, 15, 16, 16, 5, 11, 12, 14, 14, 14, 14, 7, 11, 12, 12, - 12, 12, 11, 10, 9, 10, 10, 10, 10, 10, 8, 7, 10, 11, 11, 12, 12, 6, 10, - 13, 12, 13, 13, 13, 5, 13, 14, 14, 14, 14, 15, 12, 15, 16, 16, 17, 18, 16, - 14, 16, 17, 18, 18, 17, 14, 13, 18, 19, 19, 19, 17, 13, 13, 19, 18, 19, 18, - 18, 14, 13, 20, 20, 20, 20, 19, 15, 13, 21, 22, 22, 22, 20, 16, 16, 22, 26, - 24, 24, 22, 18, 23, 26, 25, 25, 23, 19, 16, 24, 28, 28, 28, 24, 19, 15, 24, - 30, 30, 29, 24, 20, 15, 23, 29, 30, 29, 25, 21, 16, 23, 29, 33, 31, 27, 22, - 17, 24, 29, 35, 34, 29, 23, 19, 23, 29, 34, 36, 32, 26, 21, 33, 39, 38, 31, - 25, 21, 18, 33, 40, 41, 33, 27, 22, 18, 33, 39, 43, 35, 29, 22, 18, 33, 39, - 44, 36, 29, 24, 19, 32, 37, 43, 38, 30, 25, 20, 31, 36, 43, 41, 33, 27, 22, - 31, 37, 43, 42, 36, 30, 24, 7, 8, 10, 11, 11, 11, 11, 7, 8, 9, 11, 10, - 9, 8, 7, 8, 9, 9, 8, 7, 6, 6, 6, 6, 6, 6, 4, 2, 4, 3, 3, - 3, 2, 2, 2, 2, 2, 1, 1, 2, 1, 2, 3, 2, 1, 0, 2, 1, 2, 7, - 8, 8, 10, 11, 12, 13, 7, 7, 8, 9, 10, 10, 10, 6, 7, 8, 8, 8, 8, - 8, 6, 6, 5, 5, 5, 5, 4, 3, 3, 2, 3, 2, 3, 4, 3, 2, 2, 1, - 2, 2, 4, 6, 3, 2, 2, 2, 3, 4, 6, 7, 10, 11, 13, 14, 14, 6, 7, - 10, 11, 12, 12, 12, 4, 6, 9, 10, 10, 10, 9, 6, 5, 7, 8, 8, 7, 8, - 8, 2, 4, 7, 7, 7, 8, 9, 3, 5, 8, 8, 8, 8, 8, 6, 6, 9, 9, - 9, 10, 5, 10, 12, 13, 14, 15, 16, 7, 9, 12, 13, 14, 14, 14, 10, 9, 12, - 13, 13, 13, 13, 13, 8, 12, 13, 13, 14, 12, 12, 9, 13, 14, 15, 15, 15, 9, - 12, 15, 16, 16, 16, 16, 8, 15, 17, 18, 17, 16, 18, 14, 18, 19, 19, 21, 20, - 16, 16, 19, 20, 21, 21, 20, 14, 16, 20, 22, 22, 21, 20, 16, 16, 22, 23, 22, - 23, 21, 17, 15, 23, 24, 24, 23, 22, 18, 15, 23, 27, 26, 25, 24, 19, 17, 24, - 29, 27, 27, 26, 20, 26, 30, 29, 30, 27, 22, 18, 26, 31, 31, 31, 28, 22, 18, - 27, 34, 33, 33, 28, 23, 19, 26, 32, 35, 34, 29, 24, 19, 27, 33, 36, 35, 30, - 25, 21, 25, 33, 40, 38, 33, 26, 22, 27, 33, 40, 39, 34, 29, 24, 37, 43, 41, - 34, 29, 25, 21, 37, 43, 43, 37, 30, 26, 21, 36, 43, 46, 38, 32, 26, 21, 38, - 41, 48, 40, 33, 27, 23, 35, 41, 47, 42, 35, 29, 24, 35, 42, 47, 44, 37, 31, - 26, 35, 41, 47, 46, 39, 32, 27, 6, 7, 8, 9, 9, 10, 11, 6, 7, 7, 9, - 9, 8, 8, 5, 6, 7, 7, 7, 6, 6, 5, 5, 5, 5, 5, 3, 3, 3, 2, - 2, 2, 2, 1, 3, 3, 2, 2, 1, 1, 1, 3, 4, 3, 2, 2, 0, 1, 3, - 5, 6, 7, 8, 10, 12, 13, 5, 6, 7, 8, 10, 10, 10, 4, 6, 6, 7, 8, - 8, 8, 4, 4, 4, 4, 5, 6, 6, 4, 2, 2, 2, 3, 3, 6, 5, 3, 2, - 2, 4, 4, 6, 7, 4, 3, 2, 5, 5, 6, 5, 6, 9, 11, 12, 14, 14, 4, - 5, 9, 11, 12, 12, 13, 7, 5, 8, 10, 10, 10, 11, 10, 3, 6, 9, 9, 9, - 10, 12, 3, 5, 9, 10, 10, 10, 13, 4, 6, 10, 11, 11, 10, 11, 8, 7, 11, - 12, 13, 13, 6, 9, 13, 15, 16, 16, 18, 10, 9, 13, 15, 17, 17, 17, 14, 9, - 14, 15, 16, 17, 16, 16, 9, 14, 16, 17, 17, 15, 15, 11, 15, 17, 18, 18, 18, - 13, 13, 17, 19, 19, 19, 19, 12, 16, 18, 20, 20, 21, 21, 16, 19, 22, 23, 24, - 23, 18, 19, 20, 23, 24, 25, 23, 17, 19, 22, 25, 25, 25, 23, 19, 18, 24, 25, - 26, 26, 25, 20, 17, 26, 27, 27, 27, 26, 21, 17, 25, 29, 30, 29, 27, 23, 19, - 28, 33, 31, 30, 29, 24, 29, 32, 33, 32, 30, 25, 21, 29, 35, 35, 34, 31, 26, - 22, 28, 37, 36, 35, 30, 26, 22, 29, 36, 38, 37, 32, 27, 22, 28, 35, 40, 38, - 34, 29, 23, 29, 36, 42, 41, 36, 31, 26, 30, 36, 43, 44, 38, 32, 27, 40, 46, - 44, 38, 33, 28, 24, 41, 46, 47, 40, 34, 29, 24, 40, 46, 50, 41, 35, 29, 25, - 39, 46, 49, 42, 36, 30, 26, 39, 45, 49, 46, 38, 33, 27, 38, 45, 49, 48, 40, - 34, 29, 39, 45, 49, 48, 43, 36, 30, 4, 5, 5, 6, 6, 8, 8, 4, 5, 5, - 6, 6, 6, 6, 3, 4, 5, 4, 4, 4, 4, 3, 3, 3, 2, 3, 2, 2, 2, - 2, 1, 1, 2, 0, 2, 3, 2, 2, 2, 1, 0, 2, 5, 3, 2, 1, 1, 0, - 2, 4, 4, 5, 6, 8, 10, 10, 3, 4, 5, 6, 8, 8, 8, 3, 4, 4, 4, - 5, 6, 7, 4, 2, 2, 2, 3, 4, 5, 6, 2, 2, 2, 4, 3, 5, 7, 3, - 2, 2, 5, 4, 5, 10, 5, 3, 2, 6, 6, 5, 3, 4, 7, 9, 10, 12, 14, - 5, 3, 7, 10, 10, 10, 12, 9, 3, 6, 8, 9, 9, 10, 13, 2, 5, 8, 9, - 10, 9, 14, 3, 5, 9, 11, 10, 9, 15, 5, 6, 10, 12, 11, 9, 14, 8, 7, - 11, 13, 13, 13, 10, 8, 13, 15, 16, 15, 18, 14, 8, 13, 15, 17, 17, 16, 16, - 9, 14, 16, 16, 17, 16, 18, 9, 14, 16, 17, 17, 14, 18, 12, 15, 18, 18, 19, - 17, 16, 13, 17, 19, 20, 20, 19, 14, 16, 19, 20, 21, 21, 21, 17, 19, 22, 23, - 24, 23, 18, 19, 20, 23, 24, 26, 23, 17, 20, 21, 25, 25, 25, 24, 19, 20, 23, - 25, 26, 26, 24, 20, 18, 26, 28, 28, 28, 26, 21, 18, 26, 31, 31, 29, 27, 23, - 19, 27, 33, 32, 32, 28, 24, 28, 33, 33, 32, 30, 26, 22, 29, 34, 35, 35, 31, - 27, 22, 28, 38, 37, 35, 31, 26, 23, 29, 37, 37, 37, 32, 27, 23, 28, 35, 40, - 39, 34, 29, 24, 29, 35, 43, 41, 36, 31, 27, 29, 38, 43, 44, 38, 32, 27, 40, - 46, 44, 37, 32, 28, 24, 39, 45, 46, 40, 33, 29, 24, 41, 45, 49, 41, 34, 30, - 25, 40, 45, 50, 42, 35, 31, 26, 39, 44, 49, 45, 38, 33, 28, 39, 46, 50, 47, - 41, 35, 29, 40, 44, 50, 50, 43, 36, 31, 4, 5, 6, 8, 8, 6, 6, 4, 4, - 5, 7, 7, 5, 4, 3, 4, 5, 5, 6, 4, 2, 3, 3, 3, 4, 5, 3, 0, - 2, 2, 1, 2, 4, 2, 0, 2, 2, 2, 2, 3, 2, 0, 4, 3, 2, 2, 3, - 2, 0, 4, 4, 5, 6, 6, 8, 8, 3, 4, 4, 5, 6, 6, 7, 3, 4, 4, - 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 3, 2, 2, 1, 1, 1, 1, 3, 4, - 3, 2, 2, 2, 2, 3, 7, 5, 2, 2, 3, 3, 3, 3, 4, 6, 8, 9, 10, - 11, 2, 3, 6, 8, 8, 8, 9, 5, 3, 6, 7, 6, 6, 8, 9, 2, 4, 7, - 6, 6, 6, 11, 2, 4, 7, 8, 8, 6, 12, 4, 5, 8, 9, 9, 6, 10, 8, - 6, 9, 10, 10, 10, 5, 7, 11, 12, 13, 13, 14, 10, 7, 12, 13, 13, 14, 13, - 14, 8, 12, 13, 13, 13, 12, 14, 8, 12, 14, 14, 14, 11, 15, 10, 13, 15, 15, - 15, 14, 14, 12, 15, 16, 17, 16, 16, 10, 15, 17, 18, 18, 18, 18, 15, 18, 19, - 20, 21, 20, 14, 18, 18, 20, 21, 22, 20, 13, 18, 20, 22, 22, 21, 20, 16, 18, - 22, 23, 22, 23, 22, 17, 16, 24, 24, 24, 24, 22, 18, 16, 24, 27, 27, 26, 24, - 20, 17, 25, 30, 29, 28, 26, 21, 26, 29, 30, 29, 26, 22, 18, 26, 32, 30, 30, - 27, 23, 19, 27, 33, 33, 32, 27, 23, 19, 26, 33, 34, 32, 28, 24, 20, 27, 34, - 36, 35, 31, 25, 21, 27, 34, 40, 38, 33, 27, 23, 28, 34, 39, 39, 35, 29, 24, - 36, 42, 40, 34, 29, 25, 21, 37, 43, 43, 36, 30, 25, 21, 36, 42, 45, 37, 32, - 27, 21, 37, 41, 46, 38, 32, 27, 23, 35, 40, 45, 41, 35, 28, 24, 36, 42, 46, - 44, 37, 32, 25, 37, 41, 46, 46, 38, 33, 27, 2, 2, 3, 3, 3, 2, 2, 1, - 2, 3, 3, 3, 2, 2, 0, 2, 2, 3, 3, 2, 1, 1, 2, 2, 2, 2, 2, - 4, 3, 3, 3, 4, 4, 3, 4, 7, 7, 7, 6, 5, 4, 4, 13, 11, 9, 7, - 5, 4, 4, 0, 2, 2, 3, 2, 2, 1, 1, 2, 2, 3, 2, 2, 1, 2, 1, - 2, 2, 2, 1, 1, 2, 1, 2, 2, 2, 2, 3, 4, 4, 4, 5, 4, 4, 4, - 9, 9, 9, 7, 5, 4, 4, 16, 14, 10, 8, 6, 4, 4, 2, 1, 2, 1, 2, - 1, 4, 2, 1, 2, 1, 1, 1, 4, 2, 1, 0, 0, 1, 0, 5, 3, 2, 3, - 3, 3, 3, 6, 7, 6, 6, 6, 7, 6, 7, 12, 11, 11, 10, 9, 7, 7, 19, - 17, 14, 12, 10, 9, 8, 2, 4, 5, 5, 5, 5, 8, 3, 5, 5, 6, 6, 6, - 8, 7, 6, 6, 7, 7, 8, 8, 10, 9, 10, 10, 10, 11, 10, 10, 14, 14, 14, - 14, 14, 12, 13, 20, 19, 17, 16, 15, 14, 19, 26, 22, 20, 18, 16, 15, 12, 13, - 12, 13, 12, 12, 8, 13, 14, 14, 14, 14, 13, 8, 14, 16, 16, 15, 16, 15, 11, - 13, 20, 19, 19, 19, 18, 14, 17, 25, 24, 22, 23, 21, 16, 21, 27, 30, 26, 25, - 23, 17, 25, 31, 32, 29, 27, 25, 20, 21, 23, 22, 21, 18, 15, 11, 21, 26, 24, - 23, 20, 16, 11, 22, 27, 26, 25, 22, 18, 14, 22, 28, 30, 29, 25, 22, 18, 25, - 31, 35, 34, 30, 25, 20, 27, 33, 40, 38, 33, 26, 22, 31, 37, 41, 41, 35, 28, - 23, 29, 35, 34, 27, 22, 17, 13, 29, 35, 36, 29, 23, 19, 15, 30, 35, 38, 31, - 26, 21, 17, 30, 36, 41, 35, 30, 25, 21, 31, 37, 43, 40, 35, 28, 24, 34, 40, - 46, 45, 38, 31, 25, 37, 42, 46, 46, 39, 33, 27, 1, 2, 2, 2, 2, 2, 1, - 2, 1, 2, 3, 2, 2, 1, 2, 0, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, - 3, 4, 4, 4, 4, 5, 5, 4, 4, 8, 8, 8, 7, 6, 4, 4, 14, 13, 9, - 8, 6, 4, 4, 2, 0, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 1, 2, 2, - 2, 1, 2, 2, 1, 4, 2, 2, 2, 3, 2, 3, 5, 6, 5, 5, 6, 5, 4, - 5, 11, 10, 10, 8, 6, 5, 5, 18, 15, 11, 9, 7, 5, 5, 2, 2, 1, 1, - 1, 3, 6, 2, 2, 2, 2, 2, 4, 6, 3, 2, 3, 3, 4, 4, 7, 7, 3, - 6, 6, 7, 7, 9, 11, 7, 10, 10, 11, 9, 9, 15, 12, 14, 13, 12, 11, 9, - 20, 18, 17, 16, 14, 12, 12, 4, 6, 7, 8, 8, 7, 10, 7, 7, 8, 8, 9, - 9, 10, 11, 8, 10, 10, 11, 11, 11, 14, 10, 13, 14, 14, 14, 13, 14, 16, 18, - 18, 18, 17, 15, 15, 22, 23, 21, 21, 19, 18, 20, 28, 26, 24, 22, 20, 19, 15, - 15, 15, 15, 16, 14, 10, 17, 17, 17, 17, 17, 15, 10, 17, 19, 19, 19, 19, 18, - 14, 17, 22, 23, 23, 23, 22, 18, 20, 27, 28, 26, 28, 25, 20, 24, 30, 34, 32, - 29, 27, 21, 29, 34, 35, 33, 31, 28, 22, 25, 26, 24, 25, 21, 17, 13, 24, 29, - 27, 26, 23, 18, 14, 25, 31, 30, 29, 25, 22, 17, 25, 32, 34, 33, 29, 25, 22, - 28, 34, 38, 38, 34, 28, 23, 31, 37, 45, 42, 36, 30, 25, 34, 39, 45, 45, 38, - 32, 27, 33, 38, 36, 30, 25, 20, 16, 33, 39, 40, 32, 26, 21, 18, 34, 39, 43, - 34, 30, 26, 21, 33, 39, 46, 39, 33, 29, 25, 35, 40, 48, 44, 38, 31, 27, 38, - 44, 50, 48, 42, 34, 29, 40, 46, 51, 51, 44, 37, 30, 2, 1, 2, 2, 2, 2, - 1, 2, 2, 1, 2, 2, 1, 2, 2, 2, 1, 1, 2, 2, 3, 2, 3, 2, 3, - 3, 4, 5, 5, 5, 6, 5, 6, 5, 5, 10, 9, 9, 8, 7, 5, 5, 16, 13, - 11, 8, 7, 5, 5, 2, 2, 0, 2, 1, 2, 4, 3, 2, 1, 2, 1, 2, 5, - 3, 2, 1, 1, 1, 3, 6, 4, 3, 3, 3, 3, 4, 7, 8, 7, 7, 7, 7, - 5, 7, 12, 11, 11, 10, 9, 7, 7, 20, 16, 13, 11, 10, 9, 7, 3, 2, 4, - 4, 4, 5, 7, 5, 2, 4, 4, 5, 5, 8, 8, 3, 5, 7, 7, 6, 9, 11, - 4, 8, 10, 10, 10, 11, 15, 9, 11, 14, 14, 13, 11, 18, 14, 16, 17, 16, 15, - 11, 21, 19, 19, 19, 18, 16, 15, 8, 7, 10, 10, 10, 8, 11, 12, 8, 11, 11, - 12, 12, 12, 15, 9, 12, 14, 14, 15, 14, 17, 12, 17, 18, 18, 18, 15, 18, 17, - 20, 21, 22, 22, 19, 18, 24, 26, 25, 23, 23, 21, 22, 30, 28, 28, 25, 24, 23, - 17, 18, 19, 18, 19, 17, 12, 20, 19, 20, 19, 20, 19, 12, 20, 20, 22, 23, 23, - 22, 17, 20, 24, 26, 27, 27, 26, 22, 23, 29, 31, 31, 31, 29, 24, 25, 33, 36, - 35, 33, 30, 25, 30, 38, 40, 38, 36, 31, 27, 28, 29, 28, 27, 24, 21, 15, 27, - 32, 31, 30, 26, 22, 18, 27, 33, 33, 32, 30, 25, 22, 28, 35, 39, 37, 33, 29, - 25, 31, 38, 43, 42, 38, 32, 27, 35, 42, 48, 46, 40, 34, 28, 38, 44, 49, 49, - 43, 36, 30, 37, 42, 39, 34, 27, 23, 19, 37, 42, 43, 36, 30, 25, 21, 37, 42, - 46, 39, 33, 29, 25, 37, 44, 50, 42, 38, 32, 28, 39, 45, 52, 49, 42, 36, 31, - 43, 48, 54, 54, 46, 39, 33, 44, 50, 55, 55, 48, 41, 33, 2, 2, 1, 2, 2, - 1, 3, 3, 2, 2, 2, 1, 1, 4, 3, 2, 2, 2, 3, 3, 5, 3, 3, 4, - 3, 4, 5, 6, 6, 6, 7, 7, 7, 6, 6, 11, 11, 11, 10, 8, 6, 6, 17, - 15, 12, 10, 8, 6, 6, 3, 2, 2, 0, 1, 4, 6, 3, 2, 2, 1, 1, 4, - 6, 5, 3, 2, 3, 3, 5, 8, 8, 4, 4, 5, 7, 6, 9, 11, 7, 8, 9, - 10, 7, 9, 15, 12, 12, 12, 12, 10, 9, 21, 18, 14, 12, 13, 12, 9, 5, 3, - 5, 6, 6, 7, 8, 8, 3, 5, 7, 7, 6, 9, 11, 3, 5, 9, 10, 8, 11, - 15, 5, 9, 13, 13, 13, 13, 18, 10, 12, 17, 18, 16, 13, 21, 16, 17, 20, 19, - 18, 13, 24, 21, 20, 21, 21, 19, 17, 11, 8, 12, 12, 13, 10, 13, 15, 9, 12, - 14, 15, 14, 15, 18, 11, 14, 17, 18, 19, 16, 20, 14, 18, 20, 21, 21, 18, 21, - 20, 22, 24, 25, 24, 21, 22, 25, 29, 28, 26, 27, 24, 23, 31, 31, 31, 29, 29, - 27, 20, 19, 20, 21, 21, 20, 13, 24, 20, 21, 23, 23, 22, 14, 23, 22, 24, 26, - 27, 25, 20, 24, 26, 29, 30, 30, 29, 25, 24, 33, 35, 35, 35, 31, 27, 28, 37, - 40, 39, 37, 33, 28, 32, 40, 44, 40, 40, 37, 32, 29, 32, 31, 32, 27, 23, 18, - 29, 35, 33, 33, 30, 26, 22, 29, 36, 36, 37, 32, 28, 25, 29, 37, 41, 41, 37, - 33, 29, 33, 41, 47, 46, 42, 36, 31, 36, 45, 52, 50, 44, 38, 31, 40, 46, 53, - 53, 46, 40, 34, 40, 45, 43, 37, 30, 26, 22, 40, 46, 45, 38, 32, 28, 25, 39, - 45, 49, 43, 38, 32, 28, 39, 46, 53, 46, 41, 36, 33, 44, 49, 54, 52, 46, 40, - 35, 45, 52, 58, 57, 48, 43, 36, 48, 54, 60, 59, 52, 44, 38, 2, 1, 1, 3, - 3, 1, 2, 2, 2, 1, 2, 3, 2, 3, 2, 2, 1, 3, 4, 4, 4, 2, 3, - 4, 5, 6, 6, 6, 6, 7, 7, 8, 10, 8, 6, 11, 11, 11, 10, 10, 8, 7, - 17, 15, 13, 11, 10, 8, 7, 2, 2, 1, 1, 0, 2, 4, 2, 2, 1, 1, 1, - 3, 5, 5, 2, 2, 2, 3, 4, 6, 9, 3, 4, 5, 6, 5, 8, 11, 7, 8, - 9, 10, 6, 8, 15, 13, 13, 12, 11, 10, 8, 21, 18, 15, 13, 13, 12, 8, 5, - 2, 4, 5, 5, 5, 7, 10, 2, 4, 6, 7, 5, 8, 13, 2, 5, 9, 10, 6, - 10, 15, 5, 8, 12, 13, 12, 12, 17, 10, 12, 16, 17, 16, 12, 21, 16, 17, 19, - 19, 17, 12, 24, 21, 20, 21, 20, 19, 16, 13, 7, 11, 12, 11, 8, 11, 16, 9, - 11, 12, 14, 13, 13, 19, 11, 13, 16, 17, 17, 15, 21, 14, 17, 20, 20, 21, 17, - 21, 19, 22, 24, 23, 24, 21, 22, 25, 27, 28, 27, 26, 23, 24, 31, 31, 30, 28, - 27, 26, 21, 18, 19, 20, 20, 19, 11, 24, 19, 21, 21, 22, 22, 13, 25, 21, 23, - 25, 26, 24, 19, 24, 26, 27, 30, 29, 28, 24, 25, 31, 33, 34, 35, 33, 26, 27, - 36, 39, 38, 36, 34, 28, 32, 41, 42, 41, 39, 35, 30, 28, 30, 30, 28, 25, 22, - 16, 29, 33, 31, 31, 28, 24, 20, 28, 35, 34, 35, 31, 28, 24, 29, 37, 40, 39, - 37, 31, 28, 32, 40, 45, 45, 41, 35, 29, 36, 44, 51, 48, 42, 37, 32, 39, 48, - 51, 50, 45, 39, 33, 38, 43, 41, 34, 28, 24, 21, 38, 43, 43, 37, 31, 28, 24, - 37, 44, 46, 39, 36, 31, 28, 37, 45, 51, 45, 39, 36, 31, 41, 49, 54, 51, 45, - 39, 33, 44, 51, 57, 56, 47, 41, 34, 47, 52, 57, 58, 50, 43, 37, 2, 1, 3, - 5, 5, 3, 2, 2, 1, 3, 4, 6, 4, 3, 2, 1, 2, 5, 7, 6, 5, 2, - 3, 4, 6, 8, 8, 8, 5, 6, 7, 9, 11, 10, 8, 11, 11, 11, 12, 12, 10, - 8, 17, 15, 13, 12, 12, 10, 8, 2, 1, 2, 4, 2, 0, 2, 2, 2, 2, 3, - 3, 1, 4, 2, 2, 1, 4, 4, 3, 5, 5, 3, 4, 6, 6, 6, 6, 8, 7, - 8, 9, 9, 7, 7, 14, 13, 12, 12, 10, 8, 6, 21, 18, 15, 12, 10, 9, 7, - 2, 2, 3, 2, 2, 3, 5, 6, 2, 3, 3, 4, 4, 6, 10, 2, 4, 6, 7, - 5, 7, 13, 3, 8, 10, 10, 10, 10, 15, 9, 12, 14, 14, 13, 10, 19, 15, 17, - 17, 16, 15, 10, 23, 22, 19, 19, 17, 16, 14, 10, 7, 9, 9, 9, 6, 8, 14, - 7, 10, 10, 11, 11, 10, 16, 9, 11, 13, 14, 15, 12, 19, 12, 16, 18, 18, 18, - 14, 18, 17, 20, 22, 22, 21, 17, 19, 24, 25, 25, 25, 24, 21, 23, 30, 29, 28, - 26, 24, 23, 19, 16, 17, 17, 17, 16, 9, 23, 18, 18, 18, 20, 18, 10, 23, 20, - 21, 22, 23, 21, 16, 22, 24, 26, 27, 27, 26, 22, 22, 29, 31, 31, 31, 29, 23, - 25, 35, 37, 36, 34, 31, 25, 31, 38, 39, 37, 35, 32, 26, 27, 28, 27, 26, 23, - 18, 14, 28, 31, 27, 27, 25, 21, 18, 26, 32, 32, 32, 29, 25, 21, 26, 34, 37, - 36, 32, 29, 25, 30, 38, 43, 42, 39, 31, 28, 35, 42, 49, 46, 39, 33, 28, 39, - 44, 49, 49, 42, 38, 30, 35, 41, 36, 31, 25, 21, 18, 34, 39, 39, 32, 27, 25, - 20, 36, 40, 41, 36, 33, 29, 25, 35, 42, 47, 42, 36, 32, 29, 39, 44, 52, 49, - 41, 37, 31, 42, 48, 54, 52, 44, 38, 32, 45, 50, 53, 54, 47, 41, 34, 1, 4, - 5, 7, 7, 5, 3, 1, 3, 5, 7, 8, 6, 5, 1, 2, 5, 7, 9, 8, 6, - 2, 3, 6, 8, 10, 9, 8, 5, 6, 8, 10, 12, 10, 8, 10, 10, 12, 13, 12, - 10, 8, 16, 15, 13, 13, 13, 10, 8, 1, 2, 4, 5, 4, 2, 0, 2, 1, 4, - 5, 4, 3, 2, 2, 1, 3, 6, 5, 4, 4, 2, 3, 5, 7, 7, 6, 6, 6, - 7, 8, 10, 10, 8, 6, 12, 12, 12, 13, 10, 8, 6, 20, 17, 14, 13, 11, 9, - 6, 2, 1, 1, 1, 2, 2, 3, 2, 2, 1, 1, 1, 2, 4, 5, 2, 2, 3, - 3, 3, 5, 10, 3, 6, 7, 6, 7, 7, 12, 8, 10, 11, 11, 10, 7, 17, 14, - 15, 14, 12, 11, 7, 22, 20, 18, 16, 14, 13, 11, 5, 6, 6, 6, 6, 5, 7, - 11, 6, 7, 7, 8, 8, 7, 14, 7, 9, 10, 11, 11, 9, 16, 10, 14, 14, 14, - 15, 11, 16, 16, 18, 18, 18, 18, 15, 17, 23, 23, 22, 21, 19, 18, 22, 30, 26, - 24, 22, 21, 20, 16, 14, 14, 13, 14, 13, 7, 18, 15, 15, 15, 16, 15, 7, 18, - 18, 18, 19, 19, 17, 13, 19, 22, 22, 23, 23, 22, 18, 20, 27, 28, 28, 28, 25, - 20, 24, 31, 34, 32, 29, 26, 22, 29, 34, 37, 34, 32, 29, 23, 24, 24, 23, 23, - 19, 15, 11, 24, 28, 25, 24, 21, 18, 14, 24, 30, 28, 27, 26, 21, 18, 24, 31, - 33, 32, 29, 26, 22, 27, 34, 39, 36, 33, 29, 23, 32, 38, 44, 42, 35, 30, 25, - 34, 41, 45, 45, 39, 33, 26, 30, 37, 33, 27, 22, 18, 14, 32, 36, 35, 29, 24, - 21, 18, 32, 36, 38, 32, 28, 25, 21, 31, 37, 44, 38, 33, 29, 25, 34, 40, 46, - 42, 38, 32, 27, 38, 44, 48, 48, 41, 34, 29, 42, 48, 50, 50, 43, 35, 30, 2, - 2, 3, 4, 4, 3, 2, 2, 2, 3, 4, 4, 2, 2, 1, 2, 2, 3, 3, 2, - 1, 0, 2, 2, 2, 3, 2, 3, 3, 3, 3, 3, 4, 3, 3, 7, 6, 7, 6, - 5, 3, 3, 13, 11, 9, 7, 5, 3, 3, 1, 2, 3, 3, 2, 2, 2, 0, 2, - 2, 3, 2, 2, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 3, - 4, 4, 4, 4, 4, 3, 3, 9, 8, 8, 7, 5, 4, 3, 16, 13, 10, 8, 6, - 4, 3, 1, 2, 2, 2, 2, 2, 3, 2, 2, 2, 1, 2, 1, 3, 2, 1, 1, - 1, 1, 1, 4, 2, 2, 2, 2, 2, 2, 6, 6, 6, 5, 5, 6, 5, 5, 12, - 11, 10, 9, 7, 6, 5, 18, 16, 13, 11, 9, 7, 7, 2, 3, 4, 4, 4, 4, - 8, 2, 5, 4, 5, 5, 5, 8, 5, 5, 6, 6, 6, 7, 8, 8, 8, 9, 9, - 9, 10, 9, 9, 13, 13, 13, 13, 12, 12, 12, 18, 17, 16, 15, 14, 13, 18, 24, - 21, 19, 16, 15, 15, 11, 11, 12, 12, 12, 11, 7, 13, 13, 13, 13, 13, 12, 8, - 13, 15, 14, 15, 14, 13, 10, 13, 19, 18, 18, 18, 17, 14, 16, 23, 22, 21, 23, - 20, 15, 20, 26, 27, 26, 24, 22, 17, 24, 29, 31, 28, 26, 24, 19, 20, 22, 21, - 21, 18, 14, 9, 21, 24, 23, 22, 19, 15, 10, 21, 26, 25, 25, 21, 17, 13, 21, - 27, 29, 28, 25, 20, 17, 23, 28, 33, 32, 29, 23, 18, 26, 31, 38, 37, 32, 25, - 20, 29, 35, 38, 39, 34, 28, 22, 28, 35, 33, 26, 21, 17, 12, 28, 34, 35, 28, - 23, 18, 14, 28, 34, 38, 30, 25, 20, 16, 28, 34, 40, 35, 29, 24, 20, 30, 36, - 43, 39, 32, 28, 23, 32, 38, 43, 42, 36, 29, 24, 34, 40, 44, 46, 38, 32, 26, - 0, 2, 2, 3, 3, 2, 2, 1, 2, 2, 3, 2, 2, 1, 2, 1, 2, 2, 2, - 1, 2, 2, 1, 2, 2, 2, 3, 4, 4, 4, 4, 4, 5, 4, 4, 8, 8, 8, - 7, 5, 4, 4, 14, 12, 9, 7, 6, 4, 4, 2, 1, 2, 3, 2, 2, 1, 2, - 0, 2, 2, 2, 1, 1, 2, 1, 2, 2, 2, 1, 3, 2, 2, 2, 2, 2, 3, - 4, 5, 5, 5, 5, 5, 4, 4, 10, 9, 9, 8, 6, 4, 4, 17, 15, 11, 9, - 7, 5, 4, 2, 1, 1, 1, 1, 2, 6, 2, 2, 1, 1, 1, 3, 6, 2, 2, - 2, 2, 2, 3, 7, 6, 3, 5, 5, 5, 6, 8, 9, 7, 9, 9, 9, 8, 8, - 14, 12, 13, 12, 11, 10, 8, 20, 18, 16, 14, 12, 11, 10, 3, 6, 6, 6, 7, - 6, 9, 6, 7, 7, 8, 8, 8, 9, 9, 7, 9, 9, 10, 10, 10, 12, 10, 12, - 13, 13, 13, 12, 13, 15, 16, 17, 17, 16, 14, 14, 21, 21, 20, 19, 17, 16, 20, - 28, 24, 22, 20, 19, 18, 14, 15, 14, 14, 15, 13, 9, 16, 17, 16, 15, 16, 15, - 10, 16, 17, 18, 18, 18, 17, 13, 15, 22, 21, 21, 22, 20, 17, 19, 26, 27, 26, - 26, 23, 19, 23, 31, 32, 30, 28, 25, 20, 27, 33, 35, 31, 29, 27, 21, 24, 25, - 24, 24, 20, 16, 12, 23, 27, 25, 25, 22, 18, 14, 24, 30, 28, 27, 25, 20, 17, - 23, 30, 33, 31, 28, 24, 20, 27, 33, 38, 36, 32, 28, 22, 30, 36, 42, 41, 34, - 29, 24, 33, 39, 43, 42, 37, 31, 26, 32, 37, 36, 29, 23, 19, 15, 32, 37, 38, - 30, 25, 20, 17, 31, 36, 40, 33, 28, 23, 20, 32, 38, 44, 38, 32, 28, 24, 34, - 41, 46, 44, 37, 31, 25, 36, 43, 48, 49, 40, 34, 28, 39, 45, 49, 50, 42, 35, - 30, 2, 0, 2, 2, 2, 2, 1, 2, 1, 2, 2, 2, 1, 1, 2, 2, 2, 2, - 2, 2, 3, 2, 2, 2, 2, 3, 3, 4, 5, 5, 5, 5, 5, 5, 4, 9, 9, - 9, 8, 6, 5, 4, 15, 13, 10, 8, 7, 5, 4, 2, 2, 1, 2, 1, 1, 4, - 2, 2, 0, 2, 1, 1, 4, 2, 2, 1, 1, 1, 2, 5, 3, 3, 3, 3, 3, - 4, 6, 7, 6, 6, 6, 6, 4, 6, 11, 11, 11, 9, 7, 6, 6, 19, 16, 12, - 10, 9, 7, 6, 3, 2, 3, 3, 3, 5, 7, 3, 2, 3, 4, 4, 5, 7, 7, - 2, 4, 6, 6, 5, 8, 10, 3, 7, 9, 9, 9, 10, 13, 8, 11, 12, 13, 12, - 10, 17, 13, 15, 16, 15, 13, 10, 21, 19, 18, 17, 16, 15, 14, 7, 7, 9, 9, - 10, 8, 11, 11, 8, 10, 10, 11, 11, 11, 13, 8, 11, 12, 13, 13, 12, 16, 11, - 15, 16, 16, 17, 14, 17, 17, 20, 20, 20, 19, 18, 18, 23, 24, 24, 23, 21, 20, - 21, 30, 27, 25, 24, 22, 22, 17, 17, 17, 17, 18, 16, 11, 19, 18, 18, 18, 18, - 18, 11, 19, 20, 21, 21, 22, 20, 16, 19, 23, 25, 25, 25, 24, 20, 21, 30, 30, - 29, 29, 26, 22, 25, 34, 35, 34, 31, 29, 24, 30, 36, 39, 35, 34, 31, 26, 26, - 28, 27, 27, 23, 19, 15, 26, 31, 29, 28, 25, 21, 17, 26, 32, 32, 31, 28, 24, - 20, 26, 34, 37, 35, 31, 28, 23, 30, 36, 41, 40, 36, 30, 26, 33, 41, 46, 45, - 38, 32, 27, 37, 42, 48, 48, 41, 35, 28, 35, 41, 39, 32, 26, 22, 18, 35, 41, - 42, 34, 29, 24, 20, 36, 42, 45, 37, 33, 27, 23, 36, 42, 49, 41, 37, 31, 27, - 38, 45, 50, 47, 42, 35, 29, 41, 48, 53, 52, 44, 37, 31, 44, 50, 53, 54, 46, - 40, 32, 2, 2, 1, 2, 2, 1, 2, 2, 2, 1, 2, 2, 1, 3, 3, 2, 1, - 2, 3, 3, 4, 3, 3, 3, 3, 4, 5, 5, 6, 6, 7, 6, 7, 6, 5, 10, - 10, 10, 9, 8, 6, 5, 17, 15, 12, 10, 8, 6, 5, 3, 2, 2, 1, 1, 3, - 5, 3, 2, 2, 0, 1, 3, 6, 3, 2, 2, 2, 2, 4, 7, 6, 4, 4, 5, - 5, 5, 8, 10, 7, 8, 8, 9, 6, 8, 14, 12, 12, 11, 10, 9, 8, 20, 17, - 14, 12, 12, 11, 8, 3, 2, 4, 5, 5, 6, 8, 7, 3, 4, 6, 6, 6, 9, - 10, 3, 5, 8, 9, 7, 10, 14, 5, 9, 12, 12, 12, 12, 16, 9, 12, 15, 16, - 15, 12, 20, 15, 16, 19, 18, 17, 12, 23, 21, 20, 21, 19, 18, 16, 10, 7, 11, - 12, 12, 9, 13, 14, 8, 12, 13, 14, 13, 13, 17, 10, 13, 16, 16, 17, 15, 19, - 13, 17, 20, 20, 20, 17, 20, 18, 22, 24, 24, 23, 20, 20, 24, 26, 28, 26, 25, - 23, 23, 30, 30, 29, 27, 26, 25, 19, 19, 20, 20, 20, 19, 13, 23, 20, 21, 22, - 22, 21, 13, 22, 22, 23, 25, 26, 24, 19, 22, 26, 28, 28, 29, 28, 24, 24, 32, - 33, 33, 33, 31, 25, 27, 37, 39, 38, 35, 32, 27, 31, 40, 42, 39, 39, 35, 29, - 28, 31, 30, 29, 27, 22, 17, 29, 33, 32, 31, 28, 24, 20, 28, 35, 34, 35, 32, - 27, 23, 28, 37, 40, 39, 36, 31, 27, 32, 41, 46, 44, 41, 34, 29, 36, 43, 50, - 49, 42, 37, 32, 40, 47, 51, 51, 45, 38, 32, 38, 44, 41, 35, 28, 25, 20, 38, - 44, 44, 37, 32, 28, 24, 39, 44, 47, 41, 36, 31, 27, 38, 45, 52, 46, 40, 36, - 31, 41, 48, 55, 52, 44, 39, 34, 45, 51, 57, 56, 47, 40, 35, 48, 53, 56, 58, - 51, 43, 37, 2, 1, 1, 3, 3, 1, 2, 2, 1, 1, 2, 3, 2, 3, 2, 2, - 1, 3, 4, 4, 4, 2, 3, 3, 4, 6, 6, 6, 5, 6, 7, 7, 9, 8, 6, - 11, 11, 11, 10, 10, 8, 6, 17, 15, 12, 10, 9, 8, 6, 2, 2, 1, 1, 1, - 3, 4, 2, 2, 1, 1, 0, 3, 5, 4, 2, 1, 2, 2, 4, 6, 8, 3, 4, - 5, 5, 5, 7, 10, 7, 8, 9, 9, 6, 7, 14, 12, 12, 12, 11, 9, 7, 21, - 17, 14, 12, 12, 11, 7, 4, 2, 4, 5, 5, 6, 8, 9, 2, 4, 6, 6, 5, - 8, 13, 2, 5, 8, 9, 6, 10, 15, 5, 8, 12, 12, 12, 12, 17, 10, 12, 16, - 17, 16, 12, 21, 15, 17, 19, 19, 17, 12, 24, 21, 19, 20, 19, 18, 16, 13, 7, - 11, 12, 11, 9, 12, 16, 8, 11, 12, 14, 13, 13, 19, 11, 12, 15, 17, 17, 14, - 21, 14, 17, 20, 20, 20, 16, 20, 19, 22, 23, 25, 24, 19, 22, 25, 27, 27, 27, - 25, 24, 23, 31, 30, 30, 28, 27, 26, 21, 17, 19, 20, 20, 19, 12, 24, 19, 21, - 21, 22, 21, 13, 24, 21, 23, 24, 25, 24, 18, 24, 26, 27, 28, 30, 28, 24, 25, - 32, 32, 34, 33, 32, 25, 27, 34, 39, 38, 36, 33, 27, 32, 39, 43, 39, 38, 36, - 29, 28, 29, 29, 29, 26, 22, 16, 28, 33, 31, 31, 27, 24, 20, 28, 36, 35, 33, - 31, 27, 24, 28, 37, 39, 38, 35, 31, 27, 32, 39, 45, 44, 40, 34, 30, 35, 43, - 51, 47, 41, 36, 31, 39, 48, 52, 52, 45, 38, 33, 38, 43, 40, 34, 29, 24, 21, - 38, 43, 43, 37, 32, 27, 24, 37, 43, 46, 40, 36, 32, 27, 37, 44, 50, 44, 40, - 34, 31, 41, 48, 53, 51, 43, 39, 33, 45, 51, 55, 56, 48, 40, 34, 47, 53, 55, - 57, 51, 41, 37, 1, 1, 4, 6, 5, 4, 2, 1, 1, 3, 5, 5, 3, 2, 2, - 1, 2, 4, 6, 5, 4, 2, 2, 3, 5, 7, 6, 6, 5, 5, 6, 8, 10, 8, - 6, 10, 9, 9, 10, 10, 8, 6, 15, 14, 11, 10, 10, 8, 6, 2, 1, 2, 4, - 3, 1, 3, 2, 1, 1, 3, 3, 0, 3, 2, 2, 1, 3, 3, 2, 4, 4, 3, - 4, 5, 5, 4, 5, 7, 6, 7, 8, 7, 6, 5, 12, 11, 11, 10, 8, 6, 5, - 19, 16, 12, 10, 9, 8, 5, 2, 1, 3, 2, 3, 4, 6, 4, 2, 3, 3, 4, - 3, 5, 8, 2, 4, 6, 6, 4, 6, 13, 3, 7, 9, 9, 9, 8, 14, 8, 11, - 13, 13, 12, 8, 18, 14, 15, 16, 15, 13, 8, 21, 19, 18, 18, 16, 15, 13, 9, - 6, 9, 9, 9, 7, 10, 13, 7, 9, 10, 10, 10, 9, 16, 8, 11, 13, 13, 13, - 11, 18, 11, 15, 16, 17, 17, 13, 18, 17, 19, 20, 21, 19, 16, 18, 23, 25, 23, - 23, 21, 19, 21, 28, 27, 26, 24, 23, 22, 18, 16, 17, 16, 17, 17, 10, 21, 18, - 18, 18, 19, 17, 9, 21, 19, 20, 22, 21, 20, 15, 21, 23, 24, 25, 25, 24, 20, - 22, 29, 30, 30, 30, 27, 22, 25, 33, 35, 34, 32, 29, 24, 29, 37, 38, 35, 34, - 31, 26, 26, 28, 27, 26, 22, 19, 14, 26, 30, 28, 27, 25, 21, 17, 25, 32, 31, - 30, 28, 24, 20, 26, 34, 36, 35, 32, 28, 24, 28, 36, 41, 40, 36, 31, 26, 33, - 41, 47, 43, 38, 31, 27, 37, 41, 47, 47, 40, 34, 29, 35, 40, 37, 30, 26, 22, - 18, 34, 40, 40, 33, 27, 24, 20, 35, 40, 43, 36, 31, 27, 24, 34, 42, 46, 41, - 36, 32, 28, 37, 43, 48, 46, 40, 35, 30, 41, 46, 52, 51, 42, 36, 31, 44, 49, - 53, 52, 45, 39, 32, 1, 5, 6, 8, 8, 6, 4, 0, 3, 6, 8, 8, 5, 3, - 1, 2, 5, 6, 8, 6, 5, 1, 3, 5, 7, 9, 7, 6, 4, 5, 7, 8, 10, - 9, 6, 8, 8, 10, 11, 11, 9, 7, 14, 12, 11, 11, 10, 8, 7, 1, 2, 5, - 7, 5, 4, 2, 1, 1, 4, 6, 5, 3, 0, 2, 1, 3, 5, 4, 3, 2, 2, - 2, 4, 5, 5, 4, 4, 5, 6, 7, 8, 7, 6, 4, 11, 10, 10, 10, 8, 6, - 4, 17, 14, 12, 10, 8, 6, 4, 1, 1, 1, 2, 3, 3, 5, 2, 1, 0, 1, - 2, 2, 3, 3, 1, 2, 2, 2, 2, 4, 7, 2, 5, 5, 5, 5, 5, 11, 7, - 9, 9, 9, 8, 5, 15, 12, 13, 12, 11, 9, 5, 19, 17, 15, 14, 12, 10, 9, - 3, 5, 6, 6, 7, 6, 8, 8, 6, 7, 7, 8, 8, 7, 11, 7, 8, 9, 9, - 9, 8, 14, 9, 13, 13, 13, 13, 10, 15, 14, 17, 16, 17, 16, 13, 15, 20, 21, - 20, 19, 17, 16, 20, 26, 24, 22, 21, 19, 18, 14, 14, 14, 14, 15, 14, 8, 17, - 16, 15, 15, 16, 14, 7, 17, 17, 18, 18, 18, 17, 12, 16, 21, 22, 21, 22, 20, - 16, 19, 27, 27, 26, 26, 24, 18, 22, 30, 31, 30, 27, 25, 21, 27, 33, 35, 32, - 30, 27, 22, 24, 25, 24, 23, 20, 17, 12, 24, 27, 25, 24, 21, 17, 12, 23, 29, - 27, 27, 24, 20, 16, 24, 31, 31, 30, 27, 24, 20, 26, 33, 37, 35, 32, 27, 21, - 30, 36, 43, 39, 33, 29, 24, 33, 39, 43, 41, 36, 29, 25, 31, 35, 33, 27, 23, - 19, 15, 32, 36, 35, 28, 24, 20, 16, 32, 37, 38, 32, 27, 24, 20, 30, 37, 41, - 36, 31, 27, 23, 34, 39, 44, 41, 36, 30, 25, 37, 41, 47, 46, 39, 32, 28, 39, - 45, 48, 47, 41, 34, 29, 2, 2, 4, 8, 8, 6, 2, 2, 2, 3, 7, 8, 4, - 2, 2, 2, 3, 4, 5, 3, 2, 1, 2, 2, 2, 3, 2, 2, 2, 2, 3, 3, - 3, 3, 3, 6, 6, 6, 6, 4, 3, 2, 12, 10, 8, 6, 4, 3, 3, 2, 2, - 3, 5, 5, 2, 2, 1, 2, 3, 4, 4, 2, 2, 0, 2, 2, 2, 2, 2, 1, - 1, 1, 1, 2, 1, 1, 3, 3, 3, 4, 4, 3, 3, 3, 8, 7, 8, 7, 4, - 3, 3, 15, 13, 10, 7, 5, 3, 3, 0, 2, 2, 2, 2, 2, 1, 2, 2, 2, - 2, 2, 2, 1, 2, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 4, 5, - 5, 4, 4, 5, 3, 4, 11, 10, 9, 8, 6, 4, 4, 17, 16, 12, 9, 7, 6, - 5, 2, 2, 2, 3, 3, 3, 7, 2, 3, 3, 4, 4, 4, 7, 4, 4, 4, 5, - 5, 5, 7, 7, 7, 7, 7, 8, 8, 8, 7, 11, 11, 11, 12, 11, 10, 11, 17, - 16, 15, 14, 12, 12, 18, 22, 19, 17, 16, 14, 13, 10, 10, 10, 10, 11, 10, 7, - 12, 12, 12, 11, 12, 11, 7, 12, 14, 13, 13, 13, 12, 8, 12, 17, 16, 17, 16, - 15, 12, 15, 21, 20, 20, 20, 19, 13, 18, 24, 26, 24, 24, 21, 15, 22, 28, 29, - 26, 25, 23, 17, 19, 21, 20, 20, 16, 12, 8, 19, 23, 22, 22, 18, 13, 9, 20, - 25, 24, 24, 20, 15, 11, 19, 25, 27, 27, 23, 19, 15, 21, 28, 31, 31, 28, 22, - 17, 25, 30, 36, 35, 30, 24, 18, 27, 33, 38, 36, 31, 27, 21, 27, 32, 31, 25, - 20, 16, 11, 27, 33, 34, 27, 22, 16, 12, 27, 32, 36, 29, 24, 19, 15, 27, 33, - 38, 32, 27, 23, 19, 28, 35, 40, 36, 32, 26, 21, 31, 36, 41, 40, 33, 28, 22, - 34, 37, 42, 41, 35, 31, 24, 1, 2, 3, 3, 3, 2, 2, 0, 2, 2, 3, 3, - 2, 1, 1, 2, 2, 2, 2, 2, 1, 2, 1, 1, 2, 2, 2, 4, 4, 3, 4, - 4, 4, 4, 4, 7, 7, 7, 7, 5, 4, 4, 13, 11, 9, 7, 6, 4, 4, 1, - 2, 2, 3, 2, 2, 1, 2, 1, 2, 2, 2, 1, 1, 2, 0, 2, 2, 2, 1, - 1, 2, 2, 2, 2, 2, 2, 4, 5, 4, 4, 5, 4, 4, 3, 9, 9, 8, 8, - 5, 4, 4, 17, 14, 10, 8, 6, 4, 3, 2, 0, 1, 1, 2, 2, 5, 2, 2, - 1, 1, 1, 2, 5, 2, 2, 1, 1, 1, 1, 6, 4, 2, 4, 4, 4, 4, 7, - 8, 6, 7, 8, 8, 7, 7, 13, 11, 12, 11, 9, 8, 7, 19, 17, 15, 13, 11, - 10, 9, 2, 5, 5, 6, 6, 5, 8, 5, 6, 6, 7, 7, 7, 9, 8, 7, 7, - 8, 8, 8, 9, 11, 9, 11, 11, 11, 11, 11, 11, 14, 15, 15, 15, 14, 13, 13, - 20, 20, 19, 18, 16, 15, 19, 26, 23, 20, 19, 17, 17, 12, 13, 13, 13, 14, 12, - 8, 14, 15, 15, 15, 15, 13, 8, 14, 17, 16, 16, 16, 15, 12, 14, 21, 20, 19, - 20, 19, 15, 18, 26, 24, 24, 25, 22, 17, 21, 29, 30, 29, 26, 23, 19, 26, 31, - 33, 30, 29, 26, 20, 22, 24, 22, 22, 19, 15, 11, 23, 26, 24, 23, 21, 16, 12, - 22, 28, 27, 26, 22, 19, 15, 22, 28, 31, 30, 26, 22, 19, 26, 32, 35, 35, 31, - 26, 21, 28, 34, 40, 39, 32, 28, 23, 32, 37, 42, 41, 36, 29, 25, 30, 36, 35, - 28, 22, 18, 14, 30, 36, 37, 29, 23, 19, 15, 30, 36, 39, 32, 27, 22, 19, 31, - 38, 42, 36, 31, 26, 23, 32, 39, 44, 42, 34, 30, 24, 34, 40, 47, 45, 38, 32, - 27, 37, 42, 48, 48, 41, 34, 27, 1, 1, 2, 2, 2, 2, 1, 2, 1, 2, 2, - 2, 1, 1, 2, 1, 1, 2, 2, 1, 2, 2, 2, 2, 2, 2, 3, 4, 4, 5, - 4, 5, 5, 4, 4, 9, 8, 8, 7, 6, 4, 4, 15, 13, 10, 8, 6, 4, 4, - 2, 1, 1, 2, 1, 1, 3, 2, 1, 1, 2, 1, 1, 3, 2, 2, 0, 1, 2, - 1, 5, 2, 3, 2, 3, 3, 3, 5, 6, 6, 6, 6, 5, 4, 5, 11, 10, 10, - 9, 6, 5, 5, 18, 15, 12, 9, 8, 6, 5, 2, 2, 2, 2, 2, 5, 7, 2, - 2, 3, 3, 3, 5, 7, 5, 2, 4, 4, 5, 5, 8, 8, 3, 7, 7, 8, 8, - 9, 12, 7, 10, 11, 11, 10, 9, 15, 13, 15, 15, 13, 12, 9, 21, 19, 17, 16, - 15, 13, 12, 5, 7, 8, 9, 9, 8, 11, 9, 7, 9, 10, 10, 10, 11, 11, 8, - 11, 11, 12, 12, 12, 14, 10, 15, 15, 15, 15, 13, 15, 16, 18, 19, 19, 18, 17, - 16, 22, 23, 22, 21, 20, 19, 21, 28, 27, 25, 23, 22, 21, 15, 16, 16, 16, 17, - 16, 11, 17, 18, 18, 18, 18, 17, 11, 17, 19, 20, 21, 21, 19, 15, 17, 23, 24, - 23, 24, 22, 19, 20, 29, 28, 28, 28, 25, 21, 24, 33, 34, 33, 31, 27, 23, 29, - 35, 37, 33, 32, 30, 24, 26, 27, 26, 26, 23, 18, 14, 25, 30, 28, 27, 24, 20, - 15, 26, 31, 31, 31, 26, 23, 19, 25, 33, 34, 35, 31, 26, 22, 28, 35, 40, 38, - 36, 29, 24, 32, 39, 45, 43, 37, 32, 26, 36, 41, 46, 46, 40, 34, 28, 34, 41, - 38, 32, 26, 22, 17, 34, 41, 41, 34, 27, 22, 19, 34, 40, 43, 37, 31, 26, 22, - 34, 41, 47, 41, 35, 30, 26, 36, 43, 49, 44, 40, 33, 28, 39, 45, 52, 51, 43, - 35, 30, 42, 48, 52, 51, 45, 38, 32, 2, 1, 2, 4, 3, 3, 3, 2, 1, 2, - 3, 3, 2, 1, 2, 2, 1, 2, 2, 1, 3, 2, 2, 2, 2, 3, 3, 4, 5, - 5, 5, 5, 5, 4, 4, 9, 9, 8, 8, 6, 4, 4, 15, 13, 10, 8, 7, 4, - 4, 2, 2, 1, 3, 3, 4, 6, 2, 2, 1, 2, 2, 3, 5, 2, 2, 1, 0, - 0, 3, 6, 4, 3, 3, 3, 3, 4, 7, 8, 6, 6, 7, 6, 4, 7, 12, 10, - 10, 9, 8, 7, 7, 19, 16, 12, 10, 10, 9, 7, 2, 2, 4, 5, 6, 7, 9, - 4, 2, 4, 6, 6, 6, 8, 7, 2, 4, 6, 7, 6, 9, 11, 3, 7, 10, 10, - 10, 10, 14, 8, 11, 14, 14, 13, 10, 18, 13, 15, 17, 15, 15, 10, 21, 18, 18, - 18, 17, 16, 14, 7, 7, 10, 11, 12, 10, 14, 11, 8, 11, 12, 13, 13, 13, 14, - 8, 12, 13, 14, 14, 13, 17, 12, 16, 17, 18, 18, 15, 17, 17, 20, 21, 22, 21, - 19, 18, 23, 26, 24, 23, 22, 21, 21, 29, 28, 27, 25, 23, 24, 17, 18, 19, 19, - 20, 20, 14, 20, 19, 21, 21, 21, 20, 13, 19, 20, 22, 23, 23, 22, 17, 20, 25, - 26, 27, 27, 26, 21, 22, 31, 30, 31, 32, 29, 23, 25, 35, 36, 35, 33, 30, 25, - 30, 37, 40, 37, 36, 32, 26, 27, 30, 29, 29, 26, 22, 18, 27, 32, 31, 30, 27, - 23, 18, 28, 34, 34, 33, 30, 25, 21, 27, 36, 39, 38, 33, 29, 25, 30, 39, 42, - 41, 37, 32, 27, 34, 41, 47, 46, 40, 34, 29, 38, 42, 49, 50, 43, 35, 30, 36, - 44, 41, 34, 29, 25, 20, 38, 43, 43, 36, 30, 26, 21, 38, 44, 47, 40, 34, 29, - 25, 37, 44, 50, 44, 38, 33, 29, 39, 45, 52, 50, 42, 36, 30, 42, 49, 54, 54, - 46, 37, 33, 47, 51, 56, 55, 49, 41, 34, 2, 1, 3, 6, 6, 4, 3, 2, 1, - 2, 5, 6, 3, 1, 2, 2, 1, 3, 4, 2, 2, 2, 2, 2, 3, 4, 4, 4, - 4, 5, 5, 5, 7, 5, 4, 9, 8, 8, 8, 7, 5, 4, 14, 12, 10, 7, 8, - 5, 4, 2, 2, 1, 3, 3, 4, 5, 2, 2, 1, 2, 2, 3, 4, 2, 2, 1, - 0, 0, 2, 4, 4, 3, 3, 3, 3, 3, 5, 8, 6, 6, 6, 6, 3, 5, 12, - 10, 10, 9, 8, 7, 5, 18, 15, 11, 9, 9, 8, 5, 2, 2, 4, 5, 5, 6, - 8, 5, 2, 3, 6, 6, 6, 7, 8, 2, 4, 6, 7, 4, 7, 12, 3, 7, 10, - 10, 9, 9, 15, 8, 10, 13, 14, 13, 9, 18, 12, 14, 17, 16, 14, 9, 21, 18, - 16, 18, 17, 16, 14, 9, 6, 10, 11, 12, 10, 13, 12, 7, 10, 12, 13, 12, 12, - 15, 8, 12, 13, 14, 14, 12, 16, 11, 15, 17, 17, 17, 14, 18, 16, 19, 21, 22, - 21, 17, 18, 22, 24, 24, 24, 22, 21, 20, 27, 27, 26, 25, 24, 23, 17, 17, 19, - 19, 20, 19, 13, 20, 19, 20, 20, 21, 20, 12, 20, 20, 22, 23, 23, 22, 16, 20, - 23, 26, 26, 27, 25, 21, 22, 29, 31, 31, 30, 28, 23, 25, 34, 37, 35, 33, 29, - 25, 29, 37, 40, 37, 35, 32, 26, 27, 30, 29, 29, 26, 22, 17, 26, 32, 31, 30, - 27, 22, 18, 26, 34, 34, 33, 29, 25, 21, 27, 35, 39, 37, 33, 29, 25, 30, 39, - 44, 41, 37, 32, 26, 34, 41, 48, 46, 39, 33, 29, 37, 44, 48, 48, 43, 36, 30, - 37, 42, 40, 33, 29, 25, 21, 37, 42, 42, 36, 29, 25, 21, 37, 42, 45, 38, 34, - 29, 24, 37, 44, 49, 43, 36, 33, 28, 38, 46, 50, 48, 42, 35, 30, 42, 49, 53, - 52, 45, 38, 32, 45, 49, 55, 55, 47, 40, 34, 1, 3, 5, 7, 7, 5, 3, 1, - 1, 4, 6, 6, 4, 2, 2, 1, 3, 5, 5, 3, 2, 2, 1, 2, 4, 6, 5, - 4, 4, 4, 4, 6, 8, 6, 4, 8, 7, 7, 8, 8, 6, 4, 13, 11, 9, 8, - 8, 6, 4, 1, 1, 3, 5, 4, 3, 4, 1, 1, 2, 4, 4, 2, 3, 2, 1, - 1, 3, 2, 0, 3, 2, 2, 2, 3, 3, 2, 4, 6, 5, 5, 6, 5, 4, 4, - 11, 9, 9, 8, 6, 4, 3, 16, 13, 10, 8, 7, 6, 3, 2, 1, 3, 4, 4, - 6, 7, 2, 2, 4, 4, 5, 5, 6, 5, 2, 3, 4, 4, 3, 5, 10, 3, 6, - 7, 7, 7, 7, 13, 7, 9, 11, 11, 10, 7, 16, 12, 13, 14, 12, 12, 7, 19, - 17, 15, 15, 14, 13, 12, 5, 6, 9, 10, 11, 9, 11, 11, 7, 9, 11, 11, 11, - 10, 14, 7, 11, 11, 11, 11, 10, 16, 10, 14, 14, 15, 15, 11, 17, 15, 18, 19, - 19, 18, 14, 16, 20, 22, 22, 20, 20, 18, 18, 25, 25, 24, 23, 21, 20, 15, 16, - 17, 18, 18, 17, 11, 19, 17, 19, 19, 20, 18, 10, 19, 19, 20, 20, 20, 18, 14, - 19, 22, 23, 23, 24, 22, 18, 21, 28, 28, 28, 28, 25, 20, 23, 31, 34, 32, 30, - 27, 23, 26, 34, 36, 35, 32, 29, 24, 26, 28, 27, 27, 24, 19, 16, 25, 30, 28, - 28, 25, 21, 16, 25, 32, 30, 29, 25, 22, 18, 25, 33, 34, 34, 30, 26, 22, 28, - 35, 40, 38, 34, 29, 23, 31, 40, 45, 41, 36, 30, 26, 35, 40, 44, 45, 39, 33, - 27, 36, 40, 37, 31, 25, 23, 19, 35, 40, 40, 33, 28, 23, 19, 35, 40, 42, 35, - 30, 26, 22, 34, 41, 45, 39, 32, 30, 26, 37, 43, 48, 44, 37, 33, 28, 38, 44, - 50, 49, 41, 35, 29, 42, 47, 49, 50, 44, 37, 31, 3, 5, 7, 9, 9, 7, 5, - 2, 5, 7, 8, 9, 6, 4, 1, 4, 6, 7, 8, 5, 3, 1, 1, 4, 6, 8, - 6, 5, 3, 3, 5, 6, 9, 7, 4, 7, 6, 7, 8, 8, 7, 4, 10, 9, 8, - 8, 8, 7, 5, 1, 4, 6, 8, 7, 5, 4, 1, 3, 5, 7, 6, 4, 2, 1, - 1, 5, 6, 4, 3, 0, 2, 1, 3, 4, 3, 3, 2, 4, 4, 4, 6, 5, 4, - 2, 9, 8, 7, 8, 6, 4, 2, 14, 11, 8, 8, 6, 4, 2, 1, 1, 3, 3, - 4, 5, 6, 2, 1, 3, 3, 3, 4, 5, 2, 1, 2, 2, 2, 2, 3, 4, 2, - 4, 4, 3, 3, 4, 9, 6, 7, 7, 7, 6, 4, 12, 10, 10, 9, 9, 8, 4, - 16, 13, 12, 11, 10, 9, 8, 2, 6, 7, 8, 8, 8, 9, 5, 6, 8, 8, 9, - 9, 8, 9, 6, 8, 9, 9, 9, 7, 12, 8, 11, 11, 10, 11, 8, 13, 13, 15, - 14, 15, 14, 12, 12, 17, 18, 17, 17, 15, 14, 16, 22, 21, 19, 19, 17, 16, 13, - 14, 15, 15, 16, 15, 9, 15, 15, 16, 17, 17, 16, 8, 15, 17, 18, 17, 17, 15, - 12, 15, 20, 20, 20, 20, 18, 15, 17, 25, 24, 25, 24, 21, 16, 20, 27, 29, 27, - 26, 23, 18, 23, 29, 32, 29, 28, 25, 20, 23, 25, 24, 23, 21, 17, 14, 24, 27, - 26, 25, 23, 18, 13, 23, 29, 28, 26, 22, 18, 14, 23, 30, 31, 29, 26, 22, 18, - 26, 32, 36, 33, 29, 25, 20, 29, 35, 39, 37, 32, 26, 21, 31, 36, 40, 39, 33, - 28, 23, 31, 37, 34, 28, 23, 20, 17, 32, 36, 35, 29, 25, 20, 16, 32, 37, 39, - 31, 25, 22, 17, 32, 36, 40, 35, 29, 26, 21, 33, 38, 43, 39, 33, 28, 23, 36, - 40, 43, 44, 36, 30, 25, 38, 42, 45, 45, 39, 32, 26, 2, 3, 7, 11, 11, 10, - 6, 2, 2, 6, 10, 11, 9, 3, 2, 2, 4, 7, 9, 6, 2, 2, 2, 2, 4, - 6, 4, 2, 2, 2, 2, 3, 5, 4, 2, 6, 6, 6, 5, 4, 4, 2, 11, 11, - 8, 6, 4, 4, 2, 2, 2, 4, 8, 9, 5, 2, 1, 2, 3, 6, 8, 3, 2, - 1, 2, 2, 4, 4, 2, 2, 0, 2, 2, 2, 2, 1, 2, 3, 3, 3, 3, 3, - 2, 2, 8, 7, 8, 7, 4, 3, 2, 15, 13, 10, 7, 5, 3, 2, 1, 2, 2, - 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 1, 2, 0, 2, - 1, 1, 1, 1, 1, 2, 5, 4, 4, 4, 4, 3, 2, 11, 10, 9, 8, 6, 3, - 2, 17, 16, 12, 9, 6, 5, 3, 1, 1, 1, 1, 1, 2, 6, 1, 2, 3, 3, - 3, 3, 6, 3, 3, 3, 4, 4, 4, 6, 6, 6, 6, 6, 7, 7, 8, 6, 10, - 10, 10, 10, 10, 9, 11, 15, 15, 14, 12, 11, 10, 17, 21, 18, 16, 15, 13, 12, - 9, 9, 9, 10, 10, 9, 6, 11, 11, 11, 11, 11, 10, 6, 11, 12, 12, 12, 13, - 11, 7, 11, 16, 15, 15, 15, 14, 10, 14, 20, 19, 19, 20, 18, 12, 17, 23, 25, - 23, 22, 20, 14, 21, 27, 28, 26, 24, 22, 16, 18, 19, 19, 20, 16, 12, 7, 18, - 22, 21, 21, 18, 13, 9, 18, 23, 23, 23, 19, 15, 10, 18, 24, 27, 25, 22, 18, - 14, 20, 27, 30, 27, 26, 21, 16, 23, 28, 34, 31, 28, 24, 18, 27, 31, 35, 34, - 30, 25, 20, 26, 32, 29, 24, 20, 15, 10, 26, 31, 32, 26, 21, 16, 11, 26, 32, - 33, 28, 23, 18, 14, 25, 31, 36, 29, 26, 22, 18, 26, 31, 37, 34, 29, 25, 20, - 30, 34, 38, 36, 30, 26, 22, 31, 36, 37, 37, 32, 29, 24, 2, 3, 4, 4, 4, - 4, 3, 2, 3, 4, 4, 4, 3, 3, 1, 2, 3, 4, 4, 3, 1, 1, 1, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 6, 6, 6, 5, 3, 2, 2, 11, - 10, 7, 6, 4, 2, 2, 1, 3, 3, 4, 3, 3, 3, 1, 2, 3, 4, 3, 3, - 2, 1, 2, 3, 3, 3, 2, 1, 2, 0, 1, 2, 2, 1, 2, 3, 3, 3, 3, - 3, 2, 2, 8, 7, 7, 6, 4, 2, 2, 15, 12, 9, 7, 5, 3, 2, 1, 2, - 2, 3, 3, 3, 5, 2, 1, 2, 3, 3, 3, 5, 2, 1, 2, 2, 2, 2, 4, - 2, 1, 2, 2, 2, 2, 5, 6, 5, 5, 5, 5, 5, 5, 11, 10, 10, 9, 7, - 6, 5, 17, 15, 12, 10, 9, 7, 6, 2, 4, 5, 5, 6, 6, 9, 2, 5, 6, - 7, 7, 7, 8, 6, 6, 7, 7, 7, 8, 9, 9, 8, 9, 9, 9, 9, 9, 9, - 13, 13, 13, 13, 13, 11, 11, 18, 17, 16, 15, 14, 13, 17, 25, 20, 19, 17, 15, - 14, 12, 12, 13, 13, 14, 12, 9, 13, 14, 14, 14, 15, 13, 9, 13, 15, 16, 16, - 16, 14, 10, 13, 18, 18, 18, 18, 17, 13, 16, 23, 22, 22, 22, 20, 15, 20, 26, - 27, 26, 24, 22, 16, 24, 29, 31, 27, 26, 24, 17, 22, 23, 22, 22, 20, 15, 11, - 21, 25, 24, 24, 21, 16, 12, 21, 27, 26, 26, 21, 17, 13, 22, 27, 29, 27, 24, - 20, 16, 23, 29, 34, 32, 28, 23, 18, 26, 32, 39, 37, 32, 26, 20, 29, 35, 40, - 40, 34, 27, 22, 29, 36, 35, 28, 22, 18, 14, 29, 36, 38, 30, 24, 19, 15, 30, - 37, 39, 31, 25, 20, 17, 30, 34, 41, 34, 29, 24, 20, 29, 37, 42, 39, 34, 28, - 22, 32, 38, 44, 43, 37, 30, 24, 35, 41, 45, 46, 39, 32, 25, 2, 3, 4, 5, - 5, 5, 4, 2, 3, 4, 5, 5, 4, 3, 2, 2, 3, 4, 4, 2, 1, 2, 1, - 2, 2, 2, 1, 2, 3, 2, 2, 3, 3, 2, 2, 6, 6, 6, 5, 3, 2, 2, - 12, 10, 7, 5, 4, 2, 2, 2, 2, 3, 4, 4, 4, 5, 2, 2, 3, 4, 4, - 3, 4, 2, 2, 2, 3, 3, 2, 2, 2, 2, 0, 1, 2, 1, 3, 4, 3, 3, - 3, 3, 2, 4, 9, 8, 7, 6, 4, 2, 4, 16, 13, 9, 7, 5, 3, 3, 2, - 2, 3, 4, 5, 6, 8, 2, 2, 3, 4, 5, 5, 8, 2, 2, 3, 4, 4, 4, - 6, 5, 2, 4, 5, 5, 5, 7, 9, 5, 8, 8, 8, 7, 7, 12, 10, 12, 11, - 10, 9, 7, 17, 16, 15, 13, 11, 10, 9, 2, 6, 8, 9, 10, 9, 11, 5, 7, - 9, 10, 11, 11, 12, 9, 8, 10, 10, 10, 11, 11, 12, 9, 12, 12, 12, 13, 11, - 12, 14, 15, 15, 16, 16, 14, 13, 20, 21, 20, 18, 17, 16, 18, 26, 24, 22, 19, - 18, 17, 13, 15, 16, 17, 18, 17, 11, 15, 17, 17, 18, 19, 17, 11, 15, 18, 19, - 18, 19, 18, 13, 15, 22, 21, 20, 21, 20, 16, 17, 26, 26, 25, 25, 23, 17, 22, - 30, 31, 30, 27, 24, 19, 26, 33, 34, 32, 29, 26, 21, 25, 27, 26, 26, 23, 20, - 15, 24, 29, 28, 27, 24, 20, 16, 25, 31, 30, 30, 25, 20, 16, 24, 31, 32, 32, - 28, 23, 19, 26, 32, 36, 36, 32, 26, 21, 29, 35, 42, 41, 35, 28, 23, 33, 38, - 42, 42, 37, 30, 25, 33, 40, 37, 32, 27, 22, 18, 32, 39, 40, 33, 27, 22, 18, - 34, 40, 43, 35, 28, 23, 19, 33, 38, 44, 38, 32, 28, 23, 34, 40, 45, 43, 36, - 31, 25, 36, 43, 48, 47, 40, 33, 26, 38, 44, 49, 49, 42, 35, 28, 2, 3, 5, - 6, 6, 6, 4, 2, 3, 4, 6, 6, 4, 3, 2, 2, 3, 4, 4, 2, 1, 2, - 2, 1, 2, 2, 1, 2, 3, 2, 2, 3, 3, 2, 2, 7, 6, 6, 5, 4, 2, - 2, 12, 10, 8, 5, 4, 2, 2, 2, 3, 3, 5, 5, 6, 7, 2, 2, 3, 5, - 5, 4, 5, 2, 2, 3, 3, 3, 3, 4, 2, 2, 2, 0, 0, 2, 5, 5, 4, - 3, 4, 3, 3, 4, 9, 8, 7, 7, 5, 4, 5, 15, 13, 9, 8, 7, 5, 5, - 2, 2, 5, 6, 7, 8, 10, 2, 2, 5, 6, 7, 7, 9, 4, 2, 5, 6, 6, - 6, 8, 8, 2, 5, 7, 7, 7, 8, 11, 6, 8, 10, 11, 10, 8, 15, 11, 12, - 13, 12, 11, 8, 17, 15, 15, 16, 14, 13, 11, 4, 7, 11, 11, 12, 11, 14, 8, - 7, 11, 12, 13, 13, 14, 11, 8, 12, 13, 13, 13, 13, 14, 10, 14, 14, 15, 14, - 13, 14, 14, 17, 18, 18, 18, 16, 15, 20, 22, 21, 20, 19, 18, 17, 26, 25, 24, - 22, 21, 20, 15, 17, 18, 19, 20, 19, 14, 17, 19, 20, 21, 21, 20, 14, 17, 20, - 21, 22, 22, 20, 16, 17, 23, 24, 24, 23, 23, 19, 19, 27, 28, 28, 28, 26, 20, - 22, 31, 33, 32, 30, 27, 22, 27, 34, 37, 34, 32, 29, 23, 27, 29, 29, 28, 26, - 22, 18, 27, 32, 30, 30, 27, 22, 18, 27, 33, 33, 32, 28, 23, 18, 27, 33, 35, - 34, 30, 25, 21, 28, 36, 40, 38, 35, 29, 24, 31, 38, 45, 43, 36, 30, 26, 34, - 40, 45, 46, 39, 34, 27, 37, 42, 41, 35, 29, 25, 20, 36, 42, 43, 37, 30, 25, - 21, 36, 43, 45, 38, 31, 26, 22, 37, 42, 48, 41, 35, 30, 25, 37, 43, 49, 46, - 39, 33, 28, 38, 46, 51, 50, 42, 35, 30, 41, 47, 52, 53, 45, 38, 32, 2, 3, - 6, 9, 9, 7, 5, 2, 3, 5, 8, 9, 6, 3, 2, 2, 3, 6, 7, 4, 1, - 2, 1, 1, 3, 5, 3, 2, 3, 2, 2, 3, 5, 3, 2, 6, 6, 6, 5, 5, - 4, 2, 11, 9, 7, 5, 5, 3, 2, 2, 2, 3, 7, 6, 6, 7, 2, 2, 3, - 5, 6, 5, 5, 2, 2, 3, 3, 3, 3, 4, 2, 2, 2, 0, 0, 1, 4, 5, - 3, 3, 3, 3, 2, 4, 9, 7, 7, 6, 5, 4, 4, 14, 11, 8, 7, 6, 5, - 4, 1, 2, 5, 6, 7, 8, 9, 2, 2, 5, 6, 7, 7, 8, 5, 2, 4, 6, - 6, 5, 7, 8, 2, 5, 7, 7, 7, 7, 12, 5, 8, 10, 11, 10, 7, 15, 11, - 11, 13, 12, 11, 7, 16, 14, 13, 14, 14, 13, 11, 5, 6, 10, 11, 12, 11, 13, - 9, 7, 11, 12, 13, 13, 12, 11, 7, 11, 12, 13, 13, 11, 14, 9, 13, 14, 14, - 14, 12, 15, 14, 17, 19, 19, 18, 15, 14, 18, 21, 22, 21, 19, 18, 16, 23, 23, - 22, 22, 21, 20, 15, 16, 18, 19, 20, 19, 14, 18, 18, 20, 21, 21, 20, 13, 18, - 19, 21, 22, 21, 19, 15, 17, 22, 24, 24, 23, 22, 18, 19, 26, 28, 27, 28, 25, - 20, 21, 30, 32, 31, 30, 27, 22, 24, 34, 36, 34, 32, 29, 23, 26, 29, 29, 29, - 26, 22, 17, 26, 31, 31, 30, 27, 22, 17, 26, 33, 33, 32, 27, 22, 18, 26, 33, - 35, 34, 30, 25, 21, 28, 35, 39, 38, 35, 29, 24, 31, 37, 44, 42, 37, 31, 25, - 34, 38, 44, 45, 39, 34, 27, 36, 42, 41, 33, 29, 25, 20, 37, 43, 43, 36, 30, - 25, 21, 36, 42, 45, 38, 31, 26, 22, 36, 42, 46, 41, 34, 29, 25, 37, 43, 48, - 45, 39, 33, 27, 38, 46, 51, 50, 42, 35, 29, 40, 47, 51, 51, 43, 36, 31, 3, - 4, 6, 8, 8, 6, 4, 3, 3, 5, 7, 7, 5, 3, 2, 3, 4, 6, 6, 4, - 2, 1, 1, 2, 4, 5, 3, 2, 2, 2, 2, 4, 6, 4, 2, 6, 5, 5, 5, - 6, 4, 2, 9, 7, 5, 5, 6, 4, 2, 2, 3, 4, 6, 5, 6, 6, 2, 3, - 4, 5, 5, 4, 4, 1, 2, 3, 4, 3, 2, 3, 1, 1, 1, 2, 1, 0, 3, - 4, 3, 3, 3, 3, 2, 3, 8, 6, 5, 5, 3, 2, 2, 11, 8, 6, 5, 5, - 4, 3, 1, 2, 5, 5, 6, 8, 9, 2, 2, 5, 6, 6, 6, 7, 3, 1, 5, - 5, 5, 5, 6, 8, 1, 4, 5, 5, 5, 5, 11, 5, 7, 9, 9, 8, 5, 12, - 9, 9, 11, 10, 9, 5, 13, 11, 10, 12, 11, 11, 10, 3, 6, 10, 11, 11, 11, - 12, 8, 7, 11, 12, 12, 12, 11, 11, 7, 11, 12, 12, 12, 10, 14, 8, 12, 13, - 13, 13, 10, 15, 13, 15, 17, 17, 16, 13, 12, 16, 18, 19, 18, 18, 16, 13, 19, - 21, 20, 19, 19, 18, 14, 16, 18, 19, 20, 19, 13, 17, 18, 19, 20, 20, 19, 12, - 17, 18, 21, 20, 20, 19, 15, 17, 21, 22, 22, 23, 21, 17, 19, 26, 26, 26, 25, - 24, 18, 20, 28, 30, 29, 27, 25, 20, 21, 29, 32, 30, 29, 27, 21, 25, 28, 28, - 28, 24, 21, 17, 26, 30, 29, 29, 26, 21, 17, 26, 32, 31, 29, 26, 21, 18, 25, - 32, 34, 31, 27, 24, 20, 28, 33, 38, 35, 31, 27, 22, 29, 35, 41, 39, 33, 28, - 24, 30, 36, 42, 40, 36, 31, 26, 35, 40, 39, 32, 27, 23, 19, 35, 40, 41, 34, - 29, 24, 20, 36, 41, 43, 35, 29, 25, 20, 36, 39, 43, 38, 33, 28, 23, 35, 42, - 45, 42, 36, 30, 26, 38, 43, 47, 45, 39, 32, 27, 38, 43, 47, 47, 41, 33, 29, - 4, 7, 8, 11, 10, 9, 6, 4, 6, 8, 10, 10, 7, 5, 3, 5, 7, 8, 9, - 6, 3, 3, 3, 5, 7, 8, 5, 3, 1, 0, 3, 5, 7, 5, 3, 2, 2, 4, - 5, 7, 5, 3, 4, 3, 3, 4, 6, 5, 3, 4, 5, 7, 9, 8, 6, 7, 3, - 4, 6, 8, 7, 5, 4, 2, 3, 5, 7, 5, 3, 2, 2, 2, 3, 5, 4, 3, - 0, 1, 1, 2, 4, 3, 2, 0, 4, 3, 3, 4, 2, 2, 0, 7, 4, 3, 3, - 3, 1, 0, 3, 4, 4, 5, 7, 8, 8, 2, 3, 5, 6, 6, 6, 6, 2, 3, - 5, 4, 4, 4, 5, 3, 2, 3, 3, 2, 3, 3, 6, 2, 4, 4, 4, 4, 3, - 7, 4, 5, 5, 5, 5, 3, 8, 6, 6, 7, 6, 6, 6, 2, 7, 8, 8, 9, - 10, 11, 3, 7, 9, 9, 10, 10, 9, 8, 7, 9, 9, 10, 10, 8, 11, 7, 10, - 10, 10, 10, 7, 10, 9, 11, 11, 12, 11, 11, 7, 11, 13, 13, 13, 13, 12, 8, - 14, 15, 15, 14, 14, 14, 12, 15, 15, 16, 17, 16, 11, 14, 16, 17, 18, 17, 15, - 9, 14, 18, 18, 18, 18, 16, 12, 14, 20, 19, 18, 18, 17, 13, 14, 21, 22, 21, - 20, 18, 14, 14, 22, 24, 23, 22, 20, 15, 16, 22, 27, 25, 23, 21, 17, 24, 27, - 24, 24, 22, 18, 14, 24, 28, 27, 26, 23, 18, 14, 24, 29, 29, 26, 22, 19, 15, - 24, 30, 30, 27, 24, 20, 15, 23, 30, 32, 30, 25, 21, 17, 24, 30, 36, 33, 27, - 23, 19, 25, 30, 35, 34, 30, 25, 20, 32, 37, 34, 29, 24, 20, 17, 33, 37, 37, - 30, 26, 21, 16, 32, 38, 39, 32, 26, 22, 17, 32, 37, 40, 33, 27, 23, 19, 31, - 37, 40, 36, 30, 24, 20, 31, 37, 41, 38, 32, 27, 21, 33, 36, 42, 40, 34, 28, - 23, 5, 7, 10, 14, 14, 11, 8, 5, 6, 9, 13, 14, 11, 8, 4, 6, 8, 11, - 13, 10, 6, 4, 4, 5, 8, 11, 8, 2, 2, 2, 2, 4, 6, 6, 2, 3, 3, - 3, 3, 5, 6, 2, 9, 8, 5, 3, 4, 6, 2, 4, 6, 8, 11, 11, 8, 6, - 4, 5, 7, 9, 10, 7, 5, 3, 5, 6, 8, 8, 6, 4, 3, 3, 4, 5, 5, - 4, 1, 0, 2, 2, 2, 2, 2, 1, 5, 5, 5, 4, 2, 2, 1, 12, 10, 7, - 5, 2, 2, 1, 4, 5, 5, 6, 7, 6, 5, 3, 4, 5, 5, 5, 5, 5, 2, - 4, 4, 4, 4, 4, 4, 2, 2, 2, 3, 3, 3, 1, 2, 2, 2, 2, 2, 1, - 1, 8, 7, 7, 5, 3, 1, 1, 14, 14, 9, 6, 4, 1, 1, 2, 4, 4, 5, - 5, 6, 6, 2, 3, 5, 5, 5, 5, 6, 2, 3, 4, 5, 5, 5, 6, 3, 4, - 4, 4, 5, 5, 6, 3, 7, 7, 7, 7, 7, 6, 8, 13, 12, 11, 9, 8, 8, - 14, 18, 15, 13, 11, 10, 9, 9, 9, 10, 10, 11, 9, 6, 10, 11, 11, 11, 12, - 10, 6, 10, 12, 12, 12, 13, 12, 7, 10, 14, 13, 13, 14, 12, 8, 11, 17, 17, - 16, 16, 15, 9, 14, 19, 21, 20, 19, 16, 11, 18, 22, 24, 21, 20, 19, 13, 17, - 20, 20, 20, 17, 12, 8, 18, 22, 21, 21, 18, 13, 9, 17, 23, 23, 22, 19, 15, - 10, 18, 22, 24, 23, 20, 16, 11, 17, 23, 26, 24, 22, 19, 13, 19, 25, 28, 27, - 23, 20, 15, 22, 26, 29, 27, 24, 21, 17, 25, 30, 28, 25, 20, 15, 11, 26, 30, - 31, 26, 22, 16, 12, 26, 31, 33, 27, 22, 18, 13, 26, 30, 33, 27, 23, 19, 15, - 24, 29, 32, 29, 24, 21, 17, 25, 28, 32, 31, 26, 22, 19, 27, 30, 32, 32, 28, - 23, 20, 5, 6, 7, 8, 8, 7, 7, 5, 6, 7, 8, 8, 7, 6, 4, 5, 6, - 7, 7, 5, 4, 3, 4, 5, 5, 5, 3, 2, 1, 2, 2, 2, 3, 2, 1, 3, - 3, 3, 2, 3, 2, 1, 9, 7, 5, 3, 2, 2, 2, 4, 5, 7, 7, 7, 7, - 7, 4, 5, 6, 7, 7, 6, 5, 3, 4, 6, 6, 6, 5, 4, 3, 3, 3, 4, - 3, 3, 1, 2, 0, 2, 2, 2, 1, 1, 5, 4, 4, 3, 1, 2, 1, 12, 9, - 6, 4, 2, 1, 1, 3, 5, 5, 6, 7, 7, 8, 3, 4, 5, 6, 6, 6, 7, - 2, 3, 4, 5, 5, 5, 5, 3, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, - 2, 3, 8, 7, 6, 5, 4, 3, 3, 14, 12, 9, 7, 5, 4, 4, 3, 5, 6, - 7, 8, 9, 10, 2, 5, 6, 7, 8, 8, 9, 3, 6, 6, 6, 7, 7, 8, 6, - 6, 7, 7, 7, 8, 8, 6, 10, 9, 10, 10, 9, 9, 8, 15, 14, 13, 12, 10, - 10, 14, 21, 18, 15, 13, 12, 11, 11, 12, 12, 13, 14, 13, 10, 12, 14, 14, 14, - 15, 14, 9, 12, 15, 15, 15, 15, 14, 9, 13, 17, 16, 15, 16, 15, 11, 13, 20, - 19, 19, 19, 17, 12, 17, 22, 24, 23, 20, 18, 13, 21, 26, 28, 25, 23, 21, 15, - 21, 22, 21, 23, 20, 16, 11, 21, 24, 24, 24, 21, 16, 12, 21, 26, 27, 25, 22, - 17, 12, 21, 26, 27, 26, 22, 17, 13, 20, 26, 29, 29, 25, 20, 15, 22, 28, 35, - 34, 28, 22, 17, 25, 33, 36, 36, 31, 25, 18, 29, 36, 35, 28, 22, 19, 14, 29, - 35, 37, 29, 24, 19, 15, 30, 36, 39, 30, 25, 20, 15, 29, 35, 39, 32, 26, 21, - 17, 28, 34, 38, 36, 31, 24, 19, 29, 35, 41, 40, 32, 27, 21, 32, 37, 43, 41, - 35, 28, 23, 5, 7, 8, 9, 9, 9, 8, 5, 6, 7, 9, 9, 7, 6, 4, 5, - 7, 7, 7, 5, 4, 4, 4, 4, 5, 5, 3, 1, 2, 1, 2, 2, 2, 2, 1, - 3, 3, 3, 2, 2, 2, 1, 8, 7, 4, 2, 2, 2, 1, 4, 5, 7, 8, 8, - 8, 8, 4, 5, 7, 8, 8, 7, 7, 4, 5, 6, 6, 6, 5, 4, 3, 3, 3, - 4, 3, 3, 2, 2, 2, 0, 1, 1, 1, 2, 5, 4, 4, 3, 1, 1, 2, 12, - 9, 6, 3, 2, 1, 2, 4, 5, 6, 7, 8, 10, 10, 3, 4, 6, 7, 8, 8, - 9, 3, 4, 6, 6, 6, 6, 7, 3, 3, 4, 4, 4, 5, 6, 5, 2, 4, 5, - 5, 4, 5, 9, 7, 9, 8, 6, 5, 6, 14, 12, 11, 9, 8, 7, 7, 3, 7, - 8, 9, 10, 12, 12, 3, 7, 9, 10, 10, 10, 11, 7, 8, 9, 10, 10, 10, 11, - 10, 7, 10, 10, 10, 10, 10, 9, 11, 12, 12, 12, 12, 11, 9, 16, 17, 15, 14, - 13, 13, 14, 22, 20, 18, 16, 15, 14, 13, 15, 15, 16, 17, 16, 12, 14, 16, 17, - 17, 18, 16, 11, 14, 18, 19, 18, 17, 17, 13, 14, 19, 19, 19, 19, 17, 13, 14, - 23, 21, 21, 20, 19, 14, 18, 25, 27, 25, 23, 21, 16, 23, 28, 31, 28, 25, 23, - 18, 24, 25, 26, 26, 22, 18, 14, 23, 29, 26, 28, 24, 19, 15, 24, 29, 30, 28, - 24, 20, 15, 24, 29, 30, 30, 26, 20, 16, 23, 29, 33, 32, 28, 23, 17, 26, 31, - 38, 37, 30, 24, 19, 28, 34, 39, 38, 33, 26, 21, 33, 39, 38, 31, 26, 20, 17, - 33, 39, 41, 32, 27, 22, 17, 33, 40, 42, 34, 27, 23, 18, 33, 38, 43, 36, 29, - 24, 19, 31, 37, 42, 39, 33, 28, 21, 32, 37, 44, 44, 35, 29, 23, 34, 41, 45, - 45, 38, 32, 25, 5, 6, 9, 10, 10, 9, 8, 5, 6, 8, 9, 9, 8, 6, 4, - 5, 7, 8, 7, 6, 4, 4, 4, 4, 5, 6, 4, 2, 2, 2, 2, 2, 3, 2, - 1, 3, 3, 3, 2, 2, 2, 1, 8, 7, 4, 2, 2, 2, 1, 4, 6, 7, 9, - 9, 9, 10, 4, 5, 6, 8, 9, 8, 8, 4, 5, 6, 6, 6, 6, 6, 3, 3, - 3, 4, 3, 3, 3, 2, 2, 2, 0, 0, 1, 4, 6, 5, 4, 3, 2, 2, 4, - 11, 8, 6, 4, 3, 2, 4, 4, 5, 7, 9, 10, 11, 12, 3, 4, 8, 9, 9, - 10, 10, 3, 4, 7, 8, 8, 8, 8, 6, 3, 5, 6, 6, 6, 7, 8, 3, 5, - 7, 7, 6, 7, 11, 7, 9, 10, 8, 8, 7, 13, 11, 11, 12, 10, 9, 9, 3, - 8, 10, 11, 12, 13, 14, 6, 8, 11, 12, 13, 13, 13, 9, 8, 11, 12, 13, 12, - 13, 12, 8, 12, 12, 13, 13, 11, 11, 11, 14, 14, 15, 14, 14, 11, 16, 18, 18, - 16, 16, 16, 13, 20, 21, 20, 18, 17, 17, 13, 17, 18, 19, 19, 19, 15, 16, 18, - 19, 20, 21, 19, 13, 15, 19, 21, 21, 21, 19, 15, 16, 21, 22, 21, 22, 20, 15, - 15, 24, 25, 24, 24, 22, 17, 19, 27, 29, 28, 26, 23, 18, 22, 28, 32, 30, 29, - 25, 20, 26, 29, 28, 28, 26, 22, 17, 27, 31, 31, 30, 26, 22, 17, 26, 34, 33, - 32, 27, 22, 18, 26, 33, 34, 32, 27, 23, 18, 25, 32, 36, 35, 31, 25, 20, 27, - 35, 40, 39, 33, 28, 22, 30, 36, 41, 42, 35, 30, 24, 37, 42, 40, 34, 28, 24, - 20, 36, 43, 43, 35, 30, 23, 20, 36, 42, 45, 37, 31, 24, 20, 36, 41, 46, 39, - 32, 26, 22, 35, 40, 45, 42, 34, 30, 24, 35, 42, 47, 46, 38, 32, 25, 38, 43, - 48, 48, 41, 34, 27, 5, 6, 9, 12, 13, 10, 8, 5, 6, 8, 12, 12, 9, 6, - 4, 5, 7, 9, 10, 7, 3, 4, 4, 4, 6, 8, 5, 2, 2, 1, 1, 3, 6, - 4, 1, 3, 2, 2, 2, 4, 4, 1, 5, 3, 2, 2, 3, 4, 1, 4, 5, 7, - 10, 10, 9, 9, 4, 5, 6, 9, 9, 7, 7, 3, 4, 5, 7, 6, 5, 5, 3, - 3, 3, 3, 3, 3, 3, 2, 2, 1, 0, 0, 1, 3, 4, 3, 2, 2, 2, 1, - 3, 7, 4, 3, 2, 3, 2, 3, 4, 5, 7, 8, 10, 11, 11, 3, 4, 7, 9, - 9, 9, 9, 3, 4, 7, 7, 7, 7, 8, 7, 2, 4, 6, 6, 6, 6, 9, 2, - 5, 7, 7, 7, 6, 9, 4, 6, 9, 9, 8, 6, 9, 7, 7, 10, 9, 9, 9, - 3, 7, 11, 11, 12, 13, 14, 8, 7, 11, 12, 13, 13, 13, 11, 8, 12, 12, 13, - 12, 12, 12, 7, 12, 13, 13, 13, 11, 12, 10, 14, 14, 15, 15, 14, 10, 12, 15, - 16, 16, 16, 15, 9, 15, 18, 18, 17, 17, 17, 14, 17, 18, 19, 20, 20, 14, 16, - 18, 20, 20, 21, 19, 13, 16, 19, 21, 21, 21, 19, 15, 16, 21, 21, 22, 22, 20, - 16, 15, 24, 24, 24, 24, 22, 17, 16, 24, 28, 27, 26, 23, 18, 18, 27, 30, 28, - 27, 25, 20, 27, 30, 28, 28, 25, 22, 18, 26, 31, 30, 31, 27, 22, 17, 26, 34, - 33, 31, 26, 22, 18, 26, 32, 34, 32, 28, 23, 18, 25, 32, 37, 35, 31, 26, 20, - 26, 33, 39, 38, 32, 28, 22, 27, 34, 40, 40, 35, 29, 24, 37, 43, 40, 34, 30, - 24, 21, 37, 42, 43, 36, 30, 25, 20, 37, 42, 45, 36, 30, 26, 21, 36, 41, 46, - 38, 31, 27, 22, 35, 41, 44, 40, 34, 28, 24, 36, 42, 46, 45, 38, 31, 26, 35, - 41, 46, 45, 40, 33, 28, 4, 5, 6, 8, 8, 7, 6, 4, 4, 5, 8, 8, 5, - 4, 3, 4, 5, 6, 6, 4, 2, 3, 3, 3, 4, 6, 3, 1, 2, 1, 0, 2, - 5, 3, 1, 2, 2, 2, 3, 4, 3, 1, 4, 3, 2, 3, 3, 3, 1, 4, 4, - 5, 6, 6, 7, 8, 3, 4, 5, 6, 6, 6, 6, 3, 4, 4, 4, 3, 4, 4, - 2, 2, 2, 3, 2, 2, 2, 2, 1, 1, 1, 1, 0, 2, 3, 2, 2, 2, 1, - 1, 2, 7, 4, 2, 2, 3, 2, 2, 3, 4, 6, 7, 8, 9, 10, 2, 3, 6, - 7, 7, 8, 9, 3, 3, 6, 6, 6, 6, 7, 7, 2, 4, 6, 6, 5, 5, 9, - 2, 4, 6, 7, 7, 5, 10, 4, 5, 7, 8, 8, 5, 9, 7, 6, 8, 9, 9, - 9, 3, 7, 10, 11, 12, 12, 13, 8, 7, 11, 12, 13, 12, 12, 12, 8, 12, 12, - 12, 12, 11, 14, 7, 11, 13, 13, 13, 10, 14, 10, 12, 14, 14, 14, 13, 11, 12, - 14, 15, 16, 16, 15, 9, 15, 16, 17, 17, 17, 17, 14, 17, 19, 19, 20, 19, 13, - 17, 18, 19, 20, 20, 19, 12, 17, 19, 20, 21, 20, 19, 15, 17, 21, 21, 21, 22, - 20, 15, 16, 22, 24, 24, 23, 22, 17, 15, 23, 26, 26, 24, 22, 18, 16, 24, 28, - 27, 26, 24, 20, 26, 29, 28, 28, 25, 21, 17, 26, 31, 30, 30, 26, 22, 17, 26, - 33, 32, 31, 26, 22, 17, 26, 32, 33, 32, 27, 23, 18, 25, 32, 35, 33, 30, 25, - 20, 26, 33, 38, 36, 30, 26, 21, 26, 33, 38, 39, 33, 27, 23, 36, 41, 38, 32, - 27, 24, 20, 35, 41, 42, 34, 29, 25, 20, 35, 41, 44, 36, 30, 25, 20, 35, 40, - 45, 37, 31, 26, 22, 35, 40, 44, 40, 33, 27, 23, 34, 40, 44, 43, 36, 30, 25, - 35, 40, 45, 45, 37, 31, 25, 4, 6, 9, 11, 10, 9, 6, 4, 6, 8, 10, 10, - 7, 4, 3, 5, 7, 8, 9, 6, 4, 3, 3, 5, 7, 8, 5, 3, 1, 0, 3, - 5, 7, 5, 3, 2, 2, 4, 5, 7, 5, 3, 4, 3, 3, 4, 6, 5, 3, 4, - 5, 7, 9, 8, 7, 6, 3, 4, 6, 8, 7, 5, 4, 3, 4, 5, 6, 5, 3, - 2, 2, 2, 4, 5, 4, 3, 0, 1, 1, 2, 3, 3, 2, 0, 3, 2, 3, 4, - 2, 2, 0, 6, 4, 3, 3, 2, 1, 0, 3, 4, 4, 5, 7, 8, 8, 2, 3, - 5, 6, 6, 6, 6, 2, 3, 5, 4, 4, 4, 5, 3, 2, 3, 3, 3, 3, 3, - 6, 2, 4, 4, 4, 4, 3, 7, 4, 5, 5, 5, 5, 3, 9, 7, 6, 6, 6, - 6, 6, 2, 7, 8, 9, 9, 10, 11, 3, 7, 9, 9, 10, 10, 9, 8, 7, 9, - 9, 10, 9, 8, 11, 7, 10, 10, 9, 10, 7, 10, 9, 11, 11, 12, 11, 10, 8, - 11, 13, 13, 13, 13, 12, 8, 14, 15, 15, 14, 14, 13, 13, 15, 16, 16, 16, 16, - 11, 14, 17, 17, 17, 18, 16, 10, 14, 18, 18, 18, 18, 16, 12, 14, 20, 19, 18, - 18, 17, 13, 14, 21, 21, 20, 20, 18, 14, 15, 22, 24, 23, 21, 19, 15, 16, 23, - 26, 24, 24, 20, 17, 24, 25, 24, 24, 21, 18, 14, 24, 28, 27, 25, 22, 18, 14, - 24, 30, 29, 27, 22, 19, 15, 23, 29, 30, 27, 23, 20, 15, 23, 29, 32, 30, 26, - 22, 17, 24, 30, 36, 33, 28, 23, 18, 25, 30, 35, 35, 29, 25, 20, 32, 37, 34, - 29, 23, 20, 17, 32, 37, 36, 30, 25, 21, 17, 33, 37, 39, 31, 26, 22, 17, 32, - 37, 40, 33, 27, 23, 18, 31, 38, 39, 36, 29, 25, 20, 31, 36, 40, 39, 32, 26, - 20, 32, 36, 41, 40, 34, 28, 23, 10, 12, 14, 17, 18, 16, 13, 10, 11, 13, 17, - 17, 14, 12, 9, 11, 12, 14, 15, 12, 10, 9, 9, 10, 11, 14, 9, 4, 6, 7, - 7, 8, 8, 7, 4, 2, 2, 3, 3, 6, 7, 4, 5, 4, 2, 3, 5, 8, 4, - 9, 11, 12, 15, 15, 14, 12, 9, 10, 12, 14, 14, 12, 11, 8, 10, 11, 12, 12, - 11, 9, 8, 8, 9, 9, 9, 8, 3, 5, 5, 5, 5, 4, 4, 3, 0, 2, 2, - 2, 3, 3, 3, 8, 6, 3, 2, 2, 3, 3, 8, 10, 11, 11, 13, 13, 12, 8, - 9, 11, 11, 12, 12, 11, 7, 8, 10, 10, 10, 10, 9, 7, 7, 7, 7, 8, 7, - 4, 3, 3, 4, 4, 3, 3, 3, 3, 2, 2, 1, 2, 2, 3, 9, 9, 5, 2, - 1, 3, 3, 7, 9, 10, 11, 12, 13, 13, 7, 8, 10, 11, 12, 12, 12, 6, 8, - 9, 10, 10, 10, 10, 4, 7, 7, 7, 7, 7, 5, 2, 3, 4, 4, 4, 4, 5, - 3, 8, 7, 7, 6, 6, 6, 9, 13, 11, 9, 7, 7, 8, 7, 8, 9, 11, 12, - 13, 13, 8, 9, 9, 10, 11, 11, 12, 8, 10, 11, 11, 11, 9, 9, 9, 12, 12, - 11, 12, 11, 6, 8, 13, 13, 14, 14, 13, 8, 9, 15, 16, 15, 15, 15, 10, 13, - 17, 18, 16, 16, 16, 12, 16, 18, 19, 19, 15, 12, 13, 16, 20, 20, 20, 16, 12, - 11, 16, 22, 22, 21, 18, 12, 9, 16, 21, 21, 21, 19, 14, 10, 15, 21, 22, 21, - 18, 16, 12, 16, 20, 22, 21, 19, 16, 13, 17, 21, 23, 22, 20, 17, 15, 24, 28, - 27, 23, 18, 14, 12, 24, 28, 28, 24, 20, 15, 10, 24, 28, 30, 23, 21, 16, 11, - 24, 27, 29, 25, 20, 18, 13, 22, 26, 28, 25, 20, 18, 15, 22, 25, 27, 26, 20, - 18, 16, 22, 24, 27, 28, 22, 19, 16, 9, 11, 12, 13, 13, 13, 12, 9, 10, 12, - 13, 13, 11, 10, 8, 10, 11, 11, 11, 10, 8, 8, 8, 9, 9, 9, 6, 3, 5, - 6, 6, 6, 4, 3, 2, 2, 2, 2, 2, 3, 3, 3, 4, 3, 2, 2, 3, 3, - 3, 8, 10, 11, 12, 13, 13, 12, 8, 9, 10, 12, 12, 11, 10, 7, 9, 10, 10, - 10, 9, 7, 7, 7, 7, 8, 7, 6, 2, 5, 4, 4, 5, 3, 2, 2, 2, 0, - 1, 2, 2, 2, 2, 7, 5, 2, 2, 2, 2, 2, 8, 9, 10, 11, 12, 13, 13, - 7, 8, 10, 11, 11, 11, 11, 7, 8, 9, 9, 9, 9, 8, 7, 7, 6, 6, 7, - 6, 4, 3, 3, 3, 3, 2, 3, 3, 3, 3, 2, 2, 2, 3, 3, 9, 8, 5, - 3, 3, 3, 4, 7, 9, 10, 11, 13, 14, 14, 7, 9, 10, 11, 12, 12, 12, 5, - 9, 10, 10, 10, 10, 9, 6, 8, 7, 7, 8, 7, 7, 4, 6, 7, 7, 7, 7, - 8, 3, 10, 10, 9, 9, 9, 9, 9, 16, 13, 11, 10, 10, 11, 10, 11, 11, 12, - 13, 14, 14, 10, 12, 13, 13, 14, 12, 12, 11, 14, 14, 14, 14, 12, 9, 11, 15, - 15, 15, 15, 13, 9, 10, 17, 16, 16, 17, 15, 11, 12, 18, 20, 18, 18, 16, 12, - 16, 21, 23, 20, 20, 18, 14, 19, 21, 21, 21, 18, 15, 14, 20, 23, 23, 23, 19, - 15, 12, 19, 25, 25, 24, 20, 15, 11, 19, 25, 26, 25, 21, 17, 12, 18, 23, 29, - 27, 23, 18, 14, 19, 25, 31, 30, 25, 20, 15, 21, 27, 32, 32, 27, 22, 17, 29, - 34, 33, 27, 21, 17, 14, 28, 34, 36, 29, 23, 18, 13, 28, 34, 39, 30, 24, 19, - 14, 28, 34, 38, 30, 25, 20, 15, 27, 33, 39, 35, 28, 22, 17, 26, 32, 37, 37, - 29, 24, 18, 27, 33, 36, 37, 32, 26, 20, 9, 11, 12, 13, 13, 13, 12, 9, 10, - 11, 13, 13, 11, 10, 8, 9, 11, 11, 10, 9, 7, 8, 8, 8, 9, 8, 6, 2, - 6, 5, 5, 5, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 3, 1, 2, 2, - 2, 2, 8, 10, 11, 12, 13, 13, 13, 8, 9, 10, 12, 12, 11, 10, 8, 8, 10, - 10, 9, 9, 7, 8, 7, 7, 7, 7, 5, 3, 5, 4, 4, 4, 2, 2, 2, 2, - 1, 0, 2, 2, 2, 2, 6, 4, 2, 1, 2, 2, 3, 8, 9, 10, 11, 13, 14, - 15, 8, 8, 10, 12, 12, 12, 12, 7, 8, 10, 10, 10, 10, 9, 6, 7, 8, 8, - 8, 6, 5, 4, 3, 5, 5, 4, 4, 5, 5, 3, 5, 4, 4, 4, 5, 7, 6, - 7, 6, 5, 5, 5, 8, 11, 12, 13, 14, 16, 15, 6, 10, 12, 13, 14, 14, 13, - 6, 10, 12, 11, 11, 11, 10, 9, 9, 9, 9, 9, 9, 9, 7, 7, 9, 10, 10, - 10, 11, 5, 12, 12, 12, 12, 12, 12, 7, 15, 15, 14, 13, 13, 13, 11, 14, 15, - 15, 16, 16, 16, 13, 15, 16, 16, 16, 15, 13, 12, 16, 17, 17, 17, 15, 12, 13, - 18, 18, 18, 18, 17, 13, 12, 19, 19, 19, 19, 18, 13, 13, 22, 23, 22, 20, 19, - 15, 17, 22, 26, 24, 22, 21, 16, 22, 24, 25, 24, 22, 18, 16, 22, 26, 26, 27, - 23, 18, 13, 22, 29, 28, 27, 23, 18, 14, 22, 27, 28, 28, 24, 19, 15, 22, 28, - 31, 31, 26, 21, 16, 22, 28, 34, 32, 27, 22, 18, 24, 29, 35, 36, 30, 24, 20, - 32, 38, 37, 29, 24, 21, 16, 31, 38, 38, 32, 26, 21, 16, 31, 37, 41, 32, 27, - 21, 17, 31, 37, 42, 34, 28, 23, 18, 30, 35, 42, 38, 30, 24, 19, 29, 35, 41, - 40, 33, 26, 21, 30, 36, 40, 41, 34, 28, 22, 8, 9, 11, 12, 13, 12, 11, 8, - 9, 11, 12, 12, 11, 9, 7, 8, 10, 10, 10, 8, 6, 7, 7, 7, 8, 8, 5, - 2, 5, 4, 4, 5, 3, 2, 2, 2, 2, 1, 2, 2, 2, 2, 3, 2, 1, 1, - 2, 2, 2, 8, 8, 10, 12, 12, 12, 13, 7, 8, 9, 11, 12, 10, 10, 7, 8, - 9, 10, 9, 8, 8, 6, 6, 6, 7, 6, 5, 4, 4, 3, 3, 3, 2, 2, 4, - 2, 2, 2, 0, 1, 2, 4, 5, 3, 2, 1, 2, 3, 4, 7, 8, 10, 11, 13, - 14, 15, 6, 7, 10, 12, 12, 13, 12, 6, 7, 10, 10, 10, 10, 10, 5, 6, 7, - 8, 8, 7, 6, 6, 2, 4, 5, 5, 6, 6, 7, 2, 5, 6, 6, 7, 6, 6, - 5, 6, 8, 7, 8, 8, 6, 10, 12, 13, 14, 16, 15, 5, 10, 12, 13, 14, 14, - 13, 8, 10, 12, 12, 12, 12, 11, 11, 8, 11, 11, 11, 12, 11, 10, 8, 12, 12, - 12, 13, 13, 8, 11, 14, 14, 14, 14, 14, 6, 14, 15, 16, 15, 15, 16, 13, 16, - 17, 18, 19, 18, 15, 15, 18, 19, 19, 19, 18, 13, 15, 18, 20, 19, 20, 18, 14, - 14, 20, 21, 20, 21, 20, 15, 14, 21, 22, 22, 22, 20, 16, 14, 23, 25, 24, 24, - 22, 17, 16, 23, 27, 26, 25, 23, 19, 25, 27, 27, 27, 24, 21, 17, 25, 31, 29, - 30, 25, 20, 16, 25, 31, 31, 30, 26, 21, 16, 25, 31, 32, 31, 27, 22, 18, 23, - 31, 34, 33, 29, 24, 18, 24, 31, 36, 34, 31, 25, 20, 26, 32, 37, 38, 33, 27, - 22, 35, 40, 40, 33, 27, 23, 19, 35, 41, 42, 34, 29, 24, 19, 35, 40, 44, 36, - 30, 25, 19, 35, 41, 45, 37, 31, 26, 20, 33, 39, 44, 40, 33, 27, 23, 33, 39, - 45, 42, 35, 30, 23, 33, 39, 44, 44, 38, 30, 25, 6, 8, 11, 14, 14, 12, 9, - 6, 7, 10, 13, 13, 11, 7, 5, 6, 9, 11, 12, 9, 5, 5, 5, 6, 8, 10, - 7, 2, 2, 2, 2, 5, 7, 5, 2, 2, 1, 1, 2, 5, 5, 2, 3, 2, 2, - 2, 4, 5, 2, 5, 6, 8, 11, 11, 10, 10, 5, 6, 7, 10, 11, 8, 8, 4, - 5, 6, 8, 8, 6, 6, 4, 4, 4, 5, 5, 3, 2, 2, 1, 1, 2, 2, 1, - 2, 3, 2, 2, 1, 0, 1, 2, 6, 3, 2, 2, 1, 1, 2, 5, 6, 8, 9, - 10, 11, 12, 4, 5, 8, 9, 10, 10, 9, 3, 5, 8, 8, 8, 8, 7, 5, 3, - 5, 5, 5, 5, 5, 8, 2, 4, 5, 6, 6, 5, 9, 3, 5, 7, 7, 7, 5, - 8, 6, 6, 8, 8, 8, 8, 3, 8, 10, 10, 11, 13, 14, 6, 8, 10, 11, 12, - 12, 13, 10, 8, 11, 12, 12, 12, 11, 12, 7, 11, 12, 11, 12, 10, 12, 8, 12, - 13, 13, 13, 13, 9, 11, 13, 14, 14, 14, 15, 8, 14, 16, 16, 15, 15, 16, 13, - 16, 17, 18, 20, 18, 14, 15, 17, 19, 19, 20, 19, 12, 15, 19, 20, 20, 20, 19, - 14, 15, 20, 20, 21, 21, 19, 14, 14, 21, 22, 22, 22, 20, 16, 14, 23, 25, 24, - 23, 22, 17, 16, 24, 28, 26, 27, 24, 19, 26, 29, 27, 28, 24, 21, 16, 25, 30, - 29, 29, 26, 21, 17, 25, 33, 33, 31, 26, 22, 17, 25, 32, 33, 31, 27, 23, 17, - 25, 31, 35, 33, 28, 24, 18, 25, 32, 36, 36, 30, 24, 20, 26, 32, 38, 39, 33, - 27, 22, 35, 41, 39, 33, 28, 23, 19, 36, 41, 42, 35, 29, 24, 19, 36, 40, 45, - 36, 30, 24, 20, 35, 40, 45, 37, 31, 25, 21, 34, 40, 44, 40, 33, 27, 22, 34, - 39, 43, 43, 35, 29, 23, 35, 39, 44, 44, 38, 31, 25, 4, 6, 10, 12, 13, 11, - 8, 4, 5, 9, 12, 12, 9, 6, 4, 5, 7, 10, 10, 8, 4, 3, 3, 4, 7, - 9, 6, 2, 1, 1, 1, 4, 6, 4, 2, 2, 2, 2, 3, 5, 4, 2, 4, 3, - 2, 2, 4, 5, 2, 4, 5, 7, 10, 10, 8, 8, 4, 5, 6, 9, 9, 6, 6, - 3, 4, 5, 7, 7, 4, 4, 3, 2, 2, 4, 4, 2, 2, 2, 2, 1, 2, 1, - 1, 2, 3, 2, 2, 2, 1, 0, 2, 6, 4, 2, 2, 2, 1, 2, 3, 4, 6, - 7, 8, 10, 10, 3, 4, 6, 7, 8, 8, 8, 2, 3, 6, 6, 6, 6, 7, 6, - 2, 4, 5, 5, 5, 5, 8, 2, 4, 6, 6, 6, 5, 9, 4, 5, 7, 7, 7, - 5, 8, 7, 6, 8, 8, 8, 8, 2, 7, 10, 10, 11, 12, 13, 7, 7, 11, 11, - 12, 12, 12, 11, 7, 11, 12, 11, 12, 10, 12, 7, 11, 12, 12, 12, 10, 12, 9, - 13, 13, 13, 13, 13, 9, 11, 14, 14, 15, 15, 14, 9, 14, 16, 17, 16, 16, 16, - 13, 16, 18, 18, 18, 18, 13, 15, 17, 19, 20, 20, 18, 12, 15, 19, 20, 20, 20, - 18, 14, 15, 20, 21, 21, 20, 19, 15, 15, 22, 23, 22, 23, 21, 16, 15, 23, 27, - 24, 24, 21, 18, 16, 24, 28, 27, 25, 23, 19, 25, 28, 27, 27, 25, 20, 16, 26, - 30, 29, 29, 25, 21, 16, 25, 32, 32, 31, 26, 21, 17, 26, 32, 33, 31, 26, 22, - 18, 24, 31, 35, 33, 29, 23, 19, 25, 32, 37, 35, 30, 25, 21, 25, 32, 37, 38, - 32, 27, 22, 35, 40, 39, 32, 27, 23, 19, 36, 40, 41, 34, 27, 24, 19, 35, 39, - 43, 35, 30, 24, 19, 36, 39, 44, 36, 31, 26, 21, 34, 39, 44, 38, 32, 27, 23, - 34, 39, 43, 42, 35, 29, 24, 34, 40, 43, 44, 37, 30, 25, 4, 6, 8, 11, 11, - 9, 6, 4, 6, 8, 10, 10, 7, 4, 3, 5, 7, 8, 9, 6, 4, 3, 3, 5, - 7, 8, 5, 3, 1, 0, 3, 5, 7, 5, 3, 2, 2, 4, 4, 7, 5, 3, 4, - 3, 3, 4, 6, 5, 3, 4, 5, 7, 9, 8, 6, 6, 3, 4, 6, 8, 7, 5, - 4, 3, 4, 5, 7, 5, 4, 2, 2, 2, 4, 5, 4, 3, 0, 1, 1, 2, 4, - 3, 2, 0, 3, 2, 3, 4, 2, 2, 0, 7, 4, 3, 3, 3, 1, 0, 3, 4, - 5, 5, 7, 8, 8, 2, 3, 5, 6, 6, 6, 6, 2, 3, 5, 4, 4, 4, 5, - 3, 2, 3, 3, 2, 3, 3, 6, 2, 4, 4, 4, 4, 3, 7, 4, 5, 5, 5, - 5, 3, 8, 7, 6, 6, 6, 6, 6, 2, 7, 8, 8, 9, 10, 11, 3, 7, 9, - 9, 10, 10, 10, 9, 7, 10, 9, 10, 10, 8, 11, 7, 10, 10, 9, 10, 7, 10, - 9, 11, 11, 12, 11, 11, 7, 11, 13, 12, 13, 13, 12, 8, 14, 15, 14, 14, 14, - 14, 12, 16, 16, 16, 17, 16, 11, 14, 16, 17, 17, 18, 16, 10, 15, 18, 18, 18, - 17, 16, 12, 14, 20, 19, 19, 19, 17, 12, 14, 21, 21, 21, 20, 18, 14, 15, 22, - 24, 22, 21, 19, 15, 16, 23, 26, 25, 23, 21, 17, 24, 26, 24, 25, 21, 18, 14, - 24, 28, 26, 25, 22, 18, 14, 24, 30, 29, 27, 23, 19, 14, 24, 29, 30, 28, 25, - 19, 15, 23, 29, 32, 30, 25, 21, 17, 24, 30, 35, 32, 27, 23, 18, 25, 30, 35, - 35, 30, 25, 20, 32, 37, 35, 28, 24, 21, 16, 32, 37, 38, 31, 25, 20, 17, 33, - 37, 39, 32, 27, 22, 17, 32, 37, 40, 33, 27, 22, 18, 31, 36, 41, 37, 30, 24, - 20, 31, 35, 40, 40, 32, 26, 21, 32, 37, 40, 41, 34, 28, 23, 17, 19, 20, 23, - 22, 21, 20, 17, 19, 20, 22, 22, 20, 18, 16, 18, 19, 19, 20, 17, 14, 16, 16, - 16, 17, 17, 12, 7, 13, 13, 13, 12, 10, 10, 7, 9, 9, 7, 6, 8, 9, 7, - 3, 3, 4, 6, 7, 9, 7, 16, 18, 19, 21, 21, 21, 20, 15, 18, 19, 20, 20, - 19, 17, 15, 17, 18, 19, 18, 17, 14, 14, 15, 15, 16, 14, 11, 7, 12, 12, 12, - 11, 7, 7, 7, 8, 7, 6, 5, 6, 6, 6, 0, 2, 4, 4, 5, 6, 6, 15, - 17, 18, 19, 21, 21, 20, 14, 16, 17, 19, 19, 19, 17, 15, 16, 17, 17, 17, 16, - 13, 15, 14, 14, 14, 13, 11, 6, 10, 10, 10, 9, 5, 6, 6, 3, 5, 5, 4, - 5, 6, 6, 2, 2, 2, 4, 5, 5, 6, 15, 16, 17, 18, 20, 21, 21, 14, 16, - 18, 19, 19, 19, 19, 12, 16, 17, 17, 17, 16, 15, 9, 15, 14, 14, 13, 10, 10, - 6, 11, 10, 9, 5, 5, 7, 4, 4, 4, 4, 4, 5, 6, 2, 7, 5, 5, 5, - 5, 6, 14, 15, 17, 19, 19, 21, 21, 12, 15, 16, 18, 19, 18, 19, 11, 14, 15, - 15, 16, 15, 14, 12, 12, 12, 12, 11, 10, 6, 9, 10, 10, 10, 11, 11, 6, 6, - 11, 13, 12, 12, 12, 7, 7, 12, 14, 13, 13, 12, 9, 13, 15, 16, 17, 17, 19, - 21, 13, 17, 17, 18, 16, 17, 18, 13, 19, 18, 18, 14, 14, 13, 13, 18, 19, 18, - 16, 11, 8, 12, 17, 19, 18, 15, 12, 9, 12, 16, 19, 17, 15, 13, 11, 13, 15, - 18, 18, 16, 14, 12, 21, 25, 24, 21, 16, 18, 19, 21, 25, 25, 21, 17, 16, 16, - 21, 24, 26, 22, 18, 13, 12, 21, 23, 25, 21, 18, 14, 11, 19, 21, 24, 20, 16, - 14, 12, 18, 21, 22, 21, 16, 15, 13, 17, 19, 22, 22, 18, 15, 13, 15, 16, 17, - 19, 18, 18, 17, 14, 16, 17, 18, 18, 17, 15, 13, 15, 16, 16, 16, 14, 11, 13, - 14, 14, 13, 12, 9, 5, 11, 11, 10, 9, 6, 5, 4, 7, 7, 5, 4, 5, 5, - 5, 2, 2, 2, 3, 5, 5, 4, 14, 15, 16, 18, 18, 18, 17, 14, 15, 16, 17, - 18, 16, 14, 13, 14, 15, 16, 15, 13, 10, 13, 12, 13, 12, 11, 9, 4, 10, 9, - 9, 8, 4, 4, 4, 6, 5, 4, 3, 3, 4, 4, 2, 0, 2, 2, 3, 4, 4, - 13, 14, 15, 16, 18, 18, 18, 13, 13, 15, 16, 16, 16, 15, 13, 13, 14, 14, 14, - 13, 11, 12, 12, 11, 11, 10, 8, 5, 8, 8, 8, 8, 3, 4, 4, 3, 4, 4, - 3, 3, 4, 4, 2, 2, 1, 2, 3, 4, 5, 13, 15, 15, 17, 19, 19, 19, 12, - 15, 16, 17, 17, 18, 16, 10, 15, 15, 15, 15, 14, 13, 7, 14, 13, 13, 12, 9, - 9, 5, 10, 9, 8, 6, 6, 7, 3, 6, 6, 7, 7, 7, 8, 2, 9, 9, 8, - 8, 9, 9, 13, 14, 15, 17, 18, 19, 20, 11, 14, 15, 16, 17, 17, 17, 12, 13, - 14, 14, 15, 14, 12, 11, 13, 12, 12, 13, 12, 8, 9, 13, 14, 14, 14, 14, 9, - 8, 15, 16, 17, 16, 15, 11, 10, 16, 19, 19, 19, 17, 12, 16, 19, 19, 20, 17, - 18, 19, 16, 21, 21, 21, 18, 16, 16, 16, 23, 23, 22, 18, 14, 12, 17, 22, 24, - 23, 19, 15, 11, 15, 22, 25, 25, 22, 17, 12, 16, 22, 28, 28, 24, 19, 14, 17, - 23, 28, 29, 25, 21, 16, 26, 32, 31, 24, 20, 17, 18, 25, 31, 33, 26, 21, 16, - 15, 26, 31, 35, 27, 22, 17, 12, 25, 31, 36, 29, 23, 18, 14, 24, 30, 35, 32, - 25, 21, 15, 24, 31, 35, 33, 28, 23, 17, 24, 31, 35, 33, 29, 24, 19, 11, 12, - 14, 15, 15, 15, 14, 10, 12, 13, 15, 14, 13, 11, 10, 11, 13, 13, 12, 10, 8, - 10, 10, 10, 10, 9, 6, 3, 7, 7, 7, 6, 4, 3, 2, 4, 3, 3, 2, 3, - 3, 2, 2, 1, 1, 2, 3, 3, 2, 10, 11, 13, 14, 15, 14, 14, 10, 11, 12, - 13, 14, 12, 12, 10, 10, 11, 12, 11, 10, 8, 10, 9, 9, 9, 8, 6, 3, 7, - 6, 6, 6, 3, 2, 3, 3, 2, 2, 2, 2, 2, 3, 4, 2, 0, 2, 2, 2, - 3, 10, 10, 11, 13, 14, 16, 16, 10, 10, 12, 13, 13, 14, 14, 10, 10, 11, 12, - 11, 11, 10, 9, 8, 9, 9, 9, 6, 5, 4, 5, 6, 6, 4, 3, 5, 3, 2, - 3, 3, 3, 4, 5, 4, 3, 4, 4, 4, 5, 5, 10, 13, 13, 14, 16, 17, 17, - 8, 12, 13, 14, 15, 15, 14, 6, 12, 13, 13, 13, 12, 11, 8, 11, 10, 10, 10, - 9, 9, 6, 7, 8, 9, 9, 10, 9, 4, 9, 10, 10, 11, 11, 11, 4, 12, 12, - 12, 12, 12, 12, 11, 13, 14, 15, 16, 17, 17, 11, 14, 15, 15, 16, 15, 14, 11, - 15, 16, 16, 16, 14, 11, 11, 17, 17, 16, 17, 15, 11, 11, 18, 17, 18, 18, 17, - 12, 12, 19, 21, 20, 20, 18, 14, 14, 20, 23, 21, 22, 20, 16, 21, 23, 23, 23, - 20, 17, 17, 21, 25, 25, 25, 21, 17, 14, 21, 28, 27, 26, 22, 17, 13, 21, 25, - 29, 27, 22, 19, 14, 20, 27, 31, 29, 25, 20, 15, 20, 26, 33, 32, 26, 21, 17, - 22, 27, 32, 34, 29, 24, 18, 30, 35, 35, 28, 23, 19, 16, 30, 36, 38, 31, 24, - 19, 15, 30, 36, 39, 32, 26, 20, 15, 30, 35, 40, 32, 27, 22, 17, 28, 35, 40, - 35, 29, 23, 19, 28, 35, 40, 38, 30, 26, 20, 29, 35, 40, 41, 33, 28, 21, 9, - 10, 12, 13, 13, 13, 12, 8, 9, 11, 13, 13, 11, 9, 8, 9, 11, 11, 11, 9, - 7, 8, 7, 8, 9, 8, 5, 2, 5, 5, 5, 5, 4, 2, 2, 2, 2, 1, 2, - 3, 2, 2, 3, 2, 1, 2, 2, 2, 2, 8, 9, 11, 12, 13, 12, 13, 8, 9, - 10, 12, 12, 10, 10, 7, 8, 9, 10, 10, 8, 8, 7, 7, 7, 8, 7, 5, 4, - 5, 4, 3, 4, 3, 2, 3, 2, 2, 1, 1, 2, 2, 3, 4, 2, 2, 0, 1, - 2, 3, 8, 8, 10, 11, 13, 14, 14, 7, 8, 10, 12, 12, 12, 12, 7, 7, 10, - 10, 10, 10, 9, 5, 6, 8, 8, 8, 6, 6, 5, 3, 5, 5, 5, 5, 6, 6, - 2, 5, 5, 5, 6, 6, 5, 4, 5, 7, 7, 7, 7, 7, 11, 12, 13, 14, 16, - 15, 5, 10, 12, 14, 13, 13, 13, 7, 10, 11, 11, 12, 12, 11, 10, 9, 10, 11, - 11, 11, 10, 9, 8, 11, 11, 12, 12, 12, 7, 10, 13, 13, 13, 13, 14, 5, 13, - 14, 15, 14, 14, 15, 12, 15, 16, 17, 18, 17, 15, 14, 16, 18, 18, 19, 17, 13, - 14, 17, 19, 19, 18, 17, 13, 14, 20, 19, 19, 20, 18, 14, 13, 21, 21, 20, 20, - 19, 15, 14, 22, 23, 23, 22, 21, 17, 16, 22, 26, 25, 25, 23, 18, 24, 27, 26, - 26, 23, 19, 16, 24, 29, 28, 28, 24, 21, 15, 24, 31, 31, 29, 26, 20, 16, 24, - 30, 31, 30, 27, 21, 17, 23, 30, 33, 31, 27, 22, 18, 23, 30, 35, 34, 29, 24, - 19, 25, 30, 35, 36, 32, 27, 21, 33, 40, 39, 32, 26, 22, 18, 34, 40, 42, 34, - 28, 23, 18, 33, 40, 43, 35, 29, 23, 18, 34, 40, 44, 36, 30, 25, 19, 32, 38, - 44, 39, 32, 26, 21, 33, 38, 43, 42, 34, 28, 23, 32, 39, 42, 43, 36, 30, 24, - 7, 9, 13, 15, 15, 14, 10, 6, 8, 11, 15, 15, 12, 9, 6, 7, 10, 12, 13, - 10, 7, 6, 5, 7, 10, 11, 8, 4, 3, 3, 4, 6, 8, 6, 3, 1, 1, 2, - 3, 6, 6, 3, 3, 2, 2, 2, 5, 6, 3, 6, 7, 10, 13, 13, 10, 10, 6, - 7, 9, 12, 12, 9, 8, 5, 6, 8, 10, 10, 7, 6, 5, 5, 5, 7, 6, 5, - 3, 2, 2, 2, 3, 3, 3, 2, 2, 2, 2, 2, 1, 2, 3, 5, 3, 2, 1, - 0, 1, 2, 5, 6, 8, 9, 11, 12, 12, 5, 6, 8, 9, 10, 10, 10, 4, 5, - 8, 8, 8, 8, 8, 4, 4, 5, 6, 6, 5, 5, 6, 2, 3, 4, 4, 4, 4, - 8, 3, 4, 5, 5, 5, 5, 7, 5, 5, 7, 7, 7, 7, 5, 8, 10, 10, 12, - 13, 13, 4, 8, 10, 11, 11, 11, 11, 7, 8, 10, 10, 10, 10, 10, 10, 7, 10, - 11, 11, 11, 9, 10, 8, 11, 11, 12, 11, 12, 8, 10, 13, 13, 13, 13, 13, 7, - 13, 15, 15, 15, 14, 15, 12, 16, 16, 17, 18, 17, 14, 14, 16, 18, 18, 19, 17, - 12, 14, 18, 19, 19, 18, 17, 13, 14, 19, 19, 19, 19, 18, 13, 13, 21, 21, 21, - 21, 19, 15, 13, 22, 23, 23, 22, 20, 16, 15, 23, 26, 25, 24, 22, 18, 24, 27, - 26, 26, 23, 19, 15, 24, 30, 28, 28, 25, 20, 15, 24, 31, 30, 29, 24, 20, 16, - 25, 31, 31, 30, 25, 21, 16, 24, 30, 34, 32, 27, 23, 17, 24, 30, 36, 35, 28, - 23, 20, 24, 31, 35, 36, 31, 26, 20, 34, 39, 39, 32, 26, 21, 18, 34, 40, 39, - 33, 28, 23, 18, 34, 41, 43, 35, 28, 23, 18, 33, 39, 44, 35, 30, 24, 19, 32, - 39, 42, 39, 31, 26, 20, 32, 39, 43, 41, 34, 28, 23, 32, 38, 42, 43, 36, 30, - 24, 5, 8, 11, 15, 15, 13, 9, 5, 7, 10, 14, 14, 11, 7, 4, 5, 9, 11, - 13, 9, 6, 4, 4, 6, 8, 11, 7, 3, 1, 1, 2, 5, 8, 6, 3, 2, 2, - 2, 3, 6, 6, 3, 4, 3, 2, 3, 5, 6, 3, 4, 5, 9, 12, 12, 9, 9, - 4, 5, 8, 11, 11, 8, 7, 3, 5, 6, 8, 8, 6, 4, 3, 3, 3, 6, 5, - 4, 1, 2, 1, 1, 2, 2, 2, 1, 3, 2, 2, 3, 1, 1, 1, 7, 4, 2, - 2, 1, 0, 1, 4, 5, 6, 7, 9, 10, 10, 3, 4, 7, 7, 8, 8, 8, 3, - 4, 6, 6, 6, 6, 6, 4, 2, 4, 4, 4, 4, 4, 7, 2, 4, 5, 5, 4, - 4, 8, 3, 5, 6, 6, 6, 4, 8, 6, 6, 7, 7, 7, 7, 3, 7, 9, 9, - 10, 11, 12, 5, 7, 10, 10, 11, 11, 11, 8, 7, 10, 10, 10, 11, 10, 11, 7, - 10, 11, 11, 11, 8, 10, 9, 11, 12, 12, 12, 12, 8, 11, 13, 13, 14, 13, 13, - 8, 14, 15, 15, 14, 14, 15, 13, 16, 16, 17, 18, 17, 12, 15, 16, 17, 18, 19, - 17, 11, 15, 18, 19, 19, 19, 18, 13, 15, 20, 20, 20, 20, 18, 13, 14, 21, 21, - 21, 21, 19, 15, 14, 22, 25, 23, 22, 21, 16, 16, 24, 27, 25, 25, 23, 18, 24, - 28, 27, 26, 23, 19, 15, 24, 29, 28, 27, 24, 19, 15, 24, 32, 31, 29, 25, 20, - 16, 24, 31, 31, 29, 26, 21, 16, 23, 29, 33, 31, 27, 22, 18, 24, 30, 37, 34, - 28, 24, 19, 25, 30, 37, 36, 31, 26, 21, 34, 39, 37, 31, 26, 22, 18, 35, 40, - 39, 33, 27, 22, 18, 34, 39, 42, 34, 29, 24, 18, 34, 37, 42, 34, 29, 24, 19, - 33, 38, 42, 37, 31, 26, 21, 34, 38, 41, 41, 34, 27, 23, 33, 38, 42, 42, 35, - 28, 24, 4, 6, 8, 11, 11, 9, 6, 4, 6, 8, 10, 10, 7, 4, 3, 5, 7, - 8, 9, 6, 4, 3, 3, 5, 6, 8, 5, 3, 1, 0, 3, 5, 8, 5, 3, 2, - 2, 4, 5, 7, 5, 3, 4, 3, 3, 4, 6, 5, 3, 4, 5, 7, 9, 8, 7, - 6, 3, 4, 6, 8, 7, 5, 4, 3, 4, 5, 7, 5, 4, 2, 2, 2, 3, 5, - 4, 3, 0, 1, 1, 2, 4, 3, 2, 0, 3, 2, 3, 4, 2, 2, 0, 7, 4, - 3, 3, 3, 1, 0, 3, 4, 5, 5, 7, 8, 8, 2, 3, 5, 6, 6, 6, 6, - 2, 3, 5, 4, 4, 4, 5, 3, 2, 3, 3, 3, 3, 3, 5, 2, 4, 4, 4, - 4, 3, 7, 4, 5, 5, 5, 5, 3, 8, 7, 6, 6, 6, 6, 6, 2, 7, 8, - 9, 9, 10, 11, 3, 7, 9, 9, 10, 10, 9, 9, 7, 10, 9, 9, 10, 8, 11, - 7, 10, 10, 10, 10, 7, 9, 9, 11, 11, 11, 11, 11, 8, 11, 13, 13, 13, 13, - 12, 8, 14, 15, 14, 14, 14, 13, 12, 15, 16, 16, 16, 16, 11, 14, 17, 17, 17, - 18, 16, 10, 14, 17, 18, 18, 18, 16, 12, 14, 19, 18, 19, 18, 17, 12, 14, 21, - 21, 20, 19, 19, 14, 15, 22, 24, 23, 21, 19, 16, 16, 22, 26, 24, 23, 21, 17, - 24, 26, 24, 24, 21, 18, 14, 24, 28, 27, 26, 23, 18, 14, 24, 30, 28, 27, 23, - 19, 15, 24, 29, 31, 27, 24, 20, 16, 23, 28, 32, 30, 25, 21, 17, 24, 30, 34, - 33, 28, 23, 19, 24, 30, 35, 34, 30, 24, 20, 32, 37, 35, 28, 24, 20, 17, 33, - 37, 36, 30, 25, 21, 16, 33, 37, 39, 31, 26, 22, 17, 32, 37, 40, 33, 27, 23, - 19, 31, 36, 39, 36, 30, 23, 20, 31, 36, 40, 38, 32, 26, 21, 33, 36, 41, 40, - 34, 28, 22, 2, 3, 4, 8, 8, 6, 2, 2, 2, 3, 7, 8, 4, 2, 2, 2, - 2, 4, 5, 2, 2, 1, 2, 2, 2, 3, 2, 3, 2, 3, 3, 3, 4, 3, 3, - 6, 6, 6, 6, 4, 3, 3, 12, 11, 8, 6, 5, 3, 3, 2, 2, 3, 5, 5, - 2, 2, 1, 2, 3, 3, 4, 2, 1, 0, 2, 2, 2, 2, 2, 1, 1, 1, 2, - 2, 1, 1, 3, 4, 3, 4, 4, 4, 3, 3, 8, 8, 8, 7, 5, 3, 3, 15, - 13, 10, 7, 5, 4, 3, 0, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, - 1, 2, 1, 1, 1, 1, 1, 2, 2, 1, 2, 1, 2, 2, 4, 6, 5, 5, 5, - 5, 4, 4, 11, 10, 9, 8, 6, 5, 4, 18, 16, 12, 9, 7, 6, 5, 2, 2, - 2, 3, 3, 3, 7, 2, 3, 4, 4, 4, 4, 7, 4, 4, 5, 5, 5, 5, 7, - 7, 7, 7, 7, 8, 8, 8, 8, 12, 11, 11, 12, 11, 10, 12, 17, 16, 15, 14, - 13, 12, 18, 23, 20, 17, 15, 14, 13, 10, 10, 10, 10, 11, 10, 7, 12, 12, 12, - 11, 12, 11, 7, 12, 13, 13, 14, 13, 12, 8, 12, 17, 16, 16, 17, 15, 12, 15, - 21, 21, 20, 20, 19, 14, 19, 24, 25, 25, 23, 20, 15, 22, 27, 30, 27, 25, 22, - 17, 19, 21, 20, 20, 17, 13, 8, 19, 22, 22, 22, 18, 14, 10, 19, 24, 24, 24, - 19, 15, 11, 19, 25, 27, 27, 23, 19, 15, 22, 28, 32, 31, 28, 23, 17, 24, 30, - 36, 35, 30, 25, 18, 27, 34, 37, 37, 32, 26, 20, 27, 32, 32, 25, 20, 16, 11, - 27, 33, 34, 28, 22, 17, 13, 26, 34, 36, 29, 24, 19, 15, 28, 34, 38, 32, 27, - 23, 19, 29, 35, 40, 36, 32, 27, 21, 31, 37, 40, 40, 33, 27, 23, 33, 38, 42, - 42, 36, 30, 25, 1, 2, 3, 3, 3, 2, 2, 1, 2, 2, 3, 3, 2, 1, 1, - 2, 2, 2, 2, 2, 1, 2, 1, 2, 2, 2, 2, 4, 4, 3, 4, 4, 4, 4, - 4, 8, 7, 7, 7, 5, 4, 4, 13, 12, 9, 7, 6, 4, 4, 1, 2, 2, 3, - 2, 2, 1, 2, 1, 2, 2, 2, 1, 1, 2, 0, 2, 2, 2, 1, 1, 2, 2, - 2, 2, 2, 2, 4, 5, 5, 5, 5, 5, 4, 4, 10, 9, 9, 8, 6, 4, 4, - 17, 14, 11, 8, 6, 5, 4, 2, 0, 1, 2, 2, 1, 5, 2, 1, 1, 1, 1, - 1, 5, 2, 2, 1, 1, 1, 1, 6, 4, 2, 4, 4, 4, 4, 7, 8, 6, 7, - 7, 8, 7, 7, 13, 12, 12, 11, 10, 8, 7, 19, 17, 15, 13, 11, 10, 9, 2, - 5, 5, 6, 6, 6, 9, 5, 6, 6, 7, 7, 7, 9, 8, 7, 7, 8, 8, 8, - 9, 11, 10, 11, 11, 11, 12, 11, 11, 15, 15, 15, 15, 15, 14, 13, 20, 20, 18, - 17, 16, 15, 19, 26, 23, 21, 18, 18, 17, 13, 14, 13, 13, 13, 13, 9, 14, 15, - 14, 15, 15, 14, 9, 14, 17, 16, 17, 16, 15, 12, 15, 21, 20, 20, 20, 19, 16, - 18, 25, 25, 24, 24, 22, 17, 22, 28, 30, 29, 26, 24, 19, 26, 31, 33, 30, 29, - 26, 20, 22, 24, 23, 23, 19, 15, 11, 23, 26, 25, 24, 21, 16, 12, 23, 28, 27, - 26, 23, 19, 15, 23, 29, 31, 30, 27, 22, 19, 25, 32, 36, 34, 31, 26, 21, 29, - 34, 41, 39, 34, 27, 22, 32, 37, 42, 41, 36, 30, 24, 31, 36, 34, 28, 23, 18, - 14, 30, 37, 37, 30, 23, 20, 15, 31, 36, 39, 33, 26, 22, 19, 30, 36, 42, 36, - 31, 27, 23, 32, 39, 45, 41, 35, 29, 24, 34, 40, 47, 45, 39, 31, 26, 38, 43, - 47, 46, 41, 34, 28, 1, 3, 4, 5, 5, 4, 3, 1, 2, 4, 5, 5, 4, 3, - 2, 1, 4, 4, 5, 5, 5, 2, 2, 4, 5, 6, 6, 6, 4, 4, 6, 7, 8, - 7, 6, 8, 8, 9, 10, 8, 7, 6, 14, 13, 10, 10, 9, 7, 6, 2, 1, 3, - 4, 4, 3, 1, 2, 1, 3, 4, 4, 3, 1, 2, 2, 2, 4, 4, 3, 3, 2, - 3, 3, 5, 5, 5, 5, 5, 5, 6, 7, 7, 6, 4, 11, 10, 10, 10, 8, 6, - 4, 18, 15, 12, 10, 8, 6, 4, 2, 1, 0, 1, 1, 2, 5, 2, 2, 1, 1, - 1, 2, 4, 3, 2, 2, 2, 3, 3, 6, 7, 3, 6, 6, 6, 6, 8, 10, 7, - 9, 9, 9, 9, 8, 15, 12, 13, 13, 11, 10, 7, 21, 19, 16, 14, 13, 11, 10, - 3, 6, 6, 6, 7, 6, 8, 8, 6, 7, 7, 8, 8, 9, 10, 7, 9, 9, 10, - 10, 10, 12, 10, 13, 13, 13, 13, 11, 13, 15, 17, 17, 17, 16, 14, 15, 22, 22, - 21, 19, 18, 17, 20, 27, 25, 22, 21, 20, 19, 14, 15, 15, 14, 15, 13, 8, 16, - 15, 16, 16, 15, 14, 8, 16, 17, 18, 19, 18, 17, 13, 16, 22, 22, 22, 22, 21, - 17, 19, 27, 27, 26, 26, 24, 18, 23, 31, 33, 31, 29, 25, 21, 28, 34, 35, 32, - 31, 28, 22, 23, 25, 24, 23, 20, 16, 12, 23, 28, 26, 25, 21, 17, 13, 24, 29, - 28, 28, 25, 21, 17, 24, 31, 33, 32, 28, 24, 21, 27, 33, 39, 36, 33, 27, 21, - 31, 37, 42, 41, 36, 29, 24, 33, 40, 45, 44, 38, 31, 26, 32, 38, 36, 29, 24, - 19, 15, 32, 37, 38, 30, 25, 21, 17, 31, 38, 40, 35, 29, 24, 19, 32, 39, 45, - 39, 32, 28, 24, 34, 41, 46, 44, 37, 31, 25, 37, 44, 48, 48, 41, 33, 28, 40, - 45, 49, 50, 43, 36, 30, 1, 3, 6, 8, 8, 6, 3, 1, 2, 5, 7, 8, 6, - 4, 1, 2, 4, 7, 8, 7, 5, 2, 2, 5, 7, 9, 8, 7, 4, 5, 7, 9, - 11, 9, 8, 9, 9, 10, 11, 11, 9, 8, 16, 14, 12, 11, 11, 9, 7, 1, 1, - 4, 6, 5, 3, 1, 2, 1, 3, 5, 5, 2, 2, 2, 1, 2, 5, 5, 4, 3, - 2, 3, 4, 6, 6, 5, 5, 6, 6, 7, 9, 8, 7, 5, 12, 11, 11, 11, 9, - 7, 5, 19, 17, 13, 11, 9, 7, 5, 2, 2, 1, 0, 1, 2, 4, 2, 2, 1, - 1, 1, 2, 4, 5, 2, 3, 3, 3, 3, 6, 8, 3, 6, 7, 7, 7, 7, 11, - 8, 10, 10, 10, 10, 8, 16, 13, 15, 14, 13, 11, 8, 21, 20, 18, 16, 14, 12, - 11, 5, 6, 7, 7, 7, 5, 7, 9, 6, 7, 8, 8, 8, 8, 12, 7, 9, 10, - 11, 11, 10, 14, 10, 14, 15, 14, 14, 12, 15, 15, 18, 18, 18, 18, 15, 16, 23, - 22, 21, 21, 19, 17, 22, 29, 26, 24, 22, 20, 20, 15, 14, 14, 14, 14, 13, 7, - 18, 15, 16, 15, 16, 15, 8, 18, 17, 18, 19, 19, 17, 14, 17, 22, 23, 23, 23, - 22, 18, 20, 28, 28, 27, 27, 25, 20, 23, 32, 34, 32, 28, 26, 22, 28, 35, 37, - 34, 32, 28, 23, 24, 26, 24, 23, 20, 16, 12, 24, 28, 26, 26, 22, 18, 14, 24, - 30, 29, 29, 25, 21, 18, 24, 32, 34, 33, 30, 25, 22, 28, 35, 40, 38, 34, 29, - 23, 32, 37, 45, 42, 36, 30, 25, 36, 42, 45, 45, 39, 33, 27, 32, 38, 35, 29, - 23, 19, 15, 32, 38, 37, 31, 26, 21, 18, 33, 38, 41, 35, 29, 26, 21, 32, 40, - 45, 39, 35, 29, 25, 36, 43, 48, 44, 39, 33, 26, 38, 45, 50, 50, 41, 35, 29, - 41, 47, 51, 51, 44, 37, 30, 1, 3, 6, 8, 8, 6, 3, 2, 2, 5, 7, 8, - 6, 5, 2, 1, 5, 8, 9, 8, 6, 2, 3, 5, 8, 10, 9, 8, 5, 6, 8, - 10, 12, 10, 9, 10, 11, 12, 13, 13, 10, 9, 17, 15, 13, 12, 12, 10, 9, 2, - 1, 4, 6, 5, 2, 2, 2, 1, 3, 5, 5, 3, 2, 2, 2, 2, 6, 5, 4, - 4, 2, 3, 5, 7, 7, 6, 7, 7, 7, 8, 10, 10, 8, 7, 13, 12, 13, 13, - 10, 9, 7, 21, 18, 14, 13, 11, 9, 7, 2, 2, 1, 1, 0, 2, 4, 3, 2, - 1, 1, 2, 3, 5, 7, 2, 3, 4, 5, 4, 6, 10, 3, 7, 8, 8, 8, 8, - 13, 9, 11, 12, 12, 11, 8, 17, 15, 16, 15, 14, 13, 8, 23, 21, 19, 17, 15, - 14, 13, 6, 6, 7, 7, 7, 4, 7, 11, 7, 8, 8, 9, 9, 8, 13, 7, 10, - 11, 12, 12, 11, 16, 10, 15, 16, 16, 16, 13, 16, 17, 19, 20, 20, 19, 16, 18, - 24, 25, 23, 22, 21, 19, 23, 30, 28, 25, 23, 22, 22, 16, 15, 15, 15, 15, 13, - 7, 19, 17, 16, 16, 18, 16, 8, 19, 18, 19, 20, 21, 19, 15, 19, 23, 23, 25, - 25, 24, 20, 20, 28, 30, 29, 29, 26, 21, 24, 33, 35, 33, 31, 29, 23, 30, 37, - 38, 35, 33, 30, 25, 25, 26, 25, 24, 20, 16, 12, 24, 28, 26, 25, 22, 19, 15, - 24, 30, 29, 30, 27, 23, 19, 25, 32, 35, 34, 31, 27, 23, 28, 36, 41, 39, 35, - 30, 25, 33, 40, 46, 43, 38, 32, 27, 37, 42, 47, 46, 40, 34, 28, 32, 38, 35, - 28, 23, 19, 16, 33, 37, 38, 31, 26, 22, 19, 34, 38, 40, 35, 31, 27, 22, 33, - 40, 45, 40, 35, 31, 27, 35, 43, 47, 46, 39, 34, 29, 41, 46, 50, 50, 42, 36, - 30, 43, 48, 50, 53, 45, 38, 32, 3, 5, 7, 8, 8, 6, 5, 2, 4, 6, 8, - 9, 7, 6, 1, 3, 6, 9, 10, 9, 8, 2, 4, 7, 9, 12, 11, 10, 5, 7, - 10, 11, 14, 12, 10, 11, 12, 13, 14, 14, 12, 10, 17, 16, 15, 14, 14, 12, 10, - 1, 4, 5, 7, 5, 3, 2, 2, 2, 5, 6, 6, 4, 3, 2, 2, 5, 7, 7, - 6, 5, 2, 3, 6, 8, 8, 7, 8, 6, 7, 10, 11, 11, 9, 8, 13, 13, 14, - 14, 11, 10, 8, 21, 18, 15, 14, 12, 10, 8, 2, 1, 2, 2, 2, 0, 2, 2, - 2, 1, 1, 2, 1, 4, 4, 2, 1, 3, 3, 3, 5, 9, 3, 5, 6, 6, 7, - 7, 11, 9, 10, 10, 10, 10, 7, 17, 15, 15, 14, 12, 11, 7, 23, 21, 17, 15, - 14, 12, 11, 4, 5, 5, 5, 5, 3, 5, 9, 6, 6, 6, 7, 7, 7, 12, 7, - 8, 9, 10, 11, 9, 15, 10, 13, 14, 14, 14, 11, 15, 15, 18, 18, 18, 17, 15, - 17, 23, 23, 22, 20, 19, 17, 24, 30, 26, 24, 22, 20, 19, 15, 13, 13, 12, 13, - 11, 5, 18, 15, 14, 14, 15, 14, 7, 19, 16, 17, 19, 19, 18, 13, 19, 21, 22, - 23, 23, 21, 18, 19, 27, 28, 27, 27, 24, 19, 23, 31, 34, 31, 29, 25, 21, 29, - 35, 36, 33, 31, 28, 23, 23, 24, 22, 20, 18, 14, 10, 23, 26, 24, 22, 20, 17, - 13, 23, 28, 27, 27, 23, 21, 17, 23, 30, 32, 30, 29, 24, 21, 27, 34, 37, 36, - 32, 28, 23, 31, 38, 43, 42, 35, 30, 25, 35, 40, 44, 43, 37, 31, 26, 31, 33, - 30, 25, 20, 17, 14, 30, 33, 33, 27, 23, 20, 17, 31, 33, 36, 31, 27, 25, 21, - 30, 35, 42, 36, 32, 28, 25, 34, 39, 44, 43, 37, 32, 27, 38, 42, 47, 47, 40, - 33, 28, 41, 46, 49, 48, 42, 36, 30, 6, 7, 9, 10, 10, 8, 6, 5, 6, 8, - 10, 11, 9, 8, 4, 6, 8, 11, 13, 11, 9, 3, 6, 9, 12, 14, 12, 11, 5, - 8, 10, 13, 15, 14, 11, 11, 13, 14, 14, 16, 14, 11, 17, 17, 15, 15, 14, 13, - 11, 4, 6, 7, 9, 7, 5, 3, 3, 5, 7, 8, 7, 6, 5, 1, 5, 7, 9, - 8, 7, 6, 1, 5, 8, 10, 9, 9, 8, 5, 8, 10, 12, 11, 10, 8, 12, 13, - 15, 15, 12, 10, 8, 20, 18, 16, 14, 12, 10, 8, 1, 5, 5, 4, 4, 2, 0, - 2, 3, 5, 4, 3, 3, 2, 2, 2, 4, 5, 4, 5, 4, 4, 3, 6, 6, 6, - 6, 6, 8, 8, 10, 10, 10, 8, 6, 15, 15, 15, 13, 11, 9, 6, 22, 20, 17, - 14, 11, 9, 8, 2, 2, 2, 2, 1, 2, 3, 5, 3, 3, 2, 3, 3, 4, 8, - 5, 4, 6, 6, 6, 6, 11, 7, 9, 10, 10, 10, 8, 12, 14, 14, 14, 14, 13, - 11, 15, 20, 19, 17, 16, 15, 13, 22, 26, 22, 20, 18, 16, 15, 12, 10, 9, 9, - 9, 8, 3, 15, 12, 11, 11, 11, 10, 4, 15, 14, 13, 14, 14, 13, 10, 14, 18, - 18, 18, 19, 17, 14, 17, 25, 23, 23, 23, 20, 15, 22, 28, 30, 27, 24, 21, 17, - 26, 31, 33, 29, 26, 23, 19, 20, 19, 18, 16, 14, 10, 6, 19, 22, 18, 17, 15, - 13, 9, 19, 23, 22, 21, 19, 16, 13, 20, 25, 26, 26, 23, 20, 17, 23, 30, 33, - 30, 28, 23, 19, 27, 33, 38, 35, 29, 25, 20, 32, 35, 40, 38, 32, 27, 22, 24, - 28, 25, 19, 15, 13, 10, 25, 28, 27, 21, 17, 15, 13, 25, 28, 29, 25, 22, 19, - 16, 25, 29, 35, 31, 27, 23, 20, 28, 35, 39, 36, 31, 27, 22, 32, 37, 41, 41, - 34, 28, 23, 36, 40, 42, 43, 37, 30, 26, 2, 3, 8, 12, 12, 10, 7, 2, 3, - 6, 11, 11, 9, 4, 2, 2, 4, 8, 9, 7, 2, 2, 2, 2, 4, 7, 5, 2, - 2, 2, 2, 3, 5, 5, 2, 6, 6, 6, 5, 4, 5, 2, 11, 11, 8, 6, 4, - 5, 2, 2, 2, 5, 8, 9, 6, 2, 1, 2, 3, 7, 9, 4, 2, 2, 2, 2, - 4, 5, 2, 2, 0, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 2, 2, 7, - 7, 8, 6, 4, 3, 2, 15, 13, 10, 7, 5, 3, 2, 1, 2, 2, 2, 3, 2, - 2, 0, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 0, 1, 1, 1, 1, - 1, 1, 2, 5, 4, 4, 4, 4, 3, 2, 11, 9, 9, 7, 5, 3, 2, 17, 16, - 12, 9, 6, 4, 3, 1, 1, 1, 1, 1, 1, 5, 2, 2, 2, 3, 3, 3, 6, - 2, 3, 3, 3, 4, 4, 6, 5, 5, 6, 6, 6, 7, 7, 6, 10, 10, 10, 10, - 9, 9, 11, 15, 14, 14, 12, 11, 10, 17, 21, 18, 16, 14, 13, 12, 9, 9, 9, - 9, 10, 9, 6, 11, 11, 10, 11, 11, 10, 6, 11, 12, 12, 12, 12, 11, 7, 11, - 15, 14, 15, 15, 14, 11, 13, 20, 19, 19, 19, 18, 12, 17, 23, 25, 24, 21, 20, - 14, 21, 26, 27, 24, 24, 21, 16, 18, 20, 19, 19, 16, 12, 7, 18, 21, 21, 21, - 18, 12, 9, 18, 23, 22, 22, 18, 14, 10, 18, 24, 26, 25, 22, 18, 14, 20, 25, - 30, 28, 25, 21, 16, 22, 28, 33, 31, 27, 23, 18, 25, 31, 34, 34, 29, 25, 19, - 26, 31, 29, 24, 19, 15, 10, 26, 31, 31, 26, 21, 16, 11, 26, 31, 33, 27, 23, - 18, 14, 25, 31, 35, 30, 26, 21, 18, 27, 32, 35, 33, 28, 24, 20, 29, 35, 37, - 36, 31, 27, 22, 32, 34, 36, 37, 31, 28, 23, 2, 2, 3, 3, 3, 2, 2, 1, - 2, 3, 3, 3, 2, 2, 1, 2, 2, 3, 3, 2, 1, 1, 1, 2, 2, 2, 2, - 3, 3, 3, 3, 3, 4, 3, 3, 7, 6, 7, 6, 5, 3, 3, 13, 11, 8, 7, - 5, 3, 3, 1, 2, 2, 3, 2, 2, 2, 1, 2, 2, 3, 2, 2, 1, 2, 2, - 2, 2, 2, 2, 1, 2, 1, 2, 2, 1, 2, 3, 4, 4, 4, 4, 4, 3, 3, - 9, 8, 8, 7, 5, 4, 3, 16, 14, 10, 8, 6, 4, 3, 2, 1, 2, 2, 2, - 2, 3, 2, 0, 1, 1, 1, 2, 3, 2, 1, 1, 0, 1, 0, 4, 3, 2, 2, - 2, 3, 3, 6, 7, 6, 6, 6, 6, 5, 6, 12, 11, 10, 9, 8, 7, 6, 18, - 17, 13, 11, 9, 8, 7, 2, 4, 4, 4, 5, 4, 8, 3, 5, 5, 5, 6, 6, - 8, 6, 6, 6, 6, 7, 7, 8, 9, 9, 9, 10, 10, 10, 10, 10, 13, 13, 13, - 13, 13, 12, 12, 19, 18, 16, 16, 15, 14, 18, 25, 22, 19, 18, 16, 15, 12, 12, - 12, 12, 12, 12, 8, 14, 14, 13, 13, 14, 12, 8, 13, 15, 15, 15, 15, 14, 11, - 13, 19, 19, 18, 19, 18, 14, 17, 24, 23, 23, 23, 20, 16, 20, 27, 29, 27, 25, - 22, 17, 25, 30, 31, 29, 28, 25, 19, 21, 23, 22, 21, 18, 14, 10, 21, 25, 23, - 23, 20, 15, 11, 20, 26, 27, 26, 22, 17, 13, 21, 27, 28, 28, 25, 21, 17, 24, - 30, 34, 33, 30, 24, 19, 27, 33, 40, 37, 32, 26, 21, 30, 36, 40, 39, 34, 29, - 22, 29, 36, 33, 27, 20, 17, 13, 29, 35, 35, 28, 23, 18, 14, 29, 35, 38, 31, - 25, 20, 16, 29, 34, 42, 35, 30, 25, 21, 31, 37, 43, 40, 34, 29, 22, 33, 40, - 45, 43, 37, 30, 25, 35, 42, 46, 46, 39, 32, 27, 1, 3, 4, 5, 5, 4, 3, - 1, 3, 4, 5, 5, 4, 3, 1, 2, 4, 4, 5, 4, 4, 1, 2, 4, 5, 5, - 5, 6, 4, 4, 6, 7, 7, 6, 6, 8, 8, 10, 10, 8, 7, 6, 14, 12, 11, - 10, 9, 7, 6, 1, 2, 4, 5, 4, 3, 1, 1, 1, 3, 4, 4, 3, 0, 2, - 1, 3, 4, 3, 4, 3, 2, 2, 3, 5, 5, 5, 5, 5, 5, 6, 8, 7, 6, - 5, 10, 10, 10, 11, 8, 6, 5, 18, 15, 11, 10, 8, 7, 5, 2, 1, 1, 1, - 1, 1, 4, 2, 1, 0, 1, 1, 1, 4, 2, 1, 2, 2, 2, 2, 5, 5, 3, - 5, 5, 5, 5, 7, 9, 7, 8, 8, 8, 8, 7, 14, 12, 13, 11, 10, 9, 7, - 20, 18, 15, 14, 12, 10, 9, 2, 5, 6, 6, 6, 5, 8, 6, 6, 6, 7, 7, - 7, 8, 9, 7, 8, 8, 9, 9, 9, 11, 9, 12, 12, 12, 12, 11, 12, 15, 16, - 16, 16, 16, 14, 14, 21, 20, 19, 18, 17, 16, 20, 27, 24, 21, 20, 18, 17, 13, - 13, 13, 14, 14, 13, 8, 15, 15, 14, 15, 15, 14, 8, 15, 17, 17, 17, 17, 16, - 12, 15, 22, 21, 20, 21, 20, 16, 18, 26, 25, 24, 25, 23, 18, 23, 30, 32, 29, - 28, 24, 20, 26, 33, 35, 31, 30, 26, 21, 23, 25, 23, 23, 19, 15, 11, 23, 27, - 25, 24, 20, 16, 12, 23, 28, 27, 28, 24, 19, 16, 22, 30, 32, 31, 28, 23, 19, - 26, 33, 36, 35, 31, 26, 21, 29, 35, 41, 40, 34, 29, 22, 33, 38, 43, 43, 36, - 30, 24, 30, 37, 35, 28, 22, 18, 14, 31, 36, 37, 30, 24, 20, 16, 31, 36, 40, - 33, 28, 22, 19, 30, 38, 44, 38, 31, 27, 23, 33, 39, 45, 42, 36, 31, 25, 35, - 41, 48, 46, 39, 32, 27, 40, 44, 48, 51, 41, 35, 29, 1, 4, 6, 9, 9, 7, - 4, 1, 3, 5, 8, 8, 7, 5, 1, 2, 5, 7, 9, 8, 6, 1, 3, 5, 8, - 10, 8, 8, 5, 5, 7, 9, 11, 10, 8, 9, 9, 11, 12, 11, 9, 8, 15, 14, - 12, 12, 11, 10, 8, 1, 2, 4, 7, 6, 3, 1, 1, 1, 4, 6, 6, 3, 1, - 2, 1, 3, 6, 5, 4, 3, 2, 3, 4, 6, 6, 6, 6, 5, 6, 7, 9, 9, - 7, 6, 11, 11, 11, 12, 9, 8, 6, 19, 16, 13, 12, 9, 8, 6, 2, 1, 1, - 1, 2, 1, 3, 2, 1, 1, 0, 1, 1, 4, 3, 2, 2, 2, 2, 3, 5, 7, - 3, 5, 6, 5, 6, 7, 10, 8, 9, 9, 10, 8, 7, 15, 13, 14, 13, 11, 10, - 7, 21, 20, 17, 15, 13, 11, 10, 3, 5, 6, 6, 6, 4, 7, 8, 6, 7, 7, - 7, 7, 7, 11, 7, 8, 9, 10, 10, 9, 13, 9, 13, 13, 13, 13, 11, 13, 15, - 17, 16, 17, 17, 14, 16, 22, 22, 21, 19, 18, 16, 21, 28, 26, 23, 21, 20, 18, - 14, 14, 14, 14, 14, 13, 7, 16, 15, 15, 15, 15, 14, 7, 16, 17, 17, 18, 18, - 17, 13, 16, 21, 22, 22, 22, 21, 17, 19, 27, 27, 27, 26, 24, 19, 23, 30, 32, - 31, 28, 26, 20, 28, 33, 35, 32, 31, 28, 22, 23, 24, 23, 23, 19, 16, 11, 22, - 27, 25, 24, 21, 17, 13, 23, 30, 28, 28, 24, 21, 17, 23, 31, 33, 32, 28, 24, - 21, 28, 34, 36, 36, 33, 27, 22, 31, 36, 44, 42, 36, 29, 24, 34, 39, 43, 45, - 37, 32, 26, 31, 36, 35, 28, 22, 18, 14, 31, 37, 37, 31, 25, 20, 17, 31, 37, - 41, 33, 29, 25, 19, 31, 38, 45, 39, 33, 28, 24, 35, 39, 46, 44, 36, 32, 26, - 38, 45, 51, 50, 40, 33, 28, 40, 46, 50, 51, 43, 35, 30, 1, 4, 7, 10, 10, - 8, 4, 1, 3, 6, 9, 9, 7, 5, 1, 2, 5, 8, 10, 8, 6, 2, 3, 6, - 8, 11, 9, 8, 5, 6, 8, 10, 12, 10, 8, 10, 10, 12, 12, 12, 10, 8, 16, - 14, 12, 12, 12, 10, 8, 1, 2, 5, 7, 7, 4, 1, 1, 1, 4, 6, 6, 4, - 2, 2, 1, 3, 6, 6, 5, 3, 2, 3, 5, 7, 7, 6, 6, 5, 6, 8, 9, - 9, 7, 6, 12, 11, 12, 12, 9, 8, 6, 19, 17, 13, 12, 10, 8, 6, 2, 1, - 1, 1, 2, 2, 3, 2, 2, 1, 1, 0, 1, 4, 4, 2, 2, 3, 3, 2, 5, - 8, 3, 6, 6, 6, 6, 7, 11, 8, 9, 10, 10, 9, 7, 16, 14, 14, 13, 12, - 10, 7, 21, 20, 17, 15, 13, 12, 11, 4, 5, 6, 6, 6, 4, 7, 8, 6, 7, - 7, 7, 7, 7, 12, 6, 8, 10, 10, 10, 9, 13, 9, 13, 13, 14, 14, 11, 14, - 15, 17, 17, 18, 17, 14, 16, 22, 22, 21, 20, 18, 17, 21, 28, 25, 23, 22, 20, - 19, 15, 14, 14, 14, 14, 13, 7, 17, 15, 15, 15, 15, 14, 7, 16, 17, 17, 19, - 19, 17, 13, 17, 21, 23, 23, 22, 21, 17, 19, 27, 27, 27, 27, 24, 19, 24, 32, - 34, 31, 30, 26, 20, 28, 36, 36, 34, 31, 29, 23, 23, 25, 23, 23, 20, 16, 11, - 23, 27, 25, 24, 22, 17, 14, 23, 29, 28, 28, 24, 20, 17, 23, 31, 34, 33, 29, - 25, 21, 27, 34, 38, 37, 33, 28, 22, 30, 38, 44, 42, 36, 30, 24, 35, 40, 44, - 44, 37, 32, 26, 32, 35, 34, 27, 22, 18, 14, 31, 37, 36, 29, 24, 21, 17, 31, - 36, 38, 33, 29, 24, 21, 32, 39, 43, 38, 33, 28, 24, 35, 42, 46, 44, 37, 32, - 27, 37, 43, 49, 48, 42, 34, 28, 41, 46, 49, 51, 44, 36, 30, 3, 5, 6, 8, - 8, 6, 4, 2, 5, 6, 8, 8, 6, 5, 1, 4, 6, 8, 9, 8, 6, 2, 4, - 7, 9, 11, 9, 8, 4, 6, 8, 10, 12, 10, 8, 10, 10, 12, 12, 12, 10, 8, - 15, 15, 13, 12, 12, 10, 8, 1, 4, 5, 7, 5, 4, 2, 1, 3, 5, 6, 5, - 3, 2, 2, 2, 5, 6, 6, 5, 4, 2, 3, 5, 7, 7, 6, 6, 5, 6, 8, - 10, 9, 7, 6, 12, 11, 12, 12, 10, 8, 6, 19, 16, 14, 12, 10, 8, 6, 2, - 1, 2, 2, 3, 1, 3, 2, 1, 1, 1, 1, 0, 3, 3, 1, 1, 2, 2, 2, - 4, 7, 3, 5, 5, 5, 5, 5, 11, 8, 9, 9, 9, 8, 5, 15, 14, 13, 12, - 11, 9, 5, 21, 18, 16, 14, 12, 11, 9, 2, 5, 5, 5, 5, 4, 6, 7, 6, - 6, 6, 6, 6, 6, 11, 6, 7, 8, 9, 9, 7, 14, 9, 12, 12, 12, 12, 10, - 14, 14, 17, 16, 17, 16, 13, 16, 21, 21, 20, 19, 17, 16, 21, 27, 25, 22, 20, - 18, 18, 14, 13, 13, 13, 13, 13, 6, 16, 15, 14, 14, 14, 13, 6, 17, 16, 16, - 17, 17, 16, 12, 17, 21, 21, 21, 22, 19, 15, 19, 27, 27, 26, 25, 23, 18, 23, - 30, 32, 30, 27, 25, 20, 27, 33, 34, 31, 29, 27, 21, 23, 23, 22, 21, 18, 15, - 10, 23, 26, 23, 22, 19, 16, 12, 23, 28, 26, 25, 23, 19, 16, 23, 29, 32, 29, - 27, 23, 19, 26, 33, 37, 34, 31, 26, 21, 31, 37, 40, 40, 33, 28, 23, 33, 38, - 42, 42, 35, 29, 24, 30, 34, 30, 25, 20, 16, 13, 29, 34, 33, 27, 22, 20, 16, - 30, 34, 36, 30, 26, 23, 19, 29, 36, 40, 34, 30, 27, 23, 33, 39, 43, 41, 35, - 30, 25, 37, 41, 46, 46, 37, 31, 27, 40, 44, 47, 47, 40, 34, 28, 6, 7, 9, - 12, 11, 9, 6, 5, 6, 8, 11, 11, 8, 6, 4, 6, 8, 10, 11, 9, 8, 3, - 6, 9, 10, 13, 11, 9, 5, 7, 9, 11, 14, 12, 9, 9, 10, 11, 12, 14, 12, - 9, 15, 14, 12, 12, 13, 12, 9, 4, 6, 7, 9, 8, 6, 4, 3, 6, 7, 8, - 7, 5, 3, 1, 5, 7, 8, 7, 6, 5, 1, 4, 8, 9, 8, 8, 6, 5, 7, - 9, 10, 9, 9, 6, 11, 11, 12, 12, 10, 8, 6, 18, 16, 13, 12, 10, 8, 6, - 1, 5, 5, 4, 5, 4, 2, 1, 3, 4, 4, 4, 3, 0, 1, 2, 4, 4, 3, - 3, 2, 2, 3, 5, 5, 4, 4, 4, 7, 8, 8, 7, 8, 6, 4, 14, 13, 12, - 10, 8, 7, 4, 20, 17, 14, 11, 9, 7, 5, 1, 2, 2, 2, 2, 3, 5, 2, - 3, 2, 2, 3, 3, 3, 7, 4, 4, 5, 5, 5, 4, 10, 7, 8, 8, 8, 8, - 6, 10, 13, 12, 12, 12, 11, 9, 14, 19, 17, 15, 14, 13, 11, 19, 23, 20, 17, - 15, 14, 13, 11, 10, 9, 9, 10, 9, 5, 13, 12, 11, 10, 11, 9, 3, 13, 13, - 13, 14, 13, 11, 8, 13, 18, 17, 16, 17, 15, 12, 16, 23, 22, 21, 21, 18, 13, - 20, 26, 27, 25, 22, 20, 15, 23, 28, 31, 26, 24, 22, 16, 19, 19, 17, 16, 15, - 11, 8, 19, 22, 18, 17, 15, 11, 8, 19, 23, 21, 20, 17, 14, 12, 20, 25, 25, - 24, 22, 18, 15, 22, 28, 31, 28, 25, 22, 17, 27, 31, 36, 33, 27, 23, 19, 29, - 34, 38, 35, 29, 25, 20, 25, 27, 25, 19, 16, 13, 10, 25, 27, 27, 20, 17, 14, - 11, 25, 28, 29, 24, 21, 18, 15, 25, 29, 34, 29, 25, 21, 18, 28, 33, 36, 34, - 30, 24, 20, 31, 35, 40, 38, 32, 26, 21, 35, 38, 41, 41, 34, 28, 23, 3, 7, - 12, 15, 16, 14, 11, 2, 5, 10, 14, 15, 14, 8, 2, 4, 8, 11, 13, 11, 6, - 2, 2, 5, 8, 10, 10, 5, 2, 2, 3, 6, 8, 9, 5, 5, 6, 6, 5, 7, - 9, 5, 12, 11, 8, 4, 7, 9, 5, 2, 4, 8, 12, 13, 11, 5, 2, 3, 7, - 10, 12, 9, 3, 2, 2, 5, 7, 8, 6, 2, 1, 2, 2, 4, 5, 3, 2, 2, - 3, 3, 3, 3, 3, 2, 7, 7, 7, 6, 3, 2, 2, 15, 13, 9, 7, 4, 3, - 2, 2, 2, 3, 5, 6, 4, 2, 1, 2, 2, 3, 4, 3, 1, 0, 2, 2, 2, - 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 3, 2, 10, 9, - 9, 8, 5, 3, 2, 17, 16, 12, 9, 6, 4, 2, 0, 1, 1, 1, 2, 2, 4, - 1, 1, 1, 1, 1, 1, 5, 1, 2, 2, 3, 3, 3, 5, 4, 4, 5, 5, 5, - 6, 7, 5, 9, 8, 9, 9, 8, 7, 11, 14, 13, 13, 11, 10, 9, 17, 20, 17, - 15, 13, 12, 11, 8, 8, 8, 9, 9, 8, 5, 10, 10, 9, 10, 10, 9, 5, 10, - 11, 11, 11, 12, 11, 6, 10, 14, 13, 14, 14, 13, 9, 12, 18, 18, 18, 18, 17, - 11, 16, 21, 22, 21, 20, 19, 13, 19, 24, 24, 22, 21, 20, 16, 17, 18, 18, 18, - 15, 11, 7, 17, 20, 19, 19, 16, 12, 7, 17, 22, 22, 21, 19, 14, 9, 17, 22, - 23, 22, 20, 17, 13, 18, 24, 26, 24, 23, 20, 15, 21, 26, 29, 28, 24, 21, 17, - 23, 28, 30, 29, 26, 22, 18, 25, 28, 26, 22, 19, 14, 9, 24, 28, 28, 24, 20, - 16, 10, 24, 29, 31, 24, 21, 17, 13, 24, 29, 31, 26, 23, 20, 17, 25, 28, 32, - 30, 25, 22, 18, 27, 29, 33, 32, 27, 23, 20, 28, 31, 33, 34, 29, 24, 21, 2, - 2, 3, 5, 5, 3, 2, 2, 2, 3, 4, 5, 2, 2, 2, 2, 2, 3, 3, 2, - 1, 0, 2, 2, 2, 3, 2, 3, 2, 2, 3, 3, 4, 3, 3, 6, 6, 7, 6, - 4, 3, 3, 12, 11, 8, 6, 5, 3, 3, 1, 2, 3, 3, 3, 2, 2, 1, 2, - 2, 3, 2, 2, 1, 1, 2, 2, 2, 2, 2, 1, 2, 1, 2, 2, 2, 1, 3, - 4, 3, 4, 4, 4, 3, 3, 9, 8, 8, 7, 5, 3, 3, 16, 13, 10, 8, 5, - 4, 3, 1, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 0, 1, - 1, 1, 1, 3, 2, 2, 2, 1, 2, 2, 5, 6, 5, 5, 5, 5, 4, 5, 12, - 10, 10, 8, 7, 5, 5, 18, 17, 12, 10, 8, 7, 6, 2, 3, 3, 3, 4, 4, - 7, 2, 4, 4, 5, 5, 5, 8, 5, 5, 5, 5, 6, 6, 7, 8, 8, 8, 8, - 9, 9, 9, 9, 13, 12, 12, 13, 12, 11, 12, 18, 16, 16, 15, 13, 12, 18, 23, - 20, 18, 17, 15, 14, 11, 11, 11, 11, 11, 11, 7, 12, 13, 12, 13, 13, 12, 7, - 12, 14, 14, 14, 14, 13, 9, 13, 18, 17, 17, 18, 16, 13, 16, 22, 22, 21, 22, - 19, 14, 19, 26, 27, 26, 24, 22, 16, 24, 29, 31, 28, 26, 23, 18, 19, 21, 20, - 20, 17, 13, 9, 20, 23, 22, 23, 19, 14, 10, 20, 25, 25, 24, 20, 16, 12, 20, - 26, 28, 28, 24, 20, 16, 23, 28, 32, 32, 29, 23, 18, 26, 32, 37, 37, 31, 25, - 20, 28, 34, 39, 39, 33, 28, 22, 28, 34, 32, 26, 20, 16, 12, 28, 34, 34, 27, - 22, 17, 13, 27, 34, 38, 30, 24, 20, 16, 28, 34, 39, 34, 28, 23, 20, 30, 36, - 41, 39, 32, 28, 22, 32, 38, 44, 41, 36, 30, 24, 34, 40, 45, 43, 38, 31, 25, - 2, 4, 5, 6, 6, 5, 4, 1, 4, 5, 6, 6, 5, 4, 0, 3, 5, 5, 5, - 4, 4, 1, 2, 4, 5, 5, 5, 6, 3, 4, 6, 6, 7, 6, 6, 8, 8, 9, - 9, 8, 6, 6, 13, 12, 11, 9, 8, 6, 6, 0, 3, 5, 5, 5, 4, 2, 1, - 2, 4, 5, 5, 4, 2, 1, 1, 4, 4, 4, 3, 2, 2, 2, 3, 5, 4, 5, - 5, 5, 4, 6, 7, 7, 6, 5, 9, 9, 10, 10, 8, 6, 5, 17, 14, 11, 10, - 8, 6, 5, 1, 1, 2, 3, 3, 1, 4, 2, 1, 2, 2, 2, 1, 4, 2, 1, - 0, 0, 0, 0, 5, 4, 2, 3, 3, 3, 3, 6, 8, 6, 7, 7, 7, 6, 6, - 13, 11, 11, 10, 9, 7, 6, 19, 18, 14, 12, 10, 9, 8, 2, 4, 5, 5, 5, - 5, 7, 4, 5, 5, 6, 6, 6, 8, 8, 6, 7, 7, 7, 8, 8, 10, 9, 10, - 10, 11, 11, 10, 11, 14, 14, 15, 15, 14, 13, 13, 20, 19, 18, 17, 15, 15, 19, - 26, 22, 20, 18, 17, 16, 12, 13, 12, 13, 13, 12, 7, 13, 14, 14, 14, 14, 13, - 8, 14, 16, 16, 16, 16, 15, 11, 13, 20, 19, 19, 20, 18, 15, 18, 25, 24, 24, - 24, 21, 16, 22, 28, 30, 28, 26, 23, 18, 26, 31, 33, 29, 28, 25, 20, 22, 23, - 22, 22, 18, 14, 10, 22, 25, 24, 24, 20, 16, 12, 22, 27, 26, 26, 23, 18, 14, - 21, 29, 30, 29, 26, 22, 18, 26, 31, 36, 34, 30, 25, 20, 27, 34, 39, 38, 33, - 27, 21, 31, 37, 41, 41, 34, 28, 23, 29, 35, 34, 27, 22, 17, 13, 29, 36, 36, - 29, 24, 19, 14, 29, 36, 39, 32, 26, 22, 17, 30, 36, 42, 35, 30, 26, 22, 31, - 38, 44, 41, 33, 29, 24, 34, 40, 47, 47, 38, 30, 26, 37, 43, 47, 47, 39, 33, - 27, 2, 6, 9, 11, 11, 10, 7, 2, 5, 8, 11, 11, 9, 6, 0, 3, 7, 9, - 10, 7, 6, 1, 2, 5, 7, 9, 8, 7, 3, 4, 6, 8, 10, 9, 7, 7, 8, - 10, 10, 10, 9, 7, 14, 13, 11, 10, 10, 9, 7, 0, 3, 7, 10, 9, 6, 3, - 1, 2, 5, 8, 9, 6, 2, 1, 1, 4, 6, 6, 4, 2, 2, 2, 4, 6, 6, - 5, 4, 4, 5, 6, 8, 7, 6, 4, 10, 9, 10, 10, 8, 6, 4, 17, 14, 11, - 11, 8, 6, 4, 1, 1, 2, 3, 4, 3, 5, 2, 0, 2, 2, 3, 2, 4, 2, - 1, 0, 0, 0, 0, 3, 4, 2, 3, 3, 3, 3, 5, 8, 6, 7, 7, 7, 6, - 5, 13, 11, 11, 10, 9, 7, 5, 19, 17, 14, 12, 10, 9, 8, 2, 4, 5, 5, - 6, 6, 8, 5, 5, 6, 6, 7, 7, 7, 10, 6, 7, 7, 7, 7, 7, 11, 9, - 10, 11, 11, 10, 9, 12, 14, 14, 15, 14, 14, 12, 13, 20, 19, 18, 17, 16, 14, - 19, 26, 23, 21, 18, 17, 16, 12, 13, 12, 13, 14, 13, 8, 15, 14, 14, 15, 15, - 14, 7, 14, 16, 16, 16, 15, 14, 11, 14, 20, 19, 19, 20, 17, 14, 17, 25, 24, - 23, 24, 21, 16, 21, 28, 30, 28, 26, 23, 18, 25, 31, 33, 30, 27, 25, 20, 22, - 24, 22, 22, 19, 16, 12, 21, 26, 24, 24, 20, 16, 12, 22, 28, 26, 26, 21, 18, - 14, 22, 29, 30, 30, 26, 22, 18, 25, 33, 36, 34, 30, 25, 19, 28, 34, 41, 38, - 33, 27, 22, 31, 37, 42, 41, 36, 29, 23, 30, 35, 34, 28, 23, 18, 14, 29, 36, - 36, 30, 23, 19, 14, 30, 35, 38, 32, 26, 21, 17, 29, 37, 41, 35, 31, 25, 21, - 32, 39, 45, 39, 34, 29, 23, 34, 41, 47, 46, 38, 31, 26, 37, 43, 47, 46, 40, - 33, 27, 3, 6, 9, 13, 13, 10, 7, 2, 5, 8, 12, 12, 9, 6, 0, 4, 7, - 10, 11, 8, 6, 1, 3, 5, 8, 10, 9, 7, 4, 4, 6, 8, 11, 9, 7, 7, - 8, 10, 10, 10, 9, 7, 13, 12, 10, 10, 10, 9, 7, 1, 4, 7, 10, 10, 7, - 3, 1, 2, 6, 9, 9, 6, 2, 1, 1, 5, 7, 7, 4, 2, 1, 2, 4, 6, - 6, 5, 4, 4, 5, 6, 8, 7, 5, 4, 10, 9, 10, 10, 7, 6, 4, 16, 14, - 11, 10, 8, 6, 4, 1, 1, 3, 4, 5, 3, 4, 1, 1, 2, 2, 3, 2, 3, - 2, 1, 0, 0, 0, 1, 3, 4, 2, 3, 3, 3, 3, 4, 8, 6, 7, 7, 7, - 6, 4, 13, 12, 11, 10, 9, 7, 4, 19, 17, 14, 12, 10, 9, 8, 1, 5, 5, - 5, 6, 6, 8, 5, 6, 6, 6, 7, 7, 7, 9, 6, 7, 7, 7, 7, 6, 11, - 8, 11, 11, 10, 11, 8, 12, 14, 15, 15, 15, 14, 12, 13, 19, 19, 18, 17, 15, - 14, 19, 26, 23, 20, 19, 17, 16, 12, 13, 13, 13, 14, 13, 8, 14, 15, 14, 14, - 15, 13, 7, 15, 16, 16, 16, 16, 14, 11, 14, 20, 20, 20, 20, 18, 14, 17, 25, - 25, 24, 23, 21, 16, 22, 29, 30, 28, 26, 23, 18, 26, 32, 33, 31, 28, 25, 20, - 22, 23, 23, 23, 20, 16, 11, 22, 26, 24, 24, 21, 16, 12, 23, 29, 27, 26, 22, - 17, 14, 23, 29, 31, 29, 26, 22, 18, 25, 32, 37, 34, 30, 25, 19, 28, 35, 41, - 38, 33, 27, 22, 31, 36, 41, 40, 34, 30, 23, 31, 35, 33, 27, 22, 18, 14, 30, - 36, 36, 29, 23, 18, 14, 29, 36, 38, 31, 25, 21, 17, 31, 36, 40, 35, 30, 26, - 22, 32, 38, 43, 40, 34, 29, 23, 36, 41, 45, 45, 37, 31, 25, 37, 43, 46, 46, - 40, 34, 27, 3, 6, 8, 9, 9, 7, 5, 2, 6, 7, 9, 9, 6, 4, 1, 4, - 6, 8, 8, 6, 5, 1, 3, 5, 7, 9, 8, 6, 4, 4, 7, 8, 11, 9, 6, - 8, 8, 10, 10, 10, 9, 6, 13, 12, 10, 10, 10, 9, 6, 0, 4, 6, 8, 7, - 5, 3, 1, 3, 5, 7, 6, 4, 2, 1, 1, 5, 6, 4, 3, 2, 2, 2, 4, - 6, 5, 5, 4, 5, 5, 6, 8, 7, 6, 4, 10, 9, 10, 10, 7, 6, 4, 16, - 13, 11, 10, 8, 6, 4, 1, 1, 3, 3, 4, 3, 5, 2, 1, 2, 3, 3, 2, - 3, 2, 1, 0, 0, 0, 0, 2, 4, 2, 3, 3, 3, 3, 4, 9, 7, 7, 7, - 7, 6, 4, 14, 11, 11, 10, 9, 7, 4, 18, 16, 13, 11, 10, 9, 8, 2, 5, - 5, 6, 6, 6, 8, 5, 6, 6, 6, 7, 7, 6, 9, 6, 7, 7, 8, 7, 6, - 11, 8, 11, 11, 10, 11, 8, 12, 14, 15, 14, 15, 14, 11, 13, 20, 19, 18, 16, - 16, 14, 18, 25, 22, 20, 18, 17, 16, 13, 13, 13, 13, 14, 13, 8, 15, 15, 14, - 15, 15, 13, 7, 15, 16, 16, 16, 16, 14, 10, 15, 20, 20, 20, 20, 18, 15, 18, - 25, 24, 23, 24, 21, 16, 22, 28, 29, 28, 26, 23, 18, 25, 30, 32, 29, 28, 25, - 20, 23, 24, 23, 22, 19, 16, 11, 23, 26, 24, 22, 20, 16, 11, 23, 28, 26, 24, - 21, 18, 14, 22, 29, 31, 28, 25, 22, 18, 25, 31, 35, 34, 29, 24, 19, 28, 33, - 39, 37, 31, 26, 22, 31, 35, 41, 39, 33, 27, 23, 29, 34, 32, 26, 22, 18, 14, - 30, 34, 33, 27, 22, 18, 14, 29, 33, 36, 29, 24, 21, 17, 29, 34, 39, 34, 29, - 26, 21, 32, 37, 42, 38, 34, 27, 23, 34, 40, 44, 44, 35, 29, 25, 37, 41, 45, - 45, 37, 31, 27, 7, 9, 11, 13, 13, 11, 8, 6, 8, 10, 12, 13, 10, 6, 5, - 7, 9, 11, 11, 8, 6, 3, 6, 7, 10, 12, 10, 8, 4, 6, 8, 10, 13, 10, - 8, 7, 8, 9, 10, 12, 10, 7, 11, 10, 9, 9, 11, 11, 8, 5, 7, 9, 11, - 10, 7, 5, 4, 6, 8, 10, 9, 6, 4, 1, 6, 7, 9, 7, 5, 3, 0, 4, - 6, 8, 7, 6, 5, 4, 5, 7, 8, 8, 7, 5, 9, 8, 9, 10, 7, 7, 5, - 13, 11, 10, 9, 8, 6, 5, 2, 6, 6, 6, 6, 5, 4, 0, 4, 5, 5, 5, - 4, 2, 1, 3, 5, 3, 3, 3, 0, 1, 2, 3, 3, 3, 3, 2, 6, 6, 6, - 5, 5, 4, 2, 12, 10, 8, 8, 6, 4, 2, 15, 13, 10, 8, 6, 5, 3, 1, - 2, 3, 3, 4, 5, 6, 1, 3, 3, 4, 4, 4, 5, 4, 5, 4, 4, 4, 4, - 4, 7, 7, 7, 6, 6, 6, 5, 8, 12, 11, 10, 10, 9, 8, 12, 16, 14, 13, - 12, 11, 10, 15, 20, 16, 14, 14, 12, 11, 11, 10, 10, 10, 11, 10, 6, 12, 12, - 11, 11, 12, 10, 5, 12, 14, 13, 12, 12, 10, 7, 12, 17, 15, 15, 15, 13, 10, - 15, 22, 20, 19, 18, 16, 12, 19, 23, 25, 22, 20, 18, 13, 20, 25, 27, 24, 22, - 19, 15, 19, 19, 18, 17, 15, 12, 9, 19, 22, 19, 18, 16, 12, 8, 19, 23, 21, - 19, 16, 13, 10, 19, 23, 24, 22, 19, 17, 13, 21, 27, 29, 27, 23, 20, 15, 24, - 28, 34, 29, 25, 20, 17, 26, 30, 34, 34, 27, 23, 18, 25, 28, 26, 20, 17, 14, - 11, 25, 28, 28, 22, 18, 14, 11, 25, 28, 30, 23, 19, 16, 12, 25, 29, 32, 27, - 23, 19, 16, 27, 31, 36, 33, 27, 22, 18, 29, 33, 38, 36, 29, 24, 20, 30, 36, - 38, 38, 32, 26, 21, 6, 10, 15, 18, 18, 17, 15, 5, 9, 13, 16, 17, 15, 12, - 3, 7, 11, 14, 15, 13, 10, 2, 5, 8, 11, 13, 13, 9, 2, 2, 6, 9, 11, - 13, 10, 5, 5, 5, 8, 11, 13, 10, 11, 10, 6, 6, 10, 13, 9, 3, 7, 12, - 15, 15, 13, 10, 2, 6, 10, 13, 15, 13, 7, 2, 4, 8, 11, 12, 10, 4, 2, - 2, 5, 8, 8, 8, 3, 2, 3, 3, 6, 7, 7, 3, 7, 7, 6, 5, 5, 6, - 3, 14, 12, 9, 5, 4, 4, 3, 2, 4, 7, 9, 10, 9, 4, 2, 3, 5, 7, - 8, 7, 2, 1, 2, 4, 5, 4, 4, 1, 0, 2, 1, 1, 2, 1, 2, 4, 4, - 4, 4, 4, 3, 2, 10, 10, 9, 8, 6, 3, 2, 16, 15, 11, 9, 7, 4, 2, - 1, 1, 1, 2, 2, 3, 3, 0, 1, 1, 1, 1, 1, 4, 1, 1, 2, 2, 2, - 2, 4, 3, 3, 3, 4, 4, 4, 5, 5, 8, 7, 8, 8, 7, 6, 10, 13, 12, - 12, 10, 9, 8, 16, 18, 15, 13, 12, 11, 10, 7, 7, 8, 8, 9, 7, 3, 9, - 9, 9, 10, 9, 8, 4, 9, 10, 11, 11, 11, 10, 5, 9, 13, 13, 13, 13, 12, - 8, 11, 16, 16, 16, 15, 15, 10, 14, 19, 19, 18, 17, 16, 12, 18, 21, 21, 19, - 18, 17, 14, 16, 16, 16, 16, 14, 11, 6, 16, 19, 17, 17, 15, 12, 7, 16, 20, - 19, 18, 16, 13, 8, 15, 20, 20, 19, 17, 15, 12, 17, 21, 23, 21, 19, 17, 14, - 19, 22, 25, 24, 21, 18, 15, 21, 23, 27, 25, 22, 18, 16, 21, 25, 23, 19, 17, - 14, 9, 21, 25, 26, 20, 17, 15, 10, 22, 25, 27, 21, 18, 15, 12, 21, 24, 28, - 22, 18, 17, 15, 20, 25, 29, 26, 21, 19, 16, 22, 26, 29, 28, 23, 20, 17, 24, - 27, 30, 30, 24, 21, 18, 3, 3, 5, 8, 8, 6, 3, 2, 3, 4, 7, 8, 5, - 3, 2, 3, 4, 5, 6, 4, 2, 2, 2, 3, 3, 4, 2, 2, 1, 2, 2, 2, - 3, 2, 2, 5, 5, 5, 4, 3, 2, 2, 11, 9, 7, 5, 3, 2, 2, 2, 3, - 4, 6, 5, 4, 3, 2, 3, 4, 5, 5, 3, 2, 1, 2, 3, 3, 3, 3, 2, - 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 7, 6, 7, 6, 3, - 2, 2, 14, 12, 8, 6, 4, 2, 2, 1, 2, 3, 3, 3, 3, 3, 1, 2, 3, - 3, 3, 3, 3, 1, 2, 2, 2, 2, 2, 2, 2, 0, 1, 1, 1, 1, 2, 4, - 4, 3, 3, 4, 2, 3, 10, 9, 8, 7, 5, 3, 3, 17, 15, 11, 8, 6, 5, - 4, 2, 3, 3, 4, 4, 4, 7, 2, 4, 4, 5, 5, 5, 8, 3, 5, 5, 6, - 6, 6, 8, 5, 6, 6, 6, 7, 7, 8, 6, 10, 10, 10, 10, 10, 9, 10, 16, - 15, 14, 13, 11, 11, 16, 21, 18, 16, 14, 13, 12, 10, 11, 11, 11, 12, 11, 7, - 11, 12, 12, 12, 13, 12, 8, 12, 13, 14, 14, 14, 13, 9, 12, 16, 16, 15, 15, - 15, 11, 14, 20, 19, 19, 19, 17, 12, 17, 23, 25, 24, 22, 20, 14, 20, 27, 29, - 26, 24, 22, 16, 19, 21, 21, 20, 18, 14, 9, 20, 23, 23, 23, 19, 14, 10, 19, - 25, 25, 24, 21, 16, 11, 19, 24, 26, 26, 22, 18, 14, 21, 26, 31, 29, 27, 21, - 16, 23, 29, 34, 34, 28, 24, 17, 26, 31, 35, 34, 31, 25, 20, 28, 34, 32, 26, - 22, 17, 12, 27, 34, 34, 28, 23, 18, 13, 27, 33, 37, 30, 24, 19, 14, 28, 33, - 38, 31, 26, 22, 18, 27, 34, 39, 36, 30, 25, 19, 29, 36, 39, 39, 33, 27, 22, - 33, 37, 39, 41, 34, 30, 24, 5, 8, 9, 10, 10, 9, 8, 4, 7, 9, 10, 9, - 8, 7, 3, 6, 8, 8, 8, 7, 5, 2, 4, 6, 6, 7, 5, 4, 1, 2, 4, - 5, 5, 5, 4, 5, 5, 7, 6, 5, 5, 4, 10, 10, 8, 7, 6, 5, 4, 3, - 6, 8, 9, 8, 8, 6, 2, 5, 7, 9, 8, 7, 5, 1, 4, 7, 7, 7, 6, - 4, 1, 2, 4, 5, 5, 4, 3, 2, 2, 4, 5, 4, 4, 3, 7, 6, 8, 7, - 5, 4, 3, 14, 11, 9, 8, 5, 4, 3, 2, 4, 6, 6, 7, 5, 6, 1, 2, - 5, 5, 6, 5, 5, 1, 2, 3, 3, 3, 3, 3, 1, 1, 0, 0, 0, 0, 3, - 5, 4, 3, 3, 3, 3, 3, 10, 9, 8, 7, 5, 4, 3, 16, 15, 11, 8, 7, - 6, 5, 1, 4, 5, 5, 6, 6, 9, 2, 5, 5, 6, 7, 7, 8, 4, 6, 6, - 6, 6, 7, 7, 7, 7, 7, 7, 7, 8, 7, 8, 11, 11, 11, 11, 10, 10, 10, - 17, 16, 14, 13, 12, 11, 16, 22, 19, 17, 15, 14, 13, 11, 12, 12, 12, 13, 12, - 8, 12, 13, 14, 14, 14, 13, 8, 12, 15, 15, 15, 15, 13, 9, 12, 17, 16, 16, - 16, 15, 11, 15, 21, 21, 20, 20, 18, 13, 18, 25, 26, 25, 22, 19, 14, 23, 27, - 29, 26, 25, 22, 16, 21, 22, 22, 22, 19, 15, 11, 21, 25, 24, 24, 20, 15, 11, - 21, 26, 25, 25, 20, 16, 12, 21, 26, 27, 26, 23, 18, 14, 21, 28, 31, 31, 27, - 21, 16, 24, 30, 37, 35, 29, 23, 18, 28, 33, 37, 38, 31, 25, 20, 29, 33, 34, - 27, 22, 18, 13, 28, 36, 36, 29, 23, 18, 14, 28, 35, 38, 30, 24, 19, 14, 28, - 34, 39, 32, 26, 22, 18, 29, 35, 42, 38, 32, 26, 20, 31, 37, 43, 41, 34, 27, - 22, 33, 39, 44, 44, 37, 30, 23, 5, 9, 12, 15, 15, 13, 10, 4, 8, 11, 14, - 15, 12, 9, 3, 6, 10, 13, 13, 10, 7, 2, 4, 7, 10, 11, 8, 7, 1, 2, - 5, 8, 10, 9, 7, 5, 5, 7, 8, 9, 8, 7, 10, 10, 8, 8, 8, 8, 7, - 3, 7, 10, 13, 12, 10, 7, 2, 5, 9, 12, 12, 9, 5, 1, 4, 8, 10, 10, - 7, 4, 1, 2, 5, 7, 7, 5, 3, 3, 2, 4, 6, 6, 6, 3, 7, 6, 8, - 8, 6, 5, 3, 13, 12, 9, 8, 6, 4, 3, 1, 4, 6, 7, 8, 6, 6, 1, - 2, 5, 6, 6, 5, 4, 1, 1, 3, 3, 3, 3, 3, 1, 1, 0, 0, 0, 0, - 3, 5, 4, 3, 3, 3, 3, 3, 10, 8, 8, 7, 5, 4, 3, 16, 14, 11, 9, - 7, 5, 5, 1, 4, 5, 5, 6, 7, 8, 1, 5, 6, 6, 7, 7, 7, 5, 6, - 6, 6, 6, 7, 7, 8, 7, 7, 7, 7, 7, 6, 9, 11, 11, 11, 11, 11, 9, - 11, 17, 16, 15, 13, 12, 11, 16, 22, 19, 17, 15, 14, 12, 11, 12, 12, 13, 14, - 13, 9, 12, 14, 13, 14, 15, 13, 8, 12, 15, 15, 14, 15, 13, 9, 12, 17, 16, - 16, 16, 15, 11, 15, 22, 20, 20, 20, 18, 12, 18, 25, 27, 25, 22, 19, 14, 23, - 28, 29, 27, 25, 22, 16, 21, 22, 22, 22, 19, 15, 11, 21, 24, 24, 24, 20, 15, - 11, 21, 26, 26, 25, 20, 16, 11, 21, 26, 28, 26, 22, 18, 15, 22, 27, 31, 30, - 26, 21, 16, 25, 31, 37, 35, 29, 23, 18, 28, 33, 37, 37, 32, 25, 20, 29, 35, - 33, 27, 22, 18, 14, 29, 36, 36, 30, 23, 19, 14, 30, 35, 38, 30, 24, 19, 14, - 29, 35, 40, 33, 27, 22, 18, 28, 35, 40, 38, 31, 25, 20, 31, 37, 43, 40, 34, - 27, 22, 33, 40, 44, 43, 37, 29, 23, 6, 9, 13, 16, 16, 14, 10, 5, 8, 11, - 15, 15, 12, 9, 3, 6, 10, 13, 14, 11, 7, 2, 4, 7, 10, 12, 9, 6, 1, - 3, 5, 8, 11, 9, 6, 5, 6, 7, 8, 10, 9, 6, 10, 9, 8, 8, 9, 9, - 6, 3, 7, 10, 13, 13, 10, 7, 2, 6, 9, 12, 12, 9, 5, 1, 4, 8, 10, - 10, 7, 3, 1, 2, 5, 7, 7, 5, 2, 3, 2, 4, 6, 6, 5, 2, 7, 6, - 8, 8, 5, 5, 2, 13, 10, 9, 8, 6, 4, 3, 1, 4, 6, 7, 8, 6, 6, - 1, 3, 5, 6, 6, 5, 4, 1, 2, 3, 3, 3, 3, 3, 2, 1, 0, 0, 0, - 0, 3, 5, 4, 4, 4, 4, 3, 3, 11, 9, 8, 7, 6, 4, 3, 15, 13, 10, - 9, 7, 6, 5, 1, 5, 5, 6, 6, 7, 9, 2, 6, 6, 6, 7, 7, 7, 5, - 6, 7, 7, 7, 7, 6, 8, 7, 8, 7, 7, 7, 6, 9, 11, 12, 11, 12, 10, - 9, 11, 17, 16, 15, 13, 12, 11, 15, 21, 19, 17, 15, 14, 13, 11, 13, 13, 13, - 14, 13, 9, 12, 14, 14, 14, 15, 13, 8, 12, 16, 15, 15, 15, 13, 10, 13, 18, - 17, 17, 16, 15, 11, 14, 22, 21, 21, 21, 18, 13, 19, 26, 27, 25, 22, 20, 15, - 22, 27, 29, 27, 25, 22, 16, 21, 24, 22, 22, 19, 16, 11, 22, 26, 25, 24, 21, - 16, 11, 21, 28, 26, 25, 20, 16, 12, 21, 27, 27, 27, 23, 19, 15, 23, 28, 34, - 31, 27, 22, 16, 25, 31, 37, 35, 28, 24, 18, 28, 33, 37, 37, 32, 26, 19, 31, - 35, 33, 29, 22, 18, 14, 30, 36, 36, 30, 23, 18, 15, 29, 35, 37, 31, 24, 20, - 14, 31, 36, 39, 33, 28, 22, 18, 29, 35, 40, 37, 32, 26, 20, 31, 38, 42, 41, - 34, 27, 22, 34, 39, 44, 43, 37, 31, 24, 6, 9, 12, 16, 16, 13, 11, 5, 8, - 12, 15, 16, 12, 9, 3, 7, 10, 13, 14, 11, 7, 2, 5, 8, 10, 13, 9, 6, - 1, 3, 6, 8, 12, 10, 7, 5, 5, 7, 8, 11, 10, 6, 8, 7, 7, 7, 9, - 9, 7, 3, 7, 10, 13, 13, 10, 7, 2, 6, 9, 12, 12, 9, 5, 1, 4, 8, - 10, 10, 7, 3, 1, 2, 5, 7, 7, 5, 3, 3, 2, 4, 6, 6, 5, 3, 7, - 6, 7, 7, 5, 5, 3, 11, 8, 7, 7, 5, 4, 3, 2, 5, 6, 7, 8, 6, - 6, 1, 3, 5, 6, 6, 5, 4, 1, 2, 4, 3, 3, 3, 3, 2, 1, 0, 0, - 0, 0, 2, 6, 4, 4, 4, 4, 3, 2, 9, 8, 6, 6, 5, 4, 2, 13, 10, - 8, 7, 7, 6, 5, 1, 5, 5, 6, 6, 7, 9, 2, 6, 6, 7, 7, 7, 7, - 6, 6, 7, 7, 7, 7, 6, 8, 7, 8, 8, 7, 8, 6, 9, 12, 12, 11, 11, - 10, 9, 10, 15, 15, 14, 13, 12, 11, 12, 18, 17, 15, 14, 14, 13, 12, 13, 13, - 13, 14, 13, 9, 13, 14, 14, 15, 15, 13, 7, 13, 16, 16, 15, 15, 13, 10, 13, - 18, 17, 16, 17, 15, 11, 15, 23, 21, 21, 20, 18, 13, 18, 24, 26, 24, 22, 20, - 14, 20, 25, 28, 25, 23, 22, 16, 22, 24, 22, 21, 19, 15, 11, 22, 25, 24, 23, - 20, 16, 12, 22, 28, 26, 24, 20, 16, 12, 22, 26, 27, 25, 22, 19, 15, 23, 29, - 33, 30, 25, 22, 16, 25, 30, 35, 33, 28, 23, 18, 26, 31, 36, 36, 30, 25, 20, - 30, 34, 31, 26, 22, 18, 14, 30, 33, 33, 28, 22, 19, 14, 29, 33, 35, 28, 23, - 19, 15, 29, 34, 37, 30, 26, 22, 18, 29, 34, 39, 36, 29, 24, 21, 31, 36, 40, - 39, 32, 27, 21, 32, 37, 40, 40, 33, 27, 23, 8, 11, 13, 15, 15, 13, 10, 7, - 10, 12, 15, 15, 12, 8, 6, 8, 11, 13, 14, 10, 7, 5, 7, 9, 10, 12, 9, - 6, 2, 5, 7, 9, 12, 9, 6, 3, 5, 6, 8, 11, 9, 6, 4, 5, 6, 8, - 10, 9, 6, 6, 8, 11, 13, 12, 10, 7, 6, 8, 10, 12, 12, 8, 5, 4, 7, - 9, 10, 9, 7, 4, 2, 5, 7, 8, 7, 5, 3, 1, 3, 6, 7, 6, 5, 3, - 3, 4, 5, 6, 6, 5, 3, 6, 5, 5, 6, 5, 4, 3, 4, 7, 7, 7, 8, - 7, 6, 2, 6, 7, 7, 6, 5, 4, 1, 5, 5, 5, 4, 4, 2, 2, 2, 3, - 3, 3, 2, 0, 3, 3, 2, 2, 2, 1, 0, 5, 4, 3, 2, 3, 1, 0, 9, - 5, 4, 3, 2, 2, 2, 2, 4, 4, 5, 6, 8, 8, 1, 5, 4, 5, 6, 5, - 6, 1, 6, 5, 5, 5, 5, 5, 6, 6, 5, 5, 5, 5, 4, 5, 8, 7, 7, - 7, 7, 6, 6, 10, 9, 8, 8, 8, 7, 9, 14, 12, 10, 10, 9, 9, 11, 11, - 11, 11, 12, 11, 8, 12, 13, 12, 12, 12, 11, 6, 12, 14, 14, 13, 12, 11, 7, - 12, 16, 14, 13, 13, 12, 8, 13, 18, 16, 16, 15, 14, 9, 14, 19, 20, 18, 16, - 14, 10, 15, 20, 22, 21, 18, 16, 12, 19, 21, 18, 18, 16, 13, 9, 19, 22, 20, - 19, 17, 13, 9, 20, 24, 22, 20, 16, 13, 10, 20, 24, 23, 21, 17, 15, 11, 19, - 24, 26, 24, 21, 16, 12, 20, 24, 30, 27, 23, 17, 14, 21, 26, 29, 30, 25, 19, - 14, 26, 30, 27, 22, 18, 14, 12, 26, 30, 30, 23, 18, 15, 12, 26, 30, 32, 24, - 19, 16, 12, 26, 30, 33, 26, 21, 16, 14, 25, 29, 34, 30, 24, 19, 15, 25, 30, - 35, 34, 27, 21, 16, 27, 32, 36, 35, 29, 23, 17, 9, 13, 17, 22, 21, 18, 16, - 8, 12, 16, 20, 21, 18, 15, 7, 10, 14, 18, 20, 17, 13, 6, 9, 12, 15, 17, - 15, 11, 4, 5, 8, 11, 13, 14, 12, 2, 3, 6, 10, 12, 14, 12, 7, 5, 5, - 8, 12, 13, 11, 7, 10, 15, 18, 18, 15, 13, 6, 9, 13, 16, 17, 15, 11, 5, - 8, 11, 14, 15, 13, 9, 5, 6, 9, 11, 12, 11, 6, 2, 3, 5, 8, 9, 10, - 6, 3, 3, 4, 6, 8, 8, 6, 10, 8, 4, 5, 6, 6, 5, 5, 8, 10, 11, - 13, 11, 8, 5, 7, 9, 10, 11, 10, 7, 4, 6, 7, 8, 9, 8, 6, 4, 4, - 5, 5, 5, 6, 3, 0, 2, 1, 1, 1, 2, 3, 6, 6, 5, 4, 1, 2, 3, - 11, 10, 7, 5, 2, 1, 2, 5, 6, 6, 7, 7, 8, 7, 4, 5, 6, 6, 7, - 7, 7, 3, 5, 6, 6, 6, 6, 6, 2, 3, 3, 4, 4, 4, 3, 2, 3, 4, - 4, 4, 3, 3, 6, 8, 7, 7, 6, 5, 5, 11, 13, 9, 8, 8, 7, 6, 6, - 7, 7, 7, 8, 7, 7, 7, 8, 8, 9, 9, 7, 7, 7, 10, 10, 10, 11, 9, - 6, 7, 11, 10, 10, 10, 10, 5, 7, 11, 10, 10, 10, 10, 6, 9, 13, 13, 12, - 11, 10, 8, 12, 15, 15, 13, 12, 11, 9, 14, 15, 14, 14, 13, 9, 7, 14, 16, - 15, 15, 14, 11, 6, 14, 17, 16, 16, 14, 11, 7, 14, 16, 16, 15, 14, 11, 8, - 13, 15, 17, 16, 14, 11, 9, 13, 16, 20, 18, 14, 12, 10, 15, 18, 20, 19, 16, - 13, 10, 18, 23, 21, 17, 15, 12, 8, 18, 22, 23, 18, 16, 13, 9, 18, 23, 24, - 18, 16, 13, 10, 19, 22, 24, 19, 15, 13, 10, 17, 20, 23, 20, 16, 13, 11, 17, - 20, 23, 22, 18, 14, 11, 18, 22, 24, 24, 19, 15, 12, 7, 8, 10, 12, 12, 11, - 9, 6, 8, 9, 12, 12, 9, 8, 6, 7, 8, 10, 11, 8, 6, 6, 6, 6, 7, - 9, 6, 3, 3, 3, 4, 4, 4, 3, 2, 1, 2, 2, 2, 3, 3, 2, 7, 6, - 3, 2, 3, 3, 2, 6, 7, 8, 10, 10, 9, 8, 6, 7, 8, 10, 9, 8, 7, - 5, 6, 7, 8, 8, 7, 5, 4, 5, 5, 6, 5, 5, 2, 2, 2, 2, 3, 2, - 2, 2, 3, 3, 3, 2, 2, 2, 2, 10, 8, 5, 3, 1, 2, 2, 5, 6, 7, - 8, 9, 9, 8, 4, 6, 7, 8, 8, 8, 8, 4, 5, 6, 6, 6, 6, 6, 4, - 4, 4, 4, 4, 4, 3, 2, 0, 1, 1, 1, 2, 3, 6, 5, 5, 3, 1, 1, - 2, 12, 11, 7, 4, 2, 1, 2, 4, 6, 7, 8, 9, 9, 9, 4, 5, 7, 8, - 8, 8, 9, 3, 5, 6, 7, 7, 7, 7, 4, 4, 5, 5, 5, 5, 5, 3, 6, - 6, 6, 7, 7, 7, 6, 12, 11, 10, 9, 7, 8, 12, 17, 14, 12, 10, 9, 9, - 9, 10, 10, 10, 11, 10, 9, 10, 11, 11, 12, 12, 11, 9, 11, 12, 13, 13, 13, - 12, 8, 10, 14, 13, 14, 14, 13, 8, 11, 16, 16, 16, 16, 14, 9, 13, 19, 21, - 20, 19, 16, 11, 17, 22, 24, 22, 20, 18, 12, 18, 20, 20, 20, 17, 13, 9, 18, - 22, 22, 22, 19, 14, 9, 18, 24, 24, 24, 19, 15, 10, 19, 23, 25, 24, 21, 16, - 11, 17, 23, 27, 25, 23, 18, 13, 19, 25, 31, 28, 25, 20, 14, 23, 28, 31, 30, - 26, 22, 16, 27, 33, 32, 26, 21, 16, 11, 26, 32, 33, 28, 23, 17, 12, 27, 32, - 35, 28, 23, 18, 13, 26, 32, 36, 29, 25, 19, 14, 26, 31, 33, 31, 26, 22, 16, - 25, 30, 35, 33, 28, 23, 18, 27, 31, 34, 35, 30, 25, 20, 9, 11, 12, 14, 13, - 13, 12, 8, 11, 12, 13, 13, 11, 10, 6, 10, 11, 12, 12, 10, 8, 5, 8, 9, - 10, 10, 8, 5, 2, 5, 6, 6, 6, 5, 4, 1, 3, 4, 5, 5, 5, 4, 7, - 7, 5, 4, 5, 5, 4, 6, 10, 11, 13, 12, 12, 10, 5, 9, 11, 12, 12, 11, - 9, 4, 7, 10, 11, 10, 9, 7, 4, 5, 7, 8, 8, 7, 4, 2, 2, 4, 5, - 5, 4, 4, 4, 3, 5, 4, 4, 4, 4, 10, 8, 6, 5, 3, 4, 4, 5, 7, - 9, 10, 11, 10, 10, 4, 6, 8, 9, 10, 8, 8, 4, 5, 7, 7, 7, 7, 6, - 4, 3, 3, 3, 4, 4, 2, 2, 1, 0, 0, 0, 1, 2, 6, 5, 4, 3, 2, - 1, 2, 12, 10, 7, 5, 4, 3, 2, 4, 6, 7, 8, 10, 11, 10, 3, 6, 7, - 8, 9, 9, 9, 3, 6, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 7, 6, 4, - 8, 7, 8, 8, 8, 8, 7, 13, 12, 11, 10, 9, 9, 12, 18, 15, 13, 11, 10, - 10, 11, 12, 12, 12, 13, 12, 10, 11, 13, 13, 13, 14, 12, 9, 12, 14, 14, 14, - 14, 13, 9, 11, 16, 15, 15, 15, 14, 9, 12, 18, 17, 17, 17, 15, 11, 14, 20, - 21, 21, 19, 16, 12, 18, 23, 26, 23, 21, 18, 13, 20, 22, 22, 22, 19, 15, 11, - 19, 24, 23, 24, 19, 15, 11, 20, 26, 24, 24, 20, 15, 11, 20, 25, 26, 26, 21, - 17, 12, 19, 25, 29, 27, 23, 18, 13, 20, 26, 32, 32, 26, 19, 14, 23, 29, 33, - 35, 28, 22, 16, 27, 35, 33, 28, 21, 17, 13, 29, 34, 36, 29, 23, 18, 13, 28, - 35, 38, 30, 24, 19, 14, 29, 34, 38, 30, 25, 20, 15, 27, 34, 38, 34, 28, 22, - 17, 27, 34, 39, 38, 31, 24, 19, 30, 36, 40, 41, 34, 26, 21, 9, 13, 16, 19, - 18, 17, 14, 8, 11, 15, 18, 18, 16, 13, 6, 10, 14, 16, 16, 13, 10, 5, 8, - 11, 13, 14, 11, 8, 2, 5, 7, 10, 11, 9, 7, 2, 3, 5, 7, 10, 9, 7, - 7, 6, 6, 7, 9, 9, 7, 7, 10, 14, 16, 16, 14, 11, 5, 9, 12, 15, 16, - 13, 9, 4, 7, 11, 13, 13, 11, 7, 4, 5, 8, 10, 10, 9, 4, 2, 2, 4, - 7, 7, 7, 4, 4, 3, 5, 5, 5, 6, 4, 9, 7, 6, 5, 4, 5, 4, 5, - 7, 9, 10, 12, 10, 9, 4, 6, 8, 9, 10, 9, 8, 4, 5, 7, 7, 7, 7, - 5, 4, 3, 3, 3, 4, 4, 2, 1, 1, 0, 0, 0, 1, 2, 6, 5, 4, 3, - 2, 1, 2, 11, 9, 7, 5, 3, 2, 2, 4, 6, 7, 8, 9, 11, 10, 4, 6, - 7, 8, 8, 9, 8, 3, 6, 7, 6, 6, 7, 7, 6, 6, 6, 6, 6, 6, 5, - 5, 8, 7, 7, 8, 8, 7, 7, 13, 12, 11, 10, 9, 9, 11, 17, 15, 13, 11, - 10, 10, 11, 12, 12, 12, 13, 13, 10, 11, 13, 13, 14, 14, 13, 8, 11, 14, 15, - 14, 14, 12, 9, 11, 17, 15, 15, 15, 13, 9, 11, 18, 17, 17, 17, 15, 10, 15, - 21, 22, 21, 19, 16, 12, 19, 23, 25, 23, 21, 18, 13, 21, 22, 22, 21, 19, 15, - 11, 20, 24, 24, 23, 20, 15, 10, 21, 26, 26, 24, 20, 15, 11, 20, 26, 26, 25, - 21, 16, 12, 19, 25, 29, 27, 23, 18, 13, 21, 26, 33, 32, 25, 20, 15, 24, 30, - 33, 33, 28, 22, 16, 28, 35, 33, 27, 21, 17, 13, 29, 35, 36, 29, 22, 18, 13, - 29, 35, 39, 30, 23, 18, 14, 29, 34, 38, 32, 25, 19, 14, 28, 33, 39, 34, 27, - 22, 17, 28, 33, 39, 38, 30, 24, 18, 29, 34, 39, 40, 33, 26, 20, 9, 13, 16, - 20, 20, 18, 15, 8, 12, 15, 19, 20, 17, 13, 7, 10, 14, 17, 18, 14, 11, 5, - 8, 11, 14, 16, 13, 8, 3, 5, 7, 10, 13, 10, 8, 2, 3, 5, 8, 11, 10, - 8, 3, 4, 4, 7, 10, 11, 8, 7, 10, 14, 17, 16, 14, 11, 5, 9, 13, 17, - 16, 12, 9, 5, 8, 11, 14, 14, 11, 7, 4, 6, 8, 11, 10, 9, 4, 2, 2, - 5, 7, 7, 7, 4, 3, 2, 4, 5, 6, 6, 4, 6, 3, 3, 5, 4, 5, 4, - 5, 8, 10, 11, 12, 10, 10, 4, 6, 8, 9, 10, 9, 8, 4, 5, 7, 7, 7, - 7, 5, 4, 4, 3, 4, 4, 4, 2, 1, 1, 0, 0, 0, 1, 2, 5, 3, 3, - 2, 2, 1, 2, 7, 5, 4, 4, 3, 2, 2, 4, 6, 7, 8, 9, 11, 10, 4, - 6, 7, 8, 9, 9, 8, 3, 6, 7, 6, 7, 7, 6, 6, 6, 6, 6, 6, 6, - 5, 5, 8, 8, 8, 8, 7, 7, 5, 10, 10, 10, 10, 8, 8, 7, 13, 12, 11, - 11, 10, 10, 11, 12, 12, 13, 13, 12, 10, 12, 13, 13, 14, 14, 13, 8, 12, 15, - 15, 14, 14, 13, 9, 11, 17, 15, 15, 15, 13, 9, 12, 18, 17, 17, 16, 15, 10, - 14, 19, 21, 19, 19, 16, 12, 15, 20, 23, 21, 21, 18, 13, 22, 22, 22, 21, 19, - 15, 11, 21, 24, 23, 23, 19, 15, 11, 20, 26, 25, 24, 20, 15, 11, 21, 25, 26, - 26, 21, 16, 12, 20, 25, 30, 27, 23, 18, 13, 21, 26, 32, 31, 25, 19, 15, 21, - 26, 32, 31, 27, 21, 16, 29, 35, 32, 26, 22, 17, 13, 29, 34, 35, 29, 23, 18, - 14, 29, 35, 37, 30, 23, 18, 14, 29, 34, 38, 31, 25, 20, 15, 28, 32, 37, 33, - 27, 22, 16, 28, 34, 38, 36, 30, 24, 18, 29, 34, 39, 39, 32, 26, 20, 8, 12, - 16, 19, 20, 17, 14, 7, 11, 15, 19, 19, 16, 12, 6, 9, 13, 16, 17, 14, 10, - 4, 7, 10, 13, 15, 12, 8, 1, 4, 7, 9, 13, 11, 8, 2, 3, 5, 8, 12, - 11, 8, 4, 4, 4, 7, 10, 11, 8, 6, 10, 13, 16, 16, 14, 10, 5, 8, 12, - 15, 16, 12, 8, 3, 7, 11, 13, 13, 10, 6, 3, 5, 8, 10, 9, 8, 4, 1, - 2, 4, 7, 7, 7, 4, 3, 3, 4, 6, 5, 6, 4, 6, 4, 3, 5, 4, 4, - 4, 4, 7, 9, 10, 11, 9, 8, 3, 5, 8, 9, 9, 8, 6, 3, 4, 6, 6, - 6, 6, 4, 3, 2, 3, 3, 3, 3, 1, 2, 2, 1, 1, 1, 0, 1, 4, 3, - 3, 2, 2, 2, 1, 8, 6, 4, 3, 3, 2, 2, 3, 5, 6, 7, 8, 10, 9, - 2, 6, 6, 7, 7, 8, 7, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 5, 6, 8, 8, 8, 8, 8, 7, 5, 10, 10, 9, 9, 8, 8, 8, 14, 12, - 11, 10, 10, 10, 11, 12, 12, 12, 13, 13, 9, 12, 14, 13, 14, 14, 12, 7, 12, - 15, 15, 14, 14, 13, 8, 12, 17, 15, 15, 15, 13, 9, 13, 19, 17, 17, 16, 15, - 10, 14, 19, 20, 18, 18, 16, 11, 14, 20, 23, 21, 19, 18, 13, 21, 23, 22, 21, - 18, 14, 10, 22, 25, 23, 23, 19, 15, 11, 21, 26, 25, 23, 19, 15, 11, 21, 25, - 26, 24, 21, 16, 11, 20, 25, 28, 26, 22, 17, 13, 21, 26, 30, 28, 23, 19, 15, - 21, 27, 30, 30, 25, 20, 16, 28, 33, 30, 25, 21, 17, 13, 28, 33, 33, 26, 22, - 18, 13, 29, 33, 35, 27, 22, 18, 14, 29, 32, 35, 29, 23, 19, 15, 27, 32, 36, - 31, 25, 20, 16, 28, 32, 35, 34, 27, 23, 18, 27, 31, 36, 35, 29, 23, 19, 8, - 10, 13, 16, 15, 13, 10, 7, 10, 12, 15, 15, 12, 8, 6, 8, 11, 13, 14, 10, - 7, 5, 6, 9, 10, 13, 9, 6, 2, 5, 7, 9, 12, 9, 6, 3, 5, 6, 8, - 11, 10, 6, 4, 4, 6, 8, 10, 9, 6, 6, 9, 11, 13, 12, 10, 7, 5, 8, - 10, 13, 12, 8, 5, 4, 7, 9, 10, 9, 7, 4, 2, 5, 7, 8, 7, 6, 3, - 1, 3, 5, 7, 6, 5, 3, 3, 3, 5, 6, 5, 5, 3, 6, 4, 5, 6, 5, - 4, 3, 4, 7, 8, 8, 9, 7, 6, 2, 6, 7, 7, 7, 5, 4, 2, 5, 6, - 5, 4, 4, 2, 2, 3, 3, 3, 3, 2, 0, 3, 3, 2, 2, 2, 1, 0, 5, - 4, 3, 2, 2, 1, 0, 8, 5, 3, 3, 2, 2, 1, 2, 4, 4, 5, 7, 8, - 8, 1, 5, 4, 5, 6, 6, 6, 1, 6, 5, 5, 5, 5, 5, 5, 6, 5, 5, - 5, 5, 4, 5, 8, 7, 7, 7, 6, 6, 5, 10, 9, 8, 8, 8, 7, 8, 13, - 12, 10, 9, 9, 9, 11, 11, 11, 11, 12, 11, 8, 12, 12, 12, 13, 12, 11, 6, - 12, 14, 14, 13, 12, 11, 7, 12, 16, 14, 13, 13, 12, 8, 13, 18, 16, 16, 15, - 13, 9, 14, 19, 20, 17, 16, 14, 10, 15, 20, 23, 20, 18, 16, 12, 20, 21, 19, - 18, 15, 13, 9, 20, 22, 20, 18, 16, 13, 9, 20, 24, 22, 20, 16, 13, 10, 20, - 24, 23, 21, 17, 14, 11, 19, 23, 26, 24, 20, 16, 12, 20, 24, 30, 28, 23, 17, - 14, 21, 26, 29, 30, 25, 19, 14, 26, 30, 28, 22, 17, 15, 12, 26, 30, 29, 24, - 18, 15, 11, 26, 30, 32, 25, 19, 16, 12, 25, 29, 33, 26, 21, 17, 13, 25, 29, - 33, 30, 24, 20, 15, 26, 31, 35, 34, 27, 20, 16, 27, 32, 35, 35, 29, 23, 17, - 14, 17, 21, 24, 24, 22, 19, 13, 16, 20, 24, 25, 21, 18, 12, 15, 18, 21, 23, - 19, 15, 12, 13, 15, 17, 21, 16, 12, 9, 9, 11, 14, 14, 15, 12, 5, 5, 8, - 11, 13, 14, 12, 2, 3, 6, 9, 13, 15, 12, 13, 15, 19, 21, 22, 19, 17, 12, - 14, 17, 20, 21, 18, 14, 11, 13, 15, 18, 18, 16, 12, 11, 11, 13, 14, 15, 12, - 7, 8, 8, 9, 10, 9, 10, 7, 3, 3, 5, 7, 9, 9, 7, 3, 3, 3, 6, - 8, 8, 7, 11, 13, 14, 16, 18, 17, 15, 11, 12, 14, 15, 16, 15, 14, 10, 11, - 13, 13, 13, 13, 12, 10, 10, 10, 10, 11, 9, 5, 6, 6, 6, 6, 5, 5, 5, - 0, 2, 1, 2, 4, 4, 5, 4, 4, 2, 1, 3, 4, 5, 10, 11, 13, 14, 15, - 16, 15, 10, 11, 12, 14, 14, 15, 14, 9, 10, 12, 12, 12, 13, 12, 6, 9, 9, - 9, 10, 9, 7, 4, 5, 4, 5, 5, 4, 4, 0, 2, 2, 2, 3, 3, 5, 4, - 6, 3, 3, 3, 4, 5, 9, 10, 12, 13, 14, 15, 15, 8, 9, 11, 12, 13, 13, - 14, 8, 9, 10, 10, 11, 11, 12, 8, 8, 8, 8, 9, 8, 5, 5, 8, 7, 7, - 7, 6, 5, 4, 7, 7, 7, 7, 7, 5, 5, 8, 9, 8, 8, 8, 5, 11, 12, - 12, 13, 12, 14, 15, 11, 13, 13, 13, 12, 12, 13, 11, 14, 14, 13, 11, 10, 11, - 11, 13, 13, 13, 11, 9, 5, 9, 11, 13, 12, 10, 8, 5, 8, 11, 14, 13, 11, - 8, 6, 8, 12, 15, 15, 11, 9, 7, 15, 19, 18, 15, 13, 13, 14, 15, 19, 20, - 16, 13, 11, 12, 15, 18, 21, 16, 14, 11, 9, 15, 18, 20, 15, 13, 9, 6, 14, - 16, 19, 16, 11, 9, 7, 13, 15, 18, 17, 13, 10, 8, 12, 16, 19, 19, 14, 11, - 8, 12, 14, 15, 17, 17, 16, 14, 12, 13, 15, 16, 17, 14, 13, 11, 12, 14, 15, - 15, 12, 11, 10, 11, 11, 12, 12, 8, 4, 8, 8, 8, 8, 6, 5, 4, 4, 4, - 4, 3, 4, 5, 4, 2, 2, 2, 3, 4, 5, 4, 11, 13, 14, 15, 16, 15, 14, - 10, 12, 13, 15, 15, 14, 12, 10, 11, 13, 13, 13, 12, 10, 9, 10, 10, 10, 11, - 9, 4, 7, 7, 7, 7, 4, 4, 4, 2, 3, 3, 3, 3, 4, 4, 5, 4, 2, - 2, 3, 3, 4, 10, 11, 13, 14, 15, 15, 15, 9, 10, 12, 13, 14, 14, 13, 9, - 10, 12, 12, 12, 11, 10, 9, 9, 9, 9, 9, 8, 4, 5, 5, 5, 5, 3, 3, - 4, 2, 0, 1, 2, 2, 3, 4, 7, 6, 2, 0, 3, 3, 4, 10, 11, 12, 13, - 15, 16, 16, 9, 11, 12, 13, 14, 14, 14, 8, 11, 12, 12, 12, 12, 11, 5, 9, - 9, 9, 9, 8, 7, 3, 5, 5, 5, 5, 5, 5, 2, 7, 7, 6, 6, 6, 7, - 7, 13, 10, 8, 8, 8, 8, 10, 11, 12, 13, 14, 16, 16, 9, 10, 11, 13, 14, - 14, 14, 9, 11, 11, 11, 12, 12, 11, 9, 12, 11, 12, 12, 11, 7, 8, 13, 14, - 13, 14, 13, 9, 9, 15, 17, 17, 16, 15, 10, 12, 17, 19, 18, 18, 16, 11, 16, - 19, 18, 19, 16, 15, 16, 16, 21, 21, 21, 17, 13, 13, 16, 22, 23, 21, 17, 12, - 10, 16, 22, 23, 23, 19, 14, 10, 15, 21, 25, 23, 21, 17, 11, 16, 22, 27, 25, - 21, 18, 13, 18, 22, 26, 25, 23, 20, 15, 25, 30, 29, 25, 19, 15, 14, 25, 30, - 31, 26, 20, 15, 12, 25, 30, 33, 26, 21, 16, 11, 25, 30, 34, 28, 22, 18, 14, - 24, 29, 32, 27, 23, 20, 16, 24, 27, 30, 29, 24, 21, 17, 23, 27, 30, 30, 25, - 22, 19, 13, 16, 17, 18, 18, 17, 16, 12, 15, 17, 18, 18, 16, 14, 11, 14, 16, - 16, 15, 13, 11, 10, 12, 13, 13, 13, 10, 5, 7, 9, 10, 10, 8, 6, 5, 3, - 5, 7, 5, 6, 6, 5, 2, 3, 5, 5, 6, 6, 5, 11, 14, 16, 17, 17, 17, - 15, 10, 13, 15, 16, 17, 15, 13, 9, 12, 15, 15, 14, 13, 10, 9, 9, 12, 13, - 11, 9, 5, 7, 6, 8, 9, 6, 5, 5, 2, 2, 5, 5, 5, 5, 5, 5, 3, - 3, 5, 4, 5, 5, 9, 12, 14, 15, 16, 15, 14, 9, 10, 12, 14, 15, 13, 12, - 9, 10, 11, 11, 11, 11, 9, 9, 8, 8, 8, 8, 7, 3, 5, 5, 5, 4, 3, - 3, 3, 1, 1, 0, 1, 2, 3, 3, 6, 5, 3, 1, 2, 3, 3, 9, 11, 11, - 13, 15, 15, 15, 9, 11, 12, 13, 14, 14, 13, 7, 11, 11, 11, 11, 11, 10, 5, - 9, 8, 8, 8, 7, 7, 3, 5, 5, 6, 6, 6, 6, 2, 8, 8, 7, 7, 8, - 8, 6, 12, 11, 9, 9, 9, 9, 10, 10, 11, 13, 14, 15, 15, 9, 11, 12, 13, - 13, 13, 13, 10, 12, 13, 13, 13, 11, 9, 10, 13, 13, 13, 13, 12, 8, 9, 15, - 14, 15, 15, 14, 9, 10, 16, 18, 17, 17, 15, 11, 13, 18, 21, 18, 18, 17, 13, - 18, 20, 20, 20, 17, 15, 15, 18, 22, 21, 21, 18, 13, 12, 18, 24, 24, 23, 18, - 14, 10, 18, 23, 25, 24, 20, 15, 11, 18, 23, 27, 26, 21, 17, 13, 17, 23, 29, - 28, 24, 18, 14, 19, 25, 29, 31, 26, 20, 16, 27, 33, 32, 25, 20, 16, 14, 26, - 32, 34, 27, 22, 17, 12, 27, 33, 36, 28, 22, 17, 12, 27, 32, 37, 29, 24, 19, - 14, 25, 31, 37, 32, 26, 20, 16, 25, 31, 36, 35, 28, 22, 17, 26, 32, 37, 37, - 30, 24, 19, 12, 16, 19, 22, 22, 20, 18, 12, 15, 18, 21, 21, 19, 15, 10, 13, - 17, 19, 19, 17, 13, 8, 11, 14, 16, 17, 13, 8, 6, 8, 10, 12, 12, 10, 8, - 2, 4, 7, 9, 11, 10, 8, 2, 3, 5, 8, 10, 10, 8, 10, 13, 17, 20, 20, - 17, 14, 9, 12, 16, 19, 19, 16, 12, 8, 11, 14, 17, 16, 14, 9, 8, 9, 11, - 13, 13, 11, 5, 5, 5, 8, 10, 8, 8, 5, 1, 2, 4, 6, 6, 7, 5, 4, - 3, 3, 5, 5, 6, 5, 8, 11, 13, 14, 16, 13, 13, 8, 9, 12, 13, 14, 12, - 11, 7, 8, 10, 10, 10, 10, 7, 8, 7, 7, 7, 7, 6, 2, 4, 3, 3, 3, - 2, 2, 2, 2, 2, 1, 0, 1, 2, 2, 4, 3, 2, 2, 1, 2, 2, 8, 9, - 10, 11, 13, 14, 14, 8, 9, 10, 11, 12, 12, 11, 5, 9, 10, 9, 9, 9, 8, - 5, 8, 7, 6, 7, 6, 6, 3, 6, 6, 6, 6, 6, 6, 2, 8, 8, 7, 7, - 7, 7, 4, 11, 10, 9, 9, 9, 9, 9, 11, 11, 12, 13, 13, 13, 9, 11, 12, - 12, 13, 12, 11, 10, 13, 14, 13, 13, 11, 8, 10, 15, 13, 14, 14, 12, 8, 10, - 16, 15, 15, 15, 13, 9, 11, 16, 18, 17, 16, 14, 11, 12, 17, 20, 19, 18, 17, - 12, 19, 21, 20, 20, 18, 14, 13, 18, 23, 22, 22, 18, 14, 10, 19, 24, 24, 23, - 19, 14, 10, 19, 24, 25, 23, 20, 15, 10, 18, 24, 28, 26, 21, 17, 12, 18, 24, - 30, 29, 23, 18, 13, 18, 24, 30, 30, 25, 19, 15, 27, 34, 32, 26, 20, 16, 12, - 27, 34, 34, 28, 22, 17, 12, 27, 34, 37, 28, 22, 17, 13, 28, 33, 37, 30, 23, - 18, 14, 26, 32, 36, 33, 25, 19, 15, 26, 31, 36, 34, 28, 21, 17, 26, 31, 36, - 37, 29, 24, 18, 11, 15, 18, 21, 22, 20, 16, 10, 14, 17, 21, 22, 18, 14, 8, - 12, 16, 19, 20, 16, 12, 7, 10, 13, 16, 18, 14, 9, 4, 7, 9, 12, 14, 12, - 9, 0, 3, 6, 9, 13, 12, 9, 3, 3, 5, 8, 11, 12, 9, 8, 12, 16, 19, - 18, 16, 12, 7, 11, 14, 18, 18, 14, 10, 6, 10, 13, 16, 15, 13, 9, 6, 7, - 10, 12, 12, 10, 5, 3, 4, 6, 9, 9, 8, 5, 2, 2, 4, 6, 7, 7, 5, - 5, 4, 3, 6, 5, 6, 5, 6, 10, 11, 13, 14, 12, 11, 5, 8, 10, 11, 12, - 11, 8, 5, 7, 9, 9, 9, 9, 6, 6, 5, 5, 5, 6, 5, 3, 1, 1, 2, - 2, 2, 2, 2, 4, 3, 2, 1, 0, 1, 2, 7, 4, 3, 2, 1, 1, 2, 6, - 7, 8, 9, 10, 12, 11, 5, 7, 8, 9, 9, 9, 9, 4, 7, 7, 7, 7, 7, - 6, 5, 6, 6, 5, 5, 5, 5, 3, 7, 6, 6, 6, 6, 6, 4, 9, 8, 8, - 8, 7, 7, 7, 12, 10, 9, 9, 9, 9, 10, 11, 11, 11, 12, 12, 11, 11, 12, - 12, 13, 13, 11, 9, 11, 14, 14, 13, 13, 11, 8, 11, 15, 14, 13, 14, 12, 8, - 11, 17, 16, 15, 15, 13, 9, 12, 17, 18, 17, 16, 15, 10, 13, 17, 20, 19, 18, - 16, 12, 20, 21, 20, 21, 18, 14, 11, 20, 23, 23, 23, 19, 14, 9, 19, 25, 24, - 23, 19, 14, 10, 20, 24, 26, 24, 20, 15, 11, 18, 24, 27, 26, 21, 16, 12, 19, - 23, 30, 29, 23, 18, 14, 19, 24, 29, 31, 25, 20, 15, 28, 34, 32, 26, 21, 16, - 12, 27, 34, 34, 27, 21, 17, 12, 27, 33, 36, 29, 23, 18, 13, 28, 32, 37, 29, - 24, 19, 13, 26, 32, 36, 33, 25, 20, 15, 26, 32, 37, 33, 28, 22, 17, 27, 32, - 35, 36, 30, 23, 18, 10, 14, 18, 21, 21, 18, 15, 9, 12, 16, 20, 21, 17, 13, - 7, 11, 15, 18, 19, 16, 11, 6, 9, 12, 14, 16, 14, 9, 3, 6, 8, 11, 14, - 12, 9, 2, 4, 6, 9, 13, 12, 9, 4, 4, 5, 8, 11, 12, 9, 7, 11, 14, - 18, 18, 15, 11, 6, 10, 13, 17, 17, 13, 9, 5, 8, 12, 14, 14, 12, 8, 4, - 6, 9, 11, 11, 10, 5, 1, 3, 5, 8, 8, 8, 5, 2, 3, 4, 7, 7, 7, - 5, 6, 4, 4, 6, 5, 6, 5, 5, 8, 10, 11, 13, 11, 9, 3, 7, 9, 10, - 11, 9, 7, 3, 6, 7, 8, 7, 7, 4, 3, 3, 4, 4, 4, 4, 1, 2, 1, - 1, 1, 1, 2, 1, 4, 3, 2, 2, 1, 0, 1, 8, 6, 3, 3, 2, 1, 1, - 3, 5, 6, 7, 8, 10, 9, 3, 5, 6, 7, 8, 8, 7, 2, 5, 6, 6, 5, - 6, 5, 5, 6, 6, 5, 5, 5, 4, 4, 8, 7, 6, 7, 6, 6, 4, 10, 8, - 8, 8, 8, 7, 8, 12, 11, 10, 9, 9, 9, 11, 11, 11, 11, 12, 12, 9, 12, - 13, 12, 13, 13, 12, 7, 12, 14, 14, 13, 12, 11, 8, 11, 16, 14, 14, 14, 12, - 8, 12, 18, 17, 15, 16, 13, 9, 13, 18, 19, 18, 16, 15, 11, 14, 18, 21, 19, - 19, 16, 12, 20, 21, 20, 20, 17, 14, 10, 20, 23, 22, 22, 18, 14, 9, 20, 25, - 24, 23, 19, 14, 10, 20, 25, 24, 23, 20, 15, 10, 19, 25, 26, 25, 21, 16, 12, - 20, 25, 29, 28, 22, 18, 14, 20, 25, 29, 30, 24, 19, 15, 28, 33, 29, 24, 20, - 16, 12, 28, 32, 31, 26, 21, 16, 12, 28, 32, 34, 27, 23, 17, 13, 27, 31, 35, - 28, 23, 18, 14, 26, 31, 34, 31, 24, 20, 15, 26, 31, 35, 33, 26, 21, 17, 27, - 30, 35, 35, 29, 22, 18, 8, 11, 12, 16, 15, 13, 10, 7, 10, 12, 15, 15, 12, - 8, 6, 8, 11, 13, 14, 10, 7, 5, 6, 9, 10, 12, 9, 6, 2, 5, 7, 9, - 12, 9, 6, 3, 5, 6, 8, 11, 9, 6, 4, 5, 6, 8, 10, 9, 6, 6, 9, - 11, 13, 12, 10, 7, 5, 8, 10, 12, 12, 8, 5, 4, 7, 9, 10, 9, 7, 4, - 2, 5, 7, 8, 7, 6, 3, 1, 3, 5, 7, 6, 5, 3, 3, 3, 5, 6, 5, - 5, 3, 6, 4, 5, 6, 5, 4, 3, 4, 7, 8, 8, 9, 7, 6, 2, 6, 7, - 7, 7, 5, 4, 2, 5, 6, 5, 4, 4, 2, 2, 3, 3, 3, 3, 2, 0, 3, - 2, 2, 2, 2, 1, 0, 5, 4, 3, 2, 2, 1, 0, 8, 6, 3, 2, 2, 2, - 1, 2, 4, 4, 5, 6, 7, 8, 1, 4, 4, 5, 6, 5, 6, 1, 6, 5, 5, - 5, 5, 5, 5, 6, 5, 5, 5, 5, 4, 5, 8, 7, 7, 7, 7, 6, 5, 10, - 9, 8, 8, 8, 7, 8, 13, 12, 10, 9, 9, 9, 11, 11, 11, 11, 12, 11, 8, - 12, 12, 13, 12, 12, 11, 6, 12, 14, 14, 13, 12, 11, 7, 12, 16, 14, 13, 13, - 12, 8, 12, 18, 17, 15, 15, 13, 9, 13, 19, 20, 18, 16, 14, 10, 14, 20, 23, - 20, 18, 16, 11, 20, 20, 19, 17, 15, 13, 9, 20, 22, 20, 19, 16, 13, 9, 20, - 23, 22, 20, 17, 13, 10, 19, 24, 24, 21, 17, 14, 11, 19, 24, 26, 24, 20, 16, - 12, 20, 24, 30, 27, 22, 17, 13, 21, 25, 30, 29, 24, 19, 14, 26, 30, 27, 21, - 17, 14, 12, 26, 30, 29, 23, 18, 15, 12, 26, 30, 32, 25, 19, 16, 12, 26, 29, - 33, 26, 21, 17, 13, 25, 29, 33, 30, 24, 19, 15, 25, 31, 34, 34, 27, 21, 16, - 27, 32, 35, 35, 29, 23, 17, 20, 21, 23, 25, 26, 24, 23, 20, 21, 23, 24, 25, - 23, 20, 19, 21, 21, 23, 24, 20, 16, 18, 19, 19, 19, 20, 15, 11, 15, 15, 15, - 14, 14, 15, 10, 11, 11, 8, 10, 12, 14, 10, 5, 3, 5, 8, 11, 14, 10, 19, - 20, 22, 24, 24, 23, 22, 18, 20, 21, 23, 24, 22, 20, 17, 19, 20, 20, 21, 18, - 16, 17, 17, 18, 18, 16, 13, 8, 14, 14, 14, 12, 9, 9, 8, 9, 9, 7, 6, - 8, 8, 8, 2, 2, 4, 5, 7, 8, 8, 17, 19, 20, 21, 23, 24, 22, 17, 18, - 20, 21, 22, 21, 19, 17, 18, 19, 19, 19, 18, 15, 16, 16, 16, 16, 15, 12, 9, - 11, 12, 12, 11, 7, 8, 8, 4, 7, 6, 4, 6, 8, 8, 0, 2, 2, 4, 6, - 6, 8, 17, 18, 20, 21, 22, 23, 23, 16, 18, 20, 20, 21, 21, 21, 14, 19, 19, - 19, 18, 18, 17, 10, 17, 16, 16, 15, 11, 11, 8, 12, 12, 10, 6, 7, 8, 5, - 5, 5, 3, 4, 6, 7, 0, 3, 3, 3, 4, 5, 6, 15, 17, 19, 20, 21, 23, - 23, 12, 17, 18, 20, 20, 20, 21, 12, 16, 16, 17, 17, 16, 15, 12, 13, 13, 13, - 12, 10, 7, 9, 9, 8, 8, 7, 6, 6, 6, 7, 7, 6, 7, 7, 6, 4, 6, - 8, 7, 7, 8, 6, 13, 14, 15, 16, 18, 21, 23, 13, 14, 15, 16, 17, 19, 19, - 13, 14, 15, 15, 14, 15, 14, 13, 13, 13, 13, 12, 9, 6, 10, 12, 13, 12, 9, - 8, 6, 9, 10, 13, 13, 10, 8, 6, 7, 10, 14, 14, 11, 8, 7, 16, 19, 18, - 16, 17, 20, 21, 16, 19, 20, 17, 15, 17, 18, 16, 18, 21, 16, 14, 13, 13, 16, - 17, 20, 15, 12, 10, 7, 14, 16, 18, 15, 11, 9, 7, 12, 15, 17, 16, 12, 10, - 8, 11, 15, 18, 17, 13, 10, 8, 18, 19, 21, 22, 22, 21, 21, 18, 19, 20, 22, - 22, 19, 18, 17, 18, 19, 20, 19, 17, 14, 17, 17, 17, 17, 15, 12, 8, 14, 13, - 13, 11, 9, 8, 8, 10, 10, 7, 7, 8, 9, 8, 4, 2, 4, 6, 8, 8, 8, - 17, 19, 20, 21, 22, 21, 20, 16, 18, 19, 20, 21, 19, 17, 16, 17, 19, 19, 18, - 16, 13, 16, 16, 16, 16, 14, 11, 7, 14, 12, 12, 11, 7, 7, 7, 9, 8, 6, - 5, 6, 7, 7, 2, 2, 3, 4, 6, 6, 7, 16, 17, 18, 20, 21, 21, 21, 16, - 17, 18, 19, 20, 19, 18, 15, 17, 17, 17, 16, 16, 13, 15, 15, 14, 14, 13, 10, - 6, 10, 11, 11, 9, 5, 6, 6, 4, 6, 5, 3, 4, 5, 6, 2, 0, 2, 3, - 4, 5, 6, 16, 17, 18, 19, 21, 22, 22, 15, 17, 19, 19, 20, 19, 19, 13, 17, - 18, 18, 17, 16, 15, 9, 16, 15, 15, 14, 10, 11, 7, 12, 11, 10, 5, 5, 7, - 4, 6, 5, 5, 5, 5, 6, 2, 7, 6, 6, 6, 6, 7, 15, 17, 18, 20, 20, - 22, 22, 12, 16, 18, 18, 19, 19, 19, 12, 15, 16, 16, 16, 15, 13, 12, 13, 13, - 13, 12, 10, 6, 10, 10, 11, 11, 13, 11, 7, 7, 11, 14, 14, 15, 13, 8, 8, - 13, 16, 16, 16, 15, 10, 14, 16, 17, 17, 19, 21, 21, 14, 18, 18, 19, 17, 18, - 18, 14, 19, 20, 19, 16, 14, 13, 14, 19, 21, 21, 17, 12, 8, 12, 18, 22, 21, - 18, 16, 10, 12, 19, 22, 20, 19, 17, 12, 14, 19, 22, 21, 20, 17, 13, 22, 27, - 27, 22, 18, 20, 20, 22, 28, 29, 24, 18, 17, 17, 22, 27, 30, 24, 19, 14, 12, - 22, 26, 30, 24, 20, 16, 12, 20, 25, 29, 24, 19, 17, 14, 20, 25, 26, 25, 20, - 18, 15, 21, 23, 25, 25, 22, 19, 17, 16, 19, 19, 21, 20, 20, 19, 15, 18, 19, - 20, 20, 18, 16, 14, 16, 18, 19, 18, 15, 13, 13, 15, 16, 15, 15, 11, 7, 10, - 11, 12, 11, 9, 7, 6, 6, 8, 8, 6, 7, 7, 6, 1, 3, 5, 6, 7, 7, - 6, 14, 17, 19, 19, 20, 19, 18, 13, 16, 18, 19, 19, 17, 15, 12, 14, 18, 17, - 16, 15, 12, 12, 12, 14, 15, 13, 10, 6, 9, 9, 11, 10, 7, 6, 6, 5, 5, - 7, 6, 6, 6, 6, 2, 1, 4, 5, 5, 6, 6, 12, 15, 16, 18, 19, 18, 17, - 12, 13, 16, 17, 17, 16, 14, 12, 12, 14, 14, 14, 13, 10, 11, 11, 10, 11, 10, - 8, 4, 7, 7, 7, 7, 4, 4, 3, 2, 2, 3, 2, 3, 3, 3, 2, 2, 0, - 2, 3, 4, 4, 12, 13, 14, 16, 17, 18, 17, 11, 13, 14, 15, 16, 16, 14, 9, - 13, 13, 14, 13, 13, 11, 6, 12, 11, 11, 10, 8, 8, 4, 8, 7, 7, 5, 5, - 6, 2, 6, 6, 6, 6, 6, 6, 2, 8, 8, 7, 7, 7, 8, 12, 12, 14, 15, - 16, 17, 17, 10, 12, 13, 14, 15, 15, 15, 10, 12, 12, 12, 12, 12, 10, 10, 12, - 11, 12, 12, 10, 7, 8, 13, 13, 13, 14, 12, 8, 8, 14, 16, 16, 16, 14, 9, - 10, 15, 18, 17, 18, 16, 11, 16, 19, 18, 19, 16, 17, 17, 15, 20, 20, 20, 16, - 14, 14, 15, 22, 22, 20, 17, 12, 10, 16, 21, 22, 23, 18, 13, 10, 15, 21, 25, - 24, 20, 16, 11, 15, 21, 27, 27, 22, 17, 12, 17, 22, 29, 30, 24, 19, 14, 24, - 31, 30, 24, 19, 16, 16, 25, 31, 33, 26, 19, 15, 13, 24, 30, 35, 27, 21, 16, - 11, 24, 30, 35, 27, 22, 17, 13, 24, 29, 35, 31, 24, 19, 14, 24, 29, 34, 34, - 27, 21, 16, 24, 30, 34, 35, 29, 23, 18, 14, 18, 21, 23, 23, 22, 19, 13, 17, - 20, 22, 23, 20, 17, 11, 15, 19, 20, 20, 18, 15, 10, 13, 16, 18, 18, 14, 9, - 7, 10, 12, 14, 14, 11, 9, 4, 6, 8, 10, 12, 11, 9, 2, 3, 6, 9, 11, - 11, 9, 12, 15, 19, 21, 21, 19, 16, 11, 14, 18, 21, 20, 17, 13, 9, 12, 16, - 18, 18, 15, 11, 9, 10, 13, 16, 14, 12, 7, 6, 7, 9, 11, 10, 9, 6, 2, - 3, 6, 8, 8, 8, 6, 4, 2, 4, 7, 7, 7, 6, 9, 13, 14, 16, 17, 16, - 14, 9, 11, 13, 15, 15, 13, 11, 9, 10, 12, 12, 12, 11, 8, 9, 8, 8, 9, - 9, 7, 3, 5, 4, 5, 5, 4, 3, 2, 1, 0, 1, 1, 2, 3, 2, 4, 3, - 2, 0, 2, 2, 3, 9, 10, 11, 12, 13, 14, 14, 9, 10, 11, 12, 13, 12, 12, - 7, 10, 10, 10, 10, 10, 9, 4, 9, 7, 7, 7, 6, 6, 2, 5, 4, 5, 5, - 5, 5, 1, 7, 6, 6, 6, 6, 6, 4, 9, 9, 8, 7, 7, 8, 9, 10, 10, - 12, 13, 14, 14, 9, 10, 11, 12, 12, 12, 12, 9, 12, 12, 12, 12, 10, 8, 9, - 13, 12, 12, 13, 11, 7, 8, 14, 13, 13, 13, 12, 8, 10, 15, 17, 16, 15, 13, - 9, 11, 16, 19, 17, 17, 15, 10, 17, 19, 18, 18, 16, 14, 14, 17, 21, 21, 20, - 17, 12, 11, 17, 23, 22, 21, 18, 13, 9, 17, 22, 24, 22, 19, 14, 9, 17, 21, - 26, 24, 20, 16, 10, 16, 22, 28, 27, 22, 16, 12, 16, 23, 28, 29, 24, 18, 13, - 26, 32, 31, 24, 19, 15, 13, 26, 31, 33, 26, 20, 15, 11, 25, 31, 34, 27, 21, - 16, 11, 26, 31, 36, 29, 22, 17, 12, 24, 30, 35, 32, 23, 18, 14, 25, 30, 35, - 33, 26, 21, 15, 25, 30, 35, 35, 29, 23, 17, 12, 16, 20, 23, 23, 20, 18, 12, - 15, 19, 22, 23, 19, 16, 10, 14, 17, 20, 21, 17, 14, 9, 11, 14, 17, 19, 15, - 10, 5, 8, 10, 13, 15, 13, 10, 2, 5, 7, 10, 13, 13, 10, 3, 3, 6, 9, - 12, 12, 10, 10, 14, 17, 21, 20, 17, 14, 9, 12, 16, 19, 20, 16, 12, 7, 11, - 15, 17, 17, 14, 10, 6, 8, 11, 13, 13, 12, 6, 4, 5, 8, 10, 9, 9, 6, - 1, 3, 5, 7, 8, 8, 6, 5, 3, 4, 6, 6, 7, 6, 7, 11, 13, 14, 15, - 13, 11, 6, 9, 12, 13, 13, 12, 9, 6, 8, 10, 10, 10, 10, 6, 6, 6, 7, - 7, 7, 7, 2, 2, 2, 3, 3, 3, 3, 2, 3, 3, 2, 1, 1, 2, 2, 5, - 4, 3, 2, 0, 1, 2, 6, 7, 8, 9, 11, 12, 11, 6, 7, 8, 9, 10, 10, - 9, 5, 7, 7, 7, 7, 7, 6, 3, 6, 5, 5, 5, 4, 5, 2, 6, 5, 5, - 5, 5, 5, 3, 8, 7, 7, 7, 6, 6, 5, 11, 9, 8, 8, 8, 8, 9, 10, - 10, 11, 11, 12, 11, 10, 11, 11, 12, 12, 11, 9, 10, 12, 13, 12, 12, 11, 7, - 10, 14, 13, 12, 13, 11, 7, 10, 16, 14, 14, 14, 12, 8, 11, 16, 17, 16, 15, - 13, 9, 12, 16, 20, 18, 17, 15, 11, 18, 20, 20, 19, 16, 13, 11, 18, 22, 21, - 21, 18, 13, 9, 19, 24, 24, 22, 18, 13, 9, 19, 23, 25, 23, 19, 14, 10, 17, - 23, 26, 25, 20, 15, 11, 18, 23, 28, 27, 22, 17, 13, 18, 24, 29, 29, 24, 19, - 14, 27, 32, 31, 25, 19, 15, 11, 27, 32, 33, 26, 21, 16, 11, 27, 33, 35, 27, - 22, 17, 12, 26, 32, 36, 29, 22, 18, 12, 26, 31, 36, 32, 24, 19, 14, 25, 30, - 36, 34, 26, 20, 16, 25, 30, 35, 36, 29, 23, 17, 11, 15, 19, 22, 22, 20, 17, - 10, 14, 17, 21, 22, 18, 15, 9, 12, 16, 19, 20, 17, 12, 7, 10, 13, 16, 18, - 15, 10, 4, 7, 9, 12, 15, 13, 10, 2, 5, 7, 10, 14, 13, 10, 4, 4, 6, - 9, 12, 13, 10, 9, 12, 16, 20, 19, 16, 12, 7, 11, 15, 18, 18, 15, 11, 6, - 9, 13, 16, 16, 13, 9, 5, 7, 10, 13, 12, 11, 6, 1, 4, 7, 9, 9, 9, - 6, 3, 3, 5, 8, 8, 8, 6, 5, 4, 5, 7, 7, 7, 6, 6, 10, 12, 12, - 14, 12, 9, 4, 8, 10, 12, 12, 11, 7, 4, 7, 9, 9, 9, 9, 5, 4, 5, - 6, 5, 6, 6, 2, 1, 1, 3, 2, 2, 2, 2, 4, 3, 3, 2, 1, 1, 2, - 7, 5, 4, 2, 1, 0, 1, 4, 5, 6, 7, 9, 10, 9, 4, 5, 6, 7, 8, - 8, 7, 4, 5, 6, 5, 5, 5, 5, 4, 5, 4, 4, 4, 4, 3, 2, 6, 5, - 5, 5, 5, 5, 4, 8, 7, 7, 7, 6, 6, 7, 12, 9, 9, 8, 8, 8, 10, - 10, 10, 11, 11, 11, 9, 11, 12, 11, 12, 12, 10, 7, 11, 13, 13, 12, 12, 10, - 7, 11, 15, 13, 13, 13, 11, 7, 11, 16, 15, 14, 14, 12, 8, 12, 17, 17, 16, - 16, 13, 9, 13, 17, 21, 18, 17, 16, 11, 20, 20, 19, 19, 16, 13, 9, 19, 22, - 21, 20, 18, 13, 9, 19, 24, 23, 22, 17, 13, 9, 19, 23, 25, 22, 18, 14, 9, - 18, 23, 26, 24, 20, 16, 11, 18, 23, 28, 27, 21, 17, 13, 19, 23, 29, 29, 24, - 19, 14, 27, 31, 29, 24, 20, 16, 11, 26, 30, 31, 25, 20, 16, 12, 27, 32, 33, - 27, 21, 16, 11, 27, 31, 34, 28, 22, 17, 12, 26, 29, 34, 30, 23, 19, 14, 25, - 30, 34, 32, 25, 21, 16, 25, 30, 35, 34, 28, 22, 17, 10, 14, 17, 19, 19, 17, - 14, 9, 13, 15, 18, 19, 16, 13, 8, 11, 14, 16, 18, 15, 11, 7, 9, 12, 15, - 17, 13, 10, 3, 6, 9, 12, 15, 13, 10, 3, 5, 8, 10, 14, 13, 10, 5, 4, - 7, 10, 12, 13, 10, 8, 11, 15, 17, 16, 14, 11, 7, 10, 14, 16, 15, 13, 10, - 5, 9, 12, 15, 13, 12, 8, 4, 6, 9, 12, 11, 10, 6, 1, 4, 7, 9, 9, - 9, 6, 3, 4, 5, 8, 8, 8, 6, 7, 5, 5, 7, 7, 7, 6, 5, 9, 11, - 11, 12, 11, 8, 3, 7, 10, 10, 11, 9, 5, 2, 6, 8, 8, 8, 8, 3, 2, - 4, 5, 5, 5, 5, 2, 2, 2, 3, 2, 2, 2, 1, 5, 4, 3, 2, 2, 1, - 1, 8, 6, 4, 3, 2, 1, 0, 2, 4, 4, 6, 7, 9, 8, 2, 3, 4, 6, - 6, 6, 6, 1, 4, 4, 4, 4, 4, 4, 4, 5, 4, 4, 4, 4, 3, 3, 8, - 6, 5, 5, 5, 5, 5, 10, 8, 7, 7, 6, 6, 8, 13, 10, 9, 8, 8, 7, - 10, 10, 10, 10, 11, 10, 8, 11, 12, 11, 11, 11, 10, 6, 12, 13, 12, 12, 11, - 10, 6, 12, 15, 13, 12, 12, 11, 6, 12, 17, 15, 14, 13, 12, 8, 13, 17, 18, - 16, 15, 13, 9, 13, 18, 20, 17, 16, 14, 10, 19, 19, 18, 17, 15, 12, 8, 19, - 20, 19, 18, 16, 12, 8, 19, 23, 21, 19, 15, 12, 8, 19, 23, 22, 19, 16, 13, - 9, 18, 22, 24, 22, 18, 14, 10, 19, 23, 27, 25, 20, 15, 12, 18, 23, 28, 27, - 22, 17, 13, 25, 28, 25, 20, 17, 14, 11, 24, 28, 27, 22, 17, 14, 11, 24, 28, - 29, 22, 17, 14, 11, 25, 27, 30, 24, 19, 16, 12, 23, 27, 31, 28, 22, 17, 13, - 24, 28, 32, 31, 24, 19, 14, 25, 28, 32, 32, 26, 20, 15, 3, 7, 11, 15, 16, - 13, 11, 2, 5, 10, 14, 15, 13, 8, 2, 4, 8, 11, 13, 10, 5, 2, 2, 5, - 8, 10, 9, 5, 2, 2, 2, 5, 8, 10, 5, 5, 6, 6, 5, 8, 9, 5, 12, - 10, 8, 5, 6, 9, 5, 2, 4, 8, 11, 13, 10, 5, 2, 3, 7, 10, 13, 8, - 3, 2, 2, 5, 7, 9, 5, 2, 1, 2, 2, 4, 5, 3, 2, 2, 3, 3, 3, - 3, 3, 2, 7, 7, 8, 6, 3, 2, 2, 15, 13, 10, 7, 5, 3, 2, 2, 2, - 3, 5, 6, 4, 2, 1, 2, 2, 3, 4, 3, 1, 0, 2, 2, 2, 2, 2, 1, - 1, 2, 1, 1, 1, 1, 2, 4, 4, 4, 4, 4, 3, 2, 10, 10, 9, 8, 6, - 4, 2, 17, 16, 12, 9, 6, 4, 2, 0, 1, 1, 1, 2, 2, 5, 1, 2, 2, - 2, 2, 2, 5, 2, 2, 3, 3, 3, 3, 5, 4, 4, 5, 5, 5, 6, 7, 6, - 9, 9, 9, 9, 8, 7, 10, 15, 14, 13, 11, 10, 9, 17, 20, 17, 15, 13, 12, - 11, 8, 8, 8, 9, 9, 8, 5, 10, 10, 10, 10, 10, 9, 5, 10, 11, 11, 12, - 12, 10, 6, 10, 14, 14, 14, 14, 13, 9, 13, 18, 18, 18, 18, 17, 11, 15, 21, - 23, 21, 20, 18, 13, 20, 24, 25, 23, 21, 20, 15, 17, 18, 18, 18, 16, 11, 7, - 17, 20, 20, 19, 17, 12, 7, 17, 22, 21, 20, 19, 14, 9, 17, 23, 22, 22, 20, - 17, 14, 18, 24, 26, 25, 23, 20, 15, 21, 26, 29, 28, 24, 20, 17, 24, 28, 29, - 30, 25, 23, 18, 24, 29, 27, 22, 19, 15, 9, 24, 28, 29, 23, 20, 16, 11, 24, - 29, 30, 25, 21, 17, 13, 24, 29, 30, 26, 22, 20, 17, 25, 28, 32, 29, 25, 23, - 19, 26, 30, 33, 32, 26, 24, 20, 28, 32, 34, 33, 28, 25, 22, 6, 7, 8, 8, - 9, 7, 7, 5, 7, 8, 9, 9, 7, 6, 4, 6, 7, 8, 8, 7, 6, 3, 6, - 7, 7, 8, 7, 7, 3, 6, 7, 8, 9, 8, 7, 7, 9, 10, 9, 9, 8, 7, - 13, 13, 11, 10, 9, 8, 7, 4, 6, 7, 7, 7, 6, 5, 3, 6, 7, 7, 7, - 6, 5, 2, 5, 7, 7, 6, 6, 6, 1, 4, 7, 7, 6, 6, 7, 4, 5, 7, - 8, 7, 7, 6, 9, 9, 11, 10, 8, 7, 7, 16, 14, 12, 11, 8, 7, 7, 2, - 5, 6, 6, 6, 5, 2, 1, 4, 5, 5, 5, 5, 2, 1, 3, 4, 4, 5, 5, - 2, 1, 3, 4, 4, 5, 5, 4, 6, 6, 6, 6, 6, 5, 4, 11, 11, 11, 9, - 7, 5, 4, 18, 17, 13, 10, 7, 5, 4, 1, 0, 1, 1, 1, 2, 4, 1, 2, - 2, 2, 2, 2, 4, 2, 3, 2, 2, 3, 3, 4, 5, 5, 5, 6, 6, 6, 6, - 6, 10, 9, 9, 10, 9, 8, 12, 15, 14, 13, 11, 11, 9, 19, 21, 18, 15, 13, - 12, 11, 9, 8, 8, 8, 9, 7, 4, 10, 10, 9, 9, 10, 8, 4, 10, 11, 11, - 11, 11, 10, 6, 10, 15, 14, 14, 14, 13, 10, 13, 19, 18, 18, 19, 17, 11, 17, - 22, 24, 23, 21, 19, 13, 20, 26, 28, 25, 24, 21, 15, 17, 18, 17, 17, 14, 10, - 6, 17, 21, 19, 19, 16, 11, 7, 17, 21, 22, 21, 17, 13, 9, 17, 24, 25, 25, - 21, 17, 13, 20, 25, 31, 30, 25, 20, 15, 22, 28, 35, 33, 28, 22, 16, 25, 31, - 35, 36, 30, 24, 18, 25, 31, 29, 22, 17, 13, 9, 25, 30, 32, 25, 19, 15, 10, - 25, 31, 34, 27, 21, 17, 13, 24, 31, 37, 30, 26, 21, 17, 27, 33, 38, 36, 31, - 25, 18, 28, 36, 40, 40, 33, 27, 20, 32, 38, 41, 41, 35, 29, 23, 6, 9, 12, - 13, 13, 11, 9, 5, 8, 11, 13, 13, 11, 10, 4, 7, 10, 12, 13, 12, 10, 3, - 7, 10, 12, 14, 12, 11, 5, 7, 9, 12, 14, 13, 11, 8, 9, 11, 12, 14, 13, - 11, 14, 14, 12, 12, 13, 13, 11, 5, 7, 10, 12, 11, 9, 6, 4, 6, 9, 11, - 11, 9, 6, 2, 5, 8, 10, 10, 9, 7, 1, 5, 8, 11, 10, 10, 8, 4, 6, - 8, 10, 10, 11, 8, 10, 11, 11, 12, 10, 10, 8, 17, 16, 13, 12, 10, 9, 8, - 2, 5, 6, 7, 7, 5, 2, 1, 4, 5, 6, 6, 5, 2, 1, 3, 5, 5, 5, - 5, 3, 1, 3, 5, 5, 5, 6, 4, 6, 7, 7, 7, 7, 6, 4, 13, 12, 12, - 10, 8, 6, 4, 20, 18, 14, 11, 8, 6, 4, 1, 1, 0, 1, 1, 1, 3, 1, - 2, 1, 1, 1, 1, 3, 4, 3, 3, 3, 3, 3, 4, 7, 6, 6, 6, 6, 7, - 6, 8, 11, 10, 10, 10, 10, 8, 13, 16, 15, 14, 12, 11, 10, 19, 22, 19, 16, - 14, 13, 12, 9, 8, 8, 8, 8, 7, 3, 11, 10, 9, 9, 9, 8, 3, 10, 12, - 12, 12, 11, 10, 7, 10, 16, 15, 14, 15, 14, 10, 14, 21, 20, 20, 19, 17, 12, - 18, 24, 25, 23, 21, 18, 14, 22, 27, 28, 26, 24, 21, 15, 17, 19, 17, 17, 13, - 9, 5, 17, 21, 19, 18, 15, 11, 6, 17, 22, 22, 21, 17, 13, 10, 18, 24, 26, - 25, 21, 17, 13, 20, 27, 30, 30, 26, 20, 15, 23, 29, 36, 35, 29, 23, 17, 27, - 32, 37, 37, 31, 25, 19, 25, 30, 29, 22, 16, 12, 8, 25, 31, 31, 24, 18, 14, - 10, 25, 30, 35, 27, 22, 17, 13, 26, 31, 37, 31, 26, 21, 17, 27, 34, 39, 37, - 30, 25, 19, 30, 37, 43, 41, 33, 27, 20, 33, 38, 43, 43, 36, 29, 23, 7, 9, - 12, 15, 15, 13, 10, 6, 8, 11, 14, 15, 13, 10, 5, 7, 10, 13, 15, 14, 11, - 4, 7, 11, 14, 16, 14, 12, 5, 8, 11, 13, 17, 15, 12, 9, 11, 12, 13, 16, - 14, 12, 16, 15, 14, 13, 15, 15, 12, 5, 8, 10, 13, 12, 9, 6, 4, 7, 9, - 12, 12, 9, 6, 3, 5, 9, 11, 11, 10, 8, 1, 5, 9, 11, 11, 11, 9, 5, - 7, 9, 11, 11, 11, 9, 11, 12, 13, 13, 11, 10, 8, 19, 17, 14, 13, 10, 10, - 8, 3, 6, 6, 6, 7, 5, 2, 1, 4, 6, 6, 6, 5, 2, 1, 3, 5, 5, - 5, 6, 3, 2, 4, 5, 5, 6, 6, 5, 7, 8, 8, 8, 8, 7, 5, 14, 13, - 13, 11, 9, 7, 5, 21, 19, 15, 12, 9, 7, 6, 1, 1, 1, 0, 1, 1, 3, - 2, 2, 2, 1, 2, 1, 3, 5, 3, 3, 4, 4, 4, 5, 8, 6, 7, 7, 7, - 7, 7, 9, 12, 11, 11, 12, 10, 9, 14, 18, 16, 15, 14, 12, 11, 21, 24, 20, - 17, 15, 13, 12, 10, 9, 8, 8, 8, 7, 3, 11, 10, 9, 9, 9, 8, 3, 11, - 12, 12, 13, 12, 11, 7, 11, 16, 16, 16, 16, 15, 11, 15, 22, 21, 20, 21, 18, - 13, 19, 25, 26, 25, 22, 20, 14, 23, 28, 30, 27, 25, 21, 16, 18, 19, 17, 17, - 14, 9, 5, 18, 21, 19, 19, 15, 11, 7, 18, 23, 22, 22, 18, 14, 11, 18, 25, - 27, 25, 23, 19, 15, 21, 28, 32, 32, 26, 21, 16, 24, 32, 37, 36, 29, 23, 18, - 28, 34, 38, 38, 32, 26, 20, 26, 31, 29, 22, 17, 12, 8, 25, 31, 31, 24, 19, - 15, 11, 25, 30, 33, 28, 24, 18, 14, 26, 31, 37, 32, 27, 22, 18, 29, 35, 40, - 38, 31, 26, 20, 31, 38, 42, 42, 34, 28, 22, 34, 39, 44, 44, 37, 30, 24, 7, - 10, 12, 15, 15, 12, 10, 6, 9, 11, 14, 15, 13, 11, 5, 7, 11, 15, 16, 15, - 12, 4, 8, 11, 14, 17, 16, 13, 6, 9, 11, 14, 18, 16, 13, 11, 12, 14, 14, - 17, 16, 13, 17, 17, 15, 14, 16, 15, 13, 5, 8, 10, 13, 11, 9, 6, 4, 7, - 10, 12, 12, 9, 7, 3, 6, 9, 12, 12, 10, 8, 2, 6, 10, 12, 12, 11, 9, - 5, 8, 10, 12, 12, 12, 9, 12, 13, 14, 15, 12, 11, 9, 20, 19, 16, 14, 12, - 10, 9, 3, 6, 7, 6, 7, 5, 1, 1, 5, 6, 6, 6, 5, 2, 2, 4, 5, - 6, 6, 6, 4, 2, 4, 6, 6, 6, 6, 6, 7, 9, 9, 9, 10, 8, 6, 15, - 15, 14, 12, 10, 9, 6, 22, 21, 17, 14, 11, 9, 7, 2, 1, 1, 1, 0, 1, - 3, 3, 2, 2, 2, 2, 2, 3, 7, 3, 3, 4, 5, 5, 5, 9, 6, 8, 9, - 9, 8, 7, 10, 12, 12, 12, 13, 12, 10, 16, 19, 17, 16, 15, 14, 12, 22, 25, - 21, 18, 16, 15, 14, 10, 9, 8, 8, 8, 7, 2, 13, 11, 10, 9, 10, 9, 3, - 13, 12, 12, 13, 13, 12, 9, 13, 17, 17, 18, 17, 16, 12, 16, 23, 22, 22, 22, - 19, 14, 21, 27, 28, 26, 24, 21, 16, 24, 29, 31, 28, 27, 23, 17, 18, 19, 18, - 17, 13, 9, 5, 19, 21, 19, 18, 15, 12, 8, 18, 23, 22, 23, 19, 16, 12, 19, - 24, 28, 27, 23, 19, 16, 22, 29, 32, 31, 28, 23, 17, 27, 32, 39, 36, 29, 24, - 19, 30, 36, 38, 39, 33, 27, 21, 25, 29, 26, 21, 16, 12, 8, 25, 30, 29, 23, - 19, 16, 12, 26, 30, 31, 26, 23, 19, 15, 25, 32, 35, 31, 27, 24, 20, 29, 35, - 39, 38, 32, 26, 21, 32, 38, 43, 42, 35, 29, 23, 35, 40, 43, 45, 37, 31, 25, - 6, 8, 10, 12, 12, 9, 8, 6, 8, 9, 11, 12, 11, 9, 5, 7, 9, 12, 14, - 12, 11, 4, 7, 10, 13, 16, 14, 13, 6, 9, 12, 14, 18, 15, 13, 11, 13, 15, - 16, 17, 15, 13, 18, 18, 16, 15, 16, 15, 13, 5, 7, 8, 10, 8, 6, 5, 4, - 6, 8, 9, 9, 7, 6, 3, 6, 8, 10, 10, 9, 8, 2, 6, 9, 11, 11, 11, - 10, 6, 9, 11, 13, 13, 12, 9, 13, 14, 16, 15, 13, 12, 10, 22, 19, 17, 16, - 13, 11, 10, 3, 6, 5, 5, 5, 3, 2, 2, 5, 5, 4, 4, 4, 3, 2, 4, - 5, 5, 6, 6, 5, 3, 4, 6, 7, 7, 7, 8, 8, 9, 10, 11, 11, 10, 8, - 16, 17, 15, 14, 12, 10, 8, 23, 22, 18, 14, 12, 10, 8, 2, 2, 1, 1, 1, - 0, 2, 4, 2, 2, 2, 2, 3, 4, 8, 4, 3, 5, 6, 6, 6, 11, 6, 8, - 9, 9, 10, 8, 11, 13, 13, 14, 14, 12, 11, 16, 20, 18, 17, 16, 14, 13, 23, - 26, 22, 19, 17, 16, 15, 11, 9, 8, 8, 8, 7, 2, 14, 11, 10, 9, 10, 9, - 4, 14, 13, 12, 13, 14, 12, 9, 14, 17, 17, 17, 17, 17, 13, 16, 23, 23, 23, - 22, 19, 15, 21, 27, 28, 26, 23, 21, 17, 26, 31, 31, 28, 26, 22, 18, 18, 17, - 15, 13, 12, 9, 6, 18, 19, 16, 14, 12, 12, 9, 18, 21, 18, 19, 17, 15, 13, - 18, 23, 25, 24, 22, 19, 17, 22, 29, 31, 29, 26, 23, 18, 26, 33, 37, 34, 28, - 23, 20, 30, 36, 38, 37, 30, 25, 21, 22, 25, 22, 17, 13, 10, 9, 22, 25, 24, - 18, 15, 14, 12, 22, 25, 27, 22, 20, 18, 15, 22, 27, 33, 29, 25, 22, 20, 27, - 31, 37, 34, 30, 25, 21, 31, 36, 40, 40, 32, 27, 22, 35, 39, 42, 41, 35, 29, - 24, 9, 11, 13, 16, 16, 13, 10, 9, 11, 12, 15, 16, 14, 12, 8, 9, 12, 16, - 17, 15, 13, 8, 10, 13, 16, 19, 16, 14, 8, 11, 13, 17, 20, 18, 14, 11, 13, - 15, 16, 19, 18, 15, 18, 17, 16, 16, 18, 17, 14, 8, 10, 12, 13, 11, 8, 7, - 8, 9, 11, 13, 12, 10, 8, 7, 8, 11, 14, 13, 11, 9, 6, 8, 11, 14, 13, - 12, 11, 6, 10, 12, 14, 14, 13, 11, 13, 14, 16, 15, 14, 13, 11, 22, 19, 17, - 15, 13, 12, 11, 7, 8, 8, 7, 7, 5, 3, 6, 8, 8, 7, 7, 6, 4, 5, - 7, 7, 8, 8, 8, 6, 3, 7, 8, 8, 9, 9, 8, 7, 9, 10, 10, 10, 9, - 8, 16, 16, 15, 13, 11, 9, 8, 23, 22, 18, 14, 11, 9, 8, 5, 4, 3, 3, - 3, 3, 0, 2, 2, 3, 2, 2, 2, 2, 6, 2, 2, 3, 3, 3, 4, 10, 3, - 5, 6, 6, 6, 6, 9, 10, 10, 10, 10, 9, 7, 15, 18, 16, 14, 12, 10, 8, - 24, 25, 19, 15, 13, 11, 9, 4, 3, 2, 2, 2, 2, 0, 6, 3, 3, 2, 3, - 3, 2, 6, 4, 4, 5, 6, 6, 5, 6, 8, 9, 10, 10, 9, 8, 9, 14, 15, - 15, 15, 13, 9, 16, 20, 22, 20, 17, 14, 10, 22, 25, 25, 21, 19, 15, 11, 8, - 7, 6, 5, 3, 2, 1, 7, 10, 7, 6, 4, 4, 3, 8, 11, 10, 11, 9, 8, - 7, 8, 14, 17, 17, 14, 12, 10, 12, 19, 23, 23, 20, 16, 11, 18, 24, 30, 28, - 22, 17, 13, 24, 28, 31, 30, 24, 19, 14, 13, 16, 14, 8, 5, 3, 2, 13, 16, - 16, 10, 7, 6, 5, 13, 16, 19, 15, 12, 10, 8, 13, 18, 25, 21, 18, 15, 13, - 17, 24, 30, 28, 23, 19, 14, 22, 28, 34, 34, 27, 21, 15, 27, 32, 35, 35, 29, - 23, 17, 6, 10, 15, 18, 18, 16, 15, 5, 9, 14, 17, 18, 15, 13, 3, 8, 11, - 15, 16, 14, 11, 2, 5, 9, 11, 13, 13, 10, 1, 2, 6, 10, 12, 14, 10, 5, - 5, 5, 8, 11, 14, 10, 11, 9, 5, 7, 10, 14, 10, 3, 7, 12, 15, 16, 14, - 10, 2, 6, 11, 14, 15, 13, 8, 2, 5, 9, 11, 12, 11, 5, 2, 2, 6, 8, - 9, 8, 3, 2, 2, 3, 6, 7, 8, 3, 7, 7, 6, 5, 6, 6, 4, 15, 12, - 8, 5, 4, 5, 4, 2, 5, 7, 9, 11, 9, 5, 2, 3, 6, 8, 8, 8, 2, - 1, 2, 4, 5, 5, 5, 1, 0, 2, 2, 1, 2, 1, 1, 4, 4, 4, 4, 4, - 2, 1, 10, 9, 9, 8, 5, 3, 1, 16, 15, 11, 9, 6, 4, 2, 1, 1, 1, - 2, 3, 4, 2, 0, 1, 1, 2, 2, 1, 3, 1, 1, 1, 1, 1, 1, 3, 3, - 3, 3, 3, 4, 4, 4, 5, 7, 7, 7, 8, 7, 6, 9, 13, 11, 11, 10, 9, - 8, 16, 18, 14, 13, 12, 10, 9, 7, 7, 7, 8, 8, 7, 3, 8, 8, 9, 9, - 9, 8, 3, 8, 10, 10, 10, 11, 9, 5, 8, 13, 12, 13, 13, 12, 8, 11, 16, - 15, 15, 15, 14, 10, 14, 18, 19, 17, 16, 16, 12, 17, 20, 21, 18, 18, 16, 13, - 16, 16, 16, 16, 14, 10, 5, 15, 18, 17, 16, 14, 11, 7, 15, 19, 18, 17, 16, - 13, 8, 15, 19, 19, 18, 16, 15, 11, 16, 20, 22, 21, 18, 16, 13, 18, 22, 25, - 23, 20, 17, 14, 20, 24, 25, 25, 21, 18, 15, 21, 25, 22, 19, 16, 14, 8, 21, - 25, 25, 20, 16, 14, 10, 20, 25, 27, 21, 17, 15, 11, 21, 24, 27, 22, 18, 17, - 15, 21, 25, 28, 26, 21, 18, 16, 21, 25, 29, 28, 23, 19, 17, 24, 26, 29, 29, - 24, 20, 17, 7, 8, 9, 11, 11, 9, 7, 6, 7, 8, 10, 10, 8, 7, 5, 7, - 8, 9, 9, 8, 7, 4, 6, 7, 8, 8, 8, 8, 4, 7, 8, 8, 9, 8, 8, - 7, 8, 9, 9, 9, 8, 8, 13, 13, 11, 9, 9, 8, 7, 5, 7, 8, 9, 9, - 7, 6, 4, 7, 8, 8, 8, 7, 6, 3, 6, 7, 7, 7, 7, 6, 2, 5, 7, - 8, 7, 7, 7, 3, 5, 7, 8, 7, 7, 7, 8, 9, 10, 10, 8, 7, 7, 16, - 15, 12, 10, 8, 7, 7, 3, 6, 6, 6, 7, 6, 3, 2, 5, 6, 6, 6, 6, - 3, 1, 4, 5, 5, 6, 6, 3, 1, 4, 5, 5, 6, 6, 5, 5, 6, 6, 6, - 6, 6, 5, 11, 11, 11, 9, 7, 5, 5, 18, 17, 13, 10, 7, 5, 3, 2, 2, - 2, 2, 2, 2, 2, 1, 0, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, - 4, 4, 4, 4, 4, 4, 5, 6, 8, 8, 8, 8, 7, 6, 11, 14, 13, 12, 10, - 9, 8, 18, 20, 16, 14, 12, 10, 9, 7, 7, 7, 7, 7, 6, 2, 9, 9, 8, - 8, 8, 7, 3, 9, 10, 10, 10, 10, 8, 4, 9, 13, 13, 12, 13, 12, 8, 12, - 18, 17, 17, 18, 15, 10, 15, 21, 23, 21, 20, 17, 11, 19, 24, 26, 23, 22, 18, - 13, 16, 17, 17, 16, 13, 9, 5, 15, 20, 18, 18, 14, 10, 6, 15, 21, 20, 20, - 16, 12, 8, 16, 22, 24, 23, 19, 15, 11, 18, 24, 29, 28, 24, 19, 13, 20, 27, - 32, 31, 27, 21, 15, 25, 30, 34, 32, 28, 23, 17, 23, 29, 28, 22, 16, 12, 7, - 23, 29, 30, 24, 18, 13, 9, 23, 30, 33, 26, 20, 15, 11, 24, 29, 34, 29, 24, - 20, 15, 24, 31, 35, 34, 28, 23, 17, 27, 33, 37, 36, 30, 25, 19, 30, 35, 39, - 38, 33, 27, 22, 7, 10, 12, 14, 14, 12, 10, 7, 9, 12, 13, 14, 12, 10, 5, - 8, 10, 13, 13, 12, 11, 4, 8, 10, 12, 14, 13, 12, 5, 8, 10, 13, 15, 13, - 12, 8, 10, 11, 13, 14, 13, 11, 14, 14, 13, 12, 13, 13, 12, 5, 8, 11, 12, - 11, 10, 7, 5, 7, 10, 12, 11, 10, 7, 3, 6, 9, 11, 11, 10, 8, 3, 6, - 9, 11, 11, 11, 9, 5, 6, 8, 11, 11, 11, 9, 10, 11, 12, 12, 10, 10, 9, - 17, 16, 13, 12, 10, 9, 9, 4, 6, 7, 7, 8, 6, 3, 2, 5, 6, 7, 7, - 6, 3, 1, 4, 5, 5, 6, 6, 3, 1, 4, 5, 6, 6, 6, 4, 6, 7, 7, - 7, 7, 6, 5, 12, 12, 11, 10, 8, 6, 4, 19, 19, 14, 11, 8, 6, 5, 2, - 2, 1, 1, 2, 2, 3, 1, 1, 0, 1, 1, 1, 3, 2, 2, 2, 2, 2, 2, - 4, 6, 5, 5, 5, 5, 5, 5, 7, 9, 9, 9, 9, 9, 7, 12, 15, 14, 13, - 11, 10, 9, 19, 21, 17, 15, 13, 11, 11, 8, 7, 7, 7, 7, 6, 3, 9, 9, - 8, 8, 8, 7, 3, 9, 10, 10, 10, 10, 9, 5, 9, 14, 14, 14, 14, 13, 9, - 13, 19, 19, 18, 18, 16, 11, 17, 22, 24, 23, 20, 18, 12, 21, 26, 28, 24, 23, - 20, 14, 16, 18, 17, 16, 13, 9, 4, 16, 20, 18, 18, 14, 9, 6, 17, 21, 21, - 20, 16, 12, 8, 17, 24, 25, 24, 21, 16, 12, 20, 25, 30, 29, 25, 19, 14, 22, - 28, 35, 32, 28, 21, 16, 25, 31, 35, 36, 28, 23, 18, 24, 30, 27, 21, 16, 12, - 7, 24, 30, 30, 23, 18, 13, 9, 24, 30, 33, 26, 21, 16, 12, 24, 31, 36, 30, - 24, 20, 16, 25, 32, 38, 34, 29, 23, 18, 28, 34, 39, 40, 33, 26, 20, 31, 37, - 41, 41, 35, 28, 21, 8, 10, 13, 16, 16, 13, 11, 7, 9, 12, 15, 16, 14, 11, - 6, 8, 11, 14, 16, 14, 12, 5, 9, 11, 14, 17, 15, 13, 6, 8, 11, 14, 17, - 16, 13, 10, 11, 12, 14, 17, 16, 13, 16, 15, 13, 13, 15, 15, 13, 6, 8, 11, - 14, 12, 10, 7, 5, 8, 10, 13, 12, 10, 7, 4, 7, 10, 12, 12, 10, 9, 3, - 7, 10, 12, 12, 12, 9, 5, 7, 9, 12, 12, 12, 9, 11, 11, 13, 13, 11, 12, - 9, 19, 17, 15, 13, 10, 10, 9, 4, 7, 7, 7, 8, 6, 2, 3, 5, 7, 7, - 7, 6, 2, 1, 5, 6, 6, 6, 6, 4, 1, 5, 6, 6, 7, 7, 5, 7, 8, - 8, 8, 8, 7, 5, 14, 14, 13, 11, 9, 7, 5, 21, 20, 15, 12, 9, 7, 5, - 2, 1, 1, 1, 2, 2, 2, 2, 1, 1, 0, 1, 1, 3, 3, 2, 2, 2, 3, - 3, 4, 6, 5, 6, 6, 6, 6, 6, 8, 11, 10, 10, 10, 9, 8, 14, 17, 15, - 14, 12, 11, 9, 21, 23, 18, 16, 14, 12, 11, 8, 8, 7, 7, 7, 6, 3, 10, - 9, 8, 8, 8, 7, 3, 10, 11, 11, 11, 11, 10, 6, 10, 15, 15, 15, 15, 14, - 10, 13, 20, 20, 19, 19, 16, 11, 18, 25, 25, 24, 21, 18, 13, 22, 27, 28, 26, - 23, 20, 15, 17, 18, 17, 16, 12, 8, 4, 17, 20, 18, 17, 14, 10, 6, 17, 22, - 22, 21, 17, 13, 9, 17, 24, 26, 25, 21, 17, 13, 20, 26, 30, 30, 25, 20, 15, - 23, 29, 36, 33, 28, 22, 17, 27, 32, 36, 37, 30, 24, 19, 24, 30, 28, 21, 16, - 11, 7, 24, 29, 29, 23, 18, 13, 10, 24, 30, 33, 27, 21, 17, 13, 24, 31, 37, - 30, 25, 21, 17, 28, 33, 39, 36, 31, 24, 19, 30, 36, 41, 41, 33, 27, 20, 33, - 38, 43, 43, 36, 28, 22, 8, 11, 14, 17, 17, 15, 12, 7, 10, 13, 17, 17, 14, - 12, 6, 9, 12, 15, 18, 15, 13, 5, 9, 12, 15, 19, 16, 14, 6, 9, 12, 15, - 19, 17, 14, 10, 12, 13, 14, 18, 17, 14, 16, 15, 14, 14, 16, 16, 14, 6, 9, - 11, 15, 14, 11, 8, 5, 8, 11, 13, 13, 10, 8, 4, 7, 10, 13, 13, 11, 9, - 3, 7, 11, 13, 13, 12, 10, 5, 8, 10, 12, 13, 12, 10, 12, 12, 14, 14, 12, - 12, 10, 19, 17, 15, 14, 11, 11, 10, 4, 7, 8, 8, 9, 7, 3, 3, 6, 7, - 7, 7, 6, 3, 1, 5, 6, 7, 7, 7, 4, 1, 5, 7, 7, 7, 7, 6, 7, - 8, 9, 8, 8, 7, 6, 14, 14, 14, 12, 9, 7, 6, 21, 20, 16, 12, 10, 8, - 6, 2, 2, 1, 2, 2, 2, 2, 2, 1, 1, 1, 0, 0, 2, 4, 2, 2, 3, - 3, 3, 3, 7, 5, 6, 6, 6, 6, 5, 8, 11, 10, 10, 11, 9, 8, 14, 17, - 15, 14, 12, 11, 10, 21, 23, 19, 16, 14, 12, 11, 8, 7, 7, 7, 7, 6, 2, - 10, 9, 8, 8, 8, 7, 2, 10, 11, 10, 11, 11, 10, 6, 10, 15, 15, 15, 15, - 14, 10, 14, 21, 20, 20, 19, 17, 12, 18, 24, 26, 24, 21, 18, 13, 23, 28, 29, - 26, 24, 21, 15, 17, 18, 17, 15, 12, 9, 4, 16, 19, 18, 17, 13, 10, 6, 17, - 22, 21, 21, 18, 13, 9, 16, 24, 26, 25, 22, 18, 13, 20, 27, 30, 30, 26, 21, - 15, 24, 30, 37, 35, 28, 23, 17, 28, 32, 37, 37, 30, 24, 19, 24, 28, 25, 20, - 15, 11, 7, 24, 28, 28, 22, 17, 13, 10, 24, 29, 31, 25, 21, 17, 13, 24, 30, - 35, 31, 25, 21, 17, 28, 33, 38, 35, 30, 24, 19, 30, 35, 41, 40, 32, 27, 21, - 34, 39, 41, 42, 35, 29, 23, 8, 11, 14, 17, 17, 15, 11, 7, 10, 13, 16, 16, - 14, 12, 6, 9, 12, 15, 17, 16, 13, 5, 9, 12, 16, 18, 16, 14, 6, 9, 12, - 15, 18, 17, 14, 10, 12, 13, 14, 18, 17, 14, 17, 16, 14, 14, 16, 17, 14, 6, - 9, 12, 14, 13, 11, 8, 5, 8, 11, 13, 13, 10, 8, 4, 7, 10, 14, 13, 11, - 9, 3, 7, 11, 13, 13, 12, 10, 5, 8, 10, 13, 13, 12, 10, 11, 12, 14, 13, - 12, 12, 10, 19, 17, 15, 14, 11, 11, 9, 4, 7, 8, 8, 9, 7, 3, 3, 6, - 7, 7, 7, 6, 3, 2, 5, 6, 7, 7, 7, 4, 1, 5, 7, 7, 7, 7, 6, - 6, 8, 9, 9, 8, 7, 6, 14, 14, 13, 11, 9, 8, 6, 21, 19, 15, 12, 10, - 8, 6, 2, 2, 1, 1, 2, 3, 2, 1, 1, 1, 1, 0, 0, 2, 5, 2, 2, - 3, 3, 3, 3, 7, 5, 6, 6, 6, 6, 5, 9, 11, 10, 11, 10, 10, 8, 14, - 17, 16, 14, 13, 11, 10, 21, 23, 19, 16, 14, 13, 12, 9, 8, 7, 6, 7, 6, - 2, 11, 10, 8, 8, 8, 7, 2, 11, 11, 10, 11, 11, 10, 6, 10, 15, 15, 15, - 15, 14, 10, 14, 21, 20, 20, 19, 16, 12, 18, 24, 25, 23, 21, 18, 13, 23, 27, - 29, 25, 22, 20, 15, 16, 16, 14, 13, 11, 8, 5, 16, 18, 15, 13, 12, 10, 6, - 16, 20, 17, 17, 15, 12, 10, 17, 21, 23, 21, 19, 17, 13, 20, 26, 28, 26, 23, - 20, 15, 24, 29, 33, 30, 25, 21, 17, 27, 33, 34, 33, 26, 23, 19, 21, 23, 20, - 15, 13, 10, 7, 21, 24, 23, 17, 14, 13, 9, 21, 24, 25, 21, 18, 16, 13, 21, - 25, 30, 25, 22, 19, 16, 25, 29, 34, 32, 27, 23, 19, 29, 33, 37, 36, 29, 24, - 20, 32, 35, 37, 38, 32, 26, 21, 9, 11, 14, 17, 17, 14, 11, 9, 11, 13, 16, - 17, 13, 11, 8, 10, 12, 15, 17, 15, 12, 8, 10, 13, 16, 18, 15, 13, 8, 10, - 13, 15, 19, 17, 13, 11, 11, 13, 15, 18, 16, 13, 16, 15, 14, 14, 16, 17, 13, - 8, 10, 12, 14, 13, 10, 7, 8, 9, 11, 13, 13, 9, 7, 7, 8, 11, 13, 12, - 10, 8, 6, 9, 12, 14, 13, 12, 9, 6, 9, 11, 13, 13, 12, 10, 11, 12, 13, - 13, 12, 11, 10, 19, 17, 14, 13, 11, 11, 10, 7, 9, 9, 8, 9, 7, 4, 6, - 8, 8, 7, 7, 6, 3, 5, 8, 8, 7, 7, 6, 5, 4, 7, 8, 8, 7, 7, - 6, 7, 9, 9, 8, 8, 7, 6, 14, 14, 13, 11, 9, 7, 6, 21, 19, 14, 11, - 9, 7, 6, 5, 4, 3, 3, 3, 4, 2, 3, 3, 3, 2, 2, 2, 0, 2, 2, - 2, 3, 2, 2, 2, 7, 3, 4, 5, 4, 4, 4, 8, 9, 9, 8, 8, 7, 5, - 14, 15, 14, 11, 10, 8, 6, 20, 21, 16, 13, 11, 9, 7, 5, 3, 2, 2, 2, - 2, 2, 6, 4, 3, 2, 3, 2, 0, 5, 5, 4, 4, 4, 4, 3, 5, 8, 8, - 8, 8, 8, 6, 9, 14, 13, 13, 13, 10, 7, 14, 19, 20, 18, 15, 12, 8, 20, - 23, 23, 19, 17, 14, 9, 9, 9, 7, 6, 4, 3, 2, 9, 11, 9, 8, 5, 3, - 2, 8, 12, 11, 11, 9, 6, 5, 9, 14, 17, 16, 13, 10, 8, 12, 18, 22, 21, - 18, 14, 9, 17, 23, 27, 25, 20, 15, 11, 22, 26, 29, 28, 23, 17, 12, 14, 18, - 15, 10, 6, 3, 2, 13, 18, 18, 12, 8, 5, 3, 14, 18, 20, 15, 12, 9, 6, - 14, 19, 25, 21, 17, 13, 11, 17, 23, 28, 26, 22, 17, 12, 22, 26, 32, 32, 25, - 19, 14, 26, 30, 33, 33, 27, 20, 15, 10, 14, 18, 22, 22, 20, 17, 8, 12, 17, - 20, 22, 19, 16, 7, 11, 14, 17, 20, 17, 13, 5, 9, 12, 15, 16, 15, 13, 3, - 6, 10, 13, 15, 16, 14, 4, 5, 8, 11, 14, 16, 13, 10, 7, 7, 11, 13, 15, - 14, 7, 11, 15, 18, 20, 17, 13, 5, 9, 14, 17, 19, 15, 12, 4, 8, 12, 13, - 15, 14, 9, 3, 6, 9, 11, 12, 13, 8, 2, 3, 7, 10, 12, 12, 8, 6, 5, - 6, 8, 10, 11, 8, 12, 10, 6, 8, 8, 8, 8, 4, 8, 10, 12, 13, 12, 9, - 2, 7, 9, 11, 11, 11, 7, 1, 5, 8, 9, 9, 10, 4, 1, 3, 4, 5, 5, - 5, 1, 3, 3, 3, 3, 3, 3, 1, 9, 8, 7, 5, 4, 2, 1, 14, 13, 9, - 7, 5, 4, 1, 2, 2, 4, 5, 7, 8, 6, 1, 1, 2, 3, 4, 5, 2, 0, - 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 4, 6, 6, 6, 6, 5, - 4, 9, 10, 9, 8, 8, 7, 6, 14, 15, 11, 10, 9, 8, 8, 6, 6, 6, 6, - 6, 4, 6, 7, 7, 8, 8, 8, 6, 3, 7, 9, 8, 8, 9, 8, 3, 7, 10, - 10, 10, 10, 9, 6, 9, 13, 12, 12, 12, 11, 8, 11, 15, 15, 14, 13, 12, 9, - 14, 17, 17, 15, 14, 13, 10, 13, 13, 13, 13, 11, 8, 5, 12, 15, 14, 13, 12, - 9, 6, 12, 16, 15, 14, 12, 10, 7, 13, 15, 16, 15, 13, 11, 9, 13, 16, 18, - 17, 16, 12, 10, 14, 18, 22, 20, 17, 14, 11, 16, 20, 22, 21, 18, 15, 12, 17, - 20, 19, 16, 13, 11, 6, 18, 21, 21, 16, 13, 11, 8, 17, 21, 23, 17, 14, 11, - 9, 17, 21, 23, 19, 15, 13, 11, 17, 21, 24, 21, 18, 15, 12, 18, 22, 25, 25, - 19, 16, 13, 20, 23, 26, 25, 21, 16, 14, 7, 8, 10, 13, 13, 11, 9, 7, 8, - 10, 12, 13, 10, 8, 6, 8, 9, 10, 11, 9, 7, 5, 7, 8, 9, 10, 8, 8, - 5, 7, 8, 9, 10, 9, 8, 7, 8, 9, 9, 9, 8, 8, 13, 13, 11, 9, 9, - 8, 8, 7, 8, 9, 10, 11, 9, 7, 6, 7, 8, 10, 11, 8, 7, 4, 7, 8, - 8, 8, 7, 6, 3, 6, 7, 8, 7, 7, 7, 3, 6, 8, 8, 8, 8, 7, 8, - 9, 10, 9, 7, 7, 7, 16, 15, 12, 10, 8, 7, 7, 4, 7, 7, 7, 7, 7, - 5, 3, 6, 7, 7, 7, 6, 4, 2, 5, 6, 6, 6, 6, 5, 1, 5, 6, 6, - 6, 6, 6, 5, 6, 6, 6, 6, 6, 6, 11, 11, 10, 9, 7, 5, 6, 18, 17, - 13, 10, 7, 5, 4, 2, 3, 3, 3, 3, 4, 2, 1, 1, 2, 2, 2, 2, 2, - 1, 0, 1, 1, 1, 1, 2, 3, 2, 2, 3, 3, 3, 3, 5, 7, 6, 6, 7, - 6, 5, 11, 12, 12, 11, 9, 8, 7, 18, 20, 15, 13, 11, 9, 8, 6, 6, 6, - 6, 6, 5, 2, 7, 7, 7, 7, 7, 6, 2, 8, 9, 9, 8, 9, 7, 3, 8, - 12, 11, 11, 12, 11, 7, 10, 16, 16, 15, 17, 14, 9, 13, 19, 22, 20, 19, 16, - 11, 18, 23, 24, 22, 20, 18, 12, 14, 16, 15, 16, 12, 8, 4, 14, 18, 17, 18, - 14, 9, 5, 14, 20, 19, 20, 16, 11, 7, 14, 20, 22, 22, 19, 14, 10, 16, 22, - 27, 24, 22, 18, 12, 19, 25, 30, 28, 24, 20, 14, 23, 28, 31, 30, 26, 22, 16, - 22, 28, 26, 20, 16, 11, 6, 22, 28, 28, 23, 18, 12, 8, 22, 27, 31, 24, 19, - 14, 10, 22, 27, 32, 25, 22, 18, 14, 23, 28, 33, 30, 25, 22, 16, 26, 30, 34, - 32, 28, 24, 18, 28, 31, 34, 35, 29, 25, 21, 9, 12, 14, 14, 15, 13, 12, 8, - 10, 13, 14, 15, 13, 11, 6, 10, 12, 14, 14, 12, 11, 5, 8, 11, 13, 14, 13, - 12, 6, 8, 11, 14, 15, 14, 12, 8, 9, 11, 13, 15, 14, 12, 14, 14, 12, 12, - 13, 14, 12, 6, 10, 12, 13, 13, 11, 9, 6, 9, 11, 13, 13, 11, 8, 4, 7, - 10, 12, 12, 10, 9, 3, 7, 10, 12, 11, 11, 9, 4, 6, 9, 11, 11, 12, 10, - 9, 10, 12, 12, 11, 11, 9, 17, 15, 13, 12, 10, 10, 9, 4, 7, 9, 9, 9, - 8, 4, 3, 6, 8, 8, 8, 7, 4, 2, 5, 7, 7, 7, 7, 4, 2, 5, 6, - 6, 7, 7, 5, 6, 6, 7, 6, 7, 6, 5, 12, 12, 11, 10, 7, 6, 5, 19, - 18, 14, 10, 8, 6, 4, 2, 2, 3, 3, 3, 3, 2, 1, 1, 2, 2, 2, 2, - 2, 1, 1, 0, 0, 0, 0, 2, 4, 3, 3, 4, 4, 4, 5, 6, 8, 7, 7, - 8, 7, 6, 12, 14, 12, 11, 10, 8, 7, 19, 20, 16, 13, 11, 10, 9, 7, 6, - 6, 6, 6, 5, 2, 8, 8, 7, 7, 8, 6, 2, 8, 9, 9, 9, 9, 7, 4, - 8, 13, 12, 12, 12, 11, 7, 11, 17, 17, 16, 16, 14, 9, 15, 21, 23, 20, 19, - 16, 11, 19, 24, 26, 23, 21, 18, 13, 15, 17, 15, 16, 12, 8, 4, 15, 18, 18, - 17, 13, 9, 5, 15, 20, 19, 19, 15, 11, 7, 15, 21, 23, 23, 19, 15, 11, 18, - 25, 28, 26, 23, 18, 12, 20, 26, 33, 31, 26, 19, 14, 23, 29, 33, 33, 28, 22, - 16, 22, 28, 27, 21, 15, 11, 6, 22, 28, 30, 22, 17, 12, 8, 23, 28, 32, 25, - 19, 15, 11, 23, 29, 34, 28, 22, 18, 15, 24, 31, 37, 34, 28, 21, 16, 27, 34, - 39, 37, 31, 25, 18, 30, 35, 40, 40, 33, 26, 20, 9, 13, 16, 19, 19, 17, 14, - 8, 12, 15, 18, 19, 16, 13, 7, 10, 14, 17, 18, 15, 13, 6, 9, 12, 15, 17, - 15, 13, 6, 9, 11, 15, 17, 15, 13, 8, 9, 11, 14, 16, 16, 13, 14, 14, 12, - 13, 16, 15, 13, 7, 11, 14, 17, 16, 13, 10, 6, 9, 13, 16, 16, 13, 9, 5, - 8, 11, 14, 14, 11, 8, 4, 7, 10, 12, 12, 12, 9, 5, 7, 10, 12, 12, 12, - 9, 9, 10, 11, 12, 11, 11, 9, 17, 15, 13, 11, 10, 10, 9, 5, 8, 9, 10, - 11, 9, 6, 4, 6, 8, 9, 10, 9, 5, 3, 5, 7, 7, 7, 7, 4, 2, 6, - 6, 6, 6, 7, 5, 6, 7, 7, 6, 6, 6, 5, 12, 12, 11, 9, 7, 5, 5, - 19, 17, 13, 10, 7, 5, 4, 3, 2, 3, 4, 4, 5, 3, 1, 2, 2, 3, 3, - 3, 3, 1, 1, 0, 0, 0, 0, 2, 4, 3, 3, 3, 3, 3, 4, 6, 8, 7, - 7, 7, 7, 5, 12, 14, 12, 11, 10, 8, 7, 19, 20, 16, 13, 11, 10, 8, 7, - 6, 6, 7, 7, 6, 3, 8, 8, 7, 8, 8, 7, 3, 8, 9, 9, 9, 9, 7, - 4, 8, 13, 12, 12, 12, 11, 7, 11, 17, 17, 16, 16, 14, 9, 15, 21, 22, 21, - 18, 16, 11, 19, 24, 25, 23, 21, 18, 12, 15, 17, 16, 16, 13, 9, 5, 15, 19, - 18, 17, 14, 9, 5, 15, 20, 19, 18, 14, 11, 7, 15, 22, 24, 22, 19, 15, 10, - 18, 24, 28, 26, 23, 18, 12, 21, 26, 34, 32, 25, 20, 14, 24, 29, 34, 33, 27, - 22, 16, 23, 28, 27, 21, 16, 12, 7, 23, 29, 29, 22, 17, 12, 8, 23, 28, 32, - 24, 19, 15, 10, 22, 29, 35, 29, 22, 18, 14, 23, 30, 36, 34, 27, 22, 16, 27, - 32, 39, 38, 31, 24, 18, 30, 36, 40, 40, 33, 26, 20, 10, 14, 18, 20, 21, 19, - 15, 8, 12, 16, 20, 21, 17, 13, 7, 10, 15, 18, 19, 16, 13, 6, 9, 12, 15, - 19, 16, 13, 6, 9, 12, 15, 18, 16, 14, 8, 9, 11, 14, 18, 17, 13, 14, 13, - 12, 13, 16, 17, 14, 7, 11, 15, 18, 17, 14, 11, 6, 10, 13, 16, 17, 13, 9, - 5, 8, 12, 14, 14, 11, 9, 4, 7, 10, 13, 13, 12, 10, 5, 7, 10, 12, 12, - 12, 9, 10, 10, 11, 12, 12, 11, 10, 17, 15, 12, 12, 10, 11, 9, 5, 8, 10, - 11, 12, 10, 6, 4, 7, 9, 10, 10, 9, 5, 3, 6, 7, 7, 7, 7, 4, 1, - 6, 6, 6, 7, 7, 5, 6, 7, 7, 6, 6, 6, 5, 13, 12, 11, 9, 7, 6, - 5, 19, 17, 13, 10, 7, 5, 4, 3, 3, 3, 4, 5, 6, 3, 1, 1, 2, 3, - 3, 3, 2, 1, 1, 0, 0, 0, 0, 1, 4, 3, 4, 3, 3, 3, 3, 6, 8, - 7, 7, 7, 6, 5, 13, 14, 12, 11, 9, 8, 6, 19, 21, 15, 13, 11, 9, 8, - 7, 6, 6, 6, 7, 6, 3, 9, 8, 7, 7, 8, 6, 2, 9, 10, 9, 8, 8, - 7, 3, 9, 13, 12, 12, 12, 11, 7, 12, 18, 17, 16, 16, 13, 8, 15, 21, 22, - 20, 18, 15, 10, 19, 24, 26, 23, 21, 17, 12, 15, 16, 15, 15, 12, 9, 4, 15, - 19, 17, 17, 13, 9, 4, 15, 20, 19, 18, 14, 10, 7, 15, 21, 23, 21, 18, 14, - 10, 18, 24, 29, 26, 23, 17, 12, 20, 27, 33, 31, 25, 19, 14, 24, 29, 33, 33, - 28, 21, 15, 22, 27, 26, 20, 15, 11, 7, 23, 27, 27, 21, 16, 12, 7, 22, 27, - 29, 23, 18, 14, 10, 23, 28, 33, 27, 23, 18, 13, 25, 30, 35, 33, 26, 22, 16, - 27, 32, 38, 38, 30, 23, 18, 29, 34, 38, 37, 32, 25, 20, 10, 14, 17, 21, 21, - 18, 15, 9, 12, 15, 20, 20, 17, 13, 7, 11, 14, 17, 19, 15, 13, 6, 9, 12, - 16, 18, 16, 14, 6, 9, 12, 15, 19, 17, 14, 9, 10, 11, 14, 18, 17, 14, 14, - 13, 12, 14, 17, 17, 13, 7, 11, 15, 18, 17, 15, 11, 6, 10, 13, 16, 17, 13, - 9, 5, 8, 12, 15, 14, 11, 9, 4, 8, 11, 13, 13, 12, 9, 5, 7, 10, 12, - 13, 12, 10, 10, 10, 11, 12, 12, 12, 10, 16, 14, 12, 12, 11, 11, 10, 5, 8, - 10, 11, 12, 10, 6, 4, 7, 9, 10, 10, 9, 5, 3, 6, 7, 8, 7, 7, 4, - 2, 6, 7, 7, 7, 7, 5, 6, 7, 7, 7, 7, 6, 5, 13, 12, 11, 9, 7, - 5, 5, 17, 16, 12, 10, 7, 5, 4, 3, 3, 3, 4, 5, 6, 4, 1, 1, 2, - 3, 3, 3, 2, 1, 1, 0, 0, 0, 0, 1, 4, 4, 4, 3, 3, 3, 3, 7, - 9, 8, 7, 8, 6, 5, 13, 14, 12, 10, 9, 8, 6, 18, 19, 15, 13, 11, 9, - 8, 7, 6, 6, 6, 7, 6, 4, 9, 8, 7, 7, 8, 6, 2, 9, 10, 9, 8, - 8, 7, 3, 9, 14, 13, 12, 12, 10, 7, 12, 18, 17, 16, 16, 14, 9, 15, 21, - 22, 20, 18, 15, 10, 18, 23, 24, 22, 19, 17, 12, 15, 15, 14, 13, 11, 9, 4, - 16, 17, 15, 14, 12, 9, 4, 15, 19, 17, 15, 12, 10, 7, 15, 20, 21, 18, 16, - 14, 10, 18, 23, 26, 23, 20, 17, 12, 21, 25, 31, 27, 22, 18, 14, 23, 28, 31, - 29, 24, 20, 15, 20, 23, 20, 15, 13, 11, 7, 21, 23, 22, 17, 13, 11, 7, 20, - 23, 23, 19, 15, 13, 10, 20, 24, 28, 22, 18, 17, 14, 23, 26, 30, 28, 23, 19, - 16, 26, 29, 33, 32, 25, 21, 17, 28, 31, 34, 34, 27, 22, 18, 11, 13, 16, 19, - 19, 16, 13, 10, 12, 15, 18, 18, 15, 11, 8, 11, 14, 16, 17, 14, 11, 7, 9, - 12, 15, 17, 15, 12, 8, 10, 12, 15, 18, 15, 12, 8, 9, 12, 14, 17, 16, 12, - 12, 12, 11, 13, 16, 16, 12, 9, 11, 14, 16, 15, 12, 9, 7, 10, 12, 15, 14, - 11, 8, 7, 9, 12, 13, 12, 10, 7, 6, 9, 11, 13, 12, 10, 8, 6, 8, 10, - 12, 12, 11, 9, 10, 9, 10, 12, 11, 11, 8, 15, 13, 11, 11, 10, 9, 8, 7, - 9, 10, 10, 11, 9, 6, 6, 8, 9, 9, 9, 7, 4, 4, 7, 8, 7, 6, 6, - 4, 4, 8, 7, 7, 6, 6, 5, 6, 8, 7, 7, 6, 6, 5, 12, 11, 10, 8, - 6, 5, 5, 16, 15, 11, 9, 6, 5, 4, 5, 4, 4, 4, 5, 6, 4, 3, 3, - 4, 4, 3, 3, 2, 2, 2, 2, 2, 1, 1, 0, 4, 2, 3, 3, 2, 2, 2, - 7, 7, 6, 6, 6, 5, 3, 12, 13, 11, 9, 7, 6, 4, 17, 18, 13, 10, 8, - 7, 5, 4, 4, 3, 3, 3, 4, 4, 5, 5, 3, 3, 3, 3, 2, 6, 5, 4, - 4, 4, 3, 2, 5, 9, 8, 7, 7, 6, 4, 8, 14, 13, 12, 12, 9, 5, 13, - 17, 18, 16, 14, 11, 7, 16, 20, 21, 18, 15, 13, 8, 10, 10, 9, 9, 7, 4, - 3, 9, 12, 11, 10, 8, 4, 2, 9, 13, 12, 12, 8, 5, 3, 9, 15, 16, 15, - 12, 9, 6, 13, 18, 22, 20, 17, 12, 8, 16, 21, 27, 24, 19, 14, 10, 20, 24, - 27, 27, 21, 16, 11, 15, 19, 18, 13, 9, 6, 3, 15, 20, 20, 15, 10, 6, 3, - 15, 20, 22, 16, 12, 8, 5, 15, 20, 25, 20, 16, 13, 9, 18, 23, 28, 26, 21, - 16, 11, 21, 26, 31, 30, 23, 17, 13, 24, 29, 31, 32, 25, 20, 14, 13, 16, 20, - 25, 25, 24, 19, 11, 14, 18, 23, 25, 21, 17, 10, 14, 17, 20, 23, 19, 16, 8, - 12, 14, 17, 20, 18, 15, 6, 9, 12, 15, 17, 18, 15, 5, 8, 11, 13, 16, 18, - 15, 7, 8, 9, 13, 15, 18, 15, 9, 14, 17, 20, 21, 19, 15, 8, 13, 15, 19, - 21, 18, 14, 7, 11, 14, 17, 17, 15, 12, 6, 9, 12, 14, 14, 14, 11, 3, 7, - 10, 12, 13, 14, 11, 4, 6, 9, 11, 12, 12, 11, 9, 7, 8, 10, 10, 11, 11, - 7, 11, 13, 14, 16, 15, 11, 5, 10, 11, 13, 13, 14, 9, 4, 8, 10, 11, 11, - 11, 7, 3, 5, 7, 8, 8, 8, 5, 2, 4, 6, 6, 6, 6, 5, 6, 6, 5, - 5, 5, 5, 5, 10, 9, 7, 4, 3, 4, 4, 4, 6, 7, 7, 9, 11, 11, 3, - 4, 6, 6, 7, 8, 7, 1, 3, 4, 4, 4, 4, 3, 0, 0, 0, 0, 0, 0, - 0, 3, 3, 3, 3, 3, 3, 2, 6, 7, 6, 5, 4, 4, 3, 10, 12, 8, 6, - 5, 4, 4, 4, 4, 4, 4, 6, 8, 10, 4, 5, 5, 5, 5, 5, 7, 4, 5, - 6, 5, 5, 5, 2, 4, 7, 6, 6, 6, 5, 3, 5, 9, 8, 8, 8, 7, 4, - 7, 11, 11, 11, 9, 8, 5, 10, 13, 13, 12, 11, 9, 6, 9, 10, 9, 9, 8, - 6, 8, 9, 11, 10, 10, 8, 6, 4, 9, 12, 11, 11, 9, 6, 4, 9, 12, 12, - 12, 10, 7, 5, 9, 13, 15, 14, 12, 9, 6, 11, 14, 18, 16, 13, 10, 7, 13, - 16, 18, 18, 14, 11, 8, 14, 17, 16, 12, 10, 7, 6, 14, 18, 17, 14, 10, 7, - 5, 14, 17, 19, 14, 11, 8, 5, 13, 16, 20, 15, 12, 9, 7, 13, 17, 20, 17, - 15, 11, 8, 14, 18, 21, 20, 16, 12, 9, 16, 19, 22, 22, 17, 14, 10, 10, 11, - 14, 17, 17, 14, 12, 9, 11, 13, 16, 17, 14, 11, 9, 11, 12, 13, 14, 13, 10, - 8, 9, 10, 12, 13, 10, 8, 6, 7, 8, 9, 11, 9, 8, 6, 7, 8, 8, 10, - 9, 8, 12, 12, 9, 8, 9, 9, 8, 9, 10, 12, 14, 14, 12, 10, 8, 10, 11, - 13, 14, 11, 9, 7, 9, 10, 11, 11, 10, 8, 6, 8, 9, 9, 9, 8, 7, 4, - 6, 7, 8, 7, 7, 7, 7, 8, 9, 8, 7, 7, 7, 15, 13, 11, 8, 6, 7, - 7, 7, 9, 10, 9, 10, 9, 8, 5, 8, 9, 9, 9, 9, 7, 4, 8, 9, 9, - 8, 8, 7, 3, 6, 6, 7, 7, 7, 6, 3, 4, 5, 6, 6, 6, 6, 9, 9, - 10, 8, 6, 6, 6, 17, 16, 12, 9, 6, 5, 5, 4, 5, 6, 6, 6, 7, 3, - 3, 4, 5, 5, 5, 5, 3, 2, 2, 3, 3, 4, 4, 2, 0, 0, 0, 0, 0, - 0, 0, 4, 5, 4, 4, 4, 4, 3, 9, 11, 10, 9, 7, 5, 4, 17, 19, 14, - 10, 9, 7, 6, 5, 5, 6, 6, 6, 5, 3, 6, 7, 7, 7, 8, 6, 3, 6, - 8, 9, 9, 9, 7, 3, 6, 10, 9, 9, 10, 9, 4, 8, 14, 14, 14, 14, 12, - 6, 11, 17, 19, 17, 16, 14, 8, 16, 21, 21, 19, 17, 16, 10, 13, 16, 16, 16, - 13, 8, 3, 14, 18, 17, 17, 14, 9, 5, 14, 19, 20, 18, 15, 10, 6, 14, 19, - 20, 19, 17, 13, 8, 14, 20, 22, 21, 18, 16, 10, 17, 21, 26, 23, 21, 17, 12, - 20, 23, 26, 25, 21, 19, 14, 22, 26, 25, 20, 16, 11, 6, 21, 26, 26, 21, 17, - 13, 8, 22, 26, 28, 23, 19, 14, 9, 21, 26, 28, 23, 19, 16, 12, 21, 25, 28, - 25, 20, 18, 14, 22, 26, 29, 28, 23, 19, 16, 23, 26, 30, 28, 24, 21, 17, 13, - 16, 18, 20, 19, 17, 16, 11, 14, 17, 19, 20, 17, 15, 10, 14, 17, 18, 18, 15, - 13, 8, 11, 14, 16, 17, 14, 12, 6, 9, 12, 13, 15, 13, 12, 5, 8, 11, 13, - 15, 14, 12, 11, 11, 10, 13, 14, 14, 12, 10, 13, 16, 18, 17, 16, 13, 9, 12, - 16, 18, 17, 16, 13, 7, 11, 14, 16, 16, 14, 11, 6, 9, 12, 14, 13, 12, 10, - 4, 7, 10, 12, 12, 12, 10, 7, 8, 9, 11, 11, 11, 10, 14, 12, 10, 10, 10, - 10, 10, 7, 11, 13, 14, 15, 13, 9, 6, 10, 12, 13, 13, 12, 8, 5, 8, 11, - 11, 11, 11, 7, 3, 6, 7, 7, 8, 8, 5, 3, 5, 6, 6, 6, 7, 5, 9, - 9, 9, 7, 5, 5, 5, 16, 15, 11, 8, 5, 5, 4, 5, 5, 6, 7, 8, 8, - 5, 3, 4, 5, 6, 6, 6, 4, 2, 2, 3, 4, 4, 4, 3, 0, 0, 0, 0, - 0, 0, 0, 4, 4, 4, 4, 4, 3, 2, 9, 11, 9, 8, 6, 5, 4, 16, 18, - 12, 9, 8, 6, 5, 5, 5, 6, 6, 7, 6, 5, 7, 7, 7, 7, 8, 6, 4, - 7, 8, 8, 8, 8, 6, 3, 7, 10, 9, 9, 9, 7, 4, 8, 14, 13, 13, 13, - 11, 5, 11, 17, 18, 17, 15, 12, 7, 15, 20, 21, 19, 17, 15, 9, 14, 15, 15, - 16, 13, 8, 5, 14, 17, 17, 16, 14, 9, 4, 14, 20, 19, 18, 14, 9, 5, 14, - 19, 21, 19, 15, 11, 7, 14, 20, 24, 23, 19, 14, 9, 17, 23, 29, 28, 22, 16, - 11, 20, 25, 30, 30, 24, 19, 13, 22, 28, 27, 21, 16, 11, 7, 22, 28, 29, 23, - 16, 12, 7, 22, 28, 32, 24, 17, 12, 8, 22, 28, 33, 25, 20, 15, 11, 21, 27, - 33, 30, 24, 19, 13, 23, 30, 35, 34, 27, 21, 15, 25, 31, 35, 36, 29, 23, 17, - 13, 16, 20, 23, 24, 21, 18, 11, 15, 19, 23, 23, 19, 16, 10, 14, 17, 21, 21, - 19, 15, 9, 11, 15, 18, 20, 16, 14, 6, 9, 12, 15, 18, 16, 13, 6, 8, 11, - 14, 17, 16, 14, 11, 11, 11, 13, 16, 16, 13, 10, 14, 17, 20, 20, 17, 14, 9, - 13, 16, 20, 20, 16, 13, 7, 11, 15, 18, 17, 15, 11, 6, 9, 12, 14, 14, 13, - 10, 4, 7, 10, 13, 13, 13, 10, 7, 7, 9, 11, 12, 12, 10, 14, 12, 10, 11, - 11, 11, 10, 8, 11, 13, 14, 15, 14, 9, 6, 10, 12, 13, 14, 13, 8, 5, 8, - 11, 10, 11, 11, 7, 4, 6, 7, 7, 8, 8, 5, 4, 5, 6, 6, 6, 6, 5, - 9, 9, 8, 7, 5, 5, 5, 16, 14, 10, 7, 5, 4, 4, 5, 6, 6, 7, 8, - 9, 6, 3, 4, 5, 6, 6, 6, 5, 2, 3, 3, 4, 3, 4, 3, 0, 0, 0, - 0, 0, 0, 0, 4, 5, 4, 4, 4, 3, 2, 9, 11, 9, 7, 6, 5, 3, 16, - 17, 12, 9, 7, 6, 5, 6, 6, 6, 6, 7, 6, 6, 7, 7, 7, 7, 8, 6, - 5, 7, 8, 8, 8, 8, 6, 3, 7, 10, 9, 9, 9, 7, 4, 9, 14, 13, 13, - 13, 10, 5, 11, 17, 19, 17, 15, 12, 7, 15, 19, 22, 19, 17, 14, 9, 14, 15, - 15, 15, 12, 9, 6, 14, 18, 17, 16, 13, 9, 4, 14, 19, 19, 18, 14, 9, 5, - 14, 19, 20, 19, 15, 11, 7, 14, 20, 25, 23, 19, 14, 9, 17, 23, 29, 28, 21, - 16, 10, 20, 26, 30, 30, 24, 18, 12, 22, 27, 26, 20, 15, 11, 7, 22, 28, 29, - 22, 16, 12, 7, 21, 28, 31, 23, 17, 12, 7, 22, 27, 31, 24, 19, 15, 11, 21, - 28, 33, 29, 24, 18, 12, 24, 29, 35, 34, 27, 20, 14, 26, 31, 36, 36, 29, 22, - 16, 13, 17, 21, 24, 24, 21, 18, 12, 15, 19, 23, 24, 20, 16, 10, 14, 17, 21, - 22, 18, 15, 9, 12, 15, 18, 21, 17, 14, 6, 9, 12, 15, 19, 17, 14, 6, 8, - 11, 14, 18, 17, 14, 11, 10, 10, 13, 16, 16, 14, 10, 14, 18, 22, 20, 18, 14, - 9, 13, 17, 20, 20, 16, 12, 8, 11, 15, 18, 17, 14, 11, 7, 9, 12, 14, 14, - 13, 9, 5, 7, 10, 12, 13, 12, 10, 7, 8, 9, 11, 12, 12, 10, 13, 11, 10, - 11, 11, 11, 10, 8, 11, 13, 14, 15, 14, 10, 6, 10, 12, 13, 14, 12, 8, 5, - 9, 10, 11, 10, 11, 6, 4, 7, 7, 7, 7, 7, 5, 4, 5, 6, 6, 6, 6, - 5, 10, 9, 8, 7, 5, 5, 5, 15, 13, 10, 7, 5, 4, 4, 5, 6, 6, 7, - 8, 9, 6, 4, 4, 5, 6, 6, 6, 4, 2, 3, 4, 3, 3, 3, 2, 0, 0, - 0, 0, 0, 0, 0, 4, 5, 4, 4, 4, 3, 2, 9, 11, 9, 7, 6, 5, 3, - 15, 16, 12, 9, 7, 6, 5, 6, 6, 6, 6, 7, 6, 6, 7, 7, 7, 7, 8, - 6, 4, 7, 8, 8, 8, 8, 6, 2, 7, 10, 9, 9, 9, 7, 4, 9, 14, 14, - 12, 13, 10, 5, 12, 17, 19, 17, 15, 12, 7, 15, 20, 22, 19, 17, 14, 9, 14, - 16, 15, 15, 12, 8, 6, 15, 18, 17, 17, 14, 9, 4, 15, 19, 19, 18, 14, 9, - 5, 14, 19, 20, 19, 15, 10, 7, 15, 21, 24, 23, 19, 14, 9, 17, 23, 30, 27, - 21, 16, 11, 20, 25, 30, 29, 24, 18, 12, 22, 27, 26, 20, 15, 11, 7, 22, 27, - 27, 21, 16, 11, 7, 22, 27, 30, 23, 17, 12, 7, 22, 27, 30, 24, 19, 15, 11, - 22, 26, 32, 29, 23, 18, 13, 24, 29, 34, 34, 26, 20, 14, 26, 31, 35, 35, 28, - 22, 16, 13, 17, 20, 24, 25, 22, 19, 12, 16, 19, 24, 24, 21, 16, 10, 14, 18, - 21, 23, 19, 15, 9, 12, 15, 19, 21, 17, 14, 7, 10, 12, 16, 19, 16, 14, 6, - 9, 11, 15, 18, 18, 14, 9, 9, 10, 13, 17, 17, 14, 11, 14, 18, 21, 21, 18, - 14, 9, 13, 17, 20, 20, 17, 13, 8, 11, 15, 17, 18, 15, 11, 7, 9, 12, 15, - 14, 13, 9, 5, 8, 10, 13, 13, 13, 10, 7, 7, 9, 12, 12, 12, 10, 10, 9, - 9, 11, 11, 11, 10, 8, 12, 13, 15, 16, 14, 10, 7, 10, 12, 13, 14, 12, 8, - 5, 9, 11, 11, 10, 10, 6, 4, 7, 8, 7, 7, 8, 5, 4, 5, 7, 6, 6, - 6, 5, 9, 8, 7, 6, 5, 5, 5, 11, 10, 8, 6, 4, 4, 4, 6, 6, 6, - 7, 9, 9, 6, 4, 4, 5, 6, 6, 7, 4, 2, 3, 4, 4, 3, 3, 2, 0, - 0, 0, 0, 0, 0, 0, 4, 5, 4, 4, 4, 3, 2, 9, 9, 8, 6, 6, 5, - 3, 12, 13, 10, 8, 7, 6, 5, 6, 6, 6, 6, 7, 6, 6, 7, 7, 7, 8, - 8, 6, 4, 7, 9, 8, 8, 8, 6, 2, 7, 11, 9, 9, 9, 7, 3, 9, 15, - 13, 13, 13, 10, 5, 12, 16, 17, 16, 14, 12, 7, 13, 18, 19, 18, 16, 13, 8, - 14, 15, 14, 13, 12, 8, 6, 15, 17, 15, 14, 12, 9, 4, 15, 18, 17, 15, 12, - 9, 5, 14, 18, 18, 15, 14, 11, 7, 15, 20, 22, 20, 17, 13, 8, 17, 22, 25, - 22, 18, 15, 10, 18, 23, 26, 24, 21, 16, 12, 20, 22, 20, 15, 13, 10, 7, 20, - 23, 22, 17, 14, 11, 7, 20, 23, 23, 17, 14, 11, 7, 20, 23, 24, 19, 16, 14, - 10, 20, 23, 27, 24, 20, 16, 12, 22, 26, 29, 29, 22, 18, 14, 24, 27, 29, 29, - 24, 19, 15, 12, 15, 18, 21, 20, 18, 15, 11, 13, 17, 20, 20, 17, 13, 10, 13, - 15, 18, 18, 15, 12, 9, 11, 13, 15, 18, 14, 11, 7, 9, 11, 14, 17, 14, 11, - 6, 8, 10, 12, 16, 14, 11, 8, 9, 10, 12, 14, 14, 11, 11, 13, 16, 18, 17, - 15, 11, 10, 12, 14, 17, 16, 13, 10, 8, 11, 14, 15, 14, 11, 8, 8, 9, 11, - 13, 12, 10, 7, 6, 8, 10, 11, 11, 10, 7, 5, 7, 9, 11, 10, 10, 7, 10, - 9, 9, 10, 9, 9, 7, 8, 11, 12, 12, 13, 11, 8, 8, 10, 11, 11, 11, 10, - 6, 7, 9, 10, 9, 8, 8, 5, 5, 8, 7, 6, 6, 6, 4, 3, 5, 6, 5, - 5, 5, 4, 7, 7, 7, 6, 5, 4, 4, 11, 11, 8, 6, 5, 3, 3, 7, 6, - 6, 6, 7, 8, 6, 4, 5, 5, 6, 6, 5, 4, 2, 3, 4, 4, 3, 3, 2, - 0, 0, 0, 0, 0, 0, 0, 3, 4, 3, 3, 3, 3, 2, 7, 9, 7, 6, 5, - 4, 3, 12, 13, 10, 8, 6, 5, 4, 4, 4, 5, 5, 6, 6, 6, 5, 6, 5, - 6, 6, 5, 4, 6, 7, 7, 6, 6, 5, 2, 6, 8, 7, 7, 7, 6, 3, 7, - 12, 11, 11, 11, 8, 4, 10, 15, 16, 14, 12, 10, 6, 13, 17, 19, 16, 14, 12, - 7, 11, 13, 12, 12, 10, 7, 6, 11, 14, 13, 13, 10, 7, 4, 12, 16, 16, 14, - 11, 7, 4, 11, 16, 16, 15, 12, 9, 6, 12, 17, 21, 19, 15, 11, 7, 15, 20, - 24, 23, 18, 13, 8, 17, 21, 25, 25, 20, 15, 10, 18, 22, 21, 16, 12, 9, 5, - 18, 22, 23, 17, 13, 9, 5, 18, 22, 25, 18, 13, 10, 6, 18, 22, 26, 21, 16, - 12, 9, 18, 23, 27, 24, 19, 15, 10, 20, 25, 30, 28, 21, 16, 11, 22, 26, 30, - 30, 24, 18, 13, 13, 17, 21, 26, 25, 22, 19, 11, 15, 19, 23, 25, 22, 19, 10, - 14, 18, 21, 24, 21, 17, 9, 12, 15, 18, 21, 19, 15, 6, 9, 12, 15, 16, 18, - 15, 3, 6, 10, 13, 16, 17, 15, 4, 6, 8, 12, 15, 18, 15, 10, 14, 18, 21, - 21, 18, 16, 9, 13, 16, 20, 21, 18, 14, 7, 11, 15, 17, 18, 18, 12, 6, 9, - 12, 15, 15, 15, 10, 3, 6, 9, 12, 12, 14, 10, 2, 4, 7, 10, 12, 11, 10, - 6, 5, 6, 9, 10, 10, 10, 7, 11, 14, 15, 16, 15, 12, 6, 10, 12, 13, 15, - 14, 10, 5, 8, 11, 11, 12, 12, 8, 5, 6, 8, 8, 9, 9, 5, 1, 3, 4, - 5, 5, 6, 5, 4, 3, 3, 3, 3, 4, 5, 8, 7, 4, 2, 2, 2, 3, 6, - 6, 8, 9, 10, 11, 9, 5, 6, 7, 8, 8, 9, 8, 4, 5, 6, 6, 6, 7, - 7, 3, 4, 4, 4, 4, 4, 3, 0, 2, 1, 1, 2, 1, 3, 4, 5, 4, 3, - 2, 2, 3, 8, 9, 6, 4, 3, 2, 3, 4, 6, 6, 6, 7, 8, 9, 5, 6, - 6, 6, 7, 7, 8, 5, 6, 7, 7, 7, 6, 6, 5, 7, 6, 6, 6, 5, 3, - 4, 7, 6, 6, 6, 5, 3, 5, 9, 9, 8, 7, 6, 4, 8, 11, 11, 9, 9, - 7, 4, 9, 11, 11, 11, 9, 7, 8, 9, 12, 11, 12, 10, 7, 7, 10, 13, 12, - 12, 10, 8, 6, 9, 12, 12, 12, 9, 7, 4, 8, 11, 13, 12, 10, 7, 5, 9, - 12, 16, 15, 11, 8, 5, 11, 13, 16, 16, 12, 9, 6, 14, 18, 17, 14, 11, 8, - 7, 14, 18, 19, 14, 12, 9, 7, 14, 19, 21, 14, 12, 9, 7, 14, 17, 20, 15, - 11, 8, 5, 13, 16, 19, 16, 12, 9, 6, 13, 17, 19, 18, 14, 10, 7, 14, 17, - 20, 19, 15, 11, 8, 15, 17, 19, 22, 22, 19, 17, 15, 16, 18, 21, 22, 19, 16, - 14, 16, 18, 19, 20, 18, 14, 13, 14, 15, 17, 18, 15, 10, 10, 11, 12, 13, 14, - 12, 10, 6, 8, 9, 9, 12, 12, 10, 8, 8, 8, 9, 11, 12, 10, 13, 16, 17, - 19, 19, 18, 16, 13, 14, 17, 18, 18, 16, 15, 11, 14, 16, 17, 16, 15, 13, 10, - 12, 14, 14, 14, 13, 9, 7, 9, 10, 11, 10, 9, 9, 3, 6, 7, 8, 9, 9, - 9, 10, 9, 7, 8, 8, 8, 9, 12, 14, 16, 15, 16, 16, 14, 10, 13, 15, 15, - 15, 15, 13, 9, 13, 14, 14, 14, 13, 12, 7, 10, 11, 11, 12, 11, 9, 3, 6, - 8, 8, 8, 8, 8, 5, 5, 5, 6, 7, 7, 8, 12, 12, 8, 5, 6, 6, 8, - 9, 10, 11, 12, 12, 13, 10, 7, 8, 9, 10, 11, 11, 9, 6, 7, 8, 8, 8, - 9, 8, 3, 4, 4, 5, 5, 5, 4, 2, 0, 0, 0, 0, 2, 3, 5, 7, 6, - 4, 2, 1, 3, 12, 14, 9, 6, 4, 3, 3, 4, 5, 7, 8, 9, 9, 10, 5, - 6, 6, 7, 8, 8, 9, 5, 7, 7, 7, 7, 6, 7, 5, 8, 8, 8, 8, 6, - 3, 4, 10, 10, 10, 10, 9, 3, 7, 12, 13, 12, 12, 10, 5, 12, 14, 15, 13, - 12, 11, 7, 12, 14, 14, 15, 11, 8, 9, 12, 16, 15, 16, 13, 8, 8, 12, 18, - 18, 17, 14, 9, 6, 12, 16, 18, 16, 14, 10, 5, 12, 16, 17, 16, 14, 11, 7, - 12, 16, 19, 17, 15, 12, 9, 14, 17, 19, 18, 15, 13, 10, 20, 23, 22, 19, 14, - 10, 8, 19, 23, 23, 19, 15, 12, 7, 19, 23, 25, 20, 16, 12, 7, 19, 22, 25, - 19, 16, 13, 9, 18, 21, 23, 20, 16, 14, 10, 17, 19, 23, 22, 17, 13, 12, 18, - 21, 23, 23, 18, 14, 12, 17, 20, 22, 25, 24, 23, 20, 15, 19, 21, 24, 24, 21, - 19, 14, 17, 21, 22, 22, 20, 17, 13, 15, 18, 20, 21, 18, 13, 9, 12, 15, 17, - 17, 15, 13, 6, 9, 11, 14, 16, 15, 13, 7, 8, 10, 13, 15, 15, 13, 14, 17, - 20, 22, 21, 20, 18, 13, 16, 21, 22, 21, 19, 16, 11, 15, 18, 19, 20, 17, 15, - 10, 12, 16, 17, 17, 16, 11, 7, 9, 12, 14, 13, 12, 11, 4, 7, 9, 12, 12, - 12, 11, 10, 9, 8, 11, 11, 12, 11, 11, 15, 17, 18, 19, 18, 14, 10, 13, 16, - 17, 18, 16, 12, 8, 12, 14, 14, 15, 15, 11, 7, 10, 11, 11, 11, 11, 7, 4, - 6, 7, 8, 7, 8, 7, 4, 5, 5, 6, 6, 7, 7, 11, 11, 7, 4, 5, 5, - 6, 9, 9, 10, 11, 13, 13, 10, 7, 8, 9, 10, 10, 11, 9, 6, 7, 7, 7, - 7, 8, 6, 3, 4, 4, 4, 4, 4, 3, 1, 0, 0, 0, 0, 1, 2, 5, 6, - 5, 4, 2, 2, 2, 11, 13, 8, 6, 4, 3, 3, 4, 5, 6, 8, 9, 10, 10, - 6, 6, 6, 7, 8, 8, 9, 6, 7, 7, 7, 7, 6, 6, 6, 9, 8, 8, 8, - 6, 2, 5, 10, 10, 9, 9, 8, 3, 7, 13, 14, 13, 12, 9, 5, 11, 16, 18, - 15, 14, 11, 6, 13, 15, 15, 15, 11, 9, 10, 12, 16, 16, 16, 12, 8, 8, 13, - 18, 18, 17, 13, 9, 5, 13, 18, 19, 18, 15, 10, 5, 12, 18, 21, 20, 16, 11, - 6, 12, 19, 25, 24, 19, 13, 8, 16, 21, 26, 26, 21, 15, 10, 20, 27, 26, 20, - 15, 10, 9, 21, 27, 28, 22, 16, 11, 7, 20, 28, 31, 23, 17, 12, 7, 21, 26, - 31, 24, 18, 13, 8, 20, 25, 31, 27, 21, 15, 10, 20, 26, 31, 31, 23, 17, 11, - 22, 28, 32, 32, 25, 19, 13, 17, 21, 24, 28, 27, 25, 22, 15, 20, 23, 26, 26, - 24, 20, 14, 18, 21, 24, 25, 22, 19, 13, 16, 19, 21, 23, 20, 15, 9, 12, 15, - 18, 20, 18, 15, 6, 9, 12, 15, 18, 17, 15, 7, 7, 11, 14, 17, 18, 14, 14, - 18, 21, 25, 24, 22, 18, 13, 16, 21, 24, 24, 21, 17, 11, 15, 18, 21, 21, 18, - 14, 10, 13, 15, 17, 18, 16, 11, 7, 10, 12, 14, 15, 14, 11, 4, 7, 10, 12, - 13, 13, 11, 9, 8, 9, 11, 11, 12, 11, 11, 15, 17, 18, 20, 18, 14, 10, 14, - 16, 17, 18, 16, 12, 8, 12, 14, 14, 15, 15, 10, 8, 10, 11, 11, 11, 11, 7, - 4, 6, 7, 7, 8, 7, 7, 5, 5, 6, 6, 6, 6, 7, 11, 10, 7, 4, 5, - 5, 6, 9, 9, 10, 11, 13, 13, 10, 7, 8, 9, 10, 10, 10, 8, 6, 6, 7, - 7, 7, 7, 6, 3, 4, 4, 4, 4, 4, 3, 1, 0, 0, 0, 0, 1, 2, 5, - 6, 5, 4, 2, 2, 2, 10, 11, 8, 5, 4, 3, 3, 5, 5, 6, 8, 8, 10, - 10, 6, 6, 6, 7, 8, 8, 8, 6, 7, 8, 7, 7, 6, 5, 6, 9, 8, 8, - 8, 6, 2, 5, 10, 10, 9, 9, 7, 3, 7, 13, 14, 13, 11, 9, 4, 10, 15, - 18, 15, 13, 11, 6, 13, 14, 14, 15, 11, 9, 10, 13, 17, 16, 16, 12, 8, 7, - 13, 19, 18, 17, 13, 8, 5, 13, 18, 19, 18, 14, 9, 4, 12, 17, 21, 19, 15, - 10, 6, 13, 19, 24, 23, 18, 12, 8, 16, 22, 26, 26, 20, 14, 9, 21, 27, 26, - 20, 15, 10, 8, 21, 27, 28, 21, 16, 11, 6, 20, 26, 31, 22, 17, 12, 6, 20, - 26, 31, 23, 18, 13, 7, 19, 26, 30, 27, 20, 14, 9, 20, 25, 31, 30, 23, 16, - 11, 22, 27, 32, 32, 25, 19, 12, 17, 20, 24, 28, 29, 26, 23, 16, 20, 24, 28, - 28, 24, 20, 14, 18, 22, 25, 26, 23, 19, 13, 16, 19, 22, 25, 21, 15, 10, 13, - 15, 19, 21, 19, 15, 7, 9, 13, 15, 20, 18, 16, 5, 8, 12, 15, 17, 19, 15, - 14, 18, 22, 26, 25, 22, 19, 13, 17, 20, 24, 24, 21, 17, 11, 15, 19, 22, 21, - 19, 15, 10, 13, 16, 18, 18, 17, 12, 7, 10, 12, 14, 15, 14, 11, 4, 7, 10, - 12, 13, 14, 12, 5, 6, 9, 12, 12, 12, 11, 11, 16, 17, 18, 20, 18, 14, 10, - 14, 16, 17, 18, 16, 12, 9, 13, 15, 14, 15, 14, 10, 8, 11, 11, 11, 12, 11, - 7, 4, 7, 8, 8, 8, 8, 7, 4, 5, 6, 6, 6, 6, 7, 6, 5, 5, 5, - 5, 5, 6, 9, 9, 10, 12, 13, 14, 10, 8, 8, 9, 10, 10, 10, 8, 7, 7, - 8, 7, 7, 7, 6, 3, 4, 4, 4, 4, 4, 3, 2, 0, 0, 0, 0, 1, 2, - 5, 5, 3, 2, 2, 1, 1, 6, 7, 4, 4, 3, 2, 2, 5, 5, 6, 8, 9, - 10, 10, 6, 6, 6, 7, 8, 8, 8, 6, 7, 7, 7, 7, 5, 5, 6, 9, 8, - 7, 8, 6, 2, 6, 11, 9, 9, 9, 7, 3, 7, 12, 13, 12, 10, 8, 4, 7, - 12, 15, 14, 12, 10, 5, 13, 15, 14, 14, 11, 9, 10, 13, 17, 16, 15, 12, 8, - 7, 13, 19, 18, 16, 13, 8, 4, 13, 18, 19, 18, 13, 9, 4, 13, 17, 20, 19, - 15, 10, 5, 13, 18, 24, 22, 18, 11, 7, 13, 18, 24, 25, 19, 14, 8, 20, 26, - 24, 19, 14, 10, 9, 20, 26, 27, 21, 15, 10, 6, 21, 26, 28, 21, 16, 11, 6, - 21, 25, 29, 23, 17, 12, 7, 20, 25, 28, 25, 19, 14, 9, 20, 26, 30, 27, 21, - 15, 10, 20, 26, 30, 30, 24, 17, 12, 16, 20, 24, 28, 28, 26, 21, 15, 19, 23, - 27, 28, 24, 20, 13, 17, 21, 24, 26, 22, 18, 12, 15, 18, 21, 24, 20, 15, 9, - 12, 15, 17, 21, 18, 15, 7, 10, 12, 16, 19, 18, 16, 5, 8, 11, 15, 18, 18, - 15, 14, 17, 21, 25, 24, 21, 18, 12, 16, 20, 23, 23, 20, 16, 11, 14, 18, 20, - 21, 18, 14, 9, 12, 15, 18, 18, 16, 11, 7, 9, 11, 14, 14, 14, 11, 4, 7, - 10, 13, 13, 14, 11, 5, 6, 9, 12, 12, 12, 11, 11, 15, 17, 17, 19, 17, 13, - 9, 13, 15, 16, 17, 16, 11, 8, 12, 14, 14, 14, 14, 9, 7, 10, 10, 10, 11, - 11, 7, 3, 6, 7, 7, 7, 8, 6, 4, 5, 6, 6, 6, 6, 7, 7, 5, 5, - 5, 5, 5, 5, 8, 9, 10, 11, 12, 13, 9, 7, 7, 8, 9, 10, 9, 7, 5, - 6, 7, 7, 6, 6, 5, 3, 4, 3, 3, 3, 3, 3, 1, 2, 1, 1, 1, 0, - 1, 4, 5, 3, 3, 2, 2, 1, 7, 8, 5, 4, 3, 2, 2, 5, 5, 5, 7, - 8, 9, 9, 7, 6, 6, 7, 7, 7, 7, 7, 8, 7, 7, 7, 5, 4, 7, 10, - 8, 7, 7, 6, 2, 6, 11, 10, 9, 9, 7, 2, 8, 12, 12, 11, 10, 8, 4, - 8, 12, 15, 12, 11, 10, 5, 14, 14, 13, 12, 11, 8, 9, 14, 16, 15, 14, 11, - 8, 6, 14, 18, 16, 14, 11, 8, 4, 14, 18, 17, 14, 12, 8, 4, 12, 17, 19, - 16, 13, 10, 5, 13, 17, 21, 18, 14, 11, 7, 14, 18, 21, 20, 15, 12, 8, 19, - 22, 19, 15, 12, 10, 7, 19, 22, 21, 17, 14, 10, 6, 20, 22, 23, 17, 13, 10, - 6, 19, 22, 23, 18, 14, 11, 7, 18, 21, 23, 20, 16, 12, 8, 18, 21, 23, 23, - 17, 13, 10, 19, 22, 24, 24, 19, 15, 11, 14, 18, 21, 23, 24, 21, 18, 14, 17, - 20, 23, 23, 20, 16, 12, 15, 19, 21, 22, 18, 15, 11, 14, 16, 19, 20, 17, 14, - 8, 11, 13, 16, 20, 18, 14, 7, 10, 13, 15, 19, 18, 14, 6, 8, 12, 15, 18, - 17, 14, 13, 16, 18, 21, 20, 18, 15, 11, 15, 17, 20, 19, 16, 13, 10, 13, 16, - 18, 17, 15, 12, 9, 11, 14, 16, 15, 14, 11, 6, 9, 12, 14, 14, 13, 10, 5, - 8, 11, 13, 13, 12, 11, 7, 7, 9, 12, 12, 12, 11, 10, 14, 15, 15, 16, 14, - 11, 8, 12, 14, 15, 14, 13, 10, 7, 11, 13, 12, 12, 12, 8, 6, 9, 9, 9, - 9, 9, 6, 3, 7, 8, 7, 7, 7, 6, 4, 5, 6, 6, 6, 6, 6, 8, 7, - 6, 5, 5, 5, 5, 8, 8, 9, 9, 10, 11, 7, 6, 6, 7, 8, 8, 8, 5, - 4, 5, 6, 5, 5, 5, 3, 2, 3, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, - 1, 0, 5, 5, 4, 3, 2, 2, 1, 7, 10, 6, 4, 3, 2, 2, 4, 4, 4, - 5, 6, 7, 7, 5, 5, 4, 4, 5, 5, 5, 5, 4, 4, 3, 3, 2, 2, 4, - 6, 4, 4, 4, 3, 1, 5, 8, 8, 7, 7, 5, 2, 6, 11, 12, 11, 9, 7, - 3, 9, 13, 15, 12, 11, 8, 4, 8, 9, 9, 9, 7, 6, 7, 8, 11, 10, 10, - 7, 4, 4, 8, 12, 12, 11, 7, 4, 2, 8, 12, 13, 12, 9, 6, 3, 9, 13, - 17, 15, 12, 8, 4, 11, 16, 21, 19, 14, 10, 5, 13, 18, 21, 21, 16, 11, 7, - 15, 19, 17, 13, 9, 6, 6, 14, 18, 19, 14, 9, 6, 3, 14, 19, 21, 15, 10, - 6, 3, 14, 18, 22, 16, 12, 9, 6, 14, 18, 23, 21, 16, 11, 7, 16, 21, 25, - 25, 19, 13, 8, 19, 23, 25, 26, 20, 15, 10, 14, 17, 22, 25, 25, 23, 20, 13, - 16, 20, 24, 25, 22, 18, 13, 15, 18, 21, 24, 19, 16, 12, 13, 16, 19, 21, 17, - 14, 9, 10, 12, 14, 15, 16, 13, 5, 6, 8, 11, 13, 15, 13, 3, 3, 6, 9, - 13, 15, 13, 13, 15, 18, 22, 22, 19, 17, 12, 14, 17, 21, 21, 18, 16, 11, 13, - 16, 18, 18, 16, 12, 11, 11, 13, 15, 15, 13, 7, 8, 8, 9, 11, 10, 11, 8, - 3, 3, 5, 8, 9, 9, 8, 4, 3, 4, 7, 8, 8, 7, 12, 13, 15, 16, 17, - 17, 16, 11, 13, 14, 15, 16, 16, 14, 10, 12, 13, 13, 13, 14, 12, 10, 10, 10, - 10, 11, 10, 6, 6, 6, 6, 6, 5, 5, 5, 0, 2, 1, 2, 4, 4, 5, 5, - 4, 2, 1, 3, 4, 5, 11, 12, 13, 13, 15, 16, 16, 10, 11, 12, 14, 14, 15, - 14, 9, 10, 12, 12, 13, 13, 12, 6, 9, 9, 9, 9, 9, 7, 4, 5, 5, 5, - 5, 4, 4, 0, 2, 2, 1, 2, 3, 5, 5, 6, 3, 2, 3, 3, 4, 9, 11, - 12, 13, 14, 15, 16, 8, 9, 11, 12, 13, 14, 14, 8, 9, 10, 11, 11, 12, 12, - 8, 8, 8, 8, 8, 8, 5, 5, 7, 7, 6, 6, 5, 4, 3, 6, 7, 7, 7, - 6, 4, 5, 8, 9, 8, 8, 7, 5, 10, 11, 12, 12, 12, 14, 15, 10, 12, 12, - 13, 12, 12, 14, 10, 13, 13, 13, 11, 10, 11, 10, 12, 13, 12, 11, 8, 5, 8, - 11, 12, 12, 9, 7, 5, 7, 10, 14, 13, 10, 8, 5, 8, 11, 14, 14, 11, 9, - 6, 14, 19, 17, 15, 12, 12, 14, 15, 19, 19, 16, 13, 11, 12, 15, 19, 21, 15, - 13, 10, 9, 15, 18, 21, 15, 12, 9, 6, 13, 16, 18, 15, 11, 9, 7, 12, 15, - 18, 17, 13, 9, 7, 12, 16, 18, 19, 14, 11, 8, 21, 23, 24, 27, 27, 25, 23, - 20, 23, 25, 26, 26, 23, 21, 20, 22, 23, 24, 24, 22, 18, 18, 20, 21, 21, 21, - 18, 12, 15, 17, 18, 17, 16, 13, 12, 11, 13, 13, 12, 13, 13, 12, 6, 8, 10, - 12, 13, 13, 12, 19, 22, 23, 25, 25, 24, 23, 18, 21, 23, 25, 24, 22, 21, 17, - 21, 22, 22, 21, 20, 18, 16, 19, 20, 20, 19, 16, 11, 12, 15, 16, 16, 12, 12, - 11, 8, 11, 12, 10, 11, 11, 11, 4, 6, 9, 10, 10, 11, 11, 17, 20, 21, 23, - 23, 23, 20, 15, 19, 21, 22, 22, 21, 18, 14, 18, 20, 20, 19, 20, 16, 13, 15, - 16, 16, 16, 15, 11, 8, 12, 13, 13, 10, 10, 10, 2, 7, 8, 8, 9, 9, 10, - 5, 6, 6, 7, 8, 9, 10, 14, 15, 17, 18, 19, 20, 18, 12, 13, 16, 17, 17, - 17, 16, 10, 12, 13, 14, 14, 14, 13, 7, 11, 11, 11, 11, 9, 9, 4, 7, 6, - 6, 4, 5, 5, 2, 0, 0, 2, 3, 4, 6, 5, 7, 3, 2, 2, 3, 4, 11, - 12, 13, 15, 16, 17, 18, 8, 11, 13, 14, 15, 15, 16, 8, 10, 11, 11, 12, 13, - 12, 8, 8, 8, 8, 8, 7, 5, 6, 7, 7, 7, 8, 6, 4, 3, 8, 9, 8, - 8, 8, 3, 5, 8, 9, 9, 9, 8, 5, 10, 12, 12, 13, 13, 16, 18, 10, 14, - 14, 15, 12, 14, 14, 10, 15, 15, 14, 11, 10, 11, 9, 14, 15, 13, 12, 7, 3, - 9, 13, 14, 13, 10, 9, 5, 9, 12, 14, 13, 11, 9, 7, 9, 11, 14, 14, 12, - 10, 8, 17, 20, 19, 17, 13, 14, 16, 17, 20, 20, 18, 14, 11, 13, 17, 20, 22, - 17, 14, 9, 9, 17, 19, 21, 16, 13, 11, 7, 15, 17, 19, 16, 12, 10, 8, 13, - 16, 18, 17, 13, 10, 8, 12, 15, 18, 18, 14, 11, 9, 21, 24, 28, 30, 29, 29, - 26, 20, 24, 27, 28, 30, 27, 23, 18, 23, 26, 27, 27, 24, 20, 17, 20, 23, 24, - 25, 21, 15, 14, 17, 20, 21, 19, 17, 15, 10, 13, 15, 16, 18, 17, 15, 6, 9, - 12, 15, 17, 17, 15, 19, 23, 25, 28, 28, 26, 23, 17, 21, 25, 27, 27, 24, 21, - 16, 19, 24, 25, 24, 22, 18, 15, 17, 21, 22, 21, 18, 13, 12, 14, 17, 18, 15, - 14, 13, 7, 10, 12, 14, 14, 14, 13, 4, 6, 10, 13, 13, 13, 13, 16, 20, 22, - 23, 25, 22, 18, 15, 18, 20, 22, 22, 21, 17, 14, 17, 19, 19, 19, 19, 14, 12, - 15, 16, 16, 15, 14, 9, 7, 11, 12, 12, 10, 10, 9, 2, 7, 7, 8, 8, 8, - 9, 5, 5, 6, 6, 7, 7, 8, 14, 14, 15, 16, 18, 18, 16, 12, 13, 14, 15, - 16, 16, 13, 9, 12, 12, 12, 12, 12, 10, 6, 10, 9, 9, 9, 7, 8, 4, 6, - 5, 5, 3, 3, 4, 1, 0, 0, 1, 2, 3, 3, 5, 6, 3, 2, 2, 2, 2, - 10, 11, 12, 13, 14, 15, 16, 7, 10, 11, 12, 13, 13, 14, 7, 9, 10, 10, 10, - 10, 10, 7, 7, 7, 7, 7, 6, 3, 5, 7, 7, 7, 8, 6, 2, 3, 8, 10, - 9, 9, 8, 3, 5, 11, 13, 11, 11, 10, 5, 10, 13, 13, 13, 12, 14, 15, 10, - 14, 14, 15, 11, 12, 13, 10, 16, 16, 16, 11, 9, 8, 10, 15, 17, 17, 12, 7, - 3, 9, 15, 19, 18, 15, 10, 5, 9, 15, 22, 21, 17, 11, 7, 11, 17, 22, 23, - 20, 14, 8, 18, 25, 24, 18, 13, 13, 14, 19, 25, 26, 19, 14, 11, 11, 18, 24, - 29, 21, 15, 10, 7, 18, 25, 29, 22, 17, 11, 6, 18, 23, 28, 25, 19, 13, 8, - 17, 23, 28, 27, 21, 15, 10, 18, 23, 28, 29, 22, 18, 12, 20, 24, 27, 31, 31, - 28, 26, 19, 23, 27, 30, 30, 27, 23, 18, 21, 25, 27, 29, 26, 21, 16, 19, 22, - 25, 26, 23, 17, 13, 16, 18, 21, 22, 19, 16, 10, 12, 15, 17, 20, 19, 16, 6, - 9, 12, 16, 18, 19, 16, 18, 21, 25, 28, 28, 26, 22, 16, 20, 24, 27, 27, 23, - 19, 15, 18, 22, 24, 24, 22, 17, 14, 16, 19, 22, 21, 19, 13, 11, 13, 16, 18, - 16, 15, 13, 7, 9, 12, 14, 14, 14, 12, 4, 7, 10, 13, 13, 14, 12, 15, 18, - 21, 22, 24, 21, 18, 14, 17, 20, 21, 21, 19, 16, 13, 16, 18, 18, 18, 17, 13, - 11, 13, 15, 14, 15, 14, 8, 7, 10, 11, 11, 10, 9, 8, 2, 6, 7, 7, 8, - 8, 8, 3, 5, 6, 6, 7, 7, 7, 13, 13, 14, 15, 16, 17, 14, 11, 11, 13, - 14, 14, 14, 11, 8, 10, 11, 11, 11, 10, 9, 5, 8, 7, 7, 7, 6, 6, 3, - 4, 4, 4, 2, 2, 3, 1, 2, 1, 0, 1, 2, 3, 3, 4, 2, 2, 2, 2, - 2, 9, 9, 10, 11, 12, 14, 13, 6, 8, 9, 10, 11, 11, 11, 6, 8, 8, 8, - 9, 9, 8, 6, 7, 6, 6, 6, 5, 3, 4, 8, 8, 8, 8, 6, 2, 3, 9, - 10, 10, 9, 7, 3, 5, 9, 12, 11, 11, 9, 5, 11, 13, 13, 13, 11, 12, 13, - 11, 15, 15, 15, 11, 10, 10, 11, 16, 16, 16, 11, 8, 7, 11, 16, 17, 16, 12, - 8, 3, 10, 15, 19, 17, 14, 9, 5, 10, 15, 22, 21, 16, 10, 6, 11, 16, 21, - 23, 18, 13, 8, 19, 25, 24, 18, 13, 11, 12, 19, 25, 27, 20, 14, 9, 9, 18, - 25, 29, 21, 15, 10, 6, 19, 24, 29, 22, 16, 11, 6, 18, 24, 29, 24, 18, 13, - 8, 18, 23, 29, 27, 20, 14, 9, 18, 24, 30, 29, 22, 16, 11, 19, 23, 26, 31, - 30, 27, 24, 17, 22, 26, 29, 30, 27, 22, 16, 20, 23, 27, 28, 25, 21, 15, 17, - 21, 24, 27, 23, 17, 12, 15, 17, 20, 22, 20, 17, 8, 11, 13, 17, 21, 20, 16, - 6, 9, 13, 16, 19, 20, 17, 16, 20, 24, 28, 27, 25, 21, 15, 19, 22, 26, 27, - 23, 19, 14, 18, 21, 24, 23, 21, 17, 12, 15, 18, 20, 20, 18, 13, 9, 12, 14, - 17, 16, 16, 13, 6, 9, 12, 14, 14, 15, 12, 4, 7, 10, 13, 13, 14, 13, 14, - 18, 19, 20, 22, 20, 17, 12, 15, 19, 19, 20, 19, 14, 11, 15, 17, 16, 16, 17, - 12, 10, 13, 13, 13, 13, 13, 8, 6, 9, 10, 10, 9, 9, 8, 3, 6, 7, 7, - 8, 8, 8, 4, 5, 6, 6, 7, 7, 7, 11, 12, 12, 14, 15, 16, 12, 10, 10, - 11, 12, 13, 13, 10, 8, 9, 10, 9, 9, 9, 7, 4, 7, 6, 6, 6, 6, 5, - 2, 2, 2, 2, 2, 2, 3, 2, 4, 2, 1, 0, 1, 2, 4, 6, 3, 2, 2, - 1, 2, 6, 7, 8, 9, 10, 11, 12, 5, 6, 7, 9, 9, 9, 10, 5, 6, 7, - 6, 6, 7, 6, 5, 7, 6, 6, 6, 5, 3, 4, 9, 8, 7, 7, 5, 2, 5, - 9, 10, 9, 9, 7, 3, 6, 10, 12, 11, 10, 9, 4, 11, 13, 13, 13, 10, 10, - 11, 12, 15, 14, 14, 11, 8, 9, 11, 17, 16, 15, 11, 7, 5, 11, 16, 17, 16, - 12, 8, 3, 11, 16, 19, 18, 14, 9, 4, 11, 16, 22, 20, 15, 10, 6, 11, 16, - 22, 22, 17, 12, 7, 19, 25, 23, 17, 13, 9, 10, 19, 25, 25, 19, 14, 9, 7, - 20, 25, 27, 20, 15, 10, 5, 19, 24, 28, 22, 16, 11, 6, 18, 24, 28, 23, 17, - 12, 7, 18, 23, 27, 25, 20, 14, 9, 18, 23, 27, 28, 22, 16, 10, 18, 22, 26, - 29, 29, 26, 23, 16, 20, 24, 29, 29, 25, 21, 15, 19, 23, 25, 28, 23, 19, 14, - 16, 19, 23, 25, 22, 16, 10, 13, 16, 19, 23, 20, 16, 8, 11, 14, 17, 21, 20, - 17, 7, 10, 13, 16, 19, 20, 16, 15, 19, 23, 26, 26, 23, 19, 14, 17, 22, 25, - 25, 21, 18, 12, 16, 20, 22, 23, 20, 16, 11, 14, 16, 19, 19, 17, 13, 8, 11, - 13, 16, 16, 15, 13, 6, 9, 12, 14, 14, 14, 13, 5, 7, 11, 13, 13, 13, 13, - 13, 16, 18, 19, 21, 19, 15, 11, 15, 17, 18, 19, 17, 13, 10, 13, 16, 15, 16, - 15, 11, 9, 11, 12, 12, 12, 12, 8, 5, 8, 9, 9, 9, 9, 8, 3, 6, 7, - 8, 7, 7, 8, 5, 5, 6, 6, 7, 7, 7, 10, 10, 11, 12, 14, 14, 10, 9, - 9, 10, 11, 11, 11, 8, 7, 8, 8, 8, 8, 8, 6, 3, 5, 5, 5, 5, 5, - 4, 2, 1, 2, 2, 1, 2, 2, 3, 4, 3, 2, 1, 0, 1, 5, 7, 4, 3, - 2, 2, 2, 4, 4, 6, 7, 8, 9, 10, 5, 5, 5, 7, 7, 7, 8, 5, 6, - 6, 6, 5, 5, 5, 5, 8, 7, 6, 6, 5, 1, 5, 9, 8, 7, 8, 5, 2, - 6, 10, 11, 10, 9, 7, 3, 7, 10, 13, 11, 11, 9, 4, 12, 13, 12, 12, 10, - 8, 9, 12, 15, 14, 13, 11, 7, 7, 12, 17, 16, 13, 11, 6, 4, 13, 16, 16, - 14, 12, 7, 3, 11, 16, 18, 15, 13, 9, 4, 11, 16, 20, 18, 14, 10, 6, 12, - 16, 21, 20, 15, 12, 7, 18, 21, 19, 15, 12, 9, 8, 18, 21, 20, 16, 13, 9, - 5, 18, 21, 23, 16, 13, 9, 5, 18, 21, 23, 17, 14, 10, 6, 18, 20, 23, 20, - 15, 12, 8, 18, 20, 23, 21, 17, 13, 9, 18, 21, 23, 23, 18, 13, 10, 17, 20, - 24, 27, 27, 24, 21, 16, 19, 23, 26, 27, 23, 20, 14, 18, 21, 24, 26, 22, 18, - 13, 16, 18, 21, 24, 21, 17, 10, 12, 15, 18, 22, 20, 16, 8, 11, 14, 17, 21, - 20, 16, 7, 10, 13, 16, 20, 19, 17, 14, 17, 21, 24, 23, 21, 18, 13, 17, 20, - 23, 23, 20, 16, 11, 15, 19, 21, 20, 18, 14, 10, 13, 16, 19, 17, 16, 12, 7, - 11, 13, 15, 16, 15, 12, 6, 9, 12, 14, 15, 14, 12, 6, 8, 11, 13, 13, 13, - 12, 12, 15, 17, 17, 19, 17, 13, 10, 13, 16, 17, 17, 16, 11, 9, 12, 14, 14, - 14, 14, 10, 8, 10, 11, 11, 11, 11, 7, 5, 8, 9, 9, 8, 8, 7, 5, 7, - 8, 8, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 9, 9, 10, 11, 12, 13, 8, - 8, 8, 9, 9, 9, 10, 6, 6, 7, 7, 7, 6, 6, 4, 3, 4, 4, 3, 3, - 3, 3, 3, 3, 2, 2, 1, 1, 1, 5, 5, 4, 2, 2, 1, 0, 7, 7, 4, - 3, 2, 2, 2, 3, 3, 4, 5, 6, 8, 8, 4, 4, 4, 5, 5, 5, 6, 4, - 5, 4, 3, 3, 3, 3, 4, 6, 4, 3, 3, 3, 0, 5, 6, 5, 4, 4, 3, - 2, 6, 8, 9, 7, 6, 4, 2, 7, 10, 11, 8, 7, 5, 2, 6, 6, 6, 6, - 5, 7, 7, 6, 8, 7, 7, 5, 4, 5, 6, 9, 8, 7, 4, 2, 2, 6, 8, - 9, 8, 5, 3, 2, 7, 10, 13, 12, 9, 5, 2, 8, 12, 17, 15, 11, 7, 3, - 10, 14, 18, 17, 12, 8, 4, 11, 15, 14, 9, 6, 6, 6, 10, 15, 16, 10, 6, - 3, 3, 10, 15, 18, 11, 7, 3, 2, 10, 14, 18, 12, 8, 5, 3, 10, 15, 20, - 17, 12, 8, 4, 12, 17, 22, 20, 15, 10, 5, 14, 20, 23, 22, 17, 11, 7, 20, - 21, 23, 26, 26, 25, 23, 19, 21, 23, 25, 26, 23, 21, 18, 20, 21, 23, 23, 19, - 16, 18, 18, 19, 19, 20, 15, 11, 15, 15, 15, 14, 14, 14, 10, 11, 11, 8, 10, - 12, 14, 10, 5, 3, 5, 8, 11, 14, 10, 19, 20, 22, 23, 24, 23, 22, 18, 20, - 21, 24, 24, 21, 19, 18, 19, 21, 21, 20, 19, 16, 17, 17, 18, 18, 16, 13, 8, - 14, 14, 14, 13, 9, 9, 8, 9, 9, 7, 6, 8, 9, 9, 2, 2, 4, 5, 7, - 8, 8, 18, 20, 20, 21, 23, 23, 22, 17, 18, 20, 21, 22, 21, 19, 17, 18, 19, - 20, 19, 18, 16, 16, 17, 16, 16, 15, 12, 9, 11, 12, 12, 11, 7, 8, 8, 4, - 7, 6, 4, 6, 8, 8, 0, 2, 2, 4, 6, 6, 8, 17, 18, 19, 21, 23, 24, - 23, 16, 18, 20, 20, 21, 21, 20, 14, 18, 19, 19, 19, 18, 17, 10, 17, 16, 16, - 15, 12, 12, 7, 12, 11, 11, 6, 7, 8, 5, 5, 5, 3, 4, 5, 6, 0, 3, - 3, 3, 4, 5, 6, 15, 17, 19, 20, 22, 23, 23, 12, 16, 18, 19, 20, 20, 21, - 12, 16, 17, 17, 17, 17, 15, 12, 13, 13, 13, 12, 10, 7, 10, 9, 8, 8, 7, - 6, 6, 6, 7, 7, 6, 7, 7, 5, 4, 6, 8, 7, 7, 8, 6, 13, 14, 15, - 16, 19, 22, 23, 13, 14, 14, 16, 17, 18, 19, 13, 15, 15, 14, 14, 15, 14, 13, - 13, 13, 13, 12, 9, 6, 11, 12, 13, 12, 9, 8, 6, 8, 10, 13, 13, 10, 8, - 7, 7, 10, 13, 14, 11, 8, 7, 16, 19, 18, 16, 17, 20, 21, 16, 18, 19, 17, - 16, 17, 18, 16, 18, 20, 16, 14, 13, 13, 16, 17, 20, 15, 12, 10, 7, 14, 16, - 18, 16, 11, 8, 7, 12, 15, 17, 17, 12, 10, 8, 11, 15, 18, 18, 14, 10, 8, - 27, 30, 31, 32, 32, 31, 30, 26, 29, 31, 32, 32, 29, 27, 25, 28, 29, 30, 29, - 26, 23, 24, 26, 27, 27, 25, 21, 15, 21, 24, 23, 21, 18, 16, 15, 17, 19, 16, - 15, 17, 17, 15, 11, 11, 13, 15, 16, 16, 15, 25, 28, 30, 31, 30, 30, 29, 24, - 27, 30, 31, 30, 29, 26, 22, 26, 29, 28, 27, 25, 22, 22, 24, 25, 25, 23, 20, - 14, 18, 20, 22, 20, 15, 15, 14, 13, 16, 15, 14, 14, 14, 14, 7, 9, 12, 13, - 13, 14, 14, 23, 26, 27, 29, 30, 29, 26, 21, 25, 27, 29, 29, 27, 23, 20, 24, - 26, 26, 25, 24, 20, 18, 21, 22, 22, 21, 18, 14, 13, 17, 18, 17, 14, 14, 13, - 6, 13, 12, 10, 12, 12, 13, 3, 7, 8, 10, 11, 11, 13, 20, 21, 22, 24, 25, - 26, 25, 18, 20, 22, 23, 23, 22, 21, 15, 20, 20, 21, 20, 19, 18, 11, 19, 17, - 17, 16, 12, 13, 9, 14, 13, 11, 7, 8, 9, 6, 7, 6, 4, 6, 7, 7, 3, - 0, 3, 4, 5, 6, 8, 16, 19, 20, 21, 22, 24, 24, 12, 18, 20, 21, 21, 21, - 21, 12, 18, 18, 18, 18, 17, 16, 12, 14, 15, 14, 13, 10, 8, 10, 8, 9, 8, - 5, 4, 7, 6, 5, 5, 5, 5, 4, 6, 3, 3, 5, 5, 6, 5, 5, 13, 14, - 16, 17, 20, 22, 24, 13, 13, 14, 16, 18, 19, 20, 13, 13, 13, 14, 15, 16, 14, - 13, 12, 12, 12, 10, 9, 6, 10, 10, 11, 9, 7, 5, 5, 7, 8, 10, 9, 7, - 6, 4, 5, 7, 10, 10, 8, 7, 4, 14, 17, 16, 15, 18, 21, 22, 14, 16, 17, - 15, 16, 18, 18, 14, 17, 18, 14, 13, 13, 13, 14, 15, 17, 13, 11, 8, 4, 12, - 13, 15, 12, 8, 6, 5, 10, 12, 14, 13, 9, 7, 5, 8, 11, 14, 14, 10, 8, - 6, 25, 28, 31, 33, 33, 32, 29, 23, 27, 30, 32, 33, 30, 26, 21, 26, 29, 30, - 30, 27, 23, 21, 23, 26, 27, 28, 22, 17, 17, 20, 22, 23, 21, 19, 16, 13, 16, - 17, 17, 20, 19, 17, 8, 11, 14, 17, 19, 19, 16, 22, 25, 29, 31, 31, 29, 27, - 20, 25, 28, 30, 29, 28, 24, 19, 23, 26, 28, 27, 25, 21, 18, 21, 24, 25, 23, - 20, 15, 15, 17, 19, 20, 17, 16, 15, 11, 13, 15, 15, 15, 16, 15, 5, 9, 12, - 14, 15, 15, 15, 20, 23, 26, 27, 28, 26, 22, 18, 22, 24, 25, 26, 24, 20, 17, - 21, 23, 22, 22, 22, 17, 15, 18, 19, 19, 19, 17, 11, 9, 14, 15, 15, 12, 12, - 12, 3, 10, 11, 10, 10, 11, 11, 3, 6, 8, 8, 9, 9, 10, 17, 18, 18, 19, - 21, 22, 19, 14, 16, 17, 18, 19, 19, 16, 11, 15, 16, 16, 15, 15, 13, 8, 13, - 12, 12, 11, 10, 10, 6, 9, 8, 8, 5, 5, 6, 3, 3, 3, 2, 3, 4, 4, - 3, 3, 0, 2, 3, 4, 5, 12, 14, 15, 16, 17, 18, 19, 8, 13, 14, 15, 16, - 16, 16, 8, 12, 13, 13, 13, 13, 11, 8, 10, 10, 10, 9, 7, 4, 6, 6, 5, - 5, 6, 4, 4, 4, 6, 8, 8, 8, 6, 3, 2, 7, 10, 10, 10, 8, 3, 9, - 11, 11, 13, 15, 17, 18, 9, 12, 12, 13, 13, 15, 16, 9, 14, 14, 14, 11, 11, - 10, 9, 13, 15, 15, 11, 7, 3, 7, 12, 17, 17, 13, 8, 3, 7, 13, 19, 19, - 15, 10, 5, 8, 14, 20, 20, 17, 12, 6, 16, 22, 22, 16, 13, 16, 17, 16, 23, - 24, 18, 12, 13, 14, 17, 23, 26, 19, 13, 9, 10, 17, 22, 26, 20, 14, 9, 5, - 15, 21, 25, 23, 17, 12, 6, 15, 21, 25, 23, 18, 14, 8, 16, 21, 24, 24, 20, - 15, 10, 23, 26, 30, 33, 32, 30, 27, 21, 25, 29, 32, 32, 29, 26, 19, 24, 27, - 31, 31, 27, 22, 18, 21, 24, 27, 28, 24, 18, 15, 18, 20, 23, 23, 21, 18, 11, - 14, 17, 18, 22, 21, 18, 8, 11, 14, 17, 20, 21, 18, 19, 23, 27, 31, 29, 27, - 25, 18, 22, 26, 30, 29, 25, 22, 17, 20, 25, 26, 26, 24, 19, 16, 19, 22, 24, - 23, 20, 15, 13, 15, 18, 19, 18, 17, 14, 9, 11, 14, 16, 16, 16, 14, 5, 8, - 12, 15, 15, 15, 14, 17, 21, 23, 24, 26, 23, 20, 16, 19, 22, 23, 23, 21, 18, - 15, 18, 20, 20, 20, 20, 15, 13, 16, 16, 17, 17, 15, 10, 8, 12, 13, 13, 12, - 11, 10, 3, 8, 9, 9, 9, 10, 10, 3, 6, 7, 8, 8, 9, 8, 15, 15, 16, - 17, 19, 19, 15, 13, 14, 15, 16, 17, 17, 13, 10, 12, 13, 13, 13, 13, 10, 6, - 10, 9, 9, 9, 8, 8, 4, 6, 6, 6, 4, 3, 4, 2, 2, 2, 2, 2, 3, - 3, 3, 4, 2, 0, 2, 2, 3, 9, 10, 11, 12, 13, 15, 15, 6, 10, 11, 12, - 13, 13, 13, 6, 9, 9, 9, 10, 9, 9, 6, 7, 6, 6, 6, 5, 3, 4, 6, - 6, 6, 6, 4, 3, 2, 7, 9, 8, 8, 6, 2, 4, 8, 11, 10, 9, 8, 3, - 9, 11, 11, 12, 12, 14, 15, 9, 13, 13, 13, 11, 11, 11, 9, 15, 15, 14, 10, - 8, 8, 9, 14, 15, 15, 11, 6, 2, 8, 13, 18, 16, 12, 8, 3, 8, 14, 20, - 19, 14, 9, 5, 9, 14, 20, 21, 16, 11, 6, 17, 23, 22, 17, 11, 12, 13, 17, - 23, 24, 18, 12, 10, 10, 17, 23, 27, 19, 13, 8, 7, 17, 22, 27, 20, 15, 9, - 5, 16, 21, 27, 22, 16, 11, 6, 16, 22, 27, 25, 18, 13, 8, 16, 22, 27, 27, - 21, 15, 9, 20, 25, 28, 32, 32, 30, 27, 20, 23, 27, 31, 32, 27, 24, 17, 22, - 25, 29, 30, 26, 22, 17, 19, 22, 25, 28, 24, 18, 14, 16, 19, 21, 24, 22, 18, - 10, 12, 15, 18, 22, 21, 18, 8, 10, 14, 17, 20, 21, 18, 18, 22, 26, 29, 29, - 25, 22, 17, 20, 23, 27, 28, 24, 20, 15, 19, 23, 25, 25, 22, 19, 14, 17, 20, - 22, 22, 20, 14, 11, 14, 15, 18, 18, 17, 14, 7, 10, 13, 15, 16, 17, 14, 5, - 8, 12, 14, 15, 15, 14, 16, 19, 20, 22, 24, 22, 18, 14, 17, 20, 21, 22, 20, - 15, 13, 17, 18, 18, 19, 17, 13, 12, 15, 15, 14, 15, 14, 10, 8, 11, 11, 11, - 11, 10, 9, 3, 8, 9, 9, 9, 9, 9, 4, 6, 7, 7, 8, 8, 8, 13, 14, - 14, 15, 17, 18, 13, 12, 12, 13, 14, 14, 14, 11, 9, 11, 11, 11, 11, 11, 8, - 5, 9, 8, 7, 7, 7, 6, 3, 4, 4, 4, 3, 3, 3, 3, 2, 2, 2, 2, - 2, 2, 4, 5, 3, 2, 0, 1, 2, 7, 7, 8, 9, 11, 12, 12, 5, 7, 8, - 9, 9, 10, 10, 5, 6, 7, 7, 7, 7, 7, 5, 6, 5, 5, 5, 4, 2, 3, - 7, 6, 6, 6, 4, 2, 3, 8, 9, 8, 8, 6, 2, 4, 8, 11, 10, 10, 7, - 3, 10, 12, 12, 11, 9, 11, 12, 10, 14, 13, 13, 10, 8, 9, 10, 16, 15, 14, - 10, 6, 6, 10, 15, 16, 15, 11, 6, 2, 9, 14, 18, 17, 12, 8, 3, 9, 15, - 20, 19, 14, 9, 5, 10, 15, 20, 21, 16, 11, 6, 18, 24, 23, 16, 12, 10, 10, - 18, 23, 24, 18, 13, 8, 8, 18, 24, 26, 19, 13, 8, 5, 18, 23, 28, 21, 15, - 10, 4, 17, 22, 27, 23, 16, 11, 6, 17, 22, 27, 26, 18, 13, 8, 17, 22, 27, - 27, 21, 15, 9, 20, 24, 27, 31, 30, 28, 25, 18, 22, 25, 29, 30, 27, 23, 16, - 20, 24, 27, 28, 25, 21, 15, 18, 21, 24, 27, 23, 18, 12, 15, 17, 21, 24, 21, - 18, 9, 12, 15, 18, 22, 21, 18, 8, 11, 14, 17, 21, 21, 18, 17, 20, 24, 28, - 28, 25, 21, 15, 20, 23, 26, 27, 23, 19, 14, 17, 21, 24, 24, 21, 17, 13, 15, - 19, 20, 20, 19, 14, 10, 12, 15, 17, 17, 17, 14, 7, 10, 13, 15, 16, 16, 14, - 6, 9, 12, 15, 14, 14, 14, 14, 17, 20, 21, 22, 20, 16, 13, 16, 18, 19, 20, - 19, 14, 12, 15, 17, 17, 17, 16, 12, 11, 13, 13, 13, 14, 13, 9, 7, 9, 10, - 10, 10, 10, 9, 4, 8, 9, 9, 9, 9, 9, 5, 7, 7, 7, 8, 8, 8, 12, - 12, 13, 14, 15, 16, 11, 10, 11, 11, 12, 13, 13, 9, 9, 9, 10, 10, 9, 9, - 7, 5, 7, 6, 6, 6, 6, 5, 2, 3, 3, 3, 2, 3, 3, 3, 3, 2, 2, - 1, 1, 2, 5, 6, 4, 3, 1, 0, 1, 5, 5, 6, 8, 8, 10, 11, 4, 5, - 6, 7, 8, 8, 9, 4, 5, 5, 5, 5, 5, 5, 4, 6, 5, 5, 5, 3, 2, - 3, 8, 7, 6, 6, 4, 1, 4, 9, 10, 8, 8, 6, 2, 5, 9, 12, 10, 10, - 8, 3, 10, 12, 11, 11, 9, 9, 10, 10, 14, 13, 12, 10, 7, 7, 10, 16, 14, - 13, 10, 5, 4, 10, 15, 15, 14, 10, 6, 2, 10, 14, 17, 15, 12, 8, 3, 10, - 15, 19, 17, 13, 9, 5, 10, 15, 20, 19, 15, 11, 6, 17, 21, 19, 15, 11, 8, - 8, 17, 21, 20, 16, 12, 8, 6, 18, 21, 22, 16, 12, 8, 4, 17, 20, 22, 17, - 13, 9, 5, 17, 20, 23, 20, 15, 11, 6, 16, 20, 23, 21, 16, 13, 8, 16, 20, - 23, 23, 18, 13, 9, 19, 23, 26, 29, 30, 28, 24, 17, 21, 24, 29, 29, 26, 22, - 16, 20, 23, 27, 27, 24, 20, 14, 17, 20, 24, 26, 22, 18, 11, 14, 16, 20, 23, - 21, 18, 10, 13, 15, 19, 22, 21, 18, 8, 11, 15, 18, 21, 21, 18, 16, 20, 23, - 27, 26, 23, 20, 14, 19, 22, 26, 25, 22, 18, 13, 17, 20, 23, 23, 20, 16, 12, - 15, 17, 21, 20, 18, 14, 9, 12, 14, 17, 17, 17, 14, 8, 11, 13, 16, 16, 16, - 14, 6, 9, 12, 15, 15, 15, 14, 13, 17, 19, 20, 21, 19, 15, 12, 16, 18, 19, - 19, 18, 13, 11, 14, 16, 16, 16, 16, 11, 10, 12, 13, 12, 13, 13, 9, 6, 9, - 10, 10, 10, 10, 9, 5, 8, 9, 9, 9, 9, 9, 6, 7, 8, 8, 8, 8, 8, - 11, 11, 12, 13, 14, 15, 9, 9, 9, 10, 11, 12, 11, 7, 8, 8, 9, 9, 8, - 8, 6, 4, 6, 5, 5, 5, 5, 4, 3, 3, 3, 3, 3, 3, 2, 4, 4, 3, - 2, 2, 2, 2, 6, 8, 5, 3, 2, 1, 0, 2, 3, 5, 6, 7, 8, 9, 2, - 3, 4, 5, 6, 6, 7, 2, 3, 3, 3, 3, 4, 4, 2, 5, 3, 2, 2, 2, - 1, 3, 7, 5, 4, 4, 3, 0, 5, 8, 7, 5, 3, 3, 2, 7, 8, 8, 6, - 5, 3, 2, 6, 6, 5, 5, 6, 7, 9, 6, 8, 5, 5, 5, 5, 6, 6, 8, - 6, 5, 3, 3, 3, 6, 7, 7, 5, 4, 3, 1, 7, 9, 10, 8, 6, 3, 2, - 8, 10, 13, 11, 7, 4, 3, 9, 11, 14, 14, 9, 5, 3, 8, 11, 10, 6, 5, - 7, 7, 8, 11, 11, 7, 4, 4, 4, 8, 11, 13, 7, 4, 3, 2, 8, 11, 14, - 9, 6, 4, 3, 9, 11, 15, 13, 8, 5, 3, 9, 13, 18, 16, 11, 6, 3, 11, - 15, 18, 17, 12, 7, 4, 14, 17, 20, 24, 23, 22, 19, 13, 16, 19, 23, 23, 21, - 17, 12, 14, 17, 20, 21, 18, 16, 11, 13, 15, 17, 20, 18, 15, 11, 13, 14, 15, - 19, 17, 15, 9, 11, 13, 15, 17, 17, 15, 12, 12, 12, 14, 16, 17, 15, 12, 15, - 17, 20, 21, 19, 16, 11, 13, 16, 19, 21, 18, 14, 11, 13, 15, 17, 18, 16, 13, - 9, 12, 14, 15, 15, 14, 13, 9, 11, 13, 14, 14, 14, 13, 7, 10, 11, 13, 13, - 13, 13, 14, 14, 11, 12, 12, 12, 12, 10, 13, 14, 15, 16, 15, 12, 9, 12, 13, - 13, 15, 14, 11, 8, 11, 12, 12, 12, 13, 11, 7, 10, 11, 11, 12, 11, 11, 6, - 9, 11, 11, 11, 11, 11, 9, 10, 10, 9, 10, 11, 11, 15, 16, 12, 9, 9, 10, - 11, 8, 8, 9, 10, 10, 11, 4, 7, 7, 8, 8, 8, 9, 5, 6, 6, 6, 7, - 7, 7, 4, 4, 5, 5, 6, 6, 6, 4, 4, 4, 4, 5, 5, 5, 4, 9, 11, - 10, 8, 6, 3, 3, 15, 16, 12, 9, 7, 4, 2, 0, 1, 1, 2, 2, 2, 4, - 2, 2, 2, 2, 2, 1, 5, 2, 3, 3, 3, 4, 2, 4, 2, 6, 5, 6, 6, - 5, 2, 4, 9, 8, 7, 7, 7, 3, 9, 11, 11, 9, 9, 8, 4, 14, 14, 13, - 10, 9, 8, 6, 8, 8, 8, 8, 7, 2, 3, 8, 10, 9, 9, 7, 3, 2, 7, - 11, 10, 9, 8, 5, 0, 8, 10, 11, 10, 8, 7, 4, 8, 11, 14, 13, 11, 8, - 6, 10, 13, 17, 15, 12, 9, 7, 12, 15, 17, 16, 13, 10, 8, 12, 16, 14, 11, - 8, 6, 2, 12, 16, 16, 12, 9, 6, 2, 12, 16, 18, 12, 9, 7, 4, 12, 15, - 19, 14, 11, 8, 7, 12, 16, 19, 17, 13, 10, 7, 13, 17, 20, 19, 15, 11, 8, - 15, 18, 20, 21, 16, 12, 9, 15, 17, 19, 20, 21, 18, 17, 14, 16, 18, 20, 20, - 19, 17, 12, 15, 18, 19, 20, 18, 17, 11, 14, 17, 18, 20, 19, 17, 11, 14, 17, - 19, 21, 19, 17, 10, 14, 16, 18, 20, 19, 17, 13, 13, 15, 18, 20, 19, 17, 13, - 15, 18, 19, 18, 16, 14, 12, 15, 17, 19, 18, 16, 14, 11, 14, 16, 17, 17, 16, - 14, 9, 13, 16, 17, 17, 17, 15, 9, 12, 15, 17, 17, 17, 15, 8, 11, 14, 16, - 16, 16, 15, 16, 14, 13, 15, 15, 15, 15, 10, 14, 14, 15, 15, 13, 10, 9, 12, - 14, 14, 14, 13, 10, 8, 11, 12, 13, 13, 13, 10, 7, 11, 12, 12, 13, 13, 11, - 7, 10, 11, 12, 12, 12, 11, 10, 11, 10, 11, 11, 11, 11, 17, 17, 12, 10, 10, - 10, 10, 8, 8, 8, 9, 9, 9, 3, 7, 7, 7, 7, 8, 8, 3, 6, 6, 6, - 6, 6, 6, 4, 4, 5, 5, 6, 6, 6, 4, 6, 6, 5, 5, 5, 5, 4, 10, - 12, 10, 9, 6, 5, 3, 17, 19, 14, 10, 7, 5, 3, 1, 0, 1, 1, 2, 2, - 3, 2, 2, 1, 2, 2, 1, 3, 2, 3, 3, 3, 3, 1, 3, 2, 7, 6, 6, - 6, 5, 3, 5, 11, 10, 10, 11, 8, 3, 10, 14, 16, 15, 13, 10, 5, 16, 19, - 20, 16, 15, 12, 7, 9, 10, 10, 10, 7, 2, 2, 8, 12, 12, 11, 8, 3, 2, - 8, 14, 14, 14, 9, 5, 1, 8, 15, 17, 17, 13, 9, 5, 11, 17, 22, 21, 17, - 12, 7, 14, 20, 26, 25, 20, 15, 9, 18, 23, 27, 25, 21, 17, 11, 17, 22, 21, - 15, 10, 5, 1, 16, 22, 24, 17, 12, 6, 2, 16, 22, 25, 18, 13, 9, 4, 16, - 22, 27, 22, 17, 13, 9, 18, 24, 29, 26, 21, 17, 11, 20, 26, 30, 29, 23, 18, - 13, 23, 28, 30, 30, 25, 21, 15, 14, 17, 20, 22, 23, 20, 18, 13, 16, 19, 22, - 23, 20, 18, 12, 15, 18, 21, 23, 20, 18, 11, 14, 17, 21, 23, 22, 19, 12, 14, - 18, 20, 24, 23, 19, 11, 14, 17, 20, 23, 22, 19, 14, 14, 16, 19, 22, 21, 19, - 12, 15, 18, 21, 19, 17, 14, 11, 14, 18, 19, 19, 16, 14, 10, 13, 16, 19, 18, - 17, 15, 9, 13, 16, 18, 18, 18, 16, 10, 13, 15, 18, 18, 18, 15, 10, 11, 15, - 17, 18, 18, 16, 17, 16, 14, 16, 17, 16, 16, 10, 13, 15, 15, 15, 13, 9, 9, - 12, 13, 13, 14, 12, 9, 8, 11, 12, 12, 12, 13, 10, 8, 11, 12, 12, 12, 13, - 11, 7, 10, 12, 12, 12, 12, 11, 12, 12, 11, 11, 11, 11, 11, 19, 18, 14, 10, - 10, 10, 10, 8, 8, 8, 8, 8, 8, 2, 7, 7, 7, 7, 7, 7, 2, 6, 6, - 6, 6, 6, 6, 3, 4, 6, 6, 6, 6, 6, 4, 6, 7, 6, 6, 6, 5, 4, - 12, 13, 12, 10, 8, 6, 4, 19, 20, 15, 11, 8, 6, 5, 1, 1, 0, 1, 1, - 1, 2, 2, 2, 2, 1, 2, 1, 2, 2, 4, 3, 4, 4, 2, 3, 2, 7, 7, - 7, 7, 6, 4, 6, 12, 12, 11, 11, 9, 5, 11, 15, 17, 16, 14, 11, 6, 18, - 21, 20, 17, 16, 13, 7, 9, 11, 9, 9, 6, 2, 2, 9, 13, 11, 11, 7, 3, - 1, 9, 14, 14, 14, 10, 6, 2, 9, 16, 18, 17, 14, 10, 6, 12, 18, 23, 21, - 18, 13, 7, 15, 21, 28, 26, 20, 15, 9, 19, 25, 29, 27, 23, 17, 11, 16, 22, - 21, 15, 9, 5, 1, 17, 22, 23, 16, 11, 6, 2, 16, 22, 26, 19, 13, 9, 5, - 16, 23, 29, 23, 18, 14, 10, 18, 25, 31, 28, 22, 17, 11, 22, 28, 33, 33, 26, - 19, 13, 25, 30, 34, 34, 28, 21, 15, 14, 17, 21, 23, 24, 20, 18, 14, 16, 19, - 23, 24, 21, 18, 12, 15, 18, 22, 23, 22, 19, 11, 15, 18, 22, 25, 23, 20, 12, - 15, 18, 22, 26, 23, 20, 11, 14, 17, 21, 25, 23, 20, 16, 15, 17, 20, 23, 22, - 19, 12, 15, 18, 20, 20, 17, 14, 12, 14, 17, 20, 19, 17, 14, 10, 13, 17, 19, - 19, 18, 15, 9, 13, 17, 20, 19, 18, 16, 10, 13, 16, 18, 19, 19, 16, 11, 12, - 15, 18, 18, 18, 16, 18, 17, 15, 17, 17, 17, 16, 10, 13, 14, 15, 15, 12, 9, - 9, 12, 13, 13, 14, 12, 9, 9, 11, 13, 13, 13, 13, 10, 8, 11, 13, 13, 13, - 14, 11, 7, 10, 12, 12, 12, 12, 11, 13, 13, 13, 12, 12, 11, 11, 20, 19, 15, - 12, 10, 11, 10, 9, 8, 8, 8, 8, 8, 2, 8, 7, 7, 7, 7, 6, 2, 6, - 6, 6, 7, 6, 6, 3, 4, 6, 6, 6, 6, 6, 5, 6, 8, 8, 8, 8, 6, - 5, 13, 15, 13, 11, 9, 7, 5, 21, 21, 16, 12, 9, 7, 6, 2, 1, 1, 0, - 1, 1, 2, 3, 2, 2, 2, 2, 0, 2, 2, 4, 4, 4, 4, 3, 3, 2, 8, - 8, 8, 8, 7, 5, 7, 13, 12, 12, 13, 10, 6, 13, 17, 18, 17, 14, 12, 7, - 19, 22, 22, 19, 17, 14, 8, 9, 11, 9, 9, 6, 2, 2, 10, 12, 11, 11, 7, - 3, 2, 10, 15, 14, 14, 11, 6, 3, 9, 17, 18, 18, 15, 10, 7, 13, 19, 24, - 22, 18, 13, 8, 16, 22, 29, 27, 21, 16, 10, 21, 26, 30, 30, 25, 17, 12, 17, - 22, 20, 14, 9, 5, 1, 17, 22, 23, 16, 11, 6, 3, 17, 22, 25, 19, 14, 10, - 6, 17, 24, 29, 24, 18, 14, 10, 20, 26, 31, 29, 23, 18, 12, 23, 30, 35, 33, - 26, 19, 14, 25, 32, 35, 36, 28, 22, 16, 15, 18, 21, 24, 24, 21, 18, 14, 17, - 19, 23, 24, 22, 19, 12, 15, 19, 23, 25, 23, 20, 11, 16, 19, 22, 26, 24, 20, - 12, 16, 19, 23, 26, 24, 21, 12, 15, 18, 22, 26, 24, 21, 17, 17, 18, 20, 24, - 24, 21, 12, 16, 19, 22, 20, 17, 14, 12, 15, 18, 20, 20, 17, 15, 10, 14, 17, - 20, 20, 19, 16, 10, 14, 17, 20, 20, 19, 16, 10, 14, 17, 19, 20, 20, 17, 12, - 14, 16, 19, 19, 19, 17, 20, 18, 16, 18, 18, 18, 17, 10, 14, 15, 14, 15, 13, - 9, 10, 12, 13, 14, 14, 13, 10, 9, 12, 13, 14, 14, 14, 11, 9, 12, 14, 14, - 14, 14, 12, 8, 11, 13, 13, 13, 13, 12, 14, 14, 14, 13, 13, 12, 12, 22, 20, - 16, 12, 11, 11, 10, 9, 8, 8, 8, 8, 8, 2, 9, 7, 7, 7, 7, 7, 3, - 6, 6, 6, 7, 7, 7, 4, 6, 6, 7, 7, 7, 7, 6, 7, 8, 9, 9, 9, - 8, 6, 14, 16, 14, 12, 10, 8, 6, 22, 22, 17, 13, 10, 8, 7, 2, 2, 1, - 1, 0, 1, 2, 3, 2, 2, 2, 2, 1, 3, 3, 4, 4, 5, 5, 4, 3, 3, - 8, 8, 9, 9, 7, 6, 7, 14, 13, 13, 13, 11, 7, 14, 18, 19, 18, 15, 12, - 8, 20, 23, 23, 19, 18, 14, 9, 10, 10, 9, 8, 5, 2, 2, 10, 12, 10, 9, - 7, 4, 2, 10, 13, 12, 13, 10, 7, 4, 10, 15, 17, 16, 15, 11, 7, 13, 19, - 23, 21, 18, 14, 9, 17, 23, 28, 26, 20, 16, 11, 21, 27, 29, 28, 23, 18, 13, - 15, 17, 14, 10, 8, 4, 1, 15, 17, 15, 11, 9, 7, 3, 15, 17, 18, 15, 13, - 11, 7, 15, 19, 23, 20, 17, 15, 11, 18, 23, 27, 25, 22, 18, 13, 23, 27, 31, - 30, 24, 19, 15, 27, 30, 32, 32, 26, 21, 17, 13, 16, 20, 23, 23, 20, 17, 13, - 16, 18, 22, 23, 21, 19, 12, 14, 18, 22, 25, 22, 19, 11, 15, 19, 22, 26, 23, - 20, 12, 15, 18, 21, 25, 23, 20, 12, 15, 18, 21, 25, 23, 20, 18, 18, 17, 20, - 23, 23, 20, 12, 15, 17, 20, 18, 15, 13, 11, 14, 17, 19, 19, 17, 14, 10, 13, - 16, 19, 20, 17, 15, 9, 12, 16, 20, 19, 18, 16, 9, 13, 16, 19, 20, 19, 16, - 13, 14, 16, 18, 18, 18, 15, 21, 19, 17, 17, 17, 17, 16, 10, 13, 13, 13, 14, - 11, 8, 9, 12, 12, 12, 13, 12, 9, 8, 11, 12, 13, 13, 13, 10, 7, 11, 12, - 13, 13, 13, 11, 7, 11, 12, 13, 13, 13, 11, 15, 16, 15, 13, 12, 12, 11, 23, - 22, 17, 14, 11, 10, 10, 8, 7, 7, 7, 7, 7, 2, 7, 6, 6, 6, 6, 6, - 2, 4, 5, 5, 6, 6, 6, 4, 8, 5, 6, 6, 6, 7, 6, 8, 9, 10, 10, - 10, 9, 7, 15, 17, 16, 14, 11, 9, 8, 23, 24, 18, 15, 12, 10, 8, 2, 2, - 2, 1, 1, 0, 2, 4, 2, 2, 2, 2, 2, 2, 4, 3, 3, 4, 5, 5, 4, - 4, 7, 7, 8, 8, 8, 8, 8, 13, 13, 13, 13, 11, 8, 15, 19, 19, 17, 14, - 12, 9, 22, 24, 22, 18, 15, 13, 10, 6, 6, 4, 3, 3, 2, 1, 6, 7, 5, - 4, 3, 3, 2, 6, 9, 6, 7, 6, 6, 6, 6, 11, 12, 12, 11, 10, 9, 11, - 15, 19, 17, 15, 13, 10, 17, 21, 25, 22, 17, 13, 11, 22, 25, 26, 24, 19, 15, - 12, 10, 12, 8, 5, 3, 2, 2, 10, 12, 10, 6, 4, 4, 4, 10, 12, 13, 9, - 9, 8, 7, 10, 14, 18, 16, 13, 12, 10, 14, 18, 23, 22, 18, 15, 12, 19, 23, - 27, 27, 21, 16, 13, 24, 27, 28, 29, 23, 18, 13, 9, 11, 13, 15, 16, 13, 11, - 9, 11, 12, 15, 16, 14, 12, 8, 10, 12, 16, 18, 15, 13, 7, 10, 13, 16, 19, - 17, 15, 8, 11, 14, 17, 20, 17, 14, 11, 13, 15, 16, 19, 17, 14, 18, 18, 16, - 16, 18, 17, 15, 8, 10, 11, 14, 11, 9, 7, 7, 9, 11, 13, 12, 10, 8, 7, - 8, 11, 14, 13, 11, 10, 6, 9, 12, 14, 13, 12, 11, 6, 10, 12, 14, 14, 13, - 11, 13, 14, 15, 16, 14, 13, 11, 21, 19, 17, 15, 13, 12, 11, 7, 9, 8, 7, - 7, 5, 3, 6, 8, 8, 7, 7, 7, 5, 5, 7, 7, 8, 8, 8, 6, 3, 7, - 8, 9, 9, 9, 8, 7, 10, 10, 10, 10, 9, 8, 16, 16, 15, 13, 11, 9, 8, - 23, 22, 18, 14, 12, 10, 8, 5, 4, 3, 3, 3, 2, 0, 3, 2, 3, 2, 2, - 3, 2, 6, 2, 2, 3, 3, 3, 4, 10, 3, 5, 6, 6, 6, 6, 9, 10, 10, - 10, 10, 9, 7, 16, 18, 16, 14, 12, 10, 8, 23, 24, 19, 15, 12, 11, 9, 4, - 3, 2, 2, 2, 2, 0, 6, 4, 3, 2, 2, 3, 2, 6, 4, 4, 5, 5, 5, - 5, 6, 8, 8, 9, 10, 9, 8, 9, 15, 15, 15, 15, 12, 9, 15, 21, 21, 19, - 16, 14, 10, 22, 25, 25, 21, 18, 15, 11, 8, 7, 5, 5, 3, 2, 1, 8, 10, - 7, 6, 4, 4, 3, 8, 11, 10, 11, 9, 7, 6, 8, 13, 16, 16, 15, 12, 10, - 12, 19, 23, 22, 19, 16, 11, 18, 24, 30, 27, 22, 16, 13, 23, 28, 31, 30, 24, - 18, 14, 12, 16, 14, 8, 5, 3, 2, 13, 16, 16, 10, 6, 5, 4, 12, 16, 19, - 15, 12, 10, 8, 13, 18, 25, 21, 18, 15, 12, 17, 23, 29, 28, 23, 19, 14, 22, - 27, 33, 33, 26, 20, 16, 27, 32, 34, 34, 28, 23, 17, 16, 19, 23, 26, 26, 25, - 22, 15, 19, 22, 25, 26, 23, 21, 14, 17, 20, 23, 24, 22, 19, 13, 15, 17, 20, - 22, 20, 18, 12, 14, 16, 18, 21, 19, 18, 10, 12, 15, 17, 20, 20, 18, 10, 11, - 13, 16, 19, 20, 18, 14, 17, 20, 24, 24, 23, 18, 13, 16, 19, 22, 24, 22, 17, - 12, 14, 18, 20, 20, 18, 15, 11, 13, 15, 17, 18, 16, 14, 10, 12, 14, 15, 16, - 17, 14, 8, 11, 13, 14, 15, 15, 15, 11, 11, 12, 13, 14, 15, 14, 12, 14, 16, - 17, 19, 19, 14, 11, 13, 15, 16, 16, 17, 13, 10, 12, 14, 14, 15, 15, 12, 9, - 12, 12, 12, 12, 13, 12, 7, 10, 12, 12, 11, 12, 12, 8, 9, 10, 10, 11, 11, - 12, 12, 12, 10, 9, 10, 11, 12, 10, 10, 11, 11, 12, 14, 6, 8, 9, 9, 10, - 10, 11, 6, 7, 7, 8, 8, 9, 9, 5, 4, 6, 7, 7, 7, 7, 6, 5, 5, - 5, 6, 6, 7, 4, 8, 8, 7, 6, 5, 5, 4, 12, 12, 8, 6, 5, 4, 2, - 2, 2, 2, 2, 3, 4, 6, 0, 1, 1, 2, 1, 2, 5, 0, 2, 2, 1, 1, - 1, 4, 0, 2, 2, 1, 1, 1, 4, 2, 4, 3, 3, 4, 2, 2, 5, 7, 7, - 6, 5, 3, 2, 9, 10, 9, 7, 6, 4, 2, 4, 5, 5, 5, 3, 2, 4, 4, - 6, 6, 6, 3, 1, 3, 4, 7, 7, 6, 4, 1, 2, 4, 7, 8, 7, 5, 3, - 2, 4, 8, 10, 9, 7, 4, 2, 6, 10, 14, 11, 9, 6, 2, 9, 12, 14, 13, - 10, 6, 3, 9, 12, 11, 8, 5, 2, 2, 9, 12, 12, 8, 5, 2, 1, 9, 12, - 14, 9, 6, 3, 1, 9, 12, 15, 10, 7, 5, 2, 9, 12, 15, 13, 10, 7, 4, - 10, 13, 17, 16, 11, 8, 5, 12, 15, 16, 17, 13, 9, 6, 16, 19, 20, 22, 22, - 20, 18, 15, 18, 20, 21, 22, 20, 17, 14, 16, 18, 21, 22, 19, 18, 13, 15, 19, - 20, 22, 20, 18, 13, 16, 18, 20, 22, 21, 19, 11, 15, 18, 19, 21, 20, 18, 12, - 13, 17, 19, 20, 20, 18, 14, 17, 19, 21, 19, 18, 16, 13, 16, 18, 20, 19, 18, - 16, 12, 15, 17, 19, 18, 17, 16, 11, 14, 17, 18, 17, 18, 16, 11, 14, 17, 19, - 18, 18, 17, 9, 12, 15, 17, 18, 18, 16, 15, 14, 14, 16, 16, 17, 16, 12, 15, - 16, 16, 16, 15, 12, 11, 14, 15, 15, 15, 15, 12, 10, 13, 14, 14, 15, 15, 12, - 9, 12, 14, 13, 14, 14, 12, 8, 11, 13, 13, 13, 13, 12, 10, 10, 11, 12, 13, - 13, 12, 17, 16, 12, 10, 11, 11, 12, 10, 9, 10, 10, 10, 11, 4, 9, 8, 9, - 9, 9, 9, 4, 7, 7, 7, 8, 8, 8, 5, 5, 7, 7, 7, 7, 7, 6, 6, - 6, 6, 6, 6, 6, 5, 10, 11, 10, 9, 6, 5, 4, 17, 18, 13, 10, 7, 5, - 3, 2, 2, 2, 2, 2, 2, 4, 1, 0, 1, 1, 1, 2, 4, 1, 2, 2, 2, - 1, 0, 4, 1, 5, 5, 5, 5, 4, 3, 4, 9, 9, 9, 9, 7, 3, 9, 13, - 15, 14, 12, 9, 4, 16, 18, 18, 15, 14, 11, 5, 7, 9, 8, 9, 5, 1, 3, - 7, 11, 10, 10, 7, 2, 3, 7, 13, 13, 12, 8, 3, 2, 7, 13, 15, 15, 12, - 7, 4, 9, 16, 19, 18, 16, 11, 5, 12, 18, 22, 20, 17, 13, 7, 17, 21, 23, - 22, 18, 15, 9, 15, 20, 18, 14, 9, 4, 2, 15, 19, 20, 15, 11, 5, 1, 15, - 19, 21, 16, 12, 7, 3, 15, 20, 23, 19, 16, 12, 7, 16, 21, 24, 22, 18, 15, - 9, 18, 22, 25, 24, 20, 16, 12, 21, 23, 26, 25, 21, 18, 13, 16, 19, 21, 24, - 24, 22, 19, 15, 18, 20, 23, 25, 21, 19, 13, 17, 20, 23, 24, 21, 20, 13, 16, - 19, 22, 24, 22, 20, 13, 16, 19, 22, 25, 23, 20, 12, 15, 18, 21, 24, 23, 21, - 13, 14, 17, 20, 23, 24, 21, 13, 17, 20, 22, 21, 18, 16, 12, 16, 18, 21, 20, - 18, 15, 12, 14, 17, 20, 20, 18, 16, 10, 14, 17, 21, 19, 19, 17, 11, 14, 17, - 19, 20, 20, 17, 9, 13, 16, 18, 19, 19, 17, 16, 15, 15, 18, 17, 18, 17, 11, - 14, 16, 16, 16, 14, 11, 10, 13, 15, 15, 15, 14, 11, 10, 12, 14, 13, 14, 14, - 11, 9, 12, 14, 14, 14, 14, 12, 8, 11, 13, 13, 13, 13, 12, 11, 11, 12, 12, - 12, 12, 12, 18, 17, 13, 11, 11, 11, 11, 10, 9, 9, 9, 10, 9, 3, 9, 8, - 8, 8, 8, 8, 3, 8, 7, 7, 7, 7, 7, 3, 5, 7, 7, 7, 7, 7, 5, - 6, 6, 6, 6, 6, 6, 4, 11, 13, 11, 9, 7, 5, 4, 18, 20, 14, 10, 8, - 6, 4, 2, 1, 2, 2, 2, 2, 3, 1, 1, 0, 1, 1, 1, 3, 1, 2, 2, - 2, 2, 1, 3, 1, 6, 6, 6, 6, 5, 4, 5, 10, 10, 10, 10, 8, 4, 11, - 14, 16, 14, 12, 9, 5, 17, 19, 19, 16, 14, 12, 6, 7, 9, 8, 8, 5, 1, - 2, 7, 11, 10, 10, 6, 2, 2, 7, 13, 12, 12, 8, 4, 2, 8, 14, 16, 16, - 12, 8, 5, 10, 17, 21, 20, 16, 11, 6, 13, 20, 26, 25, 19, 13, 8, 17, 23, - 26, 27, 22, 16, 9, 15, 20, 19, 13, 8, 4, 1, 16, 21, 22, 15, 10, 5, 0, - 15, 20, 24, 17, 12, 8, 4, 15, 22, 27, 21, 16, 12, 8, 17, 24, 29, 27, 21, - 15, 10, 20, 26, 31, 32, 24, 18, 12, 23, 29, 33, 33, 26, 19, 14, 16, 19, 22, - 25, 25, 22, 20, 15, 18, 21, 25, 25, 22, 19, 13, 16, 20, 23, 26, 22, 21, 13, - 16, 19, 23, 26, 24, 21, 13, 16, 19, 22, 26, 25, 21, 12, 16, 19, 22, 25, 24, - 22, 15, 15, 17, 21, 25, 25, 21, 14, 16, 20, 22, 21, 19, 15, 13, 15, 19, 21, - 21, 19, 15, 12, 14, 17, 20, 21, 19, 17, 11, 15, 18, 21, 21, 20, 17, 12, 14, - 17, 20, 20, 21, 17, 11, 13, 16, 19, 20, 19, 17, 18, 16, 15, 18, 18, 18, 17, - 12, 14, 16, 16, 17, 14, 11, 11, 13, 15, 15, 15, 14, 10, 10, 12, 14, 15, 14, - 15, 11, 9, 13, 14, 14, 15, 15, 12, 9, 12, 13, 14, 14, 14, 12, 12, 13, 12, - 12, 12, 13, 12, 19, 18, 14, 11, 12, 12, 11, 10, 9, 9, 9, 9, 9, 2, 9, - 8, 8, 8, 8, 8, 2, 8, 7, 7, 8, 7, 8, 3, 5, 7, 7, 7, 7, 7, - 6, 7, 7, 7, 7, 7, 7, 4, 13, 14, 13, 11, 8, 6, 5, 19, 21, 16, 12, - 9, 7, 5, 2, 2, 1, 2, 2, 2, 2, 2, 1, 1, 0, 1, 1, 3, 2, 2, - 2, 3, 3, 2, 3, 2, 6, 6, 6, 7, 5, 5, 6, 12, 11, 11, 11, 8, 5, - 12, 16, 17, 15, 13, 10, 6, 18, 21, 20, 17, 15, 12, 7, 8, 9, 8, 8, 5, - 1, 2, 8, 11, 10, 9, 6, 2, 2, 8, 13, 13, 13, 9, 5, 3, 8, 15, 17, - 17, 13, 9, 6, 11, 18, 22, 21, 17, 12, 7, 14, 20, 26, 26, 19, 14, 9, 19, - 24, 28, 28, 22, 16, 10, 15, 21, 19, 13, 8, 3, 1, 15, 20, 21, 15, 9, 5, - 1, 15, 21, 24, 18, 13, 9, 5, 15, 22, 28, 23, 17, 13, 9, 18, 24, 30, 27, - 21, 16, 11, 20, 27, 32, 32, 24, 18, 12, 24, 30, 34, 34, 27, 20, 14, 16, 19, - 23, 26, 26, 23, 20, 15, 18, 21, 25, 26, 23, 20, 14, 17, 20, 23, 25, 24, 22, - 13, 17, 20, 24, 26, 25, 22, 14, 17, 20, 24, 27, 25, 21, 12, 16, 18, 23, 27, - 25, 22, 16, 16, 18, 22, 25, 25, 22, 14, 17, 20, 23, 22, 19, 16, 13, 16, 19, - 22, 22, 18, 16, 12, 15, 18, 21, 20, 20, 17, 11, 15, 18, 22, 21, 20, 17, 12, - 15, 18, 20, 21, 21, 17, 11, 14, 17, 20, 20, 20, 18, 18, 17, 16, 19, 18, 19, - 17, 12, 15, 15, 16, 17, 15, 11, 11, 14, 15, 15, 15, 14, 11, 10, 13, 14, 15, - 15, 15, 12, 10, 13, 15, 15, 15, 15, 12, 9, 13, 14, 14, 14, 14, 12, 13, 14, - 14, 13, 13, 13, 12, 20, 19, 15, 12, 12, 12, 12, 10, 9, 9, 9, 10, 10, 3, - 9, 8, 8, 8, 8, 8, 3, 8, 8, 8, 8, 8, 8, 3, 5, 7, 8, 8, 8, - 8, 6, 7, 8, 8, 8, 8, 7, 4, 13, 15, 13, 11, 9, 7, 5, 20, 21, 16, - 12, 10, 8, 6, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 0, 2, 3, 1, - 2, 3, 3, 3, 2, 3, 1, 6, 7, 7, 7, 6, 5, 6, 11, 11, 11, 11, 8, - 6, 12, 17, 18, 16, 13, 10, 7, 19, 21, 21, 17, 16, 12, 7, 8, 9, 8, 7, - 4, 1, 2, 8, 11, 9, 8, 6, 2, 2, 8, 12, 11, 12, 9, 5, 3, 8, 14, - 16, 15, 13, 9, 6, 11, 17, 21, 20, 18, 13, 7, 15, 21, 27, 25, 19, 14, 9, - 20, 24, 28, 26, 21, 16, 11, 14, 16, 14, 10, 7, 3, 1, 13, 16, 15, 11, 9, - 5, 2, 14, 16, 18, 14, 12, 9, 5, 14, 18, 23, 19, 16, 12, 9, 17, 22, 25, - 24, 20, 16, 11, 21, 25, 29, 29, 23, 18, 13, 24, 29, 31, 30, 25, 19, 14, 15, - 18, 21, 26, 25, 22, 18, 14, 17, 20, 24, 25, 22, 19, 13, 16, 19, 23, 24, 23, - 19, 12, 15, 19, 23, 25, 23, 20, 13, 15, 19, 22, 26, 24, 21, 11, 14, 17, 21, - 25, 24, 20, 16, 15, 16, 20, 23, 23, 21, 13, 16, 18, 22, 21, 19, 15, 12, 15, - 17, 21, 21, 17, 14, 11, 14, 17, 20, 19, 18, 15, 10, 13, 17, 20, 20, 19, 16, - 10, 14, 16, 19, 19, 19, 16, 11, 13, 16, 18, 18, 18, 16, 18, 17, 16, 17, 16, - 17, 16, 11, 14, 15, 15, 16, 14, 10, 10, 12, 13, 13, 14, 13, 9, 9, 11, 13, - 14, 13, 13, 10, 8, 12, 13, 13, 13, 13, 11, 7, 11, 12, 12, 12, 13, 11, 14, - 14, 13, 12, 11, 11, 11, 20, 19, 15, 12, 10, 10, 10, 9, 8, 8, 8, 9, 9, - 3, 8, 7, 7, 7, 7, 7, 2, 6, 6, 6, 7, 6, 6, 2, 5, 6, 6, 6, - 6, 6, 5, 7, 8, 8, 8, 8, 7, 5, 14, 16, 13, 11, 9, 7, 5, 21, 22, - 16, 12, 10, 8, 6, 1, 1, 1, 0, 1, 2, 3, 2, 2, 1, 1, 2, 0, 2, - 2, 3, 3, 4, 3, 3, 3, 2, 6, 6, 6, 6, 6, 5, 7, 12, 11, 10, 10, - 8, 6, 13, 16, 17, 14, 11, 9, 7, 19, 21, 20, 15, 13, 10, 7, 6, 6, 4, - 3, 3, 2, 2, 6, 7, 5, 4, 3, 2, 2, 6, 9, 6, 6, 4, 4, 3, 6, - 10, 10, 9, 8, 7, 7, 9, 13, 16, 14, 13, 10, 8, 14, 19, 22, 19, 14, 11, - 9, 19, 22, 23, 21, 16, 12, 9, 10, 11, 8, 5, 3, 2, 1, 10, 12, 10, 5, - 4, 3, 2, 10, 12, 12, 8, 7, 5, 5, 10, 13, 16, 13, 10, 9, 8, 12, 15, - 20, 19, 15, 12, 9, 16, 20, 24, 24, 17, 13, 10, 20, 24, 25, 25, 19, 14, 11, - 9, 11, 14, 17, 17, 14, 11, 9, 11, 13, 16, 17, 13, 11, 8, 10, 12, 15, 17, - 15, 12, 8, 10, 13, 16, 18, 16, 14, 8, 11, 13, 16, 19, 16, 13, 10, 11, 13, - 15, 18, 17, 13, 16, 15, 14, 15, 17, 17, 13, 8, 10, 12, 14, 13, 11, 7, 8, - 9, 11, 13, 13, 9, 7, 7, 8, 11, 13, 12, 10, 8, 6, 9, 12, 14, 13, 12, - 9, 6, 9, 11, 13, 13, 12, 10, 12, 12, 13, 13, 12, 12, 10, 19, 17, 14, 13, - 11, 11, 10, 7, 9, 8, 8, 9, 7, 4, 6, 8, 8, 7, 7, 6, 4, 5, 8, - 7, 8, 7, 7, 5, 4, 7, 8, 8, 7, 7, 6, 7, 9, 9, 8, 8, 8, 6, - 14, 14, 13, 11, 9, 7, 6, 21, 19, 15, 12, 9, 7, 6, 5, 4, 3, 3, 3, - 4, 2, 3, 3, 3, 3, 2, 2, 0, 3, 2, 2, 3, 2, 2, 2, 7, 3, 4, - 5, 4, 4, 4, 8, 9, 9, 8, 8, 7, 5, 14, 16, 14, 12, 10, 8, 6, 21, - 22, 16, 13, 10, 9, 7, 5, 3, 2, 2, 3, 2, 2, 5, 4, 3, 2, 3, 2, - 0, 5, 5, 4, 4, 4, 4, 3, 5, 8, 8, 8, 8, 8, 6, 9, 14, 14, 13, - 13, 10, 7, 14, 18, 19, 18, 14, 11, 8, 20, 22, 23, 19, 16, 13, 9, 9, 9, - 7, 6, 4, 3, 2, 8, 10, 8, 7, 5, 3, 2, 9, 12, 11, 11, 9, 6, 4, - 9, 14, 16, 16, 13, 10, 8, 12, 18, 22, 20, 18, 14, 9, 16, 22, 28, 26, 20, - 15, 10, 21, 26, 29, 28, 22, 17, 12, 14, 18, 15, 10, 6, 3, 2, 13, 17, 18, - 12, 8, 5, 3, 13, 17, 20, 15, 12, 9, 6, 14, 19, 25, 21, 16, 14, 10, 18, - 23, 28, 26, 21, 17, 12, 21, 27, 32, 32, 25, 19, 14, 26, 30, 32, 33, 26, 21, - 15, 16, 19, 23, 26, 26, 25, 23, 15, 18, 21, 25, 26, 23, 21, 14, 17, 20, 23, - 24, 22, 19, 13, 15, 17, 20, 22, 20, 18, 12, 14, 15, 18, 21, 20, 18, 11, 12, - 14, 17, 20, 20, 17, 10, 11, 13, 16, 19, 20, 18, 13, 17, 21, 24, 24, 23, 18, - 13, 15, 19, 22, 24, 21, 17, 12, 14, 17, 20, 21, 18, 15, 10, 13, 15, 17, 17, - 17, 15, 10, 12, 14, 15, 15, 17, 14, 8, 11, 13, 15, 15, 15, 14, 11, 11, 12, - 14, 14, 15, 14, 12, 14, 16, 18, 19, 19, 15, 11, 13, 15, 16, 17, 17, 13, 10, - 13, 13, 15, 14, 15, 12, 9, 12, 12, 12, 13, 13, 12, 7, 10, 11, 11, 11, 12, - 12, 8, 9, 9, 10, 11, 11, 12, 12, 12, 10, 9, 10, 11, 12, 10, 10, 10, 11, - 13, 13, 6, 8, 9, 9, 10, 10, 10, 5, 7, 7, 8, 8, 9, 9, 5, 4, 6, - 6, 7, 7, 7, 6, 5, 5, 6, 6, 6, 7, 5, 8, 8, 7, 6, 5, 5, 4, - 12, 12, 8, 6, 5, 4, 2, 2, 2, 2, 3, 3, 4, 6, 0, 1, 1, 2, 1, - 2, 5, 0, 2, 2, 1, 1, 1, 5, 0, 2, 2, 1, 2, 1, 3, 2, 4, 4, - 3, 4, 2, 2, 5, 7, 7, 6, 5, 3, 2, 9, 10, 10, 7, 6, 4, 2, 4, - 5, 4, 5, 3, 2, 4, 4, 6, 6, 6, 3, 1, 3, 4, 7, 7, 6, 4, 1, - 2, 4, 7, 8, 7, 5, 3, 2, 4, 8, 10, 9, 7, 4, 2, 6, 10, 13, 12, - 9, 6, 2, 9, 12, 14, 13, 10, 7, 3, 9, 12, 11, 8, 5, 2, 2, 9, 12, - 13, 8, 5, 2, 1, 9, 13, 14, 9, 6, 3, 1, 9, 12, 15, 10, 7, 5, 2, - 9, 12, 15, 13, 10, 7, 3, 10, 14, 17, 16, 11, 8, 5, 12, 15, 17, 17, 13, - 9, 6, 18, 19, 22, 24, 24, 22, 19, 17, 20, 21, 24, 24, 22, 19, 15, 18, 20, - 22, 24, 22, 20, 15, 18, 20, 21, 23, 22, 19, 14, 17, 19, 21, 24, 22, 21, 13, - 16, 19, 21, 23, 22, 20, 12, 14, 17, 20, 22, 22, 20, 15, 18, 20, 23, 22, 20, - 17, 14, 17, 20, 22, 20, 19, 17, 13, 17, 19, 21, 21, 18, 18, 12, 16, 18, 20, - 19, 18, 17, 12, 15, 18, 19, 19, 20, 18, 11, 13, 17, 19, 18, 19, 17, 14, 13, - 15, 17, 18, 18, 18, 13, 17, 17, 18, 18, 17, 14, 12, 15, 16, 16, 17, 16, 13, - 11, 14, 16, 16, 16, 17, 14, 10, 13, 15, 15, 16, 16, 14, 9, 12, 14, 14, 15, - 15, 14, 9, 11, 12, 13, 13, 14, 14, 16, 16, 12, 12, 13, 13, 13, 11, 11, 12, - 12, 12, 13, 4, 10, 10, 11, 11, 11, 11, 5, 9, 9, 9, 9, 10, 10, 5, 5, - 8, 8, 8, 8, 9, 7, 6, 7, 7, 7, 8, 8, 5, 9, 10, 9, 8, 6, 6, - 5, 16, 18, 13, 9, 6, 5, 3, 3, 3, 4, 4, 4, 3, 4, 1, 2, 2, 2, - 2, 2, 5, 1, 0, 1, 1, 1, 2, 5, 1, 3, 3, 3, 4, 2, 5, 3, 8, - 8, 8, 8, 6, 3, 8, 13, 14, 12, 10, 8, 3, 15, 17, 16, 13, 11, 9, 4, - 6, 8, 8, 8, 4, 2, 4, 6, 10, 9, 9, 6, 1, 4, 6, 11, 11, 10, 7, - 2, 3, 6, 12, 12, 12, 10, 6, 4, 8, 13, 15, 14, 12, 9, 4, 11, 15, 18, - 16, 13, 11, 6, 15, 17, 19, 17, 14, 12, 8, 13, 16, 15, 12, 8, 2, 2, 13, - 16, 16, 12, 9, 4, 2, 13, 16, 18, 13, 10, 6, 1, 13, 16, 19, 14, 12, 10, - 6, 13, 16, 20, 17, 14, 12, 8, 15, 17, 21, 20, 15, 13, 10, 17, 19, 22, 21, - 17, 14, 11, 18, 21, 24, 26, 26, 24, 21, 17, 20, 23, 26, 26, 24, 21, 15, 19, - 22, 26, 25, 23, 22, 14, 17, 21, 24, 26, 24, 22, 14, 17, 21, 23, 26, 25, 22, - 13, 16, 20, 23, 26, 25, 21, 13, 15, 18, 21, 24, 24, 22, 15, 19, 21, 24, 23, - 21, 17, 15, 18, 21, 24, 23, 20, 17, 13, 17, 20, 22, 22, 20, 17, 12, 16, 19, - 22, 22, 20, 18, 12, 15, 18, 21, 21, 22, 18, 11, 14, 17, 20, 21, 20, 18, 15, - 14, 16, 19, 19, 19, 18, 13, 17, 18, 18, 19, 17, 13, 12, 15, 17, 17, 17, 17, - 13, 11, 14, 16, 16, 16, 16, 13, 10, 13, 15, 15, 16, 16, 13, 10, 13, 15, 15, - 15, 15, 14, 10, 11, 13, 13, 14, 14, 13, 16, 16, 12, 12, 13, 13, 13, 11, 11, - 11, 11, 12, 12, 4, 10, 10, 10, 11, 10, 11, 4, 8, 9, 9, 9, 9, 9, 5, - 6, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 4, 10, 11, 10, 8, 7, - 6, 4, 17, 18, 13, 9, 7, 5, 3, 3, 3, 3, 4, 4, 3, 4, 2, 2, 2, - 2, 2, 3, 4, 2, 1, 0, 0, 0, 2, 4, 2, 4, 3, 3, 4, 3, 4, 4, - 8, 8, 8, 8, 6, 3, 9, 13, 14, 12, 10, 7, 4, 15, 18, 18, 14, 12, 9, - 5, 5, 7, 7, 7, 3, 2, 3, 5, 9, 9, 8, 5, 1, 3, 5, 11, 11, 10, - 6, 2, 3, 6, 12, 14, 14, 10, 6, 4, 8, 14, 19, 18, 15, 9, 5, 11, 17, - 24, 23, 18, 11, 6, 16, 21, 25, 26, 20, 13, 7, 13, 19, 18, 12, 7, 2, 2, - 13, 19, 20, 14, 9, 3, 2, 13, 19, 23, 16, 11, 6, 2, 13, 20, 25, 19, 15, - 10, 6, 15, 21, 26, 25, 19, 14, 8, 17, 24, 29, 28, 21, 16, 10, 20, 26, 30, - 31, 24, 17, 11, 18, 22, 26, 29, 29, 26, 23, 17, 20, 25, 28, 29, 26, 22, 15, - 19, 23, 26, 28, 24, 22, 14, 17, 20, 24, 27, 25, 22, 14, 17, 20, 23, 27, 25, - 22, 13, 16, 20, 23, 26, 25, 22, 13, 14, 18, 22, 25, 25, 22, 15, 19, 23, 26, - 25, 22, 19, 14, 18, 22, 25, 24, 21, 18, 13, 16, 20, 23, 22, 20, 17, 13, 16, - 19, 21, 22, 21, 18, 12, 15, 18, 21, 21, 21, 18, 11, 14, 17, 20, 20, 21, 18, - 15, 14, 17, 19, 19, 19, 18, 13, 17, 19, 19, 21, 18, 14, 12, 15, 17, 19, 19, - 17, 13, 11, 14, 16, 16, 16, 16, 12, 10, 14, 15, 15, 15, 15, 12, 10, 13, 14, - 14, 14, 15, 13, 10, 11, 13, 13, 13, 13, 13, 17, 16, 12, 12, 12, 12, 12, 11, - 11, 12, 12, 13, 13, 5, 11, 10, 10, 11, 11, 11, 4, 9, 9, 9, 9, 8, 8, - 4, 5, 9, 8, 8, 8, 8, 6, 7, 7, 7, 7, 7, 7, 3, 10, 11, 10, 9, - 6, 6, 3, 17, 18, 13, 9, 7, 5, 3, 3, 3, 4, 4, 5, 4, 5, 1, 2, - 2, 3, 3, 4, 4, 1, 1, 0, 0, 0, 2, 3, 1, 4, 4, 3, 4, 3, 3, - 4, 8, 8, 8, 8, 5, 3, 10, 13, 14, 12, 10, 7, 4, 15, 18, 17, 14, 12, - 9, 4, 6, 7, 7, 7, 4, 3, 4, 6, 10, 8, 9, 6, 2, 3, 6, 11, 10, - 10, 6, 2, 2, 6, 12, 14, 13, 10, 6, 4, 9, 15, 18, 18, 14, 9, 4, 12, - 17, 24, 22, 17, 11, 6, 16, 21, 24, 25, 19, 13, 7, 14, 19, 18, 12, 7, 3, - 4, 13, 19, 20, 14, 8, 3, 2, 13, 19, 22, 15, 10, 6, 2, 14, 20, 25, 19, - 14, 10, 5, 15, 21, 27, 24, 19, 13, 8, 17, 24, 29, 29, 22, 15, 9, 21, 27, - 30, 30, 23, 17, 11, 18, 22, 26, 29, 30, 27, 23, 17, 21, 24, 28, 30, 26, 21, - 15, 19, 23, 26, 27, 24, 21, 14, 17, 21, 24, 27, 25, 22, 14, 17, 20, 23, 27, - 25, 22, 14, 16, 19, 23, 26, 25, 21, 13, 15, 18, 21, 25, 25, 22, 15, 19, 23, - 26, 26, 23, 20, 14, 18, 22, 25, 25, 22, 18, 13, 16, 20, 23, 23, 20, 17, 12, - 15, 19, 21, 22, 21, 17, 13, 15, 18, 21, 21, 20, 17, 11, 13, 17, 19, 20, 20, - 17, 15, 15, 15, 18, 18, 18, 18, 13, 16, 18, 19, 21, 19, 15, 12, 15, 18, 18, - 19, 17, 13, 12, 14, 16, 16, 15, 16, 11, 11, 14, 14, 15, 15, 15, 12, 10, 13, - 14, 14, 14, 14, 12, 10, 12, 13, 13, 13, 13, 12, 17, 16, 13, 12, 12, 12, 11, - 12, 11, 11, 12, 13, 13, 6, 11, 9, 10, 11, 11, 11, 4, 9, 9, 9, 8, 8, - 8, 4, 5, 9, 8, 8, 8, 8, 6, 7, 7, 7, 7, 7, 7, 3, 11, 12, 10, - 8, 6, 5, 3, 17, 18, 13, 10, 7, 5, 3, 4, 3, 4, 4, 5, 5, 5, 1, - 1, 2, 3, 3, 3, 4, 1, 1, 0, 0, 0, 1, 2, 1, 4, 4, 3, 4, 3, - 3, 5, 9, 8, 8, 8, 6, 3, 10, 14, 14, 12, 10, 7, 4, 15, 18, 17, 13, - 12, 9, 5, 6, 7, 7, 7, 4, 4, 5, 6, 9, 8, 8, 5, 2, 3, 6, 11, - 10, 9, 6, 2, 2, 6, 13, 13, 12, 10, 6, 4, 9, 15, 18, 17, 14, 9, 5, - 12, 18, 23, 21, 16, 11, 6, 16, 20, 24, 23, 18, 13, 7, 13, 15, 13, 10, 7, - 3, 4, 13, 16, 15, 11, 8, 3, 1, 12, 15, 17, 11, 9, 6, 2, 12, 17, 20, - 16, 13, 9, 6, 15, 19, 23, 21, 18, 13, 7, 18, 23, 26, 26, 20, 15, 9, 21, - 25, 28, 28, 22, 17, 11, 17, 20, 25, 28, 28, 25, 21, 16, 19, 23, 28, 28, 24, - 21, 14, 18, 21, 25, 27, 23, 20, 13, 16, 19, 22, 26, 23, 20, 13, 16, 19, 22, - 26, 24, 21, 12, 15, 18, 22, 25, 24, 21, 13, 14, 17, 21, 23, 24, 21, 14, 18, - 21, 25, 24, 22, 18, 13, 17, 20, 24, 23, 20, 16, 12, 16, 19, 22, 21, 19, 15, - 11, 14, 17, 20, 20, 19, 16, 12, 14, 17, 20, 19, 19, 16, 9, 12, 15, 18, 18, - 19, 16, 16, 14, 14, 17, 17, 17, 16, 12, 15, 17, 18, 19, 17, 13, 11, 14, 16, - 17, 17, 16, 11, 11, 13, 15, 14, 15, 14, 10, 10, 13, 13, 13, 13, 13, 11, 9, - 12, 12, 12, 12, 12, 11, 11, 12, 11, 11, 12, 11, 11, 17, 16, 12, 10, 10, 10, - 10, 10, 10, 10, 11, 12, 12, 6, 9, 8, 9, 9, 10, 10, 4, 8, 7, 7, 7, - 7, 7, 3, 5, 7, 6, 6, 6, 6, 5, 6, 6, 6, 5, 6, 5, 2, 11, 12, - 10, 9, 7, 5, 3, 17, 17, 13, 10, 7, 5, 3, 2, 1, 2, 3, 4, 5, 5, - 1, 0, 1, 2, 2, 3, 3, 1, 2, 2, 2, 1, 0, 2, 1, 5, 4, 4, 4, - 3, 3, 5, 9, 8, 8, 8, 6, 3, 11, 14, 14, 11, 9, 7, 4, 16, 17, 17, - 13, 10, 8, 5, 5, 5, 4, 3, 3, 3, 5, 5, 7, 5, 4, 3, 2, 2, 5, - 7, 5, 4, 2, 2, 1, 5, 8, 8, 7, 6, 5, 4, 8, 11, 13, 11, 10, 8, - 5, 12, 15, 18, 16, 11, 8, 6, 16, 18, 19, 18, 13, 9, 7, 8, 9, 7, 5, - 3, 3, 3, 8, 9, 8, 6, 3, 2, 1, 8, 9, 10, 6, 4, 3, 2, 7, 10, - 13, 10, 8, 6, 6, 10, 13, 17, 16, 12, 9, 7, 13, 17, 20, 19, 14, 10, 8, - 17, 20, 21, 21, 16, 11, 8, 13, 16, 19, 22, 22, 20, 16, 12, 15, 18, 22, 22, - 19, 15, 11, 15, 18, 20, 21, 18, 15, 10, 12, 15, 18, 21, 19, 16, 9, 12, 15, - 18, 21, 20, 16, 8, 11, 14, 17, 21, 19, 16, 11, 11, 13, 16, 20, 19, 16, 11, - 14, 17, 20, 18, 17, 14, 10, 13, 16, 19, 18, 15, 12, 8, 12, 15, 17, 16, 14, - 12, 7, 10, 13, 16, 16, 14, 12, 7, 10, 12, 15, 15, 15, 12, 9, 10, 11, 14, - 14, 14, 12, 14, 12, 11, 13, 13, 13, 12, 8, 12, 13, 14, 15, 13, 10, 7, 10, - 13, 13, 13, 13, 8, 6, 9, 11, 11, 11, 10, 7, 5, 9, 9, 9, 9, 9, 7, - 6, 8, 9, 9, 9, 8, 7, 12, 11, 9, 8, 7, 7, 7, 15, 13, 10, 8, 7, - 6, 6, 6, 6, 7, 8, 9, 9, 5, 5, 4, 5, 6, 6, 7, 3, 3, 3, 4, - 4, 3, 3, 2, 2, 3, 3, 3, 2, 2, 2, 6, 7, 6, 5, 5, 4, 2, 12, - 12, 9, 8, 6, 5, 3, 15, 16, 11, 9, 7, 5, 4, 4, 3, 3, 2, 3, 4, - 5, 4, 4, 3, 3, 3, 3, 3, 4, 5, 4, 3, 2, 2, 0, 4, 8, 5, 5, - 4, 4, 3, 8, 12, 9, 9, 8, 6, 4, 11, 14, 14, 12, 10, 7, 5, 15, 17, - 17, 14, 12, 9, 5, 8, 7, 6, 5, 4, 4, 4, 7, 9, 6, 6, 4, 3, 2, - 8, 11, 8, 7, 5, 3, 2, 8, 11, 12, 11, 9, 6, 5, 10, 14, 17, 16, 13, - 9, 5, 13, 18, 22, 20, 15, 10, 7, 16, 20, 23, 22, 17, 12, 8, 12, 15, 13, - 9, 5, 4, 3, 11, 15, 16, 11, 6, 3, 2, 12, 15, 18, 12, 8, 5, 3, 12, - 16, 21, 16, 12, 9, 6, 14, 19, 24, 21, 16, 12, 8, 16, 21, 26, 26, 19, 13, - 9, 20, 24, 27, 27, 22, 15, 10, 15, 19, 23, 26, 26, 25, 22, 14, 18, 22, 25, - 25, 23, 21, 13, 17, 20, 23, 24, 21, 19, 13, 15, 18, 20, 22, 20, 18, 12, 14, - 16, 18, 21, 20, 18, 10, 12, 15, 17, 20, 20, 18, 10, 11, 13, 15, 19, 19, 18, - 14, 17, 20, 23, 24, 23, 19, 13, 16, 19, 22, 24, 21, 17, 12, 14, 17, 20, 20, - 19, 15, 11, 13, 16, 17, 17, 17, 15, 10, 12, 14, 16, 16, 17, 14, 8, 11, 12, - 14, 14, 15, 15, 11, 11, 12, 14, 14, 14, 14, 12, 14, 16, 17, 19, 19, 15, 11, - 13, 15, 16, 17, 17, 12, 10, 13, 14, 14, 14, 15, 12, 9, 12, 12, 12, 13, 13, - 12, 7, 10, 12, 12, 12, 12, 12, 8, 9, 9, 10, 11, 12, 12, 12, 13, 10, 9, - 10, 11, 11, 10, 10, 10, 11, 13, 14, 6, 8, 9, 9, 10, 10, 11, 5, 7, 8, - 8, 8, 9, 9, 5, 4, 6, 6, 7, 7, 7, 5, 5, 5, 6, 6, 6, 7, 5, - 8, 8, 7, 6, 5, 5, 4, 12, 12, 8, 6, 5, 4, 2, 2, 2, 2, 2, 3, - 4, 6, 0, 1, 1, 2, 1, 2, 5, 0, 1, 1, 1, 1, 1, 5, 0, 2, 2, - 1, 2, 1, 4, 2, 4, 4, 3, 4, 2, 2, 5, 7, 7, 6, 5, 3, 2, 9, - 10, 10, 7, 6, 4, 2, 4, 5, 4, 5, 3, 2, 5, 4, 6, 6, 5, 3, 1, - 3, 4, 7, 7, 6, 4, 1, 2, 4, 7, 8, 7, 5, 3, 2, 4, 8, 11, 9, - 7, 4, 2, 6, 10, 14, 12, 9, 6, 2, 9, 12, 14, 13, 10, 7, 3, 9, 12, - 11, 7, 5, 2, 2, 9, 12, 13, 8, 5, 2, 1, 9, 12, 14, 9, 6, 3, 1, - 9, 12, 15, 10, 7, 5, 2, 8, 12, 15, 13, 9, 7, 4, 10, 14, 17, 16, 11, - 8, 5, 12, 15, 17, 17, 13, 9, 6, 21, 24, 26, 29, 28, 27, 25, 21, 23, 26, - 28, 29, 26, 23, 19, 22, 25, 26, 27, 25, 23, 18, 21, 23, 26, 27, 24, 21, 16, - 19, 21, 23, 25, 23, 22, 15, 19, 21, 22, 24, 23, 21, 12, 15, 19, 22, 24, 23, - 22, 20, 23, 25, 27, 26, 24, 22, 18, 21, 24, 26, 26, 23, 21, 17, 20, 23, 25, - 23, 23, 20, 16, 18, 21, 23, 22, 21, 19, 14, 17, 19, 22, 21, 21, 19, 12, 15, - 18, 20, 21, 20, 19, 12, 12, 17, 19, 20, 19, 20, 17, 21, 22, 22, 22, 21, 18, - 15, 20, 21, 22, 21, 20, 17, 14, 18, 20, 20, 20, 20, 17, 12, 16, 17, 17, 18, - 18, 16, 11, 14, 16, 16, 17, 17, 16, 8, 12, 14, 14, 16, 16, 16, 13, 13, 11, - 13, 15, 15, 15, 14, 15, 16, 16, 17, 17, 8, 13, 13, 14, 15, 15, 15, 8, 10, - 12, 13, 13, 13, 14, 8, 7, 10, 10, 10, 10, 11, 9, 7, 8, 9, 9, 9, 10, - 6, 8, 8, 7, 7, 7, 8, 6, 13, 14, 10, 7, 6, 6, 5, 6, 6, 7, 8, - 8, 6, 8, 2, 5, 6, 6, 6, 6, 8, 2, 3, 4, 4, 4, 5, 9, 2, 0, - 0, 0, 0, 2, 6, 3, 5, 4, 5, 5, 3, 5, 5, 9, 9, 8, 6, 4, 3, - 11, 12, 11, 8, 6, 5, 2, 4, 6, 6, 6, 3, 5, 7, 4, 7, 7, 7, 4, - 5, 6, 4, 8, 8, 8, 6, 3, 6, 4, 8, 8, 7, 5, 3, 3, 4, 8, 9, - 8, 7, 5, 2, 7, 9, 12, 11, 8, 6, 3, 11, 12, 13, 12, 9, 6, 4, 9, - 12, 11, 9, 6, 3, 6, 9, 12, 13, 9, 7, 3, 5, 9, 13, 15, 10, 7, 4, - 3, 10, 12, 15, 9, 7, 6, 3, 8, 11, 14, 12, 8, 6, 5, 9, 13, 15, 14, - 10, 7, 6, 11, 14, 16, 16, 12, 8, 6, 22, 26, 28, 31, 31, 29, 26, 21, 24, - 28, 31, 31, 28, 25, 19, 23, 26, 29, 29, 27, 23, 18, 20, 24, 27, 29, 26, 22, - 15, 18, 21, 24, 27, 25, 22, 14, 16, 20, 23, 27, 25, 22, 12, 15, 18, 22, 25, - 25, 22, 19, 23, 26, 30, 27, 26, 22, 18, 21, 25, 28, 28, 24, 22, 16, 20, 24, - 27, 25, 24, 20, 15, 18, 21, 23, 23, 21, 19, 13, 16, 19, 22, 22, 21, 19, 11, - 15, 17, 21, 21, 21, 19, 12, 12, 16, 19, 20, 20, 19, 16, 20, 22, 23, 24, 22, - 18, 15, 18, 21, 22, 22, 21, 17, 14, 17, 20, 20, 20, 20, 15, 13, 15, 16, 16, - 17, 17, 14, 10, 13, 15, 15, 15, 16, 14, 8, 12, 13, 14, 14, 14, 14, 13, 13, - 12, 12, 13, 13, 13, 13, 14, 15, 16, 17, 17, 9, 12, 13, 14, 15, 15, 15, 8, - 9, 11, 12, 13, 12, 13, 8, 6, 9, 9, 9, 9, 9, 7, 6, 8, 8, 8, 8, - 8, 4, 8, 8, 7, 6, 6, 7, 4, 13, 15, 10, 7, 5, 5, 3, 5, 6, 7, - 8, 8, 7, 8, 2, 5, 5, 6, 7, 6, 8, 2, 3, 3, 4, 4, 4, 5, 2, - 0, 0, 0, 0, 2, 4, 3, 5, 5, 4, 5, 3, 3, 6, 10, 11, 9, 7, 4, - 2, 12, 15, 14, 11, 9, 6, 2, 4, 6, 7, 7, 4, 6, 7, 4, 8, 8, 9, - 5, 5, 6, 4, 10, 10, 10, 6, 2, 4, 4, 10, 11, 11, 7, 3, 2, 5, 11, - 15, 15, 12, 6, 2, 8, 14, 20, 19, 14, 8, 3, 13, 17, 21, 21, 16, 10, 4, - 12, 19, 18, 12, 7, 5, 6, 13, 19, 21, 14, 8, 3, 5, 13, 19, 23, 15, 10, - 4, 2, 13, 18, 23, 17, 11, 7, 3, 12, 18, 23, 21, 16, 10, 4, 14, 20, 25, - 24, 19, 12, 6, 17, 23, 25, 25, 20, 14, 8, 22, 26, 29, 32, 33, 30, 26, 20, - 24, 28, 33, 33, 29, 26, 19, 23, 27, 30, 31, 28, 23, 18, 20, 24, 27, 30, 26, - 23, 15, 18, 21, 24, 28, 26, 23, 14, 17, 19, 23, 27, 26, 22, 12, 15, 18, 22, - 26, 25, 22, 19, 23, 27, 29, 29, 27, 23, 18, 21, 26, 29, 29, 25, 22, 16, 20, - 24, 27, 26, 24, 20, 15, 18, 21, 24, 23, 22, 19, 13, 16, 19, 21, 22, 21, 19, - 12, 15, 18, 20, 21, 21, 18, 12, 12, 17, 19, 20, 19, 19, 16, 20, 22, 23, 24, - 22, 19, 15, 18, 20, 22, 23, 22, 17, 13, 17, 19, 19, 20, 19, 15, 13, 15, 15, - 16, 16, 17, 13, 10, 13, 15, 15, 14, 15, 13, 8, 12, 13, 14, 14, 13, 13, 13, - 13, 12, 12, 13, 13, 12, 14, 14, 15, 16, 17, 18, 10, 13, 13, 14, 15, 15, 15, - 8, 10, 11, 12, 12, 12, 12, 7, 6, 10, 9, 9, 9, 9, 7, 6, 8, 8, 8, - 7, 7, 4, 8, 8, 7, 6, 6, 6, 3, 13, 14, 9, 6, 5, 5, 2, 6, 6, - 7, 8, 9, 8, 9, 1, 5, 6, 6, 7, 6, 8, 1, 3, 3, 3, 4, 4, 5, - 1, 0, 0, 0, 0, 2, 3, 3, 5, 4, 4, 4, 2, 2, 6, 10, 11, 9, 6, - 3, 2, 12, 15, 14, 10, 9, 5, 2, 4, 6, 7, 7, 5, 7, 8, 4, 8, 8, - 8, 5, 5, 6, 4, 10, 10, 9, 5, 2, 3, 4, 9, 11, 10, 6, 2, 2, 5, - 11, 15, 14, 11, 5, 2, 8, 14, 20, 18, 13, 7, 2, 12, 17, 21, 21, 15, 10, - 4, 13, 19, 17, 12, 7, 5, 7, 13, 18, 20, 13, 8, 3, 4, 13, 19, 21, 14, - 9, 4, 1, 13, 17, 22, 16, 10, 6, 2, 12, 17, 24, 21, 15, 9, 4, 14, 20, - 25, 25, 18, 11, 6, 17, 22, 26, 26, 20, 14, 8, 22, 26, 30, 34, 33, 30, 28, - 21, 24, 29, 33, 33, 30, 26, 19, 23, 27, 31, 32, 28, 24, 18, 20, 24, 28, 30, - 27, 23, 15, 18, 21, 25, 29, 26, 23, 14, 17, 20, 23, 27, 27, 23, 12, 15, 19, - 23, 26, 26, 22, 19, 23, 28, 30, 29, 26, 24, 18, 21, 25, 29, 30, 26, 22, 17, - 20, 24, 27, 27, 23, 20, 15, 18, 21, 23, 24, 22, 18, 14, 16, 19, 22, 22, 22, - 18, 12, 15, 17, 20, 20, 21, 19, 12, 13, 17, 20, 19, 20, 18, 17, 20, 22, 23, - 24, 23, 18, 15, 19, 21, 22, 23, 21, 17, 15, 17, 20, 19, 20, 19, 15, 13, 16, - 16, 17, 17, 16, 13, 10, 14, 15, 15, 15, 15, 13, 9, 12, 14, 14, 14, 14, 13, - 12, 12, 12, 12, 13, 13, 12, 15, 15, 15, 16, 17, 18, 10, 13, 13, 14, 15, 15, - 15, 8, 10, 12, 12, 12, 12, 12, 7, 6, 10, 9, 9, 9, 9, 7, 6, 8, 8, - 8, 7, 8, 4, 8, 8, 7, 7, 6, 6, 3, 12, 12, 9, 6, 5, 5, 2, 6, - 6, 7, 8, 9, 8, 10, 2, 5, 6, 7, 7, 6, 8, 1, 4, 4, 4, 4, 4, - 4, 1, 0, 0, 0, 0, 1, 3, 3, 5, 4, 4, 4, 2, 2, 6, 10, 10, 8, - 6, 3, 2, 11, 13, 13, 10, 8, 5, 1, 5, 7, 7, 7, 5, 7, 8, 5, 9, - 8, 8, 5, 5, 6, 5, 10, 9, 8, 5, 2, 3, 5, 10, 10, 9, 6, 2, 2, - 5, 11, 14, 13, 10, 5, 1, 8, 14, 19, 17, 12, 7, 2, 12, 16, 20, 20, 14, - 9, 3, 12, 15, 13, 10, 6, 6, 7, 12, 15, 15, 11, 7, 4, 4, 12, 15, 16, - 11, 8, 3, 2, 12, 15, 17, 13, 10, 6, 2, 11, 16, 19, 17, 14, 9, 4, 14, - 19, 23, 23, 16, 11, 5, 16, 21, 24, 23, 19, 13, 7, 21, 24, 28, 32, 33, 29, - 25, 19, 23, 27, 31, 32, 28, 25, 18, 21, 25, 29, 30, 27, 23, 17, 20, 22, 25, - 28, 25, 21, 14, 17, 20, 23, 27, 24, 21, 13, 16, 18, 22, 26, 25, 21, 11, 14, - 17, 21, 24, 24, 21, 17, 22, 25, 29, 28, 26, 23, 17, 20, 24, 28, 28, 24, 20, - 15, 19, 22, 26, 26, 23, 18, 14, 16, 20, 22, 22, 21, 17, 12, 15, 18, 20, 20, - 20, 17, 10, 13, 16, 19, 19, 19, 17, 10, 12, 15, 18, 18, 18, 17, 16, 19, 21, - 21, 24, 21, 17, 14, 17, 20, 21, 21, 20, 15, 13, 16, 18, 18, 18, 18, 14, 12, - 14, 15, 15, 15, 15, 11, 10, 13, 14, 13, 13, 13, 12, 8, 11, 12, 12, 12, 12, - 11, 10, 10, 10, 11, 11, 11, 11, 13, 13, 14, 15, 16, 17, 9, 11, 12, 13, 14, - 14, 14, 7, 9, 11, 10, 11, 10, 10, 6, 5, 9, 8, 7, 7, 7, 6, 5, 6, - 6, 6, 6, 6, 3, 8, 7, 6, 5, 4, 5, 3, 10, 10, 7, 5, 4, 3, 2, - 5, 5, 6, 7, 8, 8, 9, 1, 4, 5, 5, 6, 6, 7, 1, 2, 3, 3, 3, - 3, 4, 1, 2, 2, 2, 1, 0, 2, 2, 6, 5, 4, 4, 2, 2, 6, 9, 9, - 7, 5, 3, 1, 9, 11, 10, 7, 6, 4, 2, 5, 4, 4, 4, 5, 7, 8, 5, - 6, 4, 4, 4, 4, 6, 5, 8, 5, 4, 2, 2, 3, 5, 7, 7, 4, 3, 2, - 1, 5, 8, 10, 8, 6, 4, 2, 8, 11, 13, 10, 7, 5, 3, 10, 12, 13, 12, - 8, 6, 3, 9, 11, 8, 5, 5, 6, 6, 9, 11, 9, 5, 4, 4, 4, 9, 11, - 11, 6, 4, 2, 1, 8, 11, 11, 7, 5, 3, 2, 8, 10, 13, 11, 8, 5, 4, - 10, 13, 15, 14, 9, 7, 4, 11, 14, 15, 15, 11, 7, 5, 17, 21, 24, 28, 27, - 25, 22, 16, 20, 24, 27, 27, 23, 20, 14, 18, 21, 24, 26, 23, 18, 13, 16, 19, - 22, 25, 20, 17, 10, 13, 15, 19, 22, 20, 17, 9, 11, 14, 18, 22, 21, 17, 7, - 10, 14, 16, 20, 20, 17, 14, 18, 21, 25, 24, 22, 18, 13, 17, 21, 24, 23, 20, - 16, 12, 15, 20, 21, 21, 19, 14, 11, 13, 16, 19, 18, 17, 13, 8, 11, 13, 16, - 16, 16, 13, 7, 9, 12, 15, 15, 15, 12, 6, 8, 12, 14, 13, 14, 13, 12, 16, - 17, 18, 19, 18, 14, 10, 14, 16, 17, 17, 16, 12, 9, 13, 15, 14, 14, 14, 10, - 9, 11, 11, 11, 11, 11, 8, 5, 8, 9, 9, 9, 9, 8, 5, 7, 8, 8, 8, - 8, 8, 6, 6, 7, 6, 7, 7, 6, 10, 10, 10, 11, 12, 13, 9, 8, 8, 9, - 10, 10, 10, 6, 6, 7, 7, 7, 7, 7, 4, 3, 4, 4, 3, 4, 4, 3, 3, - 3, 2, 2, 2, 2, 2, 5, 5, 3, 3, 2, 1, 0, 6, 7, 4, 3, 2, 2, - 1, 2, 3, 4, 5, 6, 8, 8, 4, 3, 4, 5, 5, 5, 6, 4, 5, 4, 3, - 3, 3, 3, 4, 6, 4, 3, 3, 2, 0, 4, 6, 5, 4, 4, 2, 1, 6, 7, - 8, 7, 5, 3, 2, 7, 9, 11, 8, 7, 5, 2, 7, 6, 5, 5, 5, 7, 7, - 7, 8, 6, 6, 4, 4, 5, 7, 8, 7, 7, 4, 2, 2, 7, 8, 8, 8, 5, - 3, 2, 6, 9, 12, 11, 8, 5, 2, 7, 11, 16, 15, 10, 6, 3, 9, 13, 17, - 17, 12, 7, 3, 10, 14, 13, 8, 5, 6, 6, 10, 14, 15, 10, 6, 3, 3, 10, - 14, 17, 10, 6, 3, 2, 10, 13, 17, 12, 8, 5, 2, 10, 14, 19, 16, 11, 8, - 4, 12, 16, 21, 20, 14, 9, 5, 14, 18, 22, 22, 16, 11, 6, 19, 22, 24, 28, - 28, 25, 22, 18, 21, 23, 26, 28, 25, 22, 17, 20, 22, 24, 26, 23, 20, 16, 18, - 20, 22, 24, 21, 17, 13, 15, 17, 18, 21, 19, 16, 11, 12, 14, 16, 19, 18, 16, - 8, 10, 12, 15, 17, 18, 16, 17, 20, 23, 25, 25, 23, 20, 17, 19, 22, 24, 24, - 22, 19, 15, 18, 21, 22, 22, 20, 18, 14, 16, 18, 19, 19, 18, 14, 10, 13, 14, - 15, 15, 15, 14, 8, 10, 12, 14, 14, 15, 14, 9, 9, 11, 12, 13, 13, 14, 15, - 18, 19, 20, 20, 20, 16, 13, 17, 18, 19, 19, 18, 16, 12, 16, 17, 17, 17, 17, - 15, 11, 14, 15, 15, 15, 15, 13, 7, 10, 12, 11, 12, 12, 13, 5, 8, 9, 10, - 11, 12, 12, 10, 10, 8, 8, 10, 11, 11, 12, 14, 14, 15, 15, 16, 9, 11, 12, - 13, 13, 13, 14, 9, 9, 10, 11, 11, 12, 12, 9, 6, 8, 8, 9, 9, 9, 7, - 4, 5, 5, 5, 6, 6, 6, 5, 6, 5, 4, 4, 5, 5, 10, 10, 6, 4, 3, - 3, 3, 4, 5, 6, 7, 7, 8, 9, 2, 4, 5, 6, 6, 7, 9, 2, 3, 4, - 4, 4, 5, 8, 2, 3, 3, 3, 3, 2, 4, 0, 3, 2, 2, 2, 1, 3, 3, - 4, 5, 4, 3, 1, 1, 7, 7, 7, 5, 4, 3, 1, 5, 6, 6, 7, 5, 6, - 8, 5, 7, 7, 7, 5, 5, 7, 5, 8, 8, 8, 6, 4, 6, 5, 7, 8, 7, - 5, 2, 1, 3, 6, 9, 8, 5, 2, 1, 4, 8, 11, 10, 7, 4, 1, 6, 10, - 12, 11, 8, 5, 2, 10, 13, 13, 9, 6, 5, 6, 10, 14, 14, 10, 7, 5, 6, - 10, 14, 15, 10, 7, 5, 3, 10, 13, 15, 10, 7, 4, 1, 9, 11, 14, 12, 8, - 5, 2, 8, 12, 15, 14, 9, 6, 3, 10, 13, 15, 15, 11, 7, 4, 27, 29, 32, - 35, 35, 32, 30, 25, 29, 31, 34, 34, 31, 28, 25, 27, 31, 32, 33, 30, 26, 22, - 26, 28, 30, 32, 28, 24, 20, 23, 25, 26, 28, 26, 23, 16, 19, 21, 24, 26, 25, - 23, 13, 17, 21, 23, 26, 26, 23, 24, 28, 31, 33, 32, 29, 28, 23, 26, 29, 32, - 32, 29, 26, 21, 25, 28, 30, 30, 28, 25, 20, 23, 26, 28, 26, 25, 21, 16, 20, - 22, 24, 24, 22, 21, 14, 17, 20, 21, 22, 22, 21, 10, 13, 18, 21, 21, 21, 21, - 21, 25, 28, 28, 28, 27, 24, 20, 24, 26, 27, 27, 27, 23, 18, 22, 24, 25, 26, - 25, 22, 16, 20, 21, 22, 22, 23, 18, 11, 16, 17, 18, 18, 18, 18, 7, 13, 16, - 16, 16, 17, 18, 9, 10, 13, 15, 15, 16, 17, 18, 19, 21, 22, 22, 22, 15, 16, - 18, 20, 20, 20, 21, 14, 13, 16, 17, 18, 18, 18, 14, 9, 14, 14, 14, 15, 15, - 12, 7, 10, 10, 10, 10, 11, 8, 7, 7, 7, 8, 9, 9, 6, 9, 9, 6, 6, - 7, 8, 7, 9, 11, 12, 14, 14, 13, 14, 4, 9, 11, 12, 12, 11, 14, 4, 7, - 8, 8, 9, 9, 12, 4, 5, 5, 5, 5, 6, 6, 3, 0, 0, 0, 0, 3, 6, - 3, 3, 3, 2, 1, 1, 6, 6, 6, 5, 2, 2, 2, 5, 4, 5, 6, 6, 9, - 12, 13, 4, 5, 6, 6, 8, 10, 11, 4, 6, 6, 6, 5, 7, 9, 4, 5, 5, - 5, 3, 3, 6, 2, 3, 5, 4, 2, 2, 4, 2, 4, 7, 6, 3, 2, 2, 5, - 5, 8, 7, 4, 2, 1, 7, 10, 9, 7, 7, 10, 12, 7, 10, 11, 8, 6, 8, - 10, 7, 10, 12, 7, 5, 5, 6, 7, 9, 12, 7, 4, 2, 2, 5, 8, 10, 7, - 4, 2, 1, 4, 7, 10, 9, 5, 2, 1, 5, 9, 11, 11, 7, 3, 2, 27, 30, - 34, 37, 37, 34, 32, 25, 29, 32, 36, 36, 34, 29, 23, 27, 32, 34, 35, 32, 28, - 22, 25, 28, 31, 33, 29, 24, 19, 22, 25, 27, 30, 28, 24, 16, 19, 21, 24, 29, - 27, 24, 13, 17, 20, 24, 27, 27, 24, 24, 27, 31, 34, 33, 31, 28, 22, 26, 30, - 33, 33, 31, 27, 20, 24, 29, 31, 30, 29, 25, 19, 22, 25, 28, 28, 27, 22, 16, - 18, 22, 25, 24, 23, 21, 13, 16, 19, 23, 22, 23, 21, 10, 14, 18, 21, 21, 21, - 21, 21, 24, 27, 29, 29, 28, 23, 19, 23, 26, 27, 28, 26, 22, 18, 21, 24, 24, - 25, 24, 20, 16, 20, 20, 20, 21, 22, 17, 10, 16, 17, 17, 17, 18, 16, 7, 13, - 15, 16, 16, 16, 16, 8, 11, 13, 13, 15, 15, 15, 18, 19, 20, 21, 22, 23, 15, - 15, 17, 19, 20, 19, 19, 14, 12, 16, 17, 17, 17, 17, 13, 8, 13, 13, 13, 14, - 14, 11, 6, 9, 9, 9, 9, 9, 8, 6, 7, 7, 8, 8, 8, 5, 8, 9, 5, - 6, 6, 7, 5, 8, 10, 12, 13, 13, 13, 15, 3, 9, 10, 11, 11, 11, 14, 3, - 8, 8, 8, 8, 8, 9, 3, 5, 4, 4, 4, 5, 5, 2, 0, 0, 0, 0, 2, - 4, 3, 5, 6, 5, 3, 1, 4, 7, 10, 10, 6, 5, 2, 4, 4, 5, 6, 7, - 9, 11, 13, 4, 7, 7, 7, 8, 9, 11, 4, 9, 9, 8, 5, 7, 8, 4, 8, - 10, 10, 5, 3, 4, 2, 7, 12, 12, 7, 2, 3, 3, 9, 15, 15, 10, 4, 2, - 8, 12, 16, 16, 12, 6, 1, 11, 17, 16, 11, 7, 10, 12, 11, 18, 19, 13, 7, - 8, 9, 11, 17, 21, 14, 8, 4, 6, 11, 17, 21, 15, 9, 4, 2, 10, 16, 21, - 17, 12, 6, 1, 10, 16, 20, 19, 14, 8, 2, 13, 18, 20, 20, 16, 10, 4, 27, - 30, 33, 37, 36, 35, 31, 25, 29, 32, 36, 37, 35, 30, 23, 27, 31, 35, 35, 32, - 28, 22, 25, 29, 31, 34, 30, 24, 19, 22, 24, 27, 31, 28, 25, 16, 18, 21, 25, - 29, 28, 25, 13, 16, 20, 23, 27, 27, 25, 23, 28, 30, 34, 33, 31, 29, 22, 26, - 30, 33, 34, 29, 26, 20, 24, 28, 30, 31, 28, 23, 19, 22, 24, 27, 28, 26, 20, - 17, 19, 21, 24, 24, 23, 20, 14, 16, 19, 22, 21, 22, 20, 10, 14, 18, 20, 21, - 21, 21, 20, 24, 26, 27, 29, 27, 23, 19, 22, 25, 26, 26, 25, 21, 18, 21, 23, - 24, 24, 24, 19, 15, 20, 20, 20, 21, 20, 16, 10, 16, 16, 17, 16, 16, 16, 7, - 14, 14, 15, 15, 15, 16, 8, 11, 13, 14, 14, 14, 14, 18, 18, 19, 20, 22, 22, - 15, 15, 17, 18, 19, 20, 20, 13, 11, 16, 16, 16, 16, 16, 12, 8, 14, 12, 13, - 13, 13, 11, 6, 10, 9, 9, 9, 9, 7, 6, 7, 7, 7, 7, 8, 4, 8, 8, - 5, 6, 6, 6, 4, 7, 10, 12, 13, 13, 13, 14, 3, 9, 10, 11, 11, 10, 13, - 3, 8, 8, 8, 8, 8, 9, 3, 5, 4, 4, 4, 4, 4, 2, 0, 0, 0, 0, - 2, 3, 3, 5, 6, 4, 2, 1, 3, 6, 9, 9, 6, 4, 2, 2, 4, 5, 6, - 7, 9, 12, 13, 4, 7, 7, 7, 8, 9, 10, 4, 8, 9, 8, 5, 6, 7, 4, - 8, 9, 9, 5, 3, 3, 2, 7, 11, 11, 7, 2, 3, 3, 9, 15, 15, 9, 3, - 2, 7, 12, 17, 17, 11, 5, 1, 11, 17, 16, 11, 7, 10, 11, 11, 17, 19, 12, - 7, 8, 9, 11, 17, 20, 14, 8, 4, 5, 11, 17, 21, 14, 9, 3, 2, 10, 15, - 21, 17, 11, 5, 1, 10, 16, 21, 21, 14, 7, 2, 12, 18, 22, 22, 16, 10, 4, - 26, 30, 33, 39, 37, 35, 31, 25, 29, 32, 37, 37, 33, 30, 23, 26, 32, 34, 36, - 32, 28, 22, 24, 28, 31, 33, 30, 25, 19, 21, 25, 27, 30, 28, 25, 16, 19, 21, - 25, 28, 28, 25, 14, 17, 20, 24, 27, 28, 25, 23, 28, 30, 34, 34, 31, 27, 22, - 26, 29, 32, 33, 30, 26, 21, 24, 28, 30, 31, 28, 24, 20, 22, 25, 28, 29, 26, - 20, 17, 19, 21, 23, 24, 23, 20, 14, 16, 19, 21, 22, 23, 20, 12, 15, 18, 21, - 21, 21, 20, 21, 24, 27, 27, 29, 27, 23, 19, 23, 26, 26, 26, 25, 21, 18, 22, - 23, 23, 24, 24, 19, 15, 20, 20, 20, 20, 20, 15, 10, 16, 17, 17, 17, 16, 15, - 7, 14, 15, 15, 15, 15, 14, 7, 12, 14, 14, 14, 14, 14, 18, 19, 20, 20, 22, - 21, 15, 15, 17, 18, 20, 20, 19, 13, 12, 16, 16, 16, 16, 16, 12, 8, 14, 13, - 12, 13, 13, 11, 6, 10, 9, 9, 9, 9, 7, 6, 8, 8, 7, 7, 8, 4, 7, - 5, 6, 6, 6, 6, 4, 7, 11, 12, 12, 13, 13, 15, 4, 9, 10, 11, 11, 10, - 13, 4, 8, 8, 8, 8, 8, 8, 4, 5, 5, 4, 4, 4, 4, 2, 0, 0, 0, - 0, 2, 3, 3, 4, 4, 3, 2, 2, 3, 4, 5, 5, 4, 4, 2, 2, 4, 5, - 6, 7, 9, 11, 13, 4, 7, 7, 7, 8, 9, 10, 4, 9, 8, 7, 5, 6, 7, - 4, 8, 9, 8, 5, 3, 3, 2, 7, 11, 9, 6, 2, 2, 3, 9, 14, 12, 8, - 3, 2, 4, 9, 14, 14, 10, 5, 1, 10, 14, 12, 9, 8, 10, 11, 10, 14, 14, - 10, 7, 8, 8, 10, 14, 15, 10, 7, 4, 5, 10, 13, 15, 11, 8, 3, 2, 10, - 13, 16, 14, 10, 5, 1, 10, 15, 18, 17, 12, 7, 2, 11, 15, 18, 18, 13, 9, - 3, 24, 27, 31, 35, 36, 33, 29, 22, 26, 30, 34, 36, 32, 28, 21, 25, 28, 32, - 33, 29, 25, 19, 22, 26, 29, 31, 27, 23, 17, 19, 21, 25, 29, 26, 23, 15, 17, - 19, 23, 27, 26, 22, 13, 16, 19, 22, 26, 26, 23, 21, 25, 28, 32, 31, 28, 25, - 20, 22, 27, 31, 31, 28, 23, 19, 22, 26, 28, 28, 25, 21, 17, 20, 23, 25, 25, - 23, 18, 15, 17, 19, 22, 22, 21, 18, 13, 15, 17, 20, 20, 21, 19, 10, 14, 17, - 19, 19, 19, 18, 19, 22, 23, 25, 27, 24, 20, 18, 21, 23, 24, 24, 23, 18, 17, - 19, 21, 22, 21, 20, 16, 15, 17, 18, 18, 18, 18, 13, 10, 14, 15, 14, 14, 15, - 13, 6, 13, 14, 13, 13, 13, 13, 6, 12, 12, 12, 12, 12, 12, 17, 17, 17, 18, - 19, 19, 13, 14, 15, 16, 16, 17, 17, 10, 11, 14, 14, 14, 14, 13, 9, 7, 12, - 11, 10, 10, 10, 9, 5, 8, 8, 7, 7, 7, 5, 5, 6, 6, 6, 6, 6, 3, - 6, 4, 4, 4, 4, 4, 3, 7, 8, 9, 10, 11, 11, 13, 2, 7, 8, 8, 9, - 8, 10, 2, 6, 6, 5, 6, 6, 6, 2, 3, 3, 2, 2, 3, 3, 1, 3, 2, - 2, 2, 0, 2, 2, 5, 5, 4, 2, 1, 2, 3, 6, 7, 4, 3, 2, 2, 3, - 4, 5, 7, 8, 10, 11, 3, 4, 5, 6, 7, 7, 8, 3, 6, 5, 4, 4, 4, - 5, 3, 5, 5, 3, 2, 1, 2, 3, 7, 7, 5, 4, 2, 1, 5, 7, 10, 7, - 4, 3, 0, 6, 8, 10, 8, 5, 3, 1, 6, 8, 7, 5, 7, 8, 9, 6, 8, - 7, 6, 6, 6, 6, 6, 8, 9, 5, 3, 3, 3, 6, 8, 10, 7, 4, 2, 0, - 7, 10, 11, 8, 5, 3, 2, 8, 10, 11, 10, 6, 4, 2, 9, 10, 11, 11, 7, - 4, 3, 19, 22, 26, 30, 30, 27, 23, 17, 21, 25, 29, 29, 25, 22, 16, 20, 23, - 26, 28, 24, 20, 15, 17, 21, 24, 26, 23, 18, 12, 14, 17, 20, 24, 22, 18, 10, - 13, 16, 19, 22, 22, 18, 8, 11, 15, 18, 20, 21, 18, 16, 20, 23, 27, 25, 23, - 20, 15, 18, 22, 26, 26, 22, 18, 14, 17, 21, 23, 23, 20, 16, 12, 15, 18, 21, - 20, 19, 14, 9, 12, 15, 17, 17, 17, 14, 8, 11, 14, 16, 16, 16, 14, 6, 9, - 13, 15, 14, 15, 14, 14, 17, 19, 19, 21, 20, 15, 12, 15, 17, 18, 19, 18, 13, - 11, 14, 16, 16, 16, 16, 11, 10, 12, 13, 12, 13, 13, 9, 6, 9, 10, 10, 10, - 10, 9, 5, 8, 9, 9, 9, 9, 9, 6, 7, 8, 8, 8, 8, 8, 11, 11, 12, - 13, 14, 15, 9, 10, 10, 10, 11, 11, 12, 7, 8, 9, 9, 9, 8, 8, 5, 4, - 6, 5, 5, 5, 5, 4, 3, 3, 3, 3, 3, 2, 2, 4, 3, 2, 2, 2, 2, - 1, 6, 7, 4, 3, 2, 1, 0, 3, 3, 5, 6, 7, 8, 9, 2, 3, 4, 5, - 6, 6, 7, 2, 3, 3, 3, 3, 3, 4, 2, 5, 3, 2, 2, 2, 1, 3, 6, - 4, 3, 3, 2, 0, 4, 7, 6, 4, 3, 2, 2, 6, 8, 8, 6, 4, 3, 2, - 6, 6, 5, 5, 6, 7, 8, 6, 7, 5, 5, 5, 5, 5, 6, 8, 6, 4, 3, - 2, 2, 6, 8, 6, 5, 4, 3, 1, 6, 7, 9, 8, 5, 3, 2, 7, 9, 13, - 11, 7, 4, 2, 8, 10, 14, 13, 9, 5, 3, 8, 11, 9, 6, 5, 7, 7, 8, - 11, 11, 7, 4, 4, 4, 8, 11, 13, 7, 4, 3, 2, 8, 10, 14, 8, 5, 3, - 2, 8, 11, 15, 13, 8, 5, 3, 9, 13, 17, 17, 10, 6, 3, 11, 15, 18, 18, - 12, 7, 4, 23, 25, 27, 31, 31, 29, 25, 23, 24, 26, 29, 30, 27, 25, 21, 24, - 27, 27, 28, 25, 22, 20, 21, 24, 25, 26, 22, 16, 17, 19, 20, 21, 20, 18, 16, - 12, 14, 16, 16, 18, 18, 16, 8, 11, 14, 16, 18, 18, 16, 21, 24, 25, 28, 27, - 26, 24, 20, 23, 25, 27, 27, 24, 23, 18, 22, 25, 24, 25, 22, 20, 17, 20, 22, - 22, 21, 20, 15, 14, 16, 18, 19, 16, 15, 14, 9, 12, 14, 15, 14, 15, 15, 6, - 8, 12, 14, 14, 15, 15, 19, 22, 23, 24, 24, 24, 21, 16, 20, 22, 23, 24, 23, - 21, 15, 19, 21, 22, 22, 21, 19, 14, 17, 18, 18, 18, 19, 14, 9, 13, 14, 15, - 14, 14, 13, 4, 9, 10, 11, 12, 13, 13, 7, 7, 8, 10, 11, 12, 13, 15, 17, - 18, 20, 20, 21, 16, 14, 15, 16, 18, 18, 18, 14, 11, 13, 15, 15, 15, 15, 12, - 7, 11, 11, 11, 12, 11, 10, 5, 7, 7, 7, 6, 7, 6, 3, 3, 3, 3, 5, - 6, 6, 6, 6, 4, 2, 3, 4, 5, 8, 10, 11, 13, 14, 15, 16, 5, 9, 10, - 12, 12, 13, 15, 5, 8, 9, 9, 10, 10, 11, 5, 6, 6, 6, 6, 6, 5, 3, - 3, 3, 3, 3, 2, 4, 0, 3, 3, 2, 2, 2, 5, 4, 4, 5, 3, 3, 3, - 3, 7, 8, 8, 9, 11, 14, 15, 7, 9, 8, 9, 9, 11, 13, 7, 9, 9, 9, - 7, 8, 10, 7, 8, 8, 8, 6, 5, 5, 5, 7, 9, 7, 5, 3, 2, 3, 5, - 10, 8, 6, 3, 2, 4, 7, 10, 10, 7, 4, 2, 10, 13, 13, 10, 9, 12, 13, - 10, 14, 14, 11, 9, 9, 11, 10, 13, 16, 11, 8, 7, 8, 10, 13, 15, 10, 8, - 6, 2, 9, 11, 14, 11, 7, 4, 2, 7, 10, 13, 12, 8, 5, 3, 7, 11, 13, - 13, 9, 6, 3, 30, 34, 36, 38, 39, 38, 34, 29, 33, 36, 38, 38, 35, 33, 27, - 31, 33, 36, 37, 34, 30, 26, 29, 31, 35, 35, 30, 24, 23, 26, 27, 30, 29, 27, - 24, 18, 22, 23, 25, 27, 26, 24, 14, 18, 21, 24, 26, 26, 24, 27, 31, 35, 37, - 36, 35, 31, 25, 30, 33, 36, 36, 33, 29, 24, 28, 31, 34, 34, 31, 28, 23, 26, - 30, 32, 29, 28, 22, 19, 23, 25, 27, 25, 24, 22, 15, 18, 20, 22, 23, 24, 22, - 11, 15, 19, 22, 22, 22, 22, 24, 29, 30, 32, 33, 32, 28, 22, 26, 30, 31, 30, - 31, 26, 22, 25, 28, 28, 28, 28, 23, 19, 23, 24, 25, 25, 25, 18, 13, 19, 21, - 21, 19, 19, 19, 7, 15, 16, 16, 18, 18, 19, 7, 11, 14, 15, 16, 17, 17, 21, - 23, 24, 26, 27, 27, 21, 18, 21, 22, 24, 24, 24, 19, 14, 20, 20, 21, 21, 21, - 17, 11, 17, 17, 17, 17, 17, 15, 9, 12, 12, 13, 12, 12, 11, 6, 8, 8, 9, - 9, 10, 8, 7, 5, 6, 7, 8, 8, 8, 11, 14, 16, 17, 18, 19, 20, 7, 13, - 14, 16, 17, 16, 19, 7, 13, 13, 13, 14, 14, 15, 7, 9, 10, 9, 9, 9, 8, - 5, 3, 5, 5, 4, 5, 7, 3, 0, 2, 2, 1, 3, 7, 3, 3, 3, 2, 2, - 2, 5, 7, 9, 10, 12, 15, 18, 20, 7, 7, 9, 11, 13, 16, 16, 7, 8, 8, - 8, 10, 12, 12, 7, 7, 7, 7, 6, 7, 6, 5, 5, 6, 5, 3, 2, 5, 2, - 3, 5, 4, 3, 2, 4, 3, 5, 6, 6, 4, 2, 3, 9, 11, 11, 9, 12, 16, - 17, 9, 11, 12, 10, 10, 13, 15, 9, 11, 13, 9, 7, 9, 11, 9, 10, 12, 8, - 6, 5, 4, 7, 9, 10, 8, 4, 2, 3, 5, 7, 9, 8, 4, 3, 2, 4, 6, - 9, 9, 5, 3, 2, 32, 36, 40, 42, 43, 41, 37, 31, 35, 39, 42, 42, 39, 35, - 29, 33, 38, 40, 41, 37, 33, 28, 30, 35, 37, 39, 34, 27, 25, 27, 30, 32, 33, - 30, 27, 21, 23, 26, 28, 31, 31, 27, 16, 20, 24, 27, 30, 30, 27, 29, 34, 37, - 39, 39, 37, 34, 28, 33, 35, 38, 39, 35, 32, 26, 30, 34, 36, 36, 33, 28, 25, - 28, 31, 33, 34, 30, 24, 21, 24, 27, 29, 27, 26, 24, 16, 20, 23, 25, 25, 27, - 24, 13, 17, 21, 24, 24, 25, 24, 26, 30, 32, 34, 35, 34, 29, 25, 28, 31, 33, - 33, 31, 26, 22, 26, 30, 30, 29, 29, 24, 19, 25, 26, 26, 27, 25, 20, 13, 21, - 22, 23, 20, 21, 20, 8, 17, 18, 18, 18, 19, 20, 7, 14, 16, 16, 17, 17, 18, - 23, 24, 25, 26, 28, 29, 21, 19, 22, 24, 25, 26, 26, 19, 15, 21, 22, 22, 22, - 22, 18, 11, 18, 18, 18, 18, 17, 16, 9, 13, 15, 14, 13, 12, 12, 7, 8, 10, - 10, 10, 11, 9, 7, 5, 8, 9, 9, 10, 7, 11, 16, 17, 18, 19, 19, 21, 7, - 15, 16, 17, 18, 17, 20, 7, 13, 14, 14, 14, 14, 14, 7, 9, 11, 10, 10, 9, - 8, 5, 3, 6, 6, 4, 5, 6, 3, 2, 0, 2, 3, 4, 6, 4, 3, 3, 2, - 2, 3, 5, 7, 10, 12, 13, 16, 18, 20, 7, 9, 11, 12, 14, 16, 16, 7, 7, - 9, 9, 11, 13, 12, 7, 6, 7, 7, 7, 7, 6, 5, 4, 9, 9, 5, 3, 5, - 3, 5, 11, 11, 7, 2, 5, 1, 7, 11, 12, 9, 4, 4, 9, 15, 14, 10, 14, - 17, 18, 8, 15, 16, 10, 12, 14, 14, 9, 14, 18, 11, 8, 10, 11, 8, 14, 18, - 12, 7, 5, 5, 7, 13, 17, 14, 9, 4, 4, 7, 13, 16, 14, 11, 6, 3, 8, - 13, 15, 15, 12, 8, 2, 30, 33, 38, 42, 43, 38, 36, 29, 33, 37, 41, 41, 38, - 35, 28, 31, 35, 39, 40, 36, 31, 26, 29, 33, 35, 38, 33, 27, 23, 26, 28, 30, - 32, 30, 27, 19, 22, 25, 27, 31, 30, 27, 16, 19, 22, 26, 30, 29, 27, 27, 31, - 34, 39, 38, 35, 32, 26, 30, 34, 38, 37, 34, 30, 26, 29, 32, 35, 34, 31, 26, - 23, 25, 30, 32, 31, 29, 23, 20, 23, 26, 28, 26, 26, 22, 16, 19, 22, 23, 23, - 25, 23, 12, 17, 20, 23, 23, 24, 23, 25, 29, 30, 31, 34, 32, 27, 23, 27, 29, - 31, 31, 29, 25, 22, 26, 28, 28, 28, 27, 22, 18, 23, 25, 25, 25, 23, 18, 12, - 20, 21, 21, 20, 19, 18, 7, 16, 17, 17, 17, 18, 18, 6, 14, 16, 16, 16, 16, - 16, 21, 23, 24, 25, 26, 26, 20, 18, 22, 23, 23, 24, 23, 17, 14, 20, 21, 20, - 21, 21, 16, 10, 17, 17, 17, 17, 16, 14, 8, 12, 13, 13, 12, 11, 11, 7, 8, - 10, 10, 9, 10, 7, 6, 5, 8, 8, 8, 8, 5, 9, 15, 15, 17, 17, 17, 19, - 6, 13, 14, 15, 15, 14, 17, 6, 12, 12, 12, 12, 11, 12, 6, 8, 9, 9, 8, - 7, 7, 4, 2, 5, 4, 3, 4, 5, 2, 2, 2, 0, 2, 3, 4, 3, 2, 3, - 2, 2, 2, 4, 6, 9, 10, 11, 13, 16, 17, 6, 7, 9, 10, 12, 13, 14, 6, - 7, 7, 8, 9, 10, 9, 6, 6, 7, 7, 5, 6, 4, 4, 5, 9, 9, 4, 2, - 3, 2, 5, 11, 11, 6, 1, 3, 2, 6, 11, 13, 8, 3, 3, 9, 15, 14, 9, - 12, 14, 15, 9, 15, 17, 10, 10, 12, 12, 9, 15, 18, 11, 7, 9, 9, 9, 14, - 19, 12, 7, 4, 3, 7, 13, 19, 15, 8, 3, 2, 7, 13, 18, 17, 10, 5, 2, - 8, 14, 19, 18, 13, 7, 2, 29, 31, 36, 40, 40, 38, 34, 27, 30, 35, 39, 38, - 36, 32, 25, 29, 33, 37, 38, 33, 30, 24, 27, 31, 34, 36, 32, 26, 21, 24, 26, - 30, 32, 30, 25, 18, 20, 23, 27, 30, 28, 26, 16, 18, 22, 25, 29, 29, 26, 26, - 29, 33, 37, 35, 34, 30, 25, 28, 32, 35, 36, 32, 27, 22, 27, 30, 33, 33, 30, - 25, 22, 24, 26, 30, 30, 27, 21, 19, 21, 23, 26, 25, 25, 22, 16, 18, 20, 23, - 24, 24, 21, 12, 16, 19, 22, 22, 23, 21, 23, 26, 28, 29, 31, 29, 25, 22, 25, - 27, 29, 28, 27, 23, 20, 24, 26, 26, 26, 25, 20, 17, 22, 22, 22, 23, 22, 16, - 11, 18, 19, 19, 18, 18, 16, 7, 16, 17, 16, 16, 17, 16, 7, 15, 15, 15, 15, - 16, 15, 20, 21, 21, 22, 24, 24, 17, 17, 20, 20, 21, 21, 21, 15, 13, 19, 19, - 18, 18, 18, 13, 9, 16, 15, 15, 15, 14, 12, 7, 11, 11, 11, 10, 10, 9, 7, - 8, 10, 9, 9, 9, 6, 7, 5, 8, 8, 8, 8, 4, 8, 13, 14, 14, 15, 14, - 16, 5, 12, 12, 13, 13, 11, 15, 5, 10, 10, 10, 10, 9, 10, 5, 6, 7, 6, - 6, 5, 5, 3, 1, 3, 2, 2, 2, 3, 2, 1, 3, 2, 0, 2, 3, 4, 2, - 4, 2, 2, 1, 3, 4, 6, 7, 9, 10, 13, 14, 4, 5, 6, 8, 9, 10, 11, - 4, 7, 7, 6, 7, 7, 7, 4, 6, 7, 7, 3, 4, 3, 2, 5, 10, 8, 5, - 1, 2, 0, 6, 11, 11, 6, 2, 2, 3, 7, 12, 12, 8, 3, 2, 9, 12, 11, - 8, 9, 11, 12, 9, 13, 12, 9, 8, 9, 9, 9, 13, 14, 9, 6, 6, 7, 9, - 12, 14, 10, 7, 2, 2, 8, 12, 15, 13, 8, 3, 2, 8, 13, 16, 15, 10, 5, - 1, 8, 13, 16, 16, 11, 7, 2, 26, 28, 32, 36, 37, 34, 31, 24, 27, 31, 36, - 36, 33, 29, 23, 26, 29, 33, 34, 32, 27, 21, 24, 27, 31, 33, 29, 24, 18, 21, - 24, 27, 31, 27, 24, 16, 18, 22, 25, 28, 27, 24, 15, 17, 21, 23, 27, 27, 24, - 23, 27, 30, 35, 33, 31, 27, 21, 26, 29, 32, 32, 28, 25, 21, 23, 28, 30, 31, - 28, 23, 20, 22, 24, 27, 27, 25, 20, 17, 18, 21, 24, 24, 23, 20, 15, 17, 19, - 22, 22, 22, 20, 12, 16, 18, 20, 20, 21, 19, 21, 24, 25, 27, 28, 27, 22, 19, - 22, 25, 25, 26, 24, 20, 18, 21, 23, 23, 23, 22, 18, 16, 19, 20, 20, 20, 19, - 15, 10, 16, 16, 16, 16, 16, 14, 7, 15, 16, 15, 15, 15, 14, 7, 14, 14, 13, - 14, 14, 13, 18, 19, 18, 20, 21, 21, 14, 15, 17, 18, 18, 19, 18, 12, 12, 16, - 16, 16, 15, 15, 11, 8, 14, 13, 12, 12, 11, 10, 6, 10, 9, 9, 8, 8, 7, - 6, 8, 8, 7, 7, 7, 4, 7, 4, 6, 6, 6, 6, 3, 8, 10, 11, 12, 12, - 12, 13, 3, 9, 9, 10, 11, 9, 11, 3, 8, 7, 7, 7, 7, 7, 3, 4, 4, - 3, 3, 3, 3, 1, 1, 1, 1, 2, 1, 2, 2, 3, 4, 3, 2, 0, 3, 3, - 5, 5, 3, 3, 2, 2, 3, 5, 6, 7, 8, 10, 11, 3, 4, 6, 7, 7, 8, - 8, 3, 4, 4, 4, 5, 5, 6, 3, 4, 4, 3, 2, 2, 2, 2, 5, 6, 4, - 3, 2, 2, 3, 6, 8, 6, 3, 2, 1, 5, 7, 8, 7, 4, 3, 0, 5, 7, - 6, 6, 8, 9, 10, 5, 7, 7, 6, 6, 7, 7, 6, 7, 8, 4, 3, 4, 4, - 5, 7, 8, 5, 3, 2, 1, 5, 8, 9, 7, 4, 2, 0, 6, 8, 10, 9, 5, - 3, 2, 7, 9, 10, 10, 6, 4, 3, 20, 24, 29, 32, 32, 29, 25, 20, 23, 27, - 31, 31, 28, 25, 18, 21, 25, 29, 30, 25, 22, 16, 19, 22, 26, 28, 23, 20, 13, - 16, 19, 22, 26, 23, 19, 11, 14, 17, 20, 24, 23, 20, 10, 13, 16, 19, 22, 23, - 20, 18, 21, 25, 29, 28, 26, 22, 16, 20, 24, 28, 28, 24, 20, 15, 19, 23, 25, - 24, 23, 18, 14, 17, 20, 22, 22, 20, 16, 11, 13, 16, 18, 19, 18, 16, 10, 12, - 15, 17, 18, 17, 15, 7, 11, 14, 16, 16, 16, 16, 15, 19, 21, 21, 23, 21, 17, - 14, 17, 20, 21, 21, 20, 15, 13, 16, 18, 17, 18, 18, 14, 12, 14, 15, 15, 15, - 15, 11, 8, 11, 12, 12, 12, 12, 11, 5, 10, 11, 10, 10, 10, 11, 5, 8, 9, - 9, 10, 9, 9, 14, 13, 14, 14, 16, 17, 10, 11, 11, 12, 13, 13, 14, 8, 9, - 10, 11, 11, 10, 10, 7, 5, 8, 7, 7, 7, 7, 6, 4, 5, 5, 4, 4, 4, - 3, 5, 3, 3, 3, 3, 3, 3, 6, 5, 3, 2, 2, 2, 2, 4, 5, 6, 7, - 8, 9, 10, 2, 4, 5, 6, 6, 7, 8, 2, 3, 4, 4, 4, 4, 5, 2, 3, - 2, 2, 2, 1, 2, 1, 6, 4, 3, 3, 2, 2, 4, 7, 7, 5, 3, 2, 0, - 6, 8, 8, 5, 4, 3, 1, 5, 5, 5, 5, 6, 8, 9, 4, 6, 5, 5, 5, - 6, 6, 5, 7, 5, 4, 3, 3, 3, 5, 7, 7, 5, 4, 3, 0, 6, 8, 8, - 6, 4, 3, 1, 7, 9, 10, 8, 5, 3, 2, 8, 9, 11, 10, 6, 4, 2, 8, - 10, 7, 5, 6, 7, 7, 8, 9, 9, 6, 5, 5, 5, 8, 10, 10, 5, 4, 2, - 2, 8, 10, 11, 7, 5, 3, 2, 9, 10, 12, 10, 6, 4, 3, 9, 10, 14, 13, - 8, 5, 3, 9, 11, 14, 14, 9, 5, 3, 27, 30, 32, 34, 33, 31, 30, 26, 29, - 32, 33, 33, 30, 28, 25, 29, 30, 31, 31, 27, 24, 24, 25, 27, 28, 28, 23, 17, - 20, 23, 24, 23, 21, 18, 17, 17, 19, 19, 17, 19, 18, 17, 11, 13, 16, 18, 18, - 18, 17, 25, 27, 31, 32, 31, 30, 30, 24, 28, 30, 31, 31, 29, 26, 22, 25, 28, - 30, 28, 26, 23, 21, 24, 26, 26, 25, 21, 16, 18, 20, 22, 22, 17, 16, 16, 13, - 16, 17, 16, 16, 16, 16, 7, 11, 14, 16, 15, 16, 16, 22, 26, 28, 29, 30, 29, - 26, 21, 25, 27, 28, 28, 27, 24, 19, 23, 25, 26, 26, 25, 20, 18, 21, 22, 22, - 22, 20, 15, 11, 17, 18, 18, 15, 15, 14, 5, 12, 13, 13, 13, 13, 15, 4, 7, - 10, 11, 12, 13, 13, 19, 20, 22, 23, 25, 25, 22, 17, 19, 20, 22, 23, 23, 20, - 14, 18, 19, 19, 19, 18, 16, 11, 16, 15, 15, 15, 13, 13, 8, 11, 11, 10, 8, - 8, 9, 5, 5, 5, 5, 6, 7, 7, 4, 3, 2, 4, 5, 5, 7, 13, 16, 18, - 19, 20, 22, 22, 9, 15, 17, 18, 18, 19, 20, 9, 15, 15, 16, 16, 16, 14, 9, - 11, 12, 12, 11, 9, 7, 7, 6, 7, 6, 4, 3, 7, 4, 3, 4, 3, 4, 3, - 6, 0, 3, 4, 3, 4, 4, 4, 10, 11, 13, 14, 17, 20, 21, 10, 10, 12, 13, - 16, 17, 18, 10, 11, 11, 11, 12, 14, 13, 10, 10, 10, 9, 8, 7, 6, 8, 8, - 9, 8, 5, 4, 5, 5, 7, 9, 8, 5, 4, 3, 4, 5, 8, 9, 7, 5, 3, - 12, 14, 14, 13, 15, 19, 20, 12, 14, 15, 13, 13, 15, 17, 12, 14, 16, 12, 10, - 11, 11, 12, 13, 15, 11, 9, 6, 3, 10, 12, 14, 11, 7, 4, 3, 9, 10, 13, - 12, 8, 5, 4, 7, 10, 12, 13, 9, 6, 4, 34, 37, 39, 42, 42, 40, 38, 32, - 35, 39, 42, 42, 39, 36, 31, 34, 37, 39, 39, 36, 31, 29, 32, 34, 37, 36, 31, - 25, 26, 29, 30, 31, 30, 27, 25, 22, 24, 25, 25, 28, 27, 25, 16, 19, 21, 25, - 27, 27, 25, 30, 34, 38, 41, 40, 37, 35, 29, 33, 37, 39, 40, 36, 33, 27, 32, - 35, 37, 36, 33, 30, 26, 29, 33, 34, 32, 28, 23, 23, 26, 28, 29, 27, 24, 23, - 17, 21, 23, 22, 24, 24, 23, 11, 16, 20, 22, 23, 24, 23, 27, 31, 34, 35, 36, - 35, 30, 26, 29, 33, 34, 35, 33, 29, 23, 29, 31, 31, 31, 30, 25, 21, 26, 27, - 28, 27, 25, 20, 15, 22, 24, 23, 20, 20, 20, 9, 18, 18, 17, 17, 18, 20, 6, - 13, 15, 15, 16, 17, 18, 25, 26, 27, 28, 30, 31, 25, 20, 24, 26, 27, 27, 27, - 23, 17, 23, 24, 24, 24, 23, 21, 13, 20, 20, 20, 20, 18, 17, 11, 14, 15, 15, - 12, 12, 13, 8, 8, 11, 9, 10, 11, 10, 6, 4, 7, 7, 8, 9, 9, 13, 19, - 20, 22, 22, 24, 25, 10, 19, 19, 21, 21, 21, 22, 10, 17, 18, 18, 18, 17, 17, - 10, 12, 15, 14, 13, 11, 9, 7, 6, 10, 9, 5, 6, 7, 4, 3, 3, 2, 2, - 5, 8, 3, 0, 3, 2, 2, 3, 7, 10, 14, 15, 17, 20, 22, 24, 10, 12, 14, - 16, 18, 19, 20, 10, 10, 12, 12, 15, 16, 14, 10, 9, 8, 9, 10, 9, 7, 8, - 7, 7, 6, 4, 3, 7, 5, 5, 7, 5, 4, 2, 6, 2, 4, 6, 6, 4, 3, - 5, 10, 13, 13, 13, 17, 21, 22, 10, 13, 13, 12, 16, 18, 19, 10, 13, 14, 11, - 11, 13, 13, 10, 12, 13, 10, 8, 7, 6, 8, 10, 11, 9, 5, 3, 5, 7, 8, - 9, 8, 5, 3, 3, 5, 7, 9, 9, 6, 4, 2, 36, 39, 42, 47, 46, 43, 40, - 33, 38, 41, 46, 46, 42, 38, 33, 35, 40, 43, 43, 39, 35, 31, 33, 37, 39, 41, - 36, 31, 27, 30, 34, 35, 35, 32, 30, 23, 26, 28, 30, 33, 33, 30, 19, 22, 26, - 29, 32, 32, 30, 32, 36, 41, 44, 42, 41, 38, 31, 34, 39, 42, 42, 39, 35, 29, - 34, 37, 39, 40, 38, 32, 28, 31, 35, 36, 36, 32, 26, 23, 27, 30, 32, 30, 29, - 26, 18, 23, 26, 27, 27, 27, 27, 13, 20, 23, 26, 26, 26, 26, 30, 34, 35, 37, - 38, 38, 32, 27, 31, 35, 36, 36, 35, 30, 25, 30, 34, 34, 33, 32, 27, 21, 28, - 29, 29, 29, 28, 22, 15, 24, 26, 25, 23, 23, 22, 9, 20, 21, 20, 20, 21, 22, - 8, 17, 18, 19, 19, 20, 20, 25, 28, 29, 31, 31, 32, 26, 20, 26, 28, 29, 29, - 29, 23, 17, 24, 25, 26, 25, 25, 21, 14, 21, 22, 21, 22, 20, 18, 11, 15, 18, - 18, 15, 14, 14, 9, 10, 13, 13, 13, 13, 11, 8, 5, 10, 10, 11, 12, 8, 13, - 20, 20, 22, 23, 22, 25, 10, 18, 19, 21, 21, 20, 23, 9, 16, 18, 17, 17, 17, - 17, 10, 11, 14, 13, 13, 10, 10, 7, 5, 10, 9, 6, 7, 8, 5, 3, 3, 3, - 3, 5, 8, 4, 3, 0, 2, 3, 5, 7, 8, 14, 15, 17, 19, 22, 23, 9, 12, - 14, 15, 17, 19, 19, 9, 9, 12, 12, 14, 15, 14, 9, 8, 8, 8, 10, 9, 7, - 6, 5, 7, 7, 3, 5, 7, 4, 3, 8, 7, 5, 4, 7, 2, 4, 8, 8, 6, - 2, 5, 9, 12, 12, 13, 17, 20, 21, 9, 12, 14, 11, 15, 17, 18, 9, 12, 15, - 9, 11, 13, 13, 9, 11, 14, 10, 7, 7, 6, 7, 10, 13, 11, 6, 2, 5, 5, - 10, 11, 10, 7, 4, 4, 5, 8, 10, 10, 8, 6, 3, 32, 36, 39, 43, 44, 41, - 38, 31, 35, 38, 43, 44, 39, 35, 29, 33, 37, 40, 40, 38, 33, 28, 30, 34, 37, - 38, 34, 29, 25, 28, 30, 33, 35, 31, 29, 22, 24, 26, 29, 32, 31, 28, 18, 21, - 24, 28, 31, 32, 29, 29, 34, 38, 40, 41, 37, 34, 28, 32, 35, 39, 39, 36, 31, - 27, 30, 35, 38, 37, 33, 29, 25, 28, 31, 34, 33, 31, 24, 21, 25, 27, 29, 28, - 27, 24, 17, 21, 23, 25, 26, 27, 24, 13, 18, 22, 24, 24, 25, 25, 27, 30, 33, - 34, 35, 33, 29, 25, 29, 31, 33, 34, 32, 27, 23, 28, 30, 30, 30, 29, 24, 19, - 25, 25, 26, 26, 26, 20, 13, 21, 22, 23, 21, 20, 19, 8, 17, 19, 19, 19, 19, - 19, 7, 16, 17, 18, 18, 19, 18, 23, 25, 26, 27, 29, 28, 21, 18, 23, 24, 26, - 26, 25, 19, 15, 22, 23, 22, 22, 21, 18, 12, 19, 19, 19, 18, 17, 16, 9, 13, - 15, 15, 13, 12, 12, 8, 9, 11, 11, 11, 11, 9, 8, 5, 10, 9, 10, 10, 6, - 11, 16, 18, 19, 20, 18, 21, 7, 15, 16, 17, 17, 16, 19, 7, 12, 14, 14, 13, - 13, 14, 7, 8, 11, 10, 10, 7, 8, 5, 2, 6, 6, 4, 4, 6, 3, 2, 2, - 2, 2, 3, 5, 3, 2, 2, 0, 2, 3, 4, 6, 10, 11, 13, 15, 16, 19, 6, - 9, 10, 11, 13, 14, 15, 6, 7, 8, 9, 10, 11, 10, 6, 5, 6, 5, 6, 7, - 5, 4, 3, 7, 7, 3, 3, 4, 2, 3, 10, 10, 5, 2, 4, 1, 4, 10, 12, - 7, 2, 3, 7, 13, 12, 10, 13, 16, 16, 7, 13, 15, 9, 11, 13, 13, 7, 13, - 17, 10, 8, 10, 10, 7, 12, 17, 11, 5, 5, 4, 6, 11, 17, 13, 7, 2, 3, - 5, 12, 17, 16, 9, 4, 3, 6, 12, 17, 17, 11, 6, 2, 30, 35, 39, 42, 42, - 39, 36, 29, 34, 38, 41, 42, 38, 34, 28, 31, 36, 39, 41, 36, 33, 27, 28, 32, - 36, 38, 33, 28, 24, 25, 29, 33, 34, 31, 28, 20, 22, 26, 28, 32, 31, 28, 18, - 20, 24, 27, 30, 31, 28, 28, 31, 35, 40, 39, 35, 32, 26, 30, 34, 38, 39, 34, - 30, 25, 28, 32, 36, 36, 32, 27, 24, 26, 29, 33, 33, 30, 23, 20, 23, 26, 28, - 28, 26, 23, 16, 20, 23, 25, 26, 26, 24, 13, 19, 21, 24, 24, 24, 23, 25, 29, - 30, 32, 33, 31, 27, 23, 27, 29, 31, 30, 30, 25, 21, 26, 28, 29, 28, 27, 22, - 18, 25, 25, 25, 25, 24, 18, 12, 20, 22, 21, 21, 19, 18, 8, 18, 18, 19, 19, - 18, 18, 8, 16, 18, 17, 18, 18, 16, 20, 24, 24, 25, 26, 25, 19, 17, 22, 22, - 23, 24, 22, 17, 14, 20, 21, 20, 20, 20, 15, 11, 17, 17, 17, 17, 16, 14, 8, - 12, 14, 14, 13, 12, 11, 7, 9, 11, 11, 11, 11, 7, 7, 6, 10, 9, 9, 10, - 5, 9, 15, 16, 17, 18, 15, 18, 6, 14, 15, 15, 16, 13, 16, 6, 11, 12, 12, - 12, 10, 12, 6, 6, 9, 9, 8, 6, 7, 4, 2, 5, 4, 4, 3, 4, 3, 2, - 2, 2, 2, 2, 4, 4, 2, 3, 2, 0, 2, 3, 5, 8, 9, 10, 12, 14, 16, - 5, 6, 8, 9, 11, 11, 12, 5, 5, 6, 6, 8, 9, 8, 4, 4, 6, 5, 4, - 5, 4, 2, 4, 7, 7, 3, 2, 3, 2, 4, 10, 9, 4, 1, 3, 2, 5, 10, - 11, 6, 2, 2, 7, 11, 10, 7, 11, 13, 14, 7, 11, 11, 8, 9, 11, 11, 7, - 11, 13, 8, 6, 7, 8, 7, 11, 13, 9, 5, 3, 3, 6, 10, 14, 12, 7, 2, - 3, 6, 11, 15, 14, 8, 3, 2, 7, 12, 15, 15, 10, 5, 1, 27, 31, 36, 39, - 39, 36, 33, 27, 30, 34, 38, 39, 36, 32, 24, 27, 34, 36, 37, 33, 30, 24, 26, - 29, 32, 36, 32, 26, 21, 23, 26, 29, 32, 29, 26, 18, 20, 23, 26, 30, 29, 26, - 17, 19, 22, 25, 28, 29, 26, 24, 28, 32, 37, 35, 33, 29, 24, 27, 32, 34, 36, - 30, 27, 23, 26, 29, 32, 31, 30, 25, 22, 23, 27, 29, 29, 27, 22, 18, 20, 23, - 26, 25, 24, 21, 16, 18, 20, 23, 23, 24, 22, 12, 17, 20, 22, 22, 23, 21, 23, - 26, 28, 29, 30, 28, 23, 21, 25, 27, 28, 28, 27, 22, 20, 23, 26, 25, 26, 25, - 20, 17, 22, 21, 21, 21, 21, 16, 11, 18, 18, 18, 18, 18, 16, 8, 16, 17, 16, - 17, 16, 16, 8, 15, 15, 15, 15, 15, 14, 20, 21, 21, 22, 23, 23, 15, 16, 19, - 20, 20, 21, 19, 14, 13, 18, 18, 18, 17, 17, 12, 9, 15, 14, 14, 13, 13, 12, - 7, 11, 11, 10, 10, 10, 8, 7, 9, 10, 9, 9, 9, 5, 8, 5, 8, 8, 8, - 8, 3, 8, 12, 13, 14, 14, 13, 15, 4, 11, 12, 12, 12, 10, 13, 4, 9, 9, - 9, 9, 8, 9, 4, 5, 6, 5, 5, 4, 5, 3, 2, 2, 2, 2, 2, 3, 3, - 2, 3, 2, 1, 2, 3, 4, 3, 5, 3, 2, 0, 3, 3, 6, 7, 8, 9, 11, - 13, 3, 5, 7, 8, 8, 9, 10, 3, 4, 5, 5, 6, 6, 6, 3, 3, 3, 2, - 2, 3, 3, 1, 4, 6, 4, 3, 0, 3, 2, 6, 8, 5, 4, 2, 2, 4, 7, - 8, 7, 4, 2, 2, 4, 6, 6, 7, 9, 10, 11, 4, 6, 7, 6, 7, 8, 8, - 4, 6, 7, 4, 4, 4, 6, 4, 6, 8, 4, 2, 1, 2, 3, 8, 9, 7, 4, - 2, 2, 6, 9, 9, 9, 5, 3, 0, 7, 9, 9, 9, 6, 4, 2, 22, 26, 29, - 33, 33, 30, 27, 21, 24, 29, 33, 32, 29, 26, 19, 23, 27, 30, 32, 28, 24, 18, - 21, 24, 27, 30, 26, 21, 15, 17, 21, 24, 27, 24, 21, 13, 15, 18, 22, 25, 25, - 21, 12, 15, 18, 20, 24, 24, 21, 20, 23, 27, 31, 29, 26, 23, 18, 22, 26, 29, - 29, 26, 21, 17, 20, 24, 27, 27, 24, 20, 16, 18, 21, 24, 23, 22, 17, 13, 15, - 17, 20, 20, 20, 17, 12, 13, 16, 18, 19, 19, 16, 9, 12, 16, 18, 17, 18, 17, - 18, 20, 23, 24, 25, 23, 19, 17, 19, 21, 22, 22, 21, 17, 15, 18, 20, 20, 20, - 19, 15, 14, 16, 16, 16, 16, 16, 12, 9, 13, 14, 13, 13, 13, 12, 6, 12, 13, - 12, 12, 12, 12, 6, 10, 10, 11, 11, 11, 10, 15, 15, 16, 17, 18, 18, 11, 14, - 14, 14, 15, 15, 15, 9, 11, 12, 13, 12, 12, 11, 8, 6, 11, 9, 9, 9, 9, - 7, 4, 7, 6, 6, 5, 5, 4, 5, 5, 5, 5, 4, 4, 2, 6, 4, 3, 3, - 3, 3, 2, 6, 7, 7, 8, 9, 10, 11, 2, 5, 6, 7, 7, 8, 9, 2, 4, - 5, 4, 5, 5, 5, 2, 2, 2, 2, 1, 2, 2, 1, 4, 3, 3, 2, 1, 2, - 3, 5, 5, 3, 3, 2, 1, 4, 7, 6, 4, 3, 3, 0, 4, 4, 5, 6, 7, - 8, 10, 3, 5, 5, 6, 6, 6, 7, 4, 6, 5, 4, 4, 3, 4, 4, 6, 5, - 4, 3, 2, 1, 4, 7, 8, 5, 4, 3, 0, 5, 7, 9, 7, 4, 3, 2, 6, - 8, 9, 8, 5, 3, 2, 7, 9, 7, 5, 6, 8, 8, 7, 9, 8, 5, 5, 5, - 5, 7, 9, 9, 5, 3, 2, 3, 7, 8, 11, 6, 4, 3, 1, 8, 9, 11, 9, - 5, 3, 2, 8, 9, 11, 11, 6, 4, 2, 8, 10, 12, 12, 8, 5, 3, 24, 27, - 29, 32, 31, 29, 26, 23, 26, 28, 30, 32, 29, 25, 22, 24, 27, 29, 31, 29, 25, - 21, 23, 26, 28, 31, 28, 27, 20, 23, 25, 28, 31, 29, 26, 19, 23, 25, 27, 30, - 29, 27, 16, 20, 23, 26, 29, 28, 27, 22, 24, 27, 30, 28, 25, 24, 21, 24, 26, - 29, 28, 26, 24, 19, 22, 25, 28, 27, 25, 24, 18, 22, 24, 27, 26, 25, 23, 18, - 21, 24, 27, 26, 26, 24, 16, 19, 22, 24, 25, 25, 24, 13, 16, 21, 24, 25, 24, - 24, 19, 22, 23, 24, 24, 23, 19, 18, 20, 23, 23, 24, 23, 19, 17, 20, 22, 22, - 22, 23, 19, 16, 19, 21, 21, 22, 23, 20, 14, 18, 19, 20, 21, 22, 19, 11, 16, - 18, 19, 19, 20, 20, 13, 14, 16, 17, 19, 19, 18, 17, 18, 17, 18, 18, 17, 8, - 15, 15, 16, 16, 17, 16, 9, 13, 14, 15, 15, 15, 15, 10, 9, 14, 14, 14, 15, - 15, 11, 9, 12, 12, 13, 13, 14, 8, 10, 10, 10, 11, 11, 12, 6, 13, 13, 10, - 9, 10, 10, 6, 8, 9, 9, 9, 10, 6, 8, 4, 7, 7, 8, 8, 6, 9, 4, - 6, 5, 6, 6, 5, 7, 4, 4, 4, 4, 5, 5, 7, 5, 4, 4, 4, 4, 3, - 6, 7, 7, 7, 6, 4, 3, 4, 10, 10, 8, 6, 5, 3, 4, 0, 2, 2, 2, - 2, 5, 7, 0, 3, 2, 2, 1, 4, 8, 0, 4, 3, 2, 1, 3, 6, 0, 3, - 3, 2, 1, 2, 5, 2, 3, 5, 5, 3, 3, 4, 5, 6, 9, 8, 5, 3, 3, - 8, 9, 10, 9, 6, 4, 3, 4, 7, 6, 3, 2, 3, 6, 4, 7, 7, 4, 2, - 2, 5, 4, 7, 9, 4, 2, 0, 5, 4, 7, 10, 6, 3, 2, 3, 4, 7, 11, - 9, 5, 3, 3, 5, 9, 12, 11, 7, 4, 3, 7, 11, 12, 13, 8, 5, 3, 25, - 29, 32, 33, 34, 31, 29, 25, 27, 31, 34, 34, 32, 29, 23, 26, 29, 32, 34, 31, - 29, 21, 24, 28, 32, 34, 33, 30, 21, 24, 28, 32, 35, 33, 30, 20, 23, 27, 31, - 34, 33, 30, 18, 23, 25, 30, 33, 33, 31, 23, 25, 29, 31, 30, 27, 25, 21, 25, - 28, 31, 30, 27, 25, 21, 24, 27, 30, 29, 27, 25, 19, 22, 27, 28, 29, 29, 25, - 20, 22, 26, 29, 29, 28, 26, 19, 21, 24, 28, 28, 28, 25, 15, 19, 23, 27, 27, - 27, 26, 21, 25, 25, 26, 26, 24, 19, 19, 22, 25, 24, 25, 24, 19, 18, 22, 23, - 23, 24, 24, 20, 17, 21, 22, 23, 23, 23, 20, 14, 20, 22, 21, 22, 22, 21, 12, - 18, 20, 21, 21, 22, 20, 13, 16, 18, 19, 20, 20, 18, 19, 19, 19, 19, 19, 18, - 7, 16, 17, 18, 17, 18, 16, 9, 13, 16, 16, 17, 16, 15, 10, 10, 16, 16, 15, - 16, 15, 12, 11, 14, 15, 15, 14, 14, 9, 11, 12, 13, 13, 13, 13, 6, 14, 14, - 10, 11, 12, 12, 6, 8, 10, 10, 11, 10, 6, 7, 5, 9, 9, 9, 9, 6, 9, - 5, 8, 7, 7, 7, 5, 6, 5, 6, 6, 6, 7, 4, 6, 6, 5, 5, 5, 5, - 4, 6, 8, 9, 10, 9, 6, 5, 5, 11, 14, 14, 11, 8, 6, 4, 2, 0, 1, - 1, 3, 5, 6, 2, 2, 2, 2, 2, 4, 6, 2, 4, 4, 4, 1, 4, 7, 2, - 5, 7, 7, 4, 3, 5, 3, 7, 12, 11, 9, 6, 4, 6, 12, 16, 13, 11, 7, - 4, 12, 16, 16, 14, 12, 8, 5, 6, 11, 11, 6, 1, 3, 5, 6, 12, 12, 8, - 2, 3, 5, 6, 11, 13, 9, 4, 2, 5, 6, 12, 14, 12, 8, 4, 4, 8, 13, - 16, 15, 12, 8, 5, 10, 15, 17, 16, 13, 10, 6, 14, 17, 18, 17, 14, 11, 7, - 24, 27, 31, 33, 34, 31, 28, 23, 27, 29, 33, 34, 31, 28, 22, 25, 29, 32, 33, - 31, 28, 21, 25, 28, 31, 35, 32, 29, 22, 24, 28, 31, 35, 33, 30, 21, 24, 26, - 30, 34, 33, 29, 18, 21, 25, 29, 33, 33, 30, 21, 24, 28, 31, 29, 26, 24, 21, - 24, 27, 30, 30, 26, 23, 20, 23, 26, 28, 30, 27, 25, 19, 22, 26, 29, 29, 28, - 24, 20, 22, 26, 28, 28, 28, 25, 18, 21, 24, 27, 28, 27, 25, 16, 19, 23, 26, - 26, 27, 24, 20, 23, 24, 24, 24, 22, 17, 19, 21, 23, 24, 23, 22, 17, 18, 21, - 22, 23, 23, 21, 18, 16, 21, 22, 22, 23, 22, 18, 14, 20, 22, 22, 22, 22, 18, - 12, 18, 20, 20, 21, 21, 19, 15, 17, 19, 19, 19, 19, 17, 18, 17, 17, 17, 18, - 15, 6, 16, 16, 16, 16, 17, 14, 7, 12, 15, 16, 15, 15, 14, 9, 9, 16, 15, - 15, 15, 14, 12, 10, 14, 14, 15, 14, 13, 9, 12, 12, 12, 13, 13, 12, 6, 15, - 16, 11, 11, 12, 11, 5, 8, 10, 10, 10, 9, 4, 6, 4, 9, 8, 8, 8, 4, - 7, 4, 8, 7, 7, 7, 4, 6, 4, 6, 7, 6, 7, 4, 5, 6, 6, 6, 6, - 6, 5, 5, 8, 10, 12, 10, 7, 6, 5, 12, 16, 15, 12, 9, 7, 5, 2, 1, - 0, 1, 2, 3, 4, 2, 2, 2, 2, 2, 3, 4, 2, 4, 4, 4, 1, 3, 5, - 2, 6, 8, 8, 5, 4, 5, 4, 8, 13, 13, 9, 7, 5, 8, 13, 19, 18, 12, - 8, 5, 13, 18, 20, 19, 14, 9, 6, 6, 12, 11, 5, 1, 2, 4, 6, 12, 13, - 7, 1, 2, 4, 6, 12, 15, 9, 5, 2, 4, 6, 13, 18, 13, 9, 6, 5, 9, - 15, 21, 19, 13, 9, 6, 12, 18, 24, 23, 16, 10, 7, 16, 21, 25, 25, 18, 12, - 8, 24, 27, 30, 33, 33, 31, 26, 23, 26, 30, 33, 33, 31, 27, 21, 24, 28, 32, - 33, 31, 28, 21, 24, 29, 32, 35, 32, 29, 21, 24, 28, 31, 35, 33, 30, 20, 23, - 27, 30, 34, 32, 28, 19, 21, 26, 29, 33, 33, 29, 21, 25, 27, 31, 28, 26, 22, - 21, 23, 27, 30, 28, 26, 23, 19, 22, 26, 28, 29, 28, 23, 19, 23, 26, 29, 29, - 28, 24, 20, 23, 25, 28, 29, 28, 25, 18, 22, 24, 28, 28, 27, 25, 16, 19, 23, - 27, 27, 26, 24, 20, 23, 23, 24, 23, 21, 16, 19, 21, 23, 23, 23, 21, 16, 18, - 20, 22, 22, 22, 22, 17, 16, 21, 22, 22, 22, 22, 18, 15, 20, 22, 22, 22, 21, - 17, 13, 19, 20, 20, 21, 20, 18, 16, 18, 19, 19, 19, 19, 17, 18, 17, 17, 17, - 17, 14, 5, 16, 17, 16, 16, 15, 13, 6, 13, 15, 16, 15, 15, 13, 9, 9, 16, - 15, 15, 15, 13, 12, 11, 15, 14, 15, 14, 13, 8, 12, 13, 13, 13, 13, 12, 6, - 16, 17, 13, 11, 12, 11, 5, 8, 10, 10, 9, 8, 3, 5, 5, 9, 8, 8, 7, - 3, 6, 5, 8, 7, 7, 7, 3, 5, 5, 6, 7, 7, 7, 4, 5, 6, 6, 7, - 7, 7, 7, 5, 9, 12, 13, 11, 9, 7, 5, 14, 17, 17, 13, 10, 8, 6, 2, - 1, 1, 0, 2, 3, 4, 2, 3, 2, 2, 2, 3, 3, 2, 4, 4, 5, 2, 3, - 4, 2, 6, 9, 9, 6, 5, 5, 4, 9, 14, 13, 10, 8, 6, 9, 14, 20, 18, - 12, 9, 7, 15, 19, 21, 20, 15, 10, 7, 6, 9, 7, 4, 0, 2, 3, 6, 9, - 8, 5, 2, 2, 3, 6, 9, 10, 8, 5, 3, 4, 6, 11, 15, 12, 9, 7, 6, - 10, 14, 19, 18, 14, 10, 8, 13, 19, 23, 23, 16, 11, 8, 18, 22, 24, 24, 19, - 13, 9, 20, 23, 27, 30, 30, 28, 24, 19, 23, 26, 29, 29, 27, 24, 18, 21, 25, - 28, 31, 29, 26, 17, 21, 25, 28, 31, 29, 26, 18, 22, 24, 28, 32, 29, 26, 18, - 21, 24, 27, 32, 29, 25, 16, 19, 23, 26, 29, 29, 26, 18, 21, 24, 27, 27, 22, - 19, 18, 20, 23, 26, 26, 23, 20, 17, 19, 22, 26, 26, 24, 21, 16, 19, 23, 26, - 26, 25, 22, 17, 20, 23, 26, 25, 25, 21, 15, 18, 22, 24, 24, 24, 21, 17, 18, - 20, 23, 23, 23, 21, 17, 19, 19, 20, 21, 17, 13, 16, 18, 19, 19, 19, 18, 14, - 15, 18, 19, 20, 20, 19, 14, 15, 18, 20, 19, 20, 19, 15, 13, 17, 19, 18, 19, - 19, 16, 12, 16, 17, 18, 17, 18, 15, 19, 19, 16, 16, 17, 16, 15, 15, 14, 13, - 14, 14, 12, 3, 14, 13, 13, 13, 12, 11, 4, 11, 12, 12, 13, 12, 11, 7, 8, - 13, 13, 12, 12, 12, 9, 9, 12, 12, 11, 11, 10, 7, 12, 14, 12, 11, 10, 10, - 5, 19, 20, 15, 12, 9, 9, 6, 7, 6, 6, 6, 5, 2, 3, 3, 5, 5, 4, - 4, 3, 4, 3, 4, 3, 4, 4, 3, 4, 3, 3, 4, 5, 5, 5, 5, 5, 9, - 9, 9, 9, 8, 6, 10, 15, 16, 13, 10, 8, 6, 17, 20, 19, 15, 12, 9, 7, - 2, 3, 2, 2, 0, 2, 3, 2, 4, 3, 2, 2, 2, 3, 2, 6, 4, 4, 4, - 3, 4, 2, 7, 8, 8, 7, 6, 6, 7, 12, 14, 13, 12, 9, 7, 12, 16, 20, - 18, 13, 10, 8, 18, 21, 22, 19, 15, 11, 8, 7, 9, 5, 3, 2, 1, 2, 7, - 9, 7, 3, 2, 2, 3, 7, 9, 9, 6, 5, 5, 4, 7, 9, 13, 11, 9, 8, - 8, 9, 14, 17, 17, 14, 11, 8, 15, 18, 21, 22, 16, 13, 9, 19, 23, 23, 23, - 18, 14, 10, 16, 20, 23, 26, 25, 23, 20, 15, 18, 21, 25, 25, 24, 20, 14, 17, - 21, 25, 26, 24, 21, 14, 18, 21, 24, 28, 25, 22, 14, 18, 20, 25, 28, 26, 22, - 13, 17, 20, 23, 27, 26, 23, 17, 17, 19, 22, 25, 26, 22, 14, 17, 20, 23, 22, - 19, 15, 14, 16, 19, 22, 22, 20, 17, 12, 15, 18, 22, 22, 20, 17, 12, 15, 19, - 22, 22, 21, 18, 12, 16, 18, 21, 22, 21, 18, 12, 15, 18, 21, 21, 20, 18, 19, - 18, 17, 19, 19, 20, 18, 13, 15, 16, 16, 17, 14, 11, 12, 14, 15, 15, 16, 15, - 11, 11, 13, 14, 16, 16, 16, 12, 11, 13, 15, 15, 15, 15, 13, 9, 13, 15, 14, - 15, 15, 13, 14, 15, 14, 14, 14, 14, 13, 22, 20, 17, 13, 13, 13, 12, 11, 10, - 9, 9, 9, 9, 2, 10, 9, 9, 8, 9, 8, 3, 8, 8, 8, 9, 9, 9, 4, - 6, 8, 8, 9, 9, 8, 7, 7, 8, 9, 9, 9, 8, 6, 14, 16, 14, 13, 10, - 8, 7, 21, 23, 18, 13, 11, 9, 7, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, - 1, 1, 2, 3, 2, 2, 2, 3, 4, 3, 4, 2, 5, 6, 7, 7, 7, 7, 6, - 11, 12, 11, 11, 9, 7, 13, 18, 19, 15, 13, 10, 8, 20, 22, 21, 17, 14, 11, - 9, 5, 5, 3, 3, 2, 0, 2, 5, 6, 4, 3, 2, 2, 3, 5, 8, 6, 6, - 5, 5, 4, 5, 9, 11, 10, 9, 9, 8, 9, 14, 17, 15, 14, 12, 8, 15, 19, - 23, 20, 15, 12, 10, 21, 23, 24, 21, 17, 13, 10, 9, 11, 7, 4, 3, 2, 1, - 9, 11, 9, 5, 3, 3, 3, 9, 11, 11, 8, 7, 6, 6, 9, 12, 15, 13, 11, - 10, 10, 12, 16, 20, 19, 16, 13, 11, 17, 21, 24, 24, 19, 15, 11, 21, 24, 25, - 25, 20, 16, 12, 12, 15, 18, 20, 20, 17, 15, 11, 14, 17, 20, 20, 18, 16, 10, - 13, 16, 20, 21, 20, 17, 10, 13, 17, 20, 23, 20, 18, 10, 14, 16, 20, 24, 21, - 18, 11, 13, 16, 19, 23, 22, 18, 18, 17, 16, 18, 21, 22, 18, 11, 13, 16, 18, - 17, 14, 11, 9, 12, 15, 17, 16, 15, 13, 8, 11, 15, 18, 17, 16, 14, 7, 11, - 15, 18, 17, 17, 14, 8, 11, 14, 17, 17, 16, 14, 12, 14, 15, 16, 16, 16, 14, - 20, 19, 17, 16, 15, 15, 14, 8, 11, 12, 12, 12, 10, 7, 7, 10, 11, 11, 11, - 10, 7, 7, 9, 10, 11, 11, 11, 8, 6, 9, 11, 11, 11, 11, 9, 7, 10, 11, - 11, 11, 11, 9, 16, 16, 15, 13, 11, 9, 9, 22, 21, 17, 14, 11, 9, 8, 6, - 6, 5, 5, 5, 6, 1, 6, 5, 4, 4, 4, 4, 2, 5, 3, 4, 5, 4, 4, - 3, 8, 3, 5, 6, 6, 6, 6, 8, 9, 9, 10, 10, 9, 7, 16, 17, 15, 14, - 11, 9, 7, 23, 24, 18, 15, 12, 10, 8, 3, 2, 2, 2, 2, 1, 1, 5, 3, - 2, 2, 2, 2, 2, 4, 4, 3, 4, 5, 5, 4, 5, 7, 7, 8, 9, 8, 7, - 8, 13, 13, 13, 12, 11, 8, 15, 19, 20, 17, 14, 12, 9, 22, 24, 23, 18, 16, - 13, 10, 7, 6, 4, 3, 3, 2, 0, 7, 8, 5, 4, 3, 3, 3, 7, 10, 7, - 8, 7, 6, 6, 7, 11, 13, 13, 11, 10, 9, 11, 16, 20, 19, 16, 13, 10, 17, - 21, 26, 24, 19, 14, 11, 22, 25, 28, 25, 21, 16, 12, 10, 13, 10, 6, 3, 2, - 2, 11, 13, 12, 7, 4, 4, 4, 11, 13, 16, 11, 9, 8, 7, 11, 15, 21, 17, - 14, 12, 11, 14, 21, 24, 24, 20, 16, 12, 19, 24, 30, 30, 22, 17, 13, 25, 29, - 31, 30, 25, 19, 14, 23, 27, 29, 32, 32, 30, 27, 22, 25, 28, 31, 31, 29, 26, - 21, 24, 27, 29, 31, 28, 26, 20, 23, 26, 29, 30, 29, 27, 20, 23, 26, 28, 30, - 29, 26, 19, 21, 25, 27, 30, 28, 27, 16, 20, 23, 27, 29, 28, 27, 22, 24, 27, - 29, 29, 26, 24, 20, 24, 27, 28, 28, 26, 24, 20, 22, 26, 28, 26, 25, 22, 18, - 22, 24, 27, 26, 26, 24, 18, 21, 24, 26, 26, 26, 24, 16, 19, 22, 24, 25, 25, - 24, 13, 17, 21, 24, 24, 24, 24, 19, 22, 23, 25, 25, 23, 20, 18, 21, 22, 23, - 23, 23, 19, 17, 20, 22, 22, 22, 22, 19, 15, 19, 21, 21, 22, 22, 20, 14, 18, - 20, 20, 21, 21, 20, 11, 16, 18, 18, 19, 20, 20, 13, 14, 16, 17, 18, 19, 19, - 17, 17, 17, 18, 18, 18, 8, 15, 15, 16, 16, 17, 16, 9, 13, 15, 15, 15, 16, - 15, 9, 9, 13, 14, 14, 14, 14, 12, 9, 12, 13, 13, 13, 13, 8, 10, 10, 10, - 11, 12, 12, 6, 13, 13, 9, 9, 10, 10, 6, 7, 9, 9, 9, 10, 6, 7, 4, - 7, 8, 8, 8, 6, 9, 4, 6, 6, 6, 6, 5, 7, 4, 4, 4, 4, 5, 4, - 7, 5, 4, 4, 4, 4, 3, 6, 7, 7, 7, 6, 4, 3, 5, 10, 10, 8, 6, - 5, 3, 3, 0, 2, 2, 2, 2, 5, 7, 0, 3, 2, 2, 2, 4, 8, 0, 4, - 3, 2, 1, 3, 6, 0, 3, 3, 2, 1, 2, 5, 2, 3, 5, 5, 3, 3, 3, - 5, 6, 9, 8, 5, 3, 3, 8, 8, 10, 9, 6, 4, 3, 4, 7, 6, 3, 2, - 3, 6, 4, 7, 7, 4, 2, 2, 5, 4, 7, 9, 4, 2, 0, 4, 4, 7, 10, - 5, 3, 2, 3, 4, 7, 11, 9, 5, 3, 3, 5, 9, 12, 11, 7, 4, 3, 7, - 11, 12, 12, 8, 5, 3, 28, 31, 34, 36, 36, 33, 31, 26, 29, 33, 36, 37, 35, - 32, 25, 29, 32, 35, 37, 34, 31, 24, 27, 31, 34, 36, 34, 32, 24, 27, 31, 34, - 37, 36, 31, 23, 25, 30, 33, 36, 35, 32, 20, 24, 28, 32, 35, 35, 32, 25, 29, - 32, 34, 34, 31, 27, 24, 27, 30, 33, 32, 30, 27, 22, 26, 29, 32, 32, 30, 28, - 22, 25, 29, 32, 32, 31, 28, 23, 24, 28, 32, 31, 31, 28, 20, 24, 27, 30, 30, - 31, 29, 17, 20, 25, 29, 29, 29, 28, 23, 26, 27, 28, 28, 26, 21, 22, 25, 27, - 26, 27, 25, 21, 21, 24, 25, 26, 25, 27, 22, 18, 23, 26, 24, 26, 25, 22, 16, - 22, 24, 24, 25, 24, 23, 13, 20, 22, 23, 23, 24, 22, 14, 17, 20, 22, 22, 23, - 21, 20, 20, 21, 22, 22, 19, 10, 18, 19, 20, 20, 21, 19, 11, 15, 18, 18, 18, - 19, 17, 12, 11, 18, 18, 18, 18, 17, 14, 12, 16, 17, 17, 17, 16, 11, 12, 14, - 14, 15, 15, 15, 8, 14, 13, 12, 13, 14, 13, 8, 10, 12, 13, 13, 12, 7, 10, - 6, 11, 11, 11, 11, 7, 10, 6, 10, 9, 9, 9, 7, 9, 6, 8, 8, 8, 9, - 6, 7, 7, 5, 7, 7, 7, 4, 7, 8, 7, 9, 8, 5, 4, 6, 10, 12, 12, - 9, 7, 5, 5, 3, 2, 2, 3, 4, 6, 8, 3, 0, 1, 1, 3, 7, 8, 3, - 2, 2, 2, 2, 5, 8, 3, 3, 5, 5, 2, 3, 6, 4, 5, 8, 7, 7, 5, - 5, 5, 9, 11, 9, 8, 6, 4, 11, 13, 12, 10, 8, 7, 4, 4, 8, 7, 4, - 3, 4, 7, 4, 8, 7, 5, 2, 4, 7, 4, 7, 9, 6, 2, 4, 6, 4, 8, - 10, 7, 6, 4, 4, 6, 9, 10, 9, 8, 7, 4, 8, 10, 12, 12, 9, 7, 5, - 11, 12, 13, 13, 10, 8, 6, 26, 29, 33, 35, 36, 33, 29, 25, 29, 32, 35, 35, - 33, 30, 23, 27, 31, 33, 35, 35, 30, 22, 26, 30, 34, 37, 34, 31, 23, 25, 29, - 33, 37, 34, 31, 23, 25, 29, 33, 37, 35, 31, 20, 24, 27, 32, 34, 34, 31, 23, - 27, 30, 33, 32, 28, 25, 23, 26, 29, 32, 32, 29, 25, 22, 24, 28, 31, 31, 29, - 26, 21, 25, 28, 31, 31, 29, 27, 21, 23, 27, 31, 31, 30, 26, 20, 23, 26, 29, - 30, 30, 26, 17, 21, 25, 27, 28, 29, 27, 22, 25, 26, 26, 26, 23, 19, 21, 24, - 25, 25, 25, 24, 18, 20, 22, 24, 24, 24, 24, 19, 17, 23, 24, 24, 25, 24, 20, - 15, 22, 23, 23, 24, 23, 20, 13, 20, 22, 22, 22, 22, 20, 15, 18, 20, 21, 21, - 21, 19, 19, 19, 19, 19, 19, 16, 7, 17, 18, 18, 18, 18, 15, 9, 13, 17, 17, - 17, 17, 15, 10, 10, 17, 17, 17, 17, 15, 13, 12, 16, 16, 16, 16, 14, 10, 12, - 14, 14, 14, 15, 14, 7, 15, 15, 12, 13, 13, 13, 5, 9, 11, 12, 11, 10, 5, - 7, 6, 11, 10, 10, 9, 5, 8, 6, 9, 9, 9, 8, 5, 7, 5, 7, 8, 8, - 8, 4, 6, 7, 5, 7, 7, 7, 5, 5, 9, 9, 11, 9, 7, 6, 5, 12, 14, - 14, 10, 8, 7, 5, 2, 2, 2, 2, 3, 4, 5, 2, 1, 0, 1, 2, 4, 5, - 2, 2, 2, 2, 2, 4, 6, 2, 4, 6, 6, 4, 4, 5, 4, 7, 11, 11, 9, - 7, 5, 7, 12, 17, 15, 11, 8, 5, 12, 16, 19, 18, 13, 9, 6, 4, 10, 9, - 4, 2, 3, 4, 4, 10, 12, 6, 1, 3, 4, 4, 10, 14, 8, 3, 3, 4, 4, - 11, 17, 12, 7, 5, 5, 7, 13, 19, 17, 12, 9, 6, 10, 17, 22, 21, 15, 10, - 7, 15, 19, 23, 23, 17, 11, 8, 26, 28, 32, 35, 35, 32, 29, 25, 27, 31, 34, - 35, 31, 29, 23, 26, 30, 34, 35, 33, 29, 22, 25, 30, 33, 36, 34, 31, 23, 25, - 29, 33, 37, 35, 29, 23, 25, 28, 32, 35, 34, 32, 20, 23, 27, 31, 34, 34, 31, - 23, 26, 29, 32, 31, 27, 23, 22, 25, 29, 32, 30, 27, 24, 22, 24, 28, 31, 31, - 29, 25, 21, 24, 27, 31, 31, 30, 25, 21, 24, 27, 30, 30, 29, 26, 20, 23, 26, - 30, 29, 29, 25, 18, 21, 24, 28, 27, 28, 25, 22, 24, 25, 25, 25, 23, 17, 20, - 22, 25, 25, 24, 22, 17, 19, 22, 24, 24, 24, 22, 17, 17, 23, 23, 23, 24, 23, - 19, 15, 23, 23, 24, 23, 23, 19, 13, 20, 22, 22, 22, 22, 19, 15, 19, 20, 20, - 21, 21, 18, 20, 19, 18, 18, 18, 15, 6, 17, 18, 18, 17, 17, 14, 8, 13, 17, - 17, 17, 16, 14, 10, 10, 17, 17, 17, 17, 14, 13, 12, 16, 16, 16, 15, 14, 10, - 13, 14, 14, 14, 14, 13, 7, 16, 16, 13, 13, 13, 13, 5, 9, 12, 11, 11, 9, - 4, 6, 6, 10, 10, 9, 8, 4, 8, 6, 9, 8, 9, 8, 4, 6, 5, 7, 9, - 8, 8, 4, 6, 7, 6, 7, 7, 7, 6, 5, 9, 10, 12, 10, 8, 7, 5, 13, - 16, 15, 12, 9, 8, 6, 2, 2, 2, 2, 2, 3, 4, 2, 1, 1, 0, 2, 3, - 4, 2, 2, 3, 3, 2, 3, 4, 2, 4, 7, 7, 5, 5, 5, 4, 8, 12, 11, - 9, 8, 6, 8, 13, 18, 16, 11, 8, 6, 14, 18, 20, 18, 13, 9, 7, 5, 8, - 7, 3, 1, 2, 3, 5, 8, 8, 4, 0, 2, 4, 5, 8, 10, 7, 4, 3, 4, - 5, 10, 14, 11, 8, 6, 6, 8, 13, 18, 17, 12, 9, 7, 11, 17, 22, 22, 15, - 11, 8, 16, 21, 23, 23, 18, 12, 8, 22, 25, 28, 31, 32, 29, 26, 21, 23, 27, - 31, 32, 27, 25, 19, 23, 26, 29, 32, 29, 27, 19, 23, 26, 30, 32, 30, 27, 20, - 22, 26, 29, 32, 31, 28, 19, 22, 25, 29, 32, 30, 27, 17, 20, 24, 27, 31, 31, - 27, 20, 23, 26, 29, 28, 24, 21, 18, 22, 25, 28, 27, 24, 21, 18, 20, 24, 27, - 27, 26, 21, 17, 21, 25, 27, 26, 25, 22, 19, 21, 24, 26, 26, 26, 22, 16, 20, - 22, 25, 26, 26, 23, 16, 18, 21, 24, 25, 24, 22, 18, 20, 21, 22, 23, 19, 15, - 17, 19, 21, 21, 21, 20, 15, 17, 19, 20, 20, 20, 20, 15, 15, 19, 20, 20, 21, - 20, 16, 14, 19, 20, 20, 20, 19, 16, 12, 17, 18, 19, 19, 18, 16, 17, 17, 17, - 17, 17, 17, 16, 16, 15, 15, 15, 16, 13, 4, 14, 14, 14, 14, 14, 12, 5, 12, - 14, 13, 14, 13, 12, 8, 8, 14, 14, 13, 13, 12, 10, 10, 13, 13, 13, 12, 11, - 7, 12, 12, 11, 11, 11, 11, 5, 17, 18, 14, 10, 10, 10, 5, 7, 8, 7, 7, - 7, 3, 4, 3, 7, 6, 6, 6, 3, 5, 3, 6, 5, 6, 5, 3, 4, 3, 4, - 5, 5, 5, 4, 4, 5, 7, 8, 8, 8, 7, 5, 9, 13, 14, 12, 9, 7, 6, - 15, 18, 18, 13, 11, 8, 6, 1, 2, 2, 2, 2, 2, 3, 2, 3, 2, 2, 0, - 3, 3, 2, 4, 3, 3, 3, 2, 3, 2, 6, 8, 7, 6, 5, 5, 6, 10, 13, - 12, 10, 8, 6, 11, 16, 19, 16, 12, 9, 7, 16, 20, 21, 18, 14, 10, 7, 6, - 7, 5, 3, 1, 2, 2, 6, 7, 7, 3, 2, 2, 3, 5, 7, 8, 5, 4, 3, - 3, 6, 8, 12, 10, 8, 7, 7, 9, 12, 16, 16, 13, 10, 7, 13, 17, 20, 21, - 15, 12, 8, 18, 21, 21, 21, 17, 13, 9, 17, 21, 24, 28, 28, 26, 22, 17, 19, - 24, 28, 28, 24, 21, 15, 19, 22, 25, 27, 25, 22, 15, 18, 21, 25, 29, 26, 22, - 15, 18, 21, 24, 28, 26, 23, 14, 17, 20, 24, 28, 26, 23, 15, 16, 19, 23, 25, - 27, 23, 16, 19, 22, 25, 24, 22, 18, 14, 18, 21, 23, 23, 21, 16, 13, 16, 20, - 22, 22, 20, 18, 13, 16, 20, 23, 22, 22, 19, 13, 16, 19, 22, 22, 21, 19, 12, - 14, 18, 21, 21, 21, 19, 17, 16, 17, 19, 20, 20, 18, 14, 16, 17, 18, 19, 17, - 13, 13, 15, 16, 17, 17, 16, 12, 12, 14, 15, 16, 16, 16, 12, 11, 14, 16, 16, - 16, 16, 13, 11, 14, 15, 15, 15, 15, 13, 12, 13, 14, 14, 14, 14, 13, 19, 18, - 14, 13, 13, 13, 12, 12, 11, 10, 11, 12, 12, 4, 11, 10, 10, 10, 10, 10, 3, - 9, 9, 9, 9, 9, 9, 4, 6, 9, 9, 9, 9, 9, 7, 7, 8, 8, 8, 8, - 7, 4, 12, 14, 12, 10, 8, 7, 4, 18, 20, 14, 12, 9, 7, 5, 4, 3, 3, - 3, 4, 3, 4, 1, 2, 2, 2, 2, 2, 3, 1, 1, 1, 2, 2, 2, 3, 1, - 5, 5, 5, 5, 4, 4, 5, 10, 9, 9, 9, 7, 5, 12, 15, 16, 13, 10, 8, - 6, 17, 20, 18, 14, 11, 9, 6, 4, 5, 3, 3, 2, 2, 3, 4, 6, 4, 3, - 2, 0, 2, 4, 7, 5, 5, 3, 3, 2, 4, 8, 9, 8, 7, 6, 5, 8, 12, - 14, 13, 11, 9, 6, 12, 16, 20, 17, 12, 10, 7, 18, 21, 21, 19, 14, 11, 8, - 8, 10, 6, 4, 3, 2, 2, 8, 10, 8, 5, 3, 2, 1, 8, 10, 10, 7, 5, - 4, 3, 9, 10, 14, 11, 9, 8, 7, 10, 14, 17, 16, 14, 11, 8, 14, 18, 21, - 21, 16, 12, 9, 19, 21, 23, 22, 18, 13, 10, 14, 16, 21, 24, 24, 21, 18, 13, - 16, 19, 23, 24, 20, 17, 11, 14, 18, 21, 23, 20, 18, 10, 14, 18, 21, 24, 21, - 18, 11, 14, 17, 20, 24, 22, 18, 10, 13, 16, 19, 23, 22, 18, 15, 14, 15, 18, - 22, 21, 18, 11, 14, 18, 21, 20, 17, 14, 11, 14, 17, 20, 20, 16, 13, 9, 12, - 15, 18, 18, 16, 14, 9, 12, 15, 18, 17, 17, 14, 9, 12, 15, 17, 17, 17, 14, - 11, 12, 13, 16, 16, 16, 14, 18, 16, 14, 15, 15, 15, 14, 10, 12, 14, 14, 16, - 13, 9, 9, 11, 12, 13, 13, 12, 8, 7, 10, 12, 11, 11, 12, 8, 7, 10, 11, - 11, 11, 11, 9, 6, 9, 11, 11, 10, 10, 9, 13, 13, 12, 10, 9, 9, 9, 19, - 17, 15, 11, 9, 8, 8, 8, 7, 6, 7, 8, 9, 3, 7, 6, 6, 6, 6, 6, - 2, 6, 5, 5, 5, 4, 4, 2, 4, 5, 4, 4, 4, 4, 4, 7, 8, 8, 7, - 7, 6, 4, 14, 15, 13, 11, 8, 7, 5, 19, 20, 15, 12, 9, 7, 6, 2, 2, - 1, 2, 2, 2, 3, 3, 3, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 2, 2, - 3, 6, 6, 6, 6, 5, 5, 7, 11, 11, 10, 9, 8, 5, 13, 16, 16, 13, 11, - 9, 7, 19, 20, 19, 15, 12, 10, 7, 7, 6, 4, 3, 3, 3, 3, 7, 7, 5, - 4, 3, 2, 0, 7, 9, 6, 6, 4, 3, 3, 7, 10, 10, 10, 8, 7, 6, 9, - 14, 16, 15, 12, 10, 7, 15, 18, 22, 20, 14, 10, 8, 19, 21, 23, 21, 16, 12, - 9, 10, 12, 9, 5, 3, 3, 2, 10, 12, 11, 6, 3, 2, 2, 10, 12, 13, 9, - 6, 5, 4, 10, 13, 17, 13, 11, 9, 8, 13, 16, 21, 20, 16, 12, 9, 16, 21, - 25, 24, 18, 13, 10, 20, 23, 25, 26, 20, 15, 11, 24, 26, 29, 32, 32, 30, 26, - 23, 25, 28, 31, 31, 29, 26, 22, 24, 27, 29, 31, 28, 26, 20, 23, 26, 29, 30, - 29, 27, 20, 23, 26, 29, 31, 28, 27, 19, 22, 24, 27, 30, 29, 26, 16, 20, 24, - 26, 29, 29, 27, 22, 24, 27, 29, 28, 26, 23, 21, 24, 27, 29, 27, 25, 24, 19, - 23, 25, 27, 27, 25, 23, 18, 21, 25, 27, 25, 25, 25, 18, 21, 24, 27, 26, 25, - 25, 16, 19, 23, 25, 25, 25, 24, 13, 16, 20, 24, 24, 25, 24, 19, 23, 23, 24, - 25, 23, 19, 18, 21, 22, 23, 24, 22, 20, 17, 20, 22, 22, 22, 23, 19, 15, 19, - 21, 21, 22, 22, 20, 14, 19, 19, 20, 21, 22, 20, 11, 17, 18, 19, 20, 20, 19, - 13, 14, 16, 17, 18, 19, 19, 17, 17, 17, 18, 18, 18, 7, 15, 16, 16, 16, 17, - 16, 8, 13, 15, 15, 15, 15, 15, 10, 9, 14, 14, 14, 14, 14, 12, 9, 12, 12, - 13, 13, 14, 8, 10, 10, 10, 11, 11, 12, 6, 13, 13, 9, 9, 10, 10, 6, 8, - 8, 9, 10, 10, 6, 8, 4, 7, 7, 8, 8, 6, 9, 4, 6, 6, 5, 6, 5, - 8, 4, 4, 4, 4, 5, 5, 6, 5, 4, 4, 4, 4, 3, 6, 7, 7, 7, 6, - 4, 3, 5, 10, 10, 8, 6, 4, 3, 4, 0, 2, 2, 2, 2, 5, 7, 0, 3, - 2, 2, 2, 4, 8, 0, 4, 2, 2, 1, 4, 6, 0, 3, 3, 2, 1, 2, 5, - 2, 3, 5, 5, 3, 3, 4, 5, 6, 9, 8, 5, 3, 3, 8, 9, 10, 9, 6, - 4, 3, 4, 7, 6, 3, 2, 3, 6, 4, 7, 8, 4, 2, 2, 5, 4, 7, 9, - 4, 2, 0, 5, 4, 7, 10, 6, 3, 2, 3, 4, 7, 10, 9, 5, 4, 3, 5, - 9, 12, 11, 7, 4, 3, 7, 11, 12, 12, 8, 5, 3, 30, 32, 35, 39, 38, 37, - 32, 28, 32, 34, 37, 39, 36, 33, 27, 31, 33, 37, 38, 36, 32, 26, 29, 32, 35, - 38, 37, 34, 25, 28, 33, 36, 38, 37, 35, 24, 27, 31, 35, 38, 37, 35, 22, 25, - 31, 34, 36, 37, 34, 27, 31, 33, 36, 36, 32, 29, 26, 29, 33, 35, 34, 32, 28, - 24, 28, 32, 34, 35, 33, 30, 24, 27, 31, 34, 34, 33, 30, 23, 26, 29, 33, 32, - 33, 30, 21, 25, 29, 32, 32, 33, 30, 19, 22, 27, 30, 31, 31, 30, 24, 28, 28, - 29, 30, 28, 23, 23, 27, 28, 29, 29, 28, 22, 22, 25, 27, 28, 28, 28, 23, 20, - 25, 26, 27, 28, 27, 25, 17, 24, 25, 26, 26, 26, 24, 14, 23, 24, 24, 25, 26, - 24, 15, 19, 21, 23, 24, 25, 23, 22, 23, 23, 23, 23, 21, 11, 19, 21, 21, 21, - 22, 20, 12, 16, 20, 20, 20, 20, 19, 13, 12, 20, 19, 20, 19, 19, 16, 13, 17, - 18, 19, 19, 18, 12, 13, 15, 16, 17, 17, 17, 9, 15, 13, 14, 15, 16, 16, 8, - 10, 14, 14, 14, 14, 9, 11, 7, 12, 13, 13, 12, 9, 12, 7, 11, 11, 11, 11, - 7, 10, 7, 8, 10, 10, 10, 8, 9, 8, 6, 9, 8, 9, 6, 8, 9, 8, 8, - 7, 7, 4, 7, 11, 10, 9, 7, 5, 3, 6, 4, 3, 4, 4, 6, 8, 10, 4, - 2, 2, 2, 4, 7, 9, 4, 0, 1, 1, 3, 6, 8, 4, 1, 2, 1, 2, 4, - 7, 4, 3, 4, 4, 4, 3, 7, 6, 6, 8, 6, 5, 4, 5, 8, 9, 9, 6, - 5, 4, 4, 2, 5, 3, 2, 3, 6, 9, 2, 5, 4, 3, 2, 5, 9, 2, 5, - 5, 3, 0, 4, 7, 2, 5, 6, 2, 2, 3, 5, 2, 4, 7, 5, 4, 4, 4, - 5, 6, 8, 8, 5, 4, 4, 8, 8, 9, 9, 6, 5, 4, 29, 33, 36, 39, 39, - 36, 33, 28, 31, 34, 38, 38, 36, 32, 26, 29, 34, 37, 38, 35, 32, 25, 28, 31, - 36, 39, 36, 33, 25, 29, 31, 36, 39, 37, 34, 24, 27, 30, 34, 38, 37, 33, 22, - 26, 29, 33, 36, 37, 33, 26, 29, 34, 36, 34, 32, 29, 25, 29, 32, 36, 35, 32, - 27, 24, 27, 30, 34, 34, 31, 28, 23, 26, 30, 33, 33, 32, 28, 24, 27, 30, 32, - 32, 31, 29, 22, 25, 29, 32, 32, 32, 29, 19, 23, 27, 30, 30, 30, 28, 24, 27, - 28, 29, 30, 26, 22, 23, 25, 28, 28, 28, 27, 21, 22, 25, 27, 26, 27, 26, 21, - 18, 25, 25, 25, 26, 25, 21, 16, 24, 25, 25, 26, 25, 22, 13, 22, 24, 24, 24, - 24, 22, 15, 20, 22, 23, 23, 23, 20, 22, 22, 22, 22, 23, 19, 10, 18, 20, 21, - 22, 21, 18, 11, 15, 20, 20, 20, 19, 17, 12, 11, 19, 19, 19, 18, 16, 15, 13, - 17, 18, 18, 19, 16, 11, 13, 15, 16, 16, 16, 15, 8, 15, 14, 14, 15, 15, 14, - 6, 10, 14, 14, 14, 12, 6, 10, 7, 13, 12, 13, 11, 6, 11, 7, 11, 11, 11, - 10, 5, 8, 7, 8, 10, 10, 9, 5, 8, 8, 6, 9, 9, 8, 5, 6, 9, 8, - 9, 7, 7, 5, 6, 11, 12, 12, 9, 6, 5, 5, 3, 4, 4, 5, 4, 5, 7, - 3, 2, 2, 3, 3, 5, 6, 3, 1, 0, 0, 3, 5, 7, 2, 2, 4, 4, 2, - 4, 5, 4, 5, 9, 8, 8, 5, 5, 6, 10, 15, 13, 10, 6, 4, 10, 14, 17, - 15, 11, 8, 4, 2, 8, 8, 2, 3, 4, 6, 2, 8, 10, 4, 2, 4, 6, 2, - 8, 12, 5, 1, 3, 5, 2, 9, 14, 9, 5, 4, 5, 5, 11, 16, 14, 10, 8, - 4, 8, 14, 19, 18, 13, 9, 5, 13, 18, 19, 19, 15, 10, 6, 28, 32, 36, 38, - 38, 35, 33, 27, 30, 35, 37, 39, 36, 31, 26, 29, 33, 36, 39, 34, 32, 24, 27, - 31, 35, 37, 35, 32, 25, 27, 31, 35, 37, 36, 33, 23, 26, 30, 33, 37, 35, 33, - 21, 25, 29, 31, 35, 35, 32, 25, 29, 33, 37, 35, 31, 27, 25, 29, 31, 36, 34, - 32, 27, 24, 26, 31, 33, 33, 30, 26, 23, 25, 29, 32, 32, 30, 26, 22, 25, 29, - 32, 32, 31, 26, 21, 25, 27, 31, 30, 29, 27, 19, 22, 26, 30, 29, 28, 27, 24, - 26, 29, 29, 30, 27, 20, 22, 25, 28, 28, 28, 26, 20, 21, 23, 26, 26, 26, 24, - 19, 18, 25, 25, 24, 25, 23, 19, 16, 23, 24, 24, 24, 23, 20, 13, 22, 23, 23, - 23, 23, 20, 15, 20, 21, 21, 21, 22, 18, 20, 21, 21, 22, 23, 18, 11, 18, 20, - 20, 21, 21, 17, 11, 14, 19, 18, 19, 18, 15, 12, 11, 18, 18, 17, 18, 15, 14, - 12, 16, 17, 17, 17, 14, 11, 13, 15, 16, 16, 16, 13, 7, 14, 14, 14, 14, 15, - 13, 5, 9, 14, 13, 15, 12, 7, 11, 6, 13, 12, 13, 12, 6, 11, 6, 10, 11, - 10, 9, 4, 7, 6, 7, 10, 9, 8, 4, 7, 8, 6, 8, 8, 7, 4, 4, 9, - 8, 9, 8, 6, 4, 4, 11, 12, 12, 9, 6, 5, 4, 2, 4, 4, 5, 4, 6, - 8, 2, 2, 2, 3, 3, 5, 6, 2, 1, 0, 0, 3, 3, 5, 2, 2, 4, 4, - 2, 3, 4, 4, 5, 9, 8, 7, 5, 4, 6, 10, 15, 13, 9, 6, 4, 10, 14, - 16, 15, 10, 7, 4, 3, 7, 6, 2, 3, 5, 6, 3, 7, 7, 4, 2, 3, 4, - 3, 7, 8, 5, 1, 2, 4, 3, 8, 11, 9, 4, 4, 4, 5, 11, 15, 14, 9, - 7, 4, 8, 14, 19, 19, 12, 8, 5, 13, 17, 20, 20, 14, 9, 6, 24, 29, 32, - 35, 36, 33, 29, 23, 27, 31, 34, 35, 32, 28, 22, 25, 28, 33, 34, 31, 27, 20, - 22, 26, 30, 32, 30, 28, 21, 23, 26, 30, 34, 31, 27, 20, 22, 26, 29, 33, 31, - 27, 17, 21, 24, 27, 31, 32, 28, 22, 25, 30, 33, 31, 28, 25, 21, 23, 27, 31, - 32, 28, 23, 20, 22, 27, 29, 28, 26, 22, 19, 21, 24, 27, 27, 26, 22, 20, 21, - 24, 27, 27, 27, 22, 18, 20, 23, 25, 26, 26, 23, 14, 18, 22, 25, 25, 24, 22, - 20, 23, 24, 25, 27, 23, 19, 19, 21, 24, 24, 25, 22, 17, 18, 21, 22, 22, 22, - 21, 16, 16, 20, 21, 21, 21, 21, 16, 14, 20, 20, 20, 20, 19, 16, 11, 17, 19, - 19, 19, 19, 16, 14, 15, 17, 17, 18, 18, 15, 18, 18, 17, 18, 19, 17, 9, 15, - 16, 16, 17, 17, 15, 9, 12, 16, 15, 15, 14, 12, 8, 9, 16, 14, 13, 13, 12, - 11, 10, 14, 13, 13, 12, 11, 8, 11, 11, 11, 11, 11, 10, 4, 14, 14, 10, 10, - 10, 10, 3, 7, 9, 10, 10, 10, 6, 9, 4, 9, 8, 9, 9, 4, 9, 4, 7, - 6, 6, 6, 3, 5, 4, 6, 6, 5, 5, 2, 4, 6, 5, 5, 5, 5, 4, 3, - 7, 10, 11, 9, 6, 5, 3, 12, 14, 14, 10, 8, 6, 4, 1, 1, 1, 2, 4, - 5, 7, 1, 2, 2, 2, 3, 3, 4, 1, 3, 4, 3, 0, 2, 4, 1, 5, 5, - 4, 4, 3, 3, 3, 7, 10, 9, 8, 6, 4, 8, 12, 16, 13, 9, 6, 4, 13, - 16, 18, 15, 11, 7, 5, 5, 6, 5, 3, 2, 4, 5, 4, 6, 6, 4, 2, 2, - 3, 4, 6, 7, 3, 2, 1, 2, 4, 7, 9, 7, 6, 4, 4, 6, 9, 13, 13, - 10, 7, 5, 10, 14, 17, 17, 13, 9, 6, 15, 18, 18, 18, 14, 10, 6, 20, 24, - 28, 32, 32, 29, 25, 19, 23, 26, 31, 31, 28, 24, 17, 21, 25, 28, 30, 26, 23, - 17, 19, 23, 26, 29, 26, 23, 16, 18, 21, 25, 29, 27, 23, 15, 18, 21, 24, 27, - 26, 23, 12, 16, 19, 23, 26, 27, 23, 17, 21, 25, 29, 28, 24, 21, 16, 20, 24, - 28, 27, 24, 20, 16, 18, 23, 25, 25, 21, 18, 15, 17, 20, 23, 22, 22, 19, 14, - 17, 20, 22, 22, 22, 18, 12, 16, 18, 21, 21, 21, 18, 13, 14, 17, 20, 20, 20, - 19, 15, 18, 21, 22, 23, 20, 16, 14, 17, 19, 21, 21, 19, 15, 14, 16, 18, 18, - 18, 18, 13, 13, 16, 16, 16, 16, 16, 13, 12, 15, 16, 16, 16, 15, 13, 10, 12, - 14, 14, 14, 14, 13, 15, 15, 12, 12, 13, 13, 12, 14, 13, 13, 14, 15, 15, 7, - 13, 12, 12, 13, 13, 13, 6, 10, 11, 11, 10, 10, 10, 5, 6, 10, 9, 9, 9, - 9, 7, 7, 9, 8, 8, 8, 8, 4, 10, 10, 9, 7, 7, 7, 2, 15, 16, 11, - 8, 6, 5, 3, 5, 5, 6, 6, 7, 6, 7, 1, 3, 4, 5, 5, 4, 6, 1, - 2, 2, 2, 2, 2, 3, 1, 3, 2, 2, 2, 2, 2, 4, 7, 7, 6, 6, 4, - 2, 9, 12, 12, 10, 7, 5, 3, 14, 16, 15, 11, 9, 6, 4, 3, 4, 3, 3, - 3, 5, 6, 3, 5, 4, 3, 3, 3, 3, 3, 6, 5, 4, 2, 0, 2, 4, 6, - 6, 5, 4, 3, 3, 6, 9, 11, 10, 8, 6, 4, 10, 13, 16, 14, 10, 7, 4, - 14, 16, 18, 15, 11, 8, 5, 7, 8, 7, 4, 3, 4, 4, 6, 8, 8, 5, 3, - 2, 2, 7, 8, 9, 5, 3, 2, 1, 7, 8, 11, 8, 6, 5, 4, 8, 11, 14, - 14, 11, 8, 5, 12, 15, 18, 18, 13, 9, 6, 16, 18, 19, 19, 14, 10, 7, 17, - 20, 25, 28, 28, 26, 21, 15, 19, 23, 27, 28, 25, 20, 14, 18, 21, 25, 27, 22, - 19, 12, 16, 19, 22, 24, 22, 19, 12, 14, 17, 21, 24, 23, 19, 10, 14, 16, 20, - 23, 22, 19, 11, 12, 15, 19, 22, 22, 19, 14, 17, 22, 25, 24, 22, 17, 13, 16, - 20, 24, 23, 20, 16, 12, 15, 19, 21, 21, 18, 15, 10, 13, 16, 18, 19, 17, 14, - 10, 13, 15, 18, 18, 18, 15, 9, 11, 14, 17, 17, 17, 14, 13, 12, 13, 15, 16, - 16, 14, 12, 15, 16, 18, 19, 17, 13, 10, 13, 16, 16, 17, 16, 12, 9, 12, 14, - 14, 14, 14, 10, 8, 11, 12, 12, 12, 12, 10, 7, 10, 11, 11, 11, 11, 10, 11, - 10, 10, 10, 10, 10, 9, 14, 13, 10, 9, 9, 9, 8, 9, 9, 10, 11, 12, 13, - 7, 8, 8, 9, 9, 10, 10, 5, 7, 6, 7, 7, 6, 7, 3, 4, 6, 5, 5, - 5, 5, 4, 6, 6, 5, 4, 5, 4, 2, 11, 11, 9, 7, 5, 4, 2, 14, 14, - 10, 8, 6, 4, 3, 0, 1, 2, 3, 4, 5, 6, 2, 2, 2, 3, 3, 3, 4, - 2, 3, 3, 2, 2, 1, 2, 2, 6, 4, 3, 3, 3, 2, 6, 9, 8, 7, 6, - 5, 2, 10, 12, 12, 9, 7, 6, 3, 13, 14, 14, 11, 8, 6, 4, 6, 6, 5, - 4, 4, 4, 6, 6, 8, 6, 4, 3, 2, 3, 6, 8, 7, 5, 3, 2, 0, 6, - 9, 8, 6, 5, 4, 3, 8, 11, 13, 11, 9, 6, 4, 11, 14, 17, 15, 10, 7, - 5, 14, 16, 18, 16, 12, 8, 6, 9, 10, 8, 6, 4, 4, 4, 10, 10, 10, 6, - 4, 2, 2, 9, 10, 11, 6, 4, 3, 2, 9, 11, 14, 10, 7, 6, 5, 10, 13, - 17, 15, 11, 8, 6, 13, 16, 20, 19, 13, 9, 6, 16, 19, 20, 20, 15, 11, 7, - 24, 27, 29, 31, 31, 31, 27, 23, 26, 28, 31, 32, 28, 27, 21, 24, 27, 30, 31, - 28, 25, 20, 24, 27, 29, 30, 29, 27, 20, 23, 26, 28, 30, 28, 26, 18, 22, 24, - 27, 31, 29, 26, 16, 20, 24, 26, 29, 28, 26, 21, 24, 28, 29, 28, 26, 23, 21, - 23, 25, 28, 28, 26, 23, 19, 23, 26, 28, 26, 26, 24, 18, 21, 25, 26, 26, 26, - 25, 17, 21, 24, 26, 25, 26, 24, 16, 19, 22, 25, 26, 25, 24, 13, 16, 21, 24, - 24, 25, 24, 19, 23, 24, 24, 25, 23, 20, 18, 21, 22, 23, 23, 23, 19, 17, 21, - 22, 22, 22, 23, 19, 15, 20, 21, 21, 22, 22, 20, 14, 18, 20, 20, 21, 21, 20, - 11, 16, 18, 19, 20, 20, 20, 13, 14, 16, 17, 18, 19, 19, 17, 17, 18, 18, 18, - 18, 8, 15, 15, 16, 17, 17, 16, 9, 13, 15, 15, 15, 15, 15, 10, 9, 13, 14, - 14, 15, 15, 12, 9, 12, 13, 13, 13, 14, 8, 10, 10, 10, 11, 11, 12, 6, 13, - 13, 9, 9, 10, 11, 6, 8, 8, 9, 9, 10, 6, 8, 4, 7, 8, 8, 8, 6, - 9, 4, 6, 5, 6, 6, 5, 7, 4, 4, 4, 4, 5, 5, 7, 5, 4, 4, 4, - 4, 3, 6, 7, 7, 7, 6, 4, 3, 5, 10, 10, 8, 6, 4, 3, 4, 0, 2, - 2, 2, 2, 5, 7, 0, 3, 2, 2, 2, 4, 8, 0, 4, 3, 2, 1, 4, 6, - 0, 3, 3, 2, 1, 2, 5, 2, 3, 5, 5, 3, 3, 4, 5, 6, 9, 8, 4, - 3, 3, 8, 9, 10, 9, 6, 4, 3, 4, 7, 6, 3, 2, 3, 6, 4, 7, 8, - 4, 2, 2, 5, 4, 7, 9, 4, 2, 0, 5, 4, 7, 10, 6, 3, 2, 3, 4, - 7, 11, 9, 5, 3, 3, 5, 9, 12, 12, 7, 4, 3, 7, 10, 12, 13, 8, 5, - 3, 30, 34, 37, 40, 39, 38, 34, 29, 34, 37, 40, 40, 38, 34, 28, 32, 35, 39, - 38, 38, 34, 27, 29, 34, 37, 39, 36, 33, 25, 28, 32, 35, 39, 37, 33, 23, 28, - 31, 34, 38, 37, 34, 21, 25, 29, 33, 36, 36, 34, 28, 32, 35, 37, 37, 34, 31, - 26, 31, 34, 37, 36, 33, 31, 25, 29, 33, 34, 35, 33, 30, 24, 28, 31, 33, 33, - 33, 30, 23, 26, 29, 32, 33, 32, 30, 20, 24, 28, 31, 32, 32, 30, 18, 22, 26, - 30, 30, 30, 28, 25, 30, 32, 32, 32, 30, 25, 24, 27, 30, 31, 32, 30, 25, 22, - 26, 28, 29, 29, 28, 24, 20, 25, 26, 27, 27, 27, 24, 16, 23, 25, 26, 26, 27, - 24, 13, 22, 24, 23, 25, 25, 24, 13, 18, 21, 22, 23, 23, 22, 23, 24, 24, 25, - 26, 23, 14, 19, 22, 22, 23, 23, 22, 14, 16, 21, 21, 21, 23, 20, 15, 12, 19, - 19, 19, 19, 18, 15, 12, 17, 18, 18, 18, 17, 12, 12, 14, 15, 16, 16, 16, 9, - 14, 12, 13, 14, 15, 15, 7, 10, 15, 16, 16, 15, 11, 13, 7, 13, 14, 15, 14, - 10, 13, 7, 11, 12, 12, 12, 8, 12, 7, 8, 10, 10, 10, 7, 8, 7, 5, 8, - 8, 8, 5, 8, 8, 7, 6, 6, 6, 3, 8, 10, 9, 8, 6, 4, 3, 6, 3, - 5, 6, 6, 7, 9, 11, 3, 3, 4, 4, 6, 8, 10, 3, 1, 2, 2, 4, 6, - 9, 3, 0, 2, 2, 2, 5, 7, 3, 2, 3, 3, 3, 3, 6, 5, 5, 7, 5, - 3, 3, 4, 7, 8, 7, 5, 4, 3, 3, 2, 4, 4, 2, 5, 7, 10, 2, 4, - 5, 3, 4, 6, 9, 2, 5, 6, 3, 2, 5, 6, 2, 4, 5, 3, 1, 2, 5, - 2, 4, 6, 5, 3, 3, 3, 4, 5, 7, 7, 4, 3, 3, 7, 7, 8, 9, 5, - 3, 3, 33, 36, 41, 43, 44, 41, 38, 31, 35, 39, 43, 44, 41, 37, 30, 35, 37, - 41, 43, 38, 35, 29, 33, 35, 39, 41, 38, 34, 27, 29, 33, 38, 40, 37, 33, 25, - 28, 32, 36, 40, 38, 34, 23, 26, 32, 34, 37, 38, 35, 30, 34, 38, 40, 40, 37, - 33, 29, 33, 36, 40, 40, 37, 32, 26, 32, 35, 39, 38, 35, 32, 26, 29, 32, 36, - 35, 33, 31, 25, 27, 30, 34, 34, 33, 29, 22, 26, 29, 33, 32, 32, 30, 19, 24, - 27, 31, 31, 32, 29, 27, 31, 34, 34, 34, 32, 27, 26, 29, 32, 33, 33, 32, 26, - 24, 28, 30, 31, 31, 30, 24, 20, 27, 27, 28, 28, 27, 23, 16, 25, 26, 27, 27, - 26, 23, 13, 24, 24, 25, 25, 26, 23, 14, 21, 23, 23, 24, 24, 22, 23, 25, 26, - 27, 28, 25, 17, 20, 24, 25, 26, 25, 22, 16, 15, 23, 23, 23, 23, 21, 17, 12, - 20, 20, 20, 19, 18, 16, 12, 17, 19, 19, 19, 16, 13, 13, 14, 17, 17, 17, 16, - 9, 14, 12, 15, 16, 16, 15, 7, 11, 17, 18, 19, 17, 12, 16, 8, 15, 16, 17, - 16, 10, 16, 8, 12, 14, 14, 13, 8, 12, 8, 8, 11, 11, 10, 7, 9, 8, 5, - 10, 10, 9, 5, 6, 8, 7, 7, 7, 7, 4, 8, 10, 9, 8, 6, 6, 3, 5, - 3, 7, 8, 9, 8, 10, 13, 3, 5, 6, 7, 7, 9, 10, 3, 2, 4, 4, 5, - 6, 8, 3, 2, 0, 0, 3, 6, 6, 3, 2, 5, 5, 4, 3, 5, 5, 6, 11, - 10, 6, 3, 5, 7, 11, 13, 11, 8, 4, 4, 1, 7, 7, 4, 7, 9, 10, 1, - 7, 9, 3, 6, 7, 9, 1, 7, 11, 4, 3, 5, 6, 1, 7, 11, 6, 1, 2, - 5, 1, 7, 12, 10, 7, 4, 3, 4, 10, 13, 13, 10, 5, 3, 9, 13, 14, 15, - 11, 7, 3, 33, 36, 40, 42, 44, 41, 37, 30, 34, 38, 44, 43, 40, 35, 29, 33, - 38, 41, 42, 38, 34, 28, 31, 35, 37, 40, 37, 32, 26, 28, 32, 35, 39, 36, 33, - 25, 27, 30, 34, 38, 36, 33, 23, 26, 30, 33, 36, 36, 33, 29, 33, 36, 41, 38, - 36, 32, 28, 32, 36, 39, 38, 35, 31, 26, 30, 33, 37, 36, 33, 29, 25, 27, 32, - 34, 34, 31, 28, 24, 26, 30, 32, 33, 32, 28, 22, 25, 28, 31, 31, 31, 28, 18, - 23, 27, 29, 30, 30, 27, 27, 31, 33, 33, 34, 31, 25, 25, 28, 31, 32, 32, 30, - 23, 22, 27, 29, 30, 30, 28, 22, 19, 25, 26, 26, 27, 26, 21, 15, 25, 25, 26, - 25, 24, 21, 12, 23, 24, 24, 24, 23, 21, 13, 20, 21, 22, 23, 22, 19, 22, 24, - 25, 25, 27, 23, 16, 18, 22, 24, 24, 24, 21, 15, 14, 21, 23, 22, 21, 18, 15, - 12, 19, 19, 19, 19, 15, 15, 12, 16, 19, 18, 17, 14, 12, 13, 14, 16, 16, 16, - 14, 8, 13, 12, 14, 15, 15, 14, 5, 10, 17, 17, 18, 16, 12, 16, 7, 15, 16, - 16, 15, 9, 16, 7, 11, 14, 13, 12, 7, 11, 7, 7, 11, 10, 9, 4, 7, 7, - 5, 10, 9, 8, 3, 5, 8, 7, 7, 7, 7, 3, 5, 10, 9, 8, 5, 5, 2, - 4, 2, 7, 8, 8, 8, 10, 13, 2, 5, 6, 7, 7, 8, 10, 2, 1, 4, 4, - 4, 5, 6, 2, 2, 0, 0, 2, 4, 5, 3, 2, 5, 5, 4, 2, 4, 5, 6, - 11, 10, 6, 3, 3, 7, 10, 13, 12, 7, 4, 3, 2, 6, 6, 4, 7, 9, 10, - 1, 6, 7, 3, 6, 6, 7, 1, 6, 8, 4, 2, 3, 5, 1, 6, 8, 5, 1, - 2, 3, 1, 7, 11, 11, 6, 4, 3, 4, 10, 15, 15, 9, 5, 2, 9, 13, 16, - 16, 11, 6, 3, 28, 32, 36, 40, 41, 36, 33, 27, 31, 35, 39, 40, 35, 32, 26, - 29, 34, 36, 39, 35, 30, 24, 27, 31, 34, 36, 32, 29, 22, 25, 28, 31, 34, 32, - 29, 21, 24, 26, 30, 33, 32, 29, 19, 22, 25, 28, 33, 31, 29, 26, 29, 34, 37, - 35, 33, 29, 25, 28, 32, 36, 35, 32, 28, 23, 27, 31, 34, 33, 30, 25, 22, 25, - 28, 30, 30, 28, 24, 20, 22, 25, 28, 28, 27, 23, 19, 22, 24, 27, 27, 27, 24, - 16, 19, 23, 26, 25, 26, 24, 23, 26, 29, 29, 31, 28, 23, 22, 26, 28, 28, 29, - 26, 21, 20, 23, 26, 25, 26, 25, 19, 17, 22, 22, 22, 23, 22, 18, 13, 21, 21, - 21, 21, 21, 17, 11, 19, 20, 20, 20, 19, 17, 12, 17, 18, 19, 19, 19, 16, 20, - 21, 22, 22, 24, 22, 15, 16, 20, 20, 21, 22, 19, 13, 13, 18, 19, 18, 18, 16, - 13, 10, 16, 15, 15, 15, 13, 12, 9, 14, 15, 14, 14, 12, 9, 10, 12, 12, 12, - 12, 11, 6, 12, 10, 11, 11, 11, 11, 4, 8, 14, 14, 15, 14, 11, 14, 5, 12, - 12, 13, 13, 8, 13, 5, 10, 10, 10, 10, 6, 8, 5, 5, 7, 6, 6, 3, 5, - 5, 4, 5, 5, 5, 2, 3, 6, 6, 7, 5, 3, 2, 4, 8, 9, 9, 6, 4, - 2, 3, 1, 4, 5, 6, 8, 9, 12, 1, 2, 4, 5, 6, 7, 8, 1, 2, 2, - 2, 4, 4, 5, 1, 2, 4, 2, 0, 3, 4, 2, 4, 6, 6, 4, 2, 3, 4, - 8, 12, 10, 6, 3, 2, 8, 11, 13, 11, 7, 4, 2, 4, 5, 4, 4, 6, 8, - 9, 4, 5, 5, 4, 5, 6, 6, 4, 6, 6, 3, 2, 3, 3, 3, 7, 8, 4, - 3, 1, 2, 4, 6, 9, 9, 7, 4, 2, 6, 10, 13, 13, 9, 5, 2, 11, 13, - 14, 14, 10, 6, 3, 25, 28, 32, 36, 36, 34, 29, 23, 26, 31, 35, 35, 31, 28, - 22, 25, 29, 33, 33, 30, 25, 20, 23, 27, 30, 33, 28, 24, 17, 20, 23, 26, 29, - 27, 24, 16, 19, 22, 25, 28, 27, 24, 14, 17, 21, 24, 28, 27, 24, 21, 25, 29, - 32, 32, 28, 25, 21, 24, 28, 31, 32, 27, 23, 18, 22, 27, 29, 29, 25, 22, 19, - 20, 24, 27, 26, 24, 20, 16, 18, 20, 23, 23, 22, 20, 14, 17, 19, 22, 22, 22, - 19, 11, 14, 18, 21, 21, 21, 20, 19, 22, 25, 26, 27, 25, 20, 18, 21, 24, 25, - 24, 23, 19, 17, 20, 22, 22, 22, 22, 16, 15, 18, 18, 18, 19, 19, 14, 11, 16, - 16, 16, 16, 16, 14, 9, 14, 15, 15, 15, 15, 14, 9, 12, 13, 13, 14, 14, 13, - 17, 17, 18, 18, 20, 19, 12, 15, 15, 17, 17, 17, 16, 10, 11, 15, 15, 15, 14, - 14, 9, 7, 12, 11, 11, 11, 11, 9, 7, 10, 9, 9, 9, 8, 6, 8, 7, 8, - 8, 8, 7, 3, 9, 9, 6, 6, 6, 6, 3, 7, 9, 9, 10, 11, 10, 12, 3, - 8, 8, 9, 9, 7, 10, 3, 6, 6, 6, 6, 5, 6, 3, 3, 3, 2, 2, 2, - 3, 2, 4, 3, 3, 3, 1, 3, 5, 7, 7, 6, 4, 2, 2, 7, 9, 9, 7, - 5, 3, 2, 2, 3, 4, 5, 6, 8, 10, 2, 3, 4, 5, 5, 6, 7, 2, 4, - 4, 3, 3, 3, 4, 2, 5, 5, 4, 3, 0, 2, 2, 6, 8, 6, 5, 3, 2, - 6, 9, 12, 9, 6, 4, 1, 9, 11, 12, 11, 7, 5, 2, 6, 8, 6, 4, 6, - 7, 8, 6, 8, 7, 5, 5, 5, 5, 6, 8, 9, 4, 2, 2, 3, 6, 9, 11, - 5, 3, 2, 1, 6, 8, 10, 10, 7, 5, 2, 8, 11, 13, 12, 8, 5, 3, 10, - 13, 14, 14, 10, 6, 4, 20, 24, 28, 32, 31, 29, 25, 19, 23, 27, 31, 31, 28, - 24, 18, 21, 25, 28, 31, 27, 22, 17, 19, 22, 26, 28, 25, 19, 13, 16, 19, 22, - 26, 23, 20, 11, 15, 17, 20, 24, 23, 19, 10, 13, 16, 19, 23, 23, 20, 18, 22, - 25, 29, 28, 25, 21, 17, 21, 24, 27, 28, 24, 20, 15, 19, 23, 25, 24, 22, 18, - 14, 17, 19, 22, 22, 20, 16, 11, 14, 16, 18, 19, 19, 15, 10, 12, 15, 18, 18, - 18, 15, 7, 10, 14, 16, 16, 16, 15, 15, 19, 20, 22, 23, 21, 17, 14, 17, 20, - 21, 21, 19, 15, 13, 16, 18, 18, 18, 18, 13, 12, 14, 15, 14, 14, 14, 10, 9, - 11, 12, 12, 12, 11, 10, 5, 10, 11, 10, 11, 11, 11, 6, 8, 10, 9, 9, 9, - 9, 13, 13, 14, 15, 16, 16, 10, 12, 12, 12, 13, 13, 13, 8, 9, 10, 11, 10, - 10, 10, 7, 5, 8, 7, 7, 7, 7, 6, 4, 5, 5, 4, 4, 4, 3, 5, 4, - 3, 3, 3, 3, 2, 6, 6, 3, 2, 2, 2, 1, 4, 5, 6, 7, 7, 9, 10, - 2, 4, 5, 6, 6, 7, 8, 2, 3, 4, 4, 4, 4, 5, 2, 3, 3, 2, 2, - 1, 2, 1, 6, 4, 3, 3, 2, 1, 5, 6, 6, 4, 3, 2, 0, 5, 7, 7, - 5, 4, 3, 1, 5, 5, 5, 5, 6, 8, 9, 5, 6, 5, 5, 5, 5, 6, 5, - 7, 5, 4, 3, 3, 3, 5, 7, 6, 5, 4, 3, 0, 6, 8, 8, 6, 4, 3, - 1, 6, 9, 11, 8, 5, 3, 2, 7, 9, 11, 10, 6, 4, 2, 7, 9, 7, 5, - 6, 7, 7, 8, 10, 9, 5, 5, 5, 5, 8, 10, 10, 5, 3, 2, 2, 8, 9, - 11, 7, 4, 3, 2, 8, 9, 12, 10, 6, 4, 2, 8, 10, 14, 13, 8, 4, 3, - 9, 12, 14, 14, 9, 5, 3, 27, 31, 32, 35, 35, 33, 30, 25, 29, 33, 35, 35, - 32, 29, 23, 27, 30, 33, 34, 31, 29, 23, 26, 28, 31, 33, 28, 26, 20, 23, 25, - 28, 30, 28, 26, 18, 22, 24, 27, 30, 28, 26, 15, 19, 22, 26, 28, 28, 26, 24, - 28, 30, 33, 32, 30, 27, 23, 27, 30, 31, 31, 29, 26, 21, 25, 28, 31, 30, 28, - 26, 20, 24, 27, 28, 28, 25, 23, 18, 20, 23, 25, 25, 26, 23, 16, 18, 22, 25, - 25, 24, 23, 12, 15, 20, 23, 24, 24, 23, 22, 25, 27, 27, 28, 26, 23, 20, 24, - 26, 28, 28, 26, 22, 18, 23, 25, 25, 24, 26, 22, 17, 20, 22, 22, 22, 24, 20, - 12, 18, 19, 20, 20, 21, 19, 9, 15, 17, 18, 19, 20, 19, 10, 12, 15, 16, 17, - 19, 19, 18, 20, 20, 22, 22, 22, 12, 16, 18, 19, 20, 21, 20, 13, 13, 17, 17, - 18, 18, 18, 13, 9, 14, 14, 14, 15, 15, 12, 8, 12, 12, 12, 12, 13, 8, 9, - 9, 9, 10, 11, 11, 6, 10, 10, 7, 8, 9, 9, 7, 9, 11, 12, 13, 13, 10, - 12, 4, 9, 10, 11, 11, 9, 12, 4, 8, 8, 8, 9, 8, 10, 4, 4, 5, 5, - 5, 6, 6, 3, 2, 2, 2, 2, 3, 6, 5, 5, 5, 4, 2, 2, 6, 8, 8, - 6, 4, 2, 1, 5, 2, 3, 4, 4, 7, 9, 11, 2, 4, 4, 4, 6, 8, 9, - 2, 4, 4, 4, 3, 6, 8, 2, 3, 3, 3, 2, 2, 6, 0, 3, 4, 3, 2, - 1, 5, 3, 4, 7, 5, 2, 1, 3, 6, 7, 8, 7, 3, 2, 1, 5, 8, 7, - 5, 5, 8, 9, 5, 8, 9, 6, 4, 6, 9, 5, 8, 10, 6, 4, 3, 6, 5, - 7, 10, 5, 2, 2, 3, 4, 6, 9, 7, 3, 2, 1, 4, 7, 10, 9, 5, 2, - 1, 5, 9, 10, 10, 6, 3, 1, 34, 37, 40, 44, 42, 41, 38, 33, 35, 39, 43, - 43, 40, 37, 30, 34, 38, 41, 43, 39, 36, 29, 32, 35, 39, 41, 37, 33, 26, 30, - 32, 35, 39, 34, 33, 23, 26, 30, 33, 36, 37, 33, 21, 25, 29, 33, 36, 36, 34, - 31, 35, 38, 42, 40, 37, 35, 29, 33, 37, 40, 41, 36, 33, 28, 31, 34, 38, 38, - 36, 31, 26, 29, 33, 35, 35, 34, 29, 23, 26, 29, 32, 31, 31, 28, 20, 24, 27, - 30, 31, 33, 29, 17, 21, 26, 29, 30, 30, 29, 27, 31, 33, 36, 36, 33, 29, 26, - 30, 32, 34, 34, 33, 28, 24, 28, 31, 32, 33, 32, 27, 21, 27, 27, 28, 29, 28, - 24, 15, 23, 25, 25, 25, 25, 25, 12, 21, 23, 24, 24, 24, 24, 12, 18, 21, 22, - 22, 23, 22, 25, 26, 27, 29, 28, 28, 19, 20, 23, 26, 26, 27, 24, 18, 16, 22, - 24, 24, 24, 23, 17, 12, 20, 20, 20, 21, 20, 17, 11, 16, 17, 17, 17, 17, 13, - 11, 13, 15, 15, 16, 15, 10, 12, 10, 12, 14, 14, 14, 8, 12, 17, 18, 19, 20, - 16, 19, 8, 15, 17, 18, 18, 13, 18, 8, 13, 15, 15, 15, 11, 15, 8, 8, 11, - 10, 11, 8, 9, 6, 3, 8, 7, 8, 6, 7, 7, 5, 4, 5, 5, 5, 8, 8, - 7, 5, 3, 3, 4, 7, 3, 7, 8, 10, 11, 14, 16, 3, 6, 7, 8, 10, 12, - 13, 3, 3, 5, 5, 7, 9, 11, 3, 2, 2, 2, 4, 6, 8, 3, 0, 3, 2, - 1, 4, 7, 3, 3, 4, 3, 2, 3, 7, 5, 6, 5, 4, 2, 1, 5, 4, 6, - 6, 6, 10, 12, 14, 4, 6, 7, 5, 8, 10, 11, 3, 6, 7, 4, 4, 7, 9, - 4, 5, 7, 3, 2, 3, 5, 2, 4, 5, 4, 2, 1, 5, 3, 4, 6, 5, 3, - 2, 4, 4, 5, 6, 6, 3, 2, 2, 38, 41, 46, 49, 49, 47, 45, 37, 41, 44, - 48, 50, 45, 41, 35, 38, 43, 46, 48, 44, 40, 33, 36, 39, 43, 46, 43, 36, 31, - 33, 37, 40, 43, 41, 36, 27, 30, 35, 38, 41, 40, 36, 25, 28, 33, 37, 40, 40, - 37, 35, 40, 42, 46, 46, 42, 37, 33, 37, 42, 46, 46, 41, 37, 31, 36, 40, 43, - 44, 40, 35, 30, 33, 37, 39, 40, 38, 33, 25, 30, 33, 36, 37, 36, 32, 22, 27, - 32, 34, 35, 35, 32, 18, 25, 30, 33, 33, 34, 32, 31, 36, 38, 39, 41, 37, 32, - 29, 35, 37, 38, 39, 36, 31, 27, 33, 34, 36, 36, 35, 29, 23, 31, 32, 32, 33, - 31, 25, 17, 27, 28, 28, 28, 27, 25, 14, 25, 26, 27, 27, 27, 26, 13, 22, 25, - 25, 26, 26, 24, 26, 30, 31, 32, 33, 31, 23, 22, 28, 30, 31, 30, 29, 22, 19, - 25, 27, 28, 28, 26, 22, 15, 22, 24, 24, 24, 22, 20, 13, 17, 21, 21, 21, 18, - 17, 13, 14, 18, 19, 19, 18, 13, 13, 11, 17, 17, 18, 17, 10, 14, 21, 22, 24, - 23, 19, 23, 10, 19, 21, 21, 21, 15, 22, 10, 15, 19, 18, 18, 13, 17, 10, 9, - 15, 15, 15, 10, 12, 8, 5, 12, 12, 11, 7, 9, 9, 6, 9, 9, 9, 7, 8, - 9, 7, 7, 7, 7, 7, 7, 5, 11, 13, 13, 14, 17, 20, 5, 8, 11, 12, 13, - 14, 16, 5, 4, 9, 9, 10, 11, 12, 5, 3, 5, 5, 6, 8, 8, 4, 3, 0, - 0, 3, 6, 7, 4, 3, 6, 5, 1, 5, 8, 6, 5, 7, 6, 2, 4, 6, 4, - 5, 5, 9, 13, 15, 16, 4, 6, 7, 8, 11, 13, 14, 4, 5, 9, 5, 8, 9, - 11, 4, 5, 9, 4, 3, 6, 7, 2, 4, 7, 5, 2, 3, 7, 2, 5, 8, 7, - 4, 3, 5, 4, 7, 8, 8, 5, 1, 4, 36, 40, 45, 47, 48, 45, 42, 35, 40, - 43, 48, 47, 44, 40, 33, 37, 42, 45, 46, 43, 39, 32, 35, 39, 43, 44, 40, 35, - 30, 32, 35, 39, 41, 38, 35, 27, 29, 32, 36, 40, 38, 34, 23, 28, 32, 34, 38, - 38, 34, 34, 38, 41, 45, 46, 41, 37, 33, 35, 40, 44, 44, 38, 35, 31, 35, 39, - 42, 42, 38, 33, 28, 32, 35, 39, 38, 35, 31, 24, 29, 32, 34, 36, 33, 30, 20, - 27, 30, 33, 33, 32, 30, 17, 24, 29, 32, 31, 31, 30, 31, 35, 36, 38, 38, 37, - 30, 28, 34, 36, 36, 38, 35, 29, 25, 32, 35, 34, 34, 33, 26, 21, 29, 31, 31, - 30, 30, 23, 15, 26, 27, 28, 27, 25, 24, 12, 23, 26, 27, 25, 25, 24, 12, 21, - 24, 24, 24, 24, 22, 25, 30, 29, 32, 31, 29, 23, 20, 27, 29, 29, 29, 26, 21, - 17, 26, 27, 26, 26, 23, 20, 14, 21, 23, 23, 22, 20, 19, 12, 17, 20, 20, 19, - 16, 15, 12, 13, 18, 18, 18, 15, 12, 12, 10, 16, 16, 17, 15, 8, 12, 20, 22, - 22, 21, 17, 22, 9, 18, 19, 21, 20, 14, 21, 9, 14, 18, 17, 17, 11, 16, 9, - 8, 15, 14, 13, 8, 11, 8, 4, 12, 11, 9, 5, 8, 7, 5, 9, 9, 8, 4, - 6, 8, 6, 7, 7, 7, 4, 5, 5, 11, 12, 13, 13, 15, 19, 5, 7, 11, 11, - 12, 13, 14, 5, 4, 9, 8, 9, 10, 11, 5, 3, 5, 5, 6, 6, 6, 3, 2, - 0, 0, 2, 4, 5, 3, 3, 6, 5, 1, 3, 5, 5, 5, 7, 7, 2, 3, 4, - 4, 5, 5, 9, 12, 14, 15, 4, 5, 5, 8, 10, 12, 12, 4, 5, 6, 5, 7, - 8, 9, 4, 4, 6, 3, 3, 4, 5, 2, 4, 7, 6, 1, 3, 4, 1, 5, 11, - 11, 4, 1, 4, 4, 8, 12, 12, 6, 1, 3, 33, 37, 41, 43, 44, 41, 38, 31, - 35, 39, 43, 44, 39, 36, 29, 34, 37, 42, 42, 38, 33, 28, 31, 34, 39, 41, 36, - 30, 26, 28, 31, 35, 37, 33, 31, 23, 24, 28, 32, 35, 34, 30, 21, 24, 27, 30, - 35, 34, 30, 30, 33, 38, 41, 40, 37, 32, 29, 31, 36, 40, 41, 37, 31, 28, 30, - 35, 37, 37, 34, 29, 26, 28, 31, 34, 34, 32, 26, 22, 25, 27, 30, 31, 29, 25, - 19, 23, 26, 29, 29, 28, 25, 14, 21, 25, 27, 27, 27, 25, 28, 31, 33, 34, 35, - 33, 28, 26, 30, 32, 33, 33, 31, 25, 22, 28, 30, 29, 30, 29, 23, 19, 27, 27, - 26, 28, 25, 19, 13, 22, 24, 23, 23, 22, 19, 10, 20, 22, 21, 21, 21, 20, 9, - 18, 20, 20, 20, 20, 18, 23, 26, 26, 27, 27, 27, 20, 18, 24, 25, 25, 26, 23, - 18, 15, 22, 23, 23, 22, 21, 17, 12, 19, 19, 19, 20, 17, 15, 10, 14, 16, 15, - 15, 13, 12, 9, 10, 15, 14, 14, 12, 9, 9, 7, 13, 13, 13, 12, 6, 11, 18, - 18, 19, 19, 15, 19, 7, 16, 16, 18, 17, 12, 18, 7, 12, 15, 14, 14, 10, 13, - 7, 7, 11, 11, 10, 6, 8, 5, 2, 7, 7, 6, 4, 5, 5, 3, 5, 4, 5, - 3, 4, 5, 4, 3, 3, 3, 3, 4, 3, 9, 9, 10, 12, 13, 17, 3, 7, 9, - 9, 11, 11, 12, 3, 4, 8, 7, 8, 8, 9, 3, 3, 4, 4, 4, 5, 4, 2, - 1, 3, 2, 0, 3, 4, 2, 3, 5, 4, 2, 2, 4, 3, 4, 5, 5, 3, 1, - 3, 4, 5, 6, 9, 11, 13, 13, 4, 5, 6, 8, 9, 10, 10, 4, 5, 6, 6, - 6, 7, 7, 4, 3, 5, 2, 2, 3, 3, 2, 3, 6, 5, 3, 1, 3, 2, 5, - 7, 6, 3, 2, 3, 4, 6, 7, 7, 4, 2, 2, 26, 31, 35, 39, 39, 35, 33, - 26, 30, 33, 39, 38, 36, 31, 24, 29, 32, 36, 37, 33, 29, 23, 26, 30, 33, 34, - 31, 26, 20, 24, 26, 29, 32, 29, 26, 18, 20, 23, 26, 30, 30, 26, 17, 18, 22, - 26, 29, 29, 26, 24, 28, 32, 36, 35, 33, 29, 24, 26, 31, 35, 34, 30, 27, 22, - 25, 29, 33, 31, 29, 24, 21, 24, 27, 29, 29, 27, 21, 18, 20, 23, 25, 25, 24, - 21, 16, 19, 21, 23, 23, 24, 21, 13, 17, 20, 23, 22, 22, 22, 22, 25, 28, 28, - 30, 28, 24, 21, 24, 27, 27, 28, 27, 22, 20, 23, 25, 25, 25, 25, 20, 17, 21, - 22, 21, 22, 22, 16, 11, 18, 18, 18, 18, 18, 16, 7, 17, 17, 16, 16, 17, 16, - 8, 15, 15, 15, 16, 16, 14, 20, 20, 20, 21, 23, 23, 16, 16, 19, 20, 20, 21, - 19, 14, 13, 18, 18, 18, 17, 17, 13, 9, 15, 15, 14, 14, 14, 11, 7, 12, 11, - 10, 10, 10, 8, 7, 8, 10, 9, 9, 9, 5, 7, 5, 8, 8, 7, 8, 3, 8, - 12, 13, 14, 14, 13, 15, 4, 11, 11, 12, 13, 10, 13, 4, 10, 9, 9, 9, 8, - 9, 4, 5, 6, 6, 5, 4, 5, 3, 2, 2, 2, 2, 2, 3, 3, 2, 3, 2, - 1, 2, 3, 4, 3, 5, 3, 2, 0, 3, 3, 6, 7, 8, 9, 11, 13, 3, 5, - 7, 8, 8, 9, 10, 3, 3, 5, 5, 6, 6, 6, 3, 3, 3, 2, 2, 3, 3, - 1, 4, 6, 4, 3, 0, 3, 2, 5, 8, 5, 3, 2, 2, 4, 7, 8, 7, 4, - 2, 2, 4, 6, 6, 7, 8, 10, 11, 4, 6, 6, 6, 7, 8, 8, 4, 6, 7, - 4, 4, 4, 6, 4, 6, 8, 4, 2, 1, 2, 3, 8, 9, 7, 4, 2, 2, 6, - 8, 10, 9, 5, 3, 0, 7, 9, 10, 9, 6, 4, 2, 21, 26, 31, 32, 34, 32, - 27, 20, 24, 28, 32, 34, 30, 25, 19, 22, 27, 30, 32, 28, 23, 18, 21, 24, 28, - 30, 26, 21, 15, 18, 21, 24, 27, 24, 21, 13, 15, 18, 21, 24, 24, 20, 12, 14, - 17, 21, 24, 25, 21, 20, 23, 26, 31, 29, 27, 24, 19, 22, 26, 29, 29, 26, 22, - 17, 21, 24, 27, 27, 24, 19, 16, 18, 21, 24, 23, 22, 17, 13, 15, 17, 20, 20, - 20, 17, 12, 13, 16, 19, 19, 19, 17, 9, 12, 15, 18, 17, 18, 17, 18, 20, 22, - 23, 25, 23, 18, 16, 19, 21, 22, 23, 21, 16, 15, 18, 19, 19, 19, 19, 15, 14, - 16, 16, 16, 16, 16, 12, 9, 12, 13, 13, 12, 13, 12, 6, 12, 12, 12, 11, 12, - 12, 6, 10, 11, 10, 11, 11, 10, 15, 15, 15, 16, 17, 18, 11, 13, 13, 14, 15, - 15, 15, 9, 10, 12, 12, 12, 12, 11, 8, 6, 11, 9, 8, 8, 8, 7, 4, 7, - 6, 6, 5, 5, 4, 5, 5, 5, 4, 4, 4, 2, 6, 4, 3, 3, 3, 3, 2, - 6, 7, 7, 8, 9, 10, 11, 2, 5, 6, 7, 7, 8, 9, 2, 4, 5, 4, 5, - 5, 5, 2, 2, 2, 2, 1, 2, 2, 1, 4, 4, 3, 2, 2, 2, 3, 5, 5, - 4, 2, 2, 1, 4, 6, 7, 4, 3, 3, 0, 3, 4, 5, 6, 7, 8, 10, 4, - 5, 5, 6, 6, 6, 7, 4, 7, 5, 4, 4, 4, 4, 4, 6, 5, 4, 3, 2, - 1, 4, 7, 8, 5, 4, 3, 0, 6, 7, 9, 7, 4, 3, 2, 6, 8, 10, 8, - 5, 3, 2, 7, 9, 7, 5, 6, 8, 8, 7, 9, 8, 5, 5, 5, 5, 7, 9, - 10, 5, 3, 2, 3, 7, 8, 11, 6, 4, 3, 1, 7, 9, 11, 8, 5, 3, 2, - 8, 9, 12, 11, 6, 4, 2, 8, 10, 12, 12, 8, 5, 3, 31, 34, 37, 39, 39, - 37, 34, 28, 33, 36, 38, 38, 35, 32, 27, 31, 34, 37, 37, 35, 31, 26, 28, 32, - 34, 35, 32, 27, 22, 25, 29, 30, 32, 29, 27, 18, 22, 24, 26, 30, 29, 27, 15, - 19, 23, 26, 29, 28, 27, 26, 31, 35, 36, 36, 34, 32, 26, 30, 34, 36, 37, 33, - 31, 24, 28, 31, 34, 34, 31, 28, 22, 26, 30, 32, 30, 30, 24, 20, 22, 25, 28, - 27, 26, 24, 16, 19, 22, 24, 25, 25, 24, 12, 16, 20, 24, 24, 25, 24, 24, 29, - 31, 31, 33, 30, 27, 23, 26, 29, 30, 31, 31, 26, 21, 26, 28, 28, 29, 29, 25, - 19, 23, 25, 24, 25, 25, 20, 12, 19, 20, 21, 21, 21, 20, 8, 16, 18, 18, 19, - 20, 20, 8, 13, 16, 16, 18, 18, 19, 21, 22, 24, 25, 25, 27, 18, 18, 20, 21, - 24, 23, 24, 17, 14, 19, 21, 21, 21, 21, 16, 11, 17, 17, 17, 17, 17, 15, 8, - 12, 12, 13, 13, 13, 11, 7, 9, 9, 10, 11, 12, 8, 9, 7, 7, 8, 9, 10, - 8, 10, 14, 15, 16, 17, 17, 18, 6, 12, 13, 15, 15, 14, 17, 6, 11, 11, 11, - 12, 11, 14, 6, 7, 8, 8, 8, 8, 7, 4, 2, 3, 3, 3, 5, 7, 3, 2, - 2, 2, 0, 3, 7, 5, 5, 4, 2, 2, 2, 5, 5, 6, 8, 9, 12, 15, 17, - 5, 5, 7, 8, 11, 13, 14, 5, 6, 6, 6, 8, 10, 11, 5, 5, 5, 5, 4, - 6, 6, 3, 3, 4, 3, 2, 2, 6, 0, 4, 5, 4, 2, 1, 5, 4, 4, 6, - 5, 2, 2, 3, 7, 9, 9, 8, 10, 13, 15, 7, 9, 10, 8, 8, 11, 13, 7, - 9, 11, 7, 6, 7, 9, 7, 8, 10, 6, 4, 3, 5, 5, 7, 9, 6, 3, 1, - 3, 4, 5, 9, 8, 3, 2, 1, 5, 6, 9, 9, 4, 2, 1, 37, 41, 44, 47, - 48, 44, 42, 35, 39, 43, 47, 48, 44, 40, 33, 38, 41, 45, 45, 42, 38, 32, 36, - 38, 42, 45, 40, 34, 29, 31, 35, 39, 39, 36, 34, 24, 28, 31, 33, 37, 37, 34, - 22, 25, 29, 32, 36, 36, 34, 33, 36, 41, 46, 42, 42, 39, 31, 36, 41, 44, 45, - 42, 36, 30, 34, 38, 41, 41, 39, 35, 29, 32, 36, 38, 39, 35, 30, 25, 29, 31, - 34, 33, 33, 30, 20, 25, 28, 32, 31, 31, 28, 16, 22, 26, 31, 30, 30, 30, 30, - 35, 36, 37, 39, 37, 33, 28, 33, 35, 36, 37, 36, 31, 26, 31, 33, 34, 34, 34, - 29, 22, 29, 30, 31, 31, 30, 24, 16, 24, 26, 26, 25, 26, 25, 11, 21, 23, 24, - 24, 24, 25, 10, 19, 21, 23, 23, 23, 22, 26, 29, 30, 31, 32, 33, 24, 21, 26, - 29, 30, 31, 29, 23, 18, 25, 27, 27, 27, 26, 21, 14, 22, 23, 23, 23, 22, 19, - 12, 16, 19, 19, 18, 17, 16, 11, 12, 15, 16, 16, 16, 12, 10, 8, 13, 14, 14, - 15, 9, 13, 20, 21, 22, 24, 21, 24, 10, 18, 20, 20, 22, 18, 22, 10, 15, 17, - 17, 18, 15, 17, 10, 9, 14, 14, 13, 10, 12, 8, 4, 9, 9, 9, 8, 9, 5, - 3, 5, 5, 6, 6, 9, 7, 5, 3, 3, 4, 5, 7, 6, 12, 13, 14, 17, 19, - 21, 6, 10, 11, 13, 15, 17, 18, 6, 6, 9, 10, 12, 13, 14, 6, 5, 6, 6, - 8, 9, 8, 4, 3, 3, 3, 3, 6, 7, 4, 0, 4, 3, 1, 4, 7, 3, 3, - 5, 3, 2, 3, 6, 6, 8, 8, 10, 15, 17, 19, 6, 8, 9, 9, 13, 15, 16, - 6, 8, 9, 7, 9, 11, 12, 6, 7, 8, 5, 5, 7, 6, 4, 5, 6, 5, 2, - 3, 7, 2, 4, 5, 4, 2, 1, 5, 3, 5, 5, 5, 3, 2, 4, 42, 47, 50, - 55, 55, 54, 48, 41, 45, 49, 54, 55, 52, 45, 39, 43, 47, 51, 52, 50, 45, 38, - 40, 45, 48, 51, 45, 39, 34, 38, 41, 44, 46, 42, 40, 31, 34, 38, 41, 44, 42, - 39, 27, 30, 35, 40, 42, 43, 40, 40, 43, 48, 51, 52, 48, 44, 38, 43, 47, 51, - 50, 46, 42, 35, 40, 45, 48, 48, 46, 42, 34, 38, 42, 44, 44, 42, 35, 29, 35, - 38, 41, 40, 38, 34, 22, 31, 34, 37, 37, 38, 34, 19, 29, 33, 35, 36, 37, 36, - 37, 40, 44, 44, 45, 44, 39, 33, 40, 42, 42, 43, 42, 37, 29, 38, 40, 41, 40, - 39, 34, 25, 35, 37, 36, 37, 35, 30, 20, 30, 33, 33, 32, 29, 29, 14, 26, 30, - 30, 29, 30, 29, 13, 23, 27, 29, 28, 28, 27, 29, 34, 36, 37, 39, 38, 30, 25, - 32, 34, 36, 36, 34, 27, 21, 30, 33, 32, 33, 30, 26, 18, 26, 29, 28, 29, 26, - 25, 16, 20, 25, 25, 24, 20, 21, 14, 14, 22, 21, 21, 20, 17, 14, 10, 19, 20, - 20, 19, 13, 17, 27, 28, 29, 29, 25, 30, 13, 22, 27, 27, 27, 22, 28, 13, 18, - 24, 23, 24, 18, 22, 13, 12, 20, 20, 19, 13, 17, 11, 7, 16, 15, 14, 9, 12, - 9, 5, 11, 11, 11, 8, 10, 9, 6, 8, 10, 10, 8, 9, 9, 15, 18, 20, 20, - 23, 26, 9, 12, 17, 18, 19, 20, 22, 9, 8, 15, 15, 16, 17, 17, 9, 7, 11, - 11, 12, 11, 11, 7, 5, 6, 6, 5, 8, 9, 5, 4, 0, 1, 4, 6, 9, 5, - 3, 2, 2, 3, 6, 8, 7, 8, 11, 16, 19, 21, 22, 7, 7, 9, 14, 18, 18, - 18, 8, 7, 8, 11, 14, 15, 15, 7, 6, 6, 7, 10, 10, 9, 6, 4, 5, 3, - 3, 5, 8, 4, 2, 4, 4, 2, 5, 7, 3, 2, 4, 4, 2, 4, 6, 42, 45, - 48, 52, 53, 51, 46, 40, 42, 47, 52, 52, 48, 43, 38, 42, 46, 49, 52, 47, 42, - 35, 40, 44, 46, 48, 45, 38, 32, 37, 39, 44, 44, 42, 38, 29, 33, 36, 39, 42, - 41, 37, 26, 30, 34, 38, 41, 41, 38, 38, 42, 46, 49, 48, 46, 43, 37, 40, 45, - 49, 48, 44, 40, 35, 38, 43, 47, 46, 42, 35, 33, 38, 40, 43, 41, 39, 33, 26, - 34, 36, 39, 38, 36, 32, 22, 29, 32, 36, 35, 35, 32, 17, 28, 32, 35, 34, 34, - 33, 35, 40, 42, 42, 44, 41, 35, 31, 39, 39, 42, 42, 39, 33, 28, 37, 39, 38, - 38, 37, 30, 24, 33, 34, 35, 35, 32, 28, 18, 28, 31, 31, 30, 29, 28, 13, 24, - 29, 28, 29, 28, 28, 13, 21, 27, 27, 27, 27, 25, 27, 34, 34, 35, 37, 33, 27, - 23, 30, 33, 34, 33, 31, 26, 20, 27, 32, 31, 30, 27, 24, 16, 24, 28, 28, 27, - 23, 23, 14, 17, 24, 23, 23, 18, 19, 13, 13, 21, 21, 20, 17, 16, 12, 9, 19, - 20, 19, 17, 11, 16, 24, 26, 27, 26, 23, 27, 12, 20, 25, 26, 24, 19, 26, 12, - 16, 23, 23, 21, 15, 20, 12, 10, 19, 19, 17, 10, 15, 10, 6, 15, 15, 12, 7, - 11, 9, 5, 11, 11, 11, 6, 8, 8, 5, 7, 9, 9, 6, 7, 8, 14, 18, 18, - 18, 19, 24, 8, 9, 16, 16, 17, 17, 19, 8, 6, 14, 13, 14, 14, 14, 8, 5, - 10, 9, 10, 9, 9, 6, 3, 5, 5, 4, 6, 7, 4, 3, 1, 0, 3, 5, 7, - 4, 3, 1, 2, 2, 4, 6, 6, 7, 11, 14, 17, 19, 20, 6, 7, 10, 13, 15, - 16, 16, 6, 6, 9, 10, 12, 13, 13, 6, 5, 5, 6, 8, 8, 7, 4, 4, 4, - 3, 3, 4, 6, 3, 2, 6, 6, 1, 4, 5, 2, 3, 6, 6, 2, 3, 4, 34, - 39, 42, 47, 46, 43, 40, 34, 37, 42, 46, 46, 43, 37, 32, 35, 40, 44, 45, 41, - 36, 31, 33, 37, 40, 42, 38, 32, 28, 30, 33, 37, 38, 36, 33, 25, 27, 29, 33, - 37, 36, 32, 23, 25, 28, 32, 35, 36, 32, 32, 35, 40, 44, 44, 40, 36, 32, 35, - 38, 43, 42, 38, 33, 30, 33, 38, 40, 40, 36, 31, 28, 31, 34, 37, 36, 34, 28, - 22, 29, 30, 34, 33, 30, 27, 19, 25, 27, 30, 30, 30, 28, 15, 25, 27, 29, 29, - 30, 27, 30, 34, 37, 36, 36, 34, 29, 27, 32, 34, 35, 36, 33, 28, 24, 30, 33, - 32, 32, 30, 25, 21, 29, 29, 30, 30, 27, 23, 15, 24, 26, 26, 25, 23, 22, 11, - 22, 24, 23, 23, 22, 22, 10, 19, 22, 22, 22, 22, 20, 25, 28, 28, 29, 30, 29, - 23, 20, 26, 27, 28, 28, 25, 20, 16, 24, 26, 25, 25, 22, 19, 13, 20, 22, 21, - 22, 18, 18, 11, 15, 19, 18, 17, 14, 14, 10, 11, 17, 15, 15, 14, 11, 10, 7, - 15, 14, 14, 13, 7, 12, 20, 20, 21, 21, 17, 22, 9, 17, 19, 20, 19, 14, 20, - 9, 13, 17, 17, 16, 11, 15, 9, 8, 14, 13, 12, 7, 10, 7, 3, 10, 9, 8, - 4, 7, 6, 3, 7, 6, 6, 3, 5, 5, 4, 5, 5, 4, 4, 4, 5, 10, 12, - 12, 13, 15, 19, 5, 8, 11, 11, 12, 13, 14, 4, 4, 10, 9, 9, 10, 10, 5, - 3, 6, 6, 6, 6, 5, 3, 2, 1, 1, 2, 3, 4, 2, 1, 4, 3, 0, 3, - 4, 3, 2, 4, 3, 2, 2, 3, 5, 5, 8, 10, 12, 14, 15, 5, 5, 7, 10, - 11, 12, 12, 5, 5, 6, 7, 8, 9, 9, 5, 4, 4, 4, 4, 5, 4, 3, 2, - 5, 4, 2, 2, 4, 1, 4, 5, 5, 2, 2, 3, 3, 4, 5, 5, 3, 0, 2, - 28, 33, 37, 40, 41, 38, 35, 28, 31, 36, 40, 39, 37, 33, 26, 29, 35, 38, 38, - 34, 31, 26, 28, 31, 35, 37, 33, 28, 23, 25, 28, 30, 34, 31, 27, 19, 22, 24, - 28, 32, 31, 27, 18, 21, 23, 27, 30, 31, 28, 27, 30, 34, 38, 36, 35, 30, 26, - 30, 32, 37, 37, 33, 28, 25, 28, 31, 34, 33, 32, 26, 23, 26, 28, 30, 30, 28, - 22, 20, 22, 25, 27, 27, 26, 22, 17, 20, 22, 25, 25, 25, 22, 13, 19, 21, 24, - 24, 25, 22, 25, 28, 29, 30, 31, 30, 25, 23, 26, 29, 30, 29, 28, 23, 21, 26, - 27, 27, 27, 27, 21, 18, 23, 23, 23, 24, 23, 17, 12, 20, 20, 20, 20, 19, 17, - 8, 19, 19, 18, 18, 18, 17, 8, 16, 17, 17, 17, 17, 15, 21, 22, 22, 23, 24, - 23, 17, 17, 21, 22, 22, 23, 21, 15, 13, 19, 20, 20, 19, 18, 14, 10, 16, 16, - 16, 16, 15, 13, 8, 12, 13, 12, 12, 11, 10, 8, 9, 11, 11, 10, 10, 6, 8, - 6, 10, 9, 9, 9, 4, 9, 14, 15, 16, 16, 13, 17, 5, 13, 13, 14, 14, 10, - 15, 6, 11, 11, 11, 11, 8, 10, 6, 6, 8, 7, 7, 5, 6, 4, 2, 4, 3, - 3, 3, 3, 3, 2, 2, 1, 2, 2, 3, 4, 2, 4, 2, 1, 2, 3, 3, 7, - 8, 9, 10, 12, 14, 3, 6, 7, 8, 9, 10, 10, 3, 4, 6, 6, 6, 7, 7, - 3, 3, 3, 3, 3, 4, 3, 1, 3, 5, 3, 2, 1, 3, 1, 5, 6, 4, 3, - 0, 3, 2, 5, 6, 6, 3, 2, 2, 4, 6, 6, 7, 9, 11, 12, 4, 7, 6, - 7, 8, 9, 9, 4, 6, 6, 5, 5, 5, 6, 4, 5, 6, 3, 2, 2, 2, 2, - 5, 7, 6, 3, 2, 2, 5, 6, 8, 7, 4, 2, 1, 5, 7, 8, 8, 5, 3, - 0, 24, 28, 32, 36, 35, 32, 29, 23, 26, 30, 34, 36, 32, 28, 21, 25, 29, 32, - 34, 31, 25, 19, 22, 26, 30, 32, 28, 23, 17, 20, 22, 26, 28, 27, 23, 15, 17, - 20, 23, 27, 26, 23, 14, 16, 19, 22, 25, 26, 23, 21, 24, 28, 34, 32, 28, 26, - 20, 24, 28, 31, 31, 28, 24, 18, 22, 26, 29, 28, 26, 22, 18, 20, 23, 25, 26, - 23, 19, 15, 17, 20, 22, 21, 21, 18, 13, 15, 18, 20, 20, 21, 19, 11, 13, 17, - 20, 19, 19, 18, 18, 22, 24, 25, 27, 25, 20, 17, 20, 23, 24, 24, 23, 19, 17, - 19, 22, 22, 21, 22, 17, 14, 18, 18, 18, 18, 18, 14, 10, 14, 15, 15, 15, 15, - 14, 6, 13, 14, 13, 13, 14, 13, 6, 12, 12, 12, 12, 13, 12, 17, 17, 17, 18, - 20, 20, 13, 14, 15, 16, 17, 17, 17, 11, 11, 14, 14, 14, 14, 13, 10, 7, 12, - 11, 11, 11, 10, 9, 5, 9, 8, 7, 7, 7, 5, 6, 7, 7, 6, 6, 6, 3, - 7, 4, 5, 5, 5, 5, 3, 7, 9, 9, 10, 11, 11, 13, 2, 7, 8, 9, 9, - 8, 11, 2, 6, 6, 6, 6, 6, 7, 2, 3, 3, 2, 2, 3, 3, 1, 2, 2, - 2, 2, 0, 2, 2, 4, 5, 4, 2, 1, 2, 3, 6, 7, 4, 3, 2, 2, 3, - 4, 5, 7, 8, 10, 11, 3, 4, 5, 6, 7, 7, 8, 3, 5, 4, 4, 4, 5, - 5, 3, 4, 5, 3, 2, 1, 2, 3, 6, 8, 5, 4, 2, 2, 4, 8, 10, 7, - 4, 3, 0, 6, 9, 10, 8, 5, 3, 1, 6, 8, 6, 5, 7, 8, 9, 6, 8, - 8, 6, 6, 6, 7, 6, 8, 9, 5, 3, 3, 4, 6, 7, 10, 7, 5, 2, 0, - 7, 9, 10, 8, 5, 3, 2, 8, 10, 11, 10, 6, 4, 2, 9, 10, 11, 11, 7, - 5, 3, 33, 37, 40, 43, 42, 41, 37, 32, 36, 40, 42, 42, 40, 36, 30, 34, 38, - 40, 41, 37, 34, 29, 32, 36, 37, 38, 33, 27, 25, 28, 32, 33, 32, 29, 28, 22, - 24, 27, 28, 32, 29, 28, 16, 20, 24, 27, 29, 30, 28, 30, 34, 38, 40, 40, 38, - 35, 29, 33, 37, 42, 40, 37, 34, 27, 31, 35, 38, 36, 34, 30, 26, 29, 32, 34, - 34, 32, 25, 23, 26, 28, 31, 28, 27, 25, 18, 22, 24, 25, 27, 26, 25, 13, 17, - 21, 24, 24, 25, 24, 27, 32, 33, 35, 36, 35, 31, 26, 29, 33, 34, 35, 34, 29, - 24, 29, 31, 31, 31, 31, 26, 20, 26, 27, 28, 28, 26, 21, 14, 22, 24, 24, 22, - 21, 21, 8, 17, 19, 19, 19, 20, 21, 7, 14, 17, 17, 18, 19, 19, 24, 25, 26, - 28, 30, 30, 24, 20, 24, 25, 27, 27, 27, 22, 17, 23, 24, 24, 24, 23, 20, 13, - 19, 20, 20, 20, 19, 17, 11, 14, 16, 16, 14, 13, 14, 8, 9, 11, 10, 11, 12, - 10, 7, 5, 8, 9, 10, 10, 9, 12, 18, 19, 20, 22, 22, 23, 9, 17, 18, 19, - 20, 19, 22, 9, 15, 16, 16, 16, 16, 16, 9, 11, 13, 13, 12, 10, 10, 6, 5, - 8, 8, 4, 6, 8, 4, 3, 1, 2, 3, 5, 8, 3, 2, 2, 1, 2, 4, 7, - 8, 12, 14, 15, 18, 21, 22, 8, 10, 12, 14, 16, 18, 18, 8, 8, 10, 10, 13, - 14, 14, 8, 7, 7, 7, 8, 9, 7, 6, 5, 6, 5, 3, 4, 7, 3, 3, 5, - 4, 3, 2, 6, 0, 3, 5, 5, 3, 2, 5, 8, 11, 11, 11, 16, 19, 20, 9, - 11, 12, 10, 14, 16, 17, 9, 11, 12, 9, 10, 12, 13, 9, 10, 11, 8, 6, 6, - 6, 7, 8, 10, 7, 4, 2, 5, 5, 7, 8, 7, 4, 3, 3, 4, 5, 7, 8, - 4, 3, 2, 39, 43, 46, 51, 52, 48, 44, 38, 42, 45, 50, 49, 46, 43, 36, 39, - 44, 48, 48, 45, 39, 35, 38, 42, 44, 45, 40, 34, 31, 35, 36, 40, 41, 37, 34, - 27, 30, 33, 34, 38, 38, 34, 22, 26, 29, 34, 37, 37, 33, 36, 40, 46, 48, 48, - 43, 41, 34, 38, 42, 47, 47, 42, 38, 32, 36, 41, 43, 44, 41, 35, 31, 34, 38, - 41, 40, 37, 30, 27, 32, 34, 36, 34, 33, 30, 21, 27, 30, 31, 32, 33, 30, 15, - 23, 25, 30, 30, 30, 29, 33, 36, 40, 41, 42, 40, 35, 31, 35, 38, 40, 41, 39, - 33, 28, 34, 37, 38, 36, 36, 31, 24, 31, 33, 33, 33, 31, 26, 17, 27, 28, 29, - 27, 26, 26, 12, 22, 25, 24, 24, 25, 26, 10, 18, 22, 23, 23, 24, 24, 27, 31, - 32, 34, 35, 35, 28, 23, 30, 31, 32, 32, 33, 25, 20, 28, 30, 29, 29, 28, 24, - 16, 24, 25, 26, 25, 22, 22, 13, 18, 21, 21, 18, 18, 18, 12, 11, 17, 16, 16, - 17, 14, 10, 7, 15, 14, 15, 15, 11, 15, 23, 24, 25, 26, 25, 28, 12, 20, 22, - 24, 24, 22, 26, 12, 17, 21, 21, 20, 18, 20, 12, 11, 17, 16, 16, 12, 14, 10, - 5, 13, 12, 9, 8, 10, 7, 5, 7, 6, 7, 7, 9, 5, 4, 4, 4, 5, 7, - 8, 9, 16, 18, 19, 22, 23, 25, 9, 13, 16, 18, 20, 20, 22, 9, 9, 14, 14, - 16, 17, 16, 9, 8, 10, 10, 12, 11, 9, 7, 6, 5, 5, 4, 7, 9, 4, 3, - 3, 3, 2, 5, 9, 4, 0, 3, 4, 2, 4, 7, 9, 9, 10, 15, 19, 22, 22, - 9, 9, 10, 13, 18, 19, 19, 9, 9, 11, 11, 13, 15, 14, 9, 8, 10, 7, 9, - 9, 7, 7, 7, 8, 6, 3, 4, 7, 5, 5, 6, 5, 3, 3, 6, 2, 4, 5, - 5, 3, 2, 5, 44, 47, 53, 55, 56, 52, 48, 42, 47, 51, 53, 55, 51, 47, 41, - 45, 50, 51, 54, 50, 44, 39, 42, 44, 49, 50, 47, 40, 36, 39, 42, 46, 46, 42, - 39, 31, 34, 38, 40, 44, 43, 39, 27, 31, 35, 39, 42, 43, 39, 40, 45, 49, 52, - 52, 48, 45, 39, 44, 47, 52, 50, 47, 42, 36, 42, 45, 48, 49, 45, 39, 35, 39, - 42, 44, 44, 41, 34, 28, 36, 39, 41, 39, 38, 35, 23, 32, 35, 36, 37, 36, 35, - 18, 29, 32, 36, 35, 36, 34, 36, 42, 44, 45, 47, 44, 38, 33, 41, 41, 45, 45, - 43, 37, 30, 39, 40, 41, 41, 39, 34, 25, 35, 37, 37, 37, 36, 30, 20, 31, 34, - 34, 31, 30, 30, 15, 26, 30, 29, 30, 29, 30, 13, 22, 28, 28, 28, 29, 28, 29, - 35, 36, 38, 39, 38, 31, 26, 34, 36, 37, 37, 35, 29, 22, 31, 34, 33, 34, 31, - 27, 18, 27, 30, 29, 30, 26, 25, 16, 20, 26, 25, 24, 21, 22, 15, 14, 22, 21, - 21, 20, 17, 14, 10, 19, 20, 20, 19, 14, 17, 25, 28, 30, 29, 26, 31, 14, 23, - 27, 28, 28, 23, 29, 14, 19, 25, 25, 24, 20, 24, 14, 13, 21, 20, 21, 13, 16, - 12, 8, 16, 16, 13, 10, 13, 9, 5, 11, 11, 12, 9, 11, 9, 6, 8, 10, 10, - 8, 10, 10, 16, 19, 21, 22, 24, 27, 10, 12, 18, 20, 21, 22, 23, 9, 8, 17, - 16, 17, 18, 18, 10, 8, 13, 12, 13, 12, 11, 8, 5, 7, 7, 5, 8, 10, 6, - 5, 2, 1, 4, 7, 9, 5, 3, 0, 2, 4, 6, 8, 9, 8, 12, 17, 21, 23, - 24, 9, 8, 11, 16, 20, 20, 20, 9, 8, 9, 13, 15, 16, 16, 8, 7, 7, 8, - 11, 11, 9, 6, 5, 5, 3, 4, 5, 8, 4, 3, 4, 4, 2, 5, 7, 3, 2, - 4, 4, 2, 4, 6, 44, 48, 53, 55, 55, 53, 49, 41, 48, 50, 54, 54, 52, 48, - 40, 44, 49, 52, 53, 49, 44, 39, 42, 47, 48, 51, 47, 42, 35, 39, 42, 45, 46, - 44, 40, 31, 34, 38, 42, 44, 43, 40, 27, 33, 36, 39, 43, 43, 40, 41, 44, 48, - 53, 53, 48, 43, 39, 45, 48, 51, 50, 47, 42, 36, 42, 46, 48, 48, 46, 39, 33, - 40, 43, 46, 45, 42, 35, 28, 36, 40, 41, 40, 38, 35, 22, 32, 35, 39, 38, 37, - 35, 18, 29, 34, 37, 35, 36, 36, 36, 41, 44, 45, 46, 44, 37, 34, 39, 43, 44, - 43, 41, 35, 29, 39, 41, 41, 40, 39, 33, 26, 37, 37, 37, 37, 36, 30, 19, 31, - 34, 34, 32, 30, 29, 15, 26, 31, 30, 30, 29, 29, 14, 21, 30, 29, 29, 28, 27, - 30, 36, 38, 38, 38, 36, 30, 25, 33, 35, 37, 35, 33, 28, 21, 30, 34, 34, 32, - 30, 26, 17, 24, 31, 30, 30, 24, 25, 15, 19, 26, 27, 24, 20, 21, 15, 14, 24, - 23, 22, 19, 17, 14, 10, 20, 22, 21, 18, 14, 16, 25, 29, 30, 27, 24, 30, 13, - 22, 27, 28, 26, 20, 28, 13, 17, 25, 24, 23, 17, 23, 13, 12, 21, 21, 19, 12, - 17, 11, 7, 17, 17, 13, 8, 13, 10, 6, 12, 13, 12, 7, 10, 9, 6, 8, 12, - 11, 7, 9, 9, 14, 19, 20, 19, 22, 26, 9, 10, 18, 18, 18, 19, 22, 9, 6, - 16, 15, 15, 16, 16, 9, 5, 12, 12, 11, 11, 10, 7, 4, 6, 7, 5, 7, 8, - 5, 3, 2, 2, 3, 5, 8, 5, 3, 2, 0, 3, 5, 7, 7, 7, 12, 16, 18, - 20, 22, 7, 7, 11, 14, 17, 17, 18, 7, 7, 9, 12, 13, 14, 14, 7, 6, 5, - 8, 9, 9, 8, 5, 4, 3, 2, 4, 5, 7, 3, 2, 5, 4, 2, 4, 6, 3, - 1, 5, 5, 1, 4, 5, 38, 42, 47, 47, 48, 47, 43, 36, 41, 44, 48, 49, 45, - 41, 34, 39, 43, 45, 47, 44, 38, 33, 36, 40, 43, 45, 41, 34, 31, 33, 37, 39, - 41, 39, 35, 26, 29, 32, 35, 39, 37, 35, 23, 28, 31, 34, 38, 38, 34, 34, 39, - 43, 47, 46, 41, 38, 34, 38, 41, 45, 44, 40, 36, 31, 35, 40, 43, 42, 39, 33, - 29, 34, 36, 40, 39, 36, 30, 24, 30, 33, 36, 35, 33, 30, 21, 27, 30, 32, 32, - 32, 29, 16, 26, 29, 31, 31, 31, 30, 31, 35, 38, 39, 39, 37, 31, 29, 35, 37, - 38, 38, 35, 30, 26, 32, 35, 35, 36, 33, 27, 22, 31, 32, 31, 32, 30, 24, 16, - 26, 27, 28, 27, 25, 24, 11, 24, 25, 26, 25, 24, 24, 11, 20, 24, 24, 24, 24, - 22, 25, 30, 30, 31, 32, 30, 24, 21, 29, 28, 30, 31, 28, 22, 18, 26, 28, 28, - 27, 24, 21, 15, 21, 24, 25, 24, 20, 20, 12, 15, 21, 20, 20, 16, 16, 11, 12, - 18, 18, 17, 15, 12, 11, 8, 17, 17, 16, 15, 9, 13, 21, 23, 24, 23, 19, 24, - 10, 19, 22, 22, 21, 16, 23, 10, 14, 19, 19, 18, 13, 17, 10, 9, 16, 16, 15, - 8, 12, 8, 4, 12, 12, 10, 5, 9, 7, 4, 9, 8, 8, 4, 6, 7, 4, 6, - 7, 7, 4, 5, 6, 12, 14, 15, 15, 17, 20, 6, 8, 12, 13, 14, 14, 16, 6, - 5, 11, 10, 11, 11, 12, 6, 4, 8, 7, 7, 7, 6, 4, 2, 2, 2, 3, 4, - 5, 2, 2, 3, 3, 2, 3, 5, 3, 2, 4, 3, 0, 3, 4, 5, 5, 10, 12, - 14, 16, 17, 5, 6, 9, 11, 12, 13, 13, 5, 6, 8, 9, 9, 10, 10, 5, 5, - 4, 5, 6, 6, 5, 3, 2, 3, 3, 1, 3, 4, 2, 3, 5, 4, 2, 2, 4, - 2, 4, 5, 4, 3, 2, 3, 31, 36, 40, 43, 43, 40, 36, 30, 33, 38, 43, 43, - 39, 35, 28, 32, 37, 39, 42, 37, 33, 28, 30, 33, 36, 40, 35, 29, 25, 27, 29, - 33, 35, 32, 29, 21, 24, 26, 30, 34, 32, 29, 20, 21, 26, 29, 32, 32, 29, 29, - 32, 36, 40, 38, 35, 33, 29, 31, 35, 38, 37, 35, 30, 26, 30, 33, 36, 36, 32, - 29, 25, 28, 30, 33, 33, 31, 24, 20, 25, 27, 29, 29, 27, 24, 18, 22, 25, 27, - 27, 27, 24, 14, 21, 24, 26, 26, 26, 24, 26, 30, 32, 33, 34, 32, 27, 25, 29, - 30, 31, 31, 30, 25, 23, 27, 29, 29, 29, 28, 22, 18, 26, 25, 26, 26, 24, 19, - 13, 22, 22, 22, 22, 21, 19, 9, 20, 20, 20, 20, 20, 19, 9, 17, 20, 18, 19, - 19, 17, 23, 24, 24, 26, 27, 25, 19, 18, 23, 23, 25, 24, 22, 17, 14, 22, 22, - 21, 22, 19, 16, 11, 18, 19, 18, 18, 16, 14, 9, 13, 15, 14, 14, 12, 11, 9, - 10, 13, 12, 12, 12, 8, 9, 7, 12, 11, 11, 11, 5, 10, 17, 17, 18, 18, 15, - 19, 7, 15, 16, 16, 16, 12, 17, 6, 12, 13, 13, 13, 9, 12, 7, 6, 10, 9, - 9, 6, 7, 5, 2, 6, 5, 5, 3, 5, 4, 2, 4, 3, 3, 3, 4, 4, 3, - 2, 2, 2, 2, 3, 4, 9, 9, 10, 11, 13, 16, 4, 7, 9, 9, 10, 11, 12, - 4, 4, 8, 7, 8, 8, 8, 4, 3, 4, 4, 4, 5, 4, 2, 1, 4, 3, 1, - 2, 3, 2, 3, 6, 4, 2, 2, 3, 2, 5, 6, 5, 3, 0, 3, 4, 5, 6, - 8, 10, 12, 13, 4, 5, 6, 8, 9, 10, 10, 4, 5, 6, 5, 6, 6, 7, 4, - 4, 6, 3, 2, 3, 3, 2, 4, 8, 5, 3, 0, 3, 3, 6, 7, 7, 4, 2, - 2, 5, 7, 7, 8, 5, 2, 2, 25, 28, 34, 37, 37, 34, 31, 24, 28, 32, 36, - 37, 32, 29, 23, 26, 30, 34, 36, 32, 27, 22, 24, 28, 31, 34, 30, 24, 19, 21, - 24, 27, 31, 28, 24, 17, 18, 21, 24, 29, 28, 24, 15, 17, 21, 24, 27, 27, 24, - 23, 27, 31, 34, 33, 30, 27, 22, 25, 29, 33, 33, 28, 25, 20, 24, 28, 31, 30, - 27, 24, 20, 22, 24, 28, 27, 26, 20, 17, 18, 21, 23, 24, 23, 20, 15, 17, 19, - 21, 22, 22, 20, 12, 16, 19, 21, 21, 21, 20, 21, 24, 26, 27, 28, 26, 22, 20, - 23, 24, 25, 26, 25, 20, 19, 21, 23, 23, 23, 22, 18, 16, 20, 20, 20, 19, 19, - 14, 10, 16, 16, 16, 16, 16, 14, 7, 16, 15, 15, 15, 15, 15, 7, 14, 14, 14, - 14, 14, 13, 18, 19, 19, 20, 21, 21, 14, 15, 17, 18, 19, 19, 18, 12, 12, 16, - 16, 16, 15, 15, 11, 8, 14, 13, 12, 12, 12, 10, 6, 10, 9, 9, 8, 8, 7, - 6, 8, 8, 7, 7, 7, 4, 7, 4, 6, 6, 6, 6, 3, 8, 11, 11, 12, 13, - 12, 14, 3, 9, 10, 10, 11, 9, 12, 4, 8, 8, 7, 7, 7, 8, 3, 4, 4, - 4, 3, 3, 3, 1, 1, 1, 1, 1, 1, 3, 2, 3, 4, 3, 2, 0, 2, 3, - 5, 5, 3, 2, 2, 2, 3, 5, 6, 7, 8, 10, 12, 3, 4, 6, 7, 7, 8, - 9, 3, 4, 4, 4, 5, 5, 6, 3, 3, 4, 3, 2, 2, 2, 1, 5, 6, 4, - 3, 2, 2, 3, 6, 8, 6, 3, 2, 1, 5, 7, 8, 7, 4, 3, 0, 5, 7, - 6, 6, 8, 9, 10, 5, 7, 6, 6, 6, 7, 7, 5, 7, 8, 4, 3, 4, 4, - 5, 7, 8, 5, 3, 2, 1, 5, 8, 9, 7, 4, 3, 0, 6, 8, 10, 9, 5, - 3, 2, 7, 9, 10, 10, 6, 4, 2, 31, 36, 39, 41, 40, 39, 36, 31, 35, 38, - 41, 41, 38, 36, 30, 33, 36, 40, 42, 39, 36, 29, 32, 36, 39, 41, 39, 38, 28, - 31, 35, 38, 42, 40, 37, 28, 30, 34, 38, 41, 42, 36, 25, 29, 33, 37, 40, 40, - 37, 29, 32, 36, 40, 38, 35, 32, 28, 32, 35, 38, 38, 34, 32, 27, 30, 34, 38, - 38, 34, 32, 25, 29, 34, 36, 37, 36, 32, 25, 29, 32, 36, 36, 36, 33, 24, 28, - 32, 35, 36, 35, 32, 21, 26, 30, 34, 34, 35, 32, 27, 31, 31, 32, 33, 30, 25, - 27, 29, 30, 30, 32, 29, 25, 24, 28, 29, 30, 30, 30, 25, 21, 27, 28, 29, 30, - 30, 25, 19, 27, 28, 28, 29, 30, 26, 15, 24, 26, 28, 28, 28, 26, 16, 22, 25, - 26, 26, 26, 25, 24, 25, 25, 25, 25, 22, 13, 22, 23, 23, 25, 24, 21, 14, 17, - 22, 22, 23, 22, 20, 15, 14, 22, 21, 22, 23, 20, 17, 15, 19, 20, 21, 21, 19, - 14, 15, 17, 19, 19, 19, 18, 10, 16, 14, 17, 17, 18, 17, 8, 12, 16, 16, 17, - 15, 10, 12, 9, 15, 15, 15, 14, 10, 13, 9, 13, 13, 13, 13, 8, 12, 9, 9, - 13, 13, 12, 9, 10, 10, 7, 11, 11, 11, 6, 8, 10, 9, 8, 9, 9, 5, 8, - 12, 11, 9, 7, 7, 4, 7, 4, 6, 6, 6, 7, 9, 10, 4, 4, 4, 5, 5, - 9, 10, 4, 2, 2, 3, 5, 7, 9, 4, 2, 1, 1, 3, 6, 8, 5, 4, 4, - 4, 4, 4, 7, 7, 6, 8, 6, 4, 4, 6, 9, 9, 9, 7, 5, 4, 5, 0, - 4, 3, 1, 4, 7, 9, 0, 4, 4, 2, 4, 6, 8, 0, 4, 5, 2, 2, 5, - 8, 0, 3, 4, 2, 2, 4, 6, 2, 4, 5, 5, 5, 4, 5, 5, 6, 8, 8, - 5, 5, 4, 8, 8, 9, 9, 6, 5, 4, 37, 41, 45, 47, 47, 45, 41, 37, 40, - 44, 46, 48, 46, 42, 36, 39, 42, 47, 47, 46, 43, 34, 37, 41, 45, 48, 46, 42, - 34, 37, 41, 45, 49, 46, 42, 33, 36, 41, 44, 47, 45, 42, 30, 35, 38, 43, 47, - 46, 42, 36, 39, 42, 45, 43, 41, 36, 34, 37, 41, 44, 44, 39, 36, 33, 36, 40, - 42, 43, 40, 36, 32, 36, 38, 43, 42, 42, 37, 30, 35, 38, 42, 41, 40, 37, 28, - 34, 38, 41, 41, 40, 37, 25, 31, 36, 40, 40, 40, 37, 33, 36, 38, 38, 37, 34, - 28, 31, 34, 36, 38, 36, 34, 28, 28, 34, 36, 36, 35, 34, 29, 25, 34, 34, 36, - 36, 34, 30, 22, 32, 34, 35, 35, 34, 30, 19, 30, 33, 33, 33, 32, 30, 18, 28, - 31, 31, 32, 32, 28, 28, 31, 31, 30, 29, 25, 16, 25, 29, 29, 30, 28, 24, 18, - 21, 28, 28, 28, 27, 23, 20, 17, 26, 29, 27, 27, 23, 23, 18, 23, 27, 27, 26, - 22, 19, 19, 20, 25, 25, 25, 21, 15, 18, 17, 23, 24, 24, 21, 11, 16, 22, 22, - 22, 16, 12, 16, 12, 19, 21, 21, 16, 11, 18, 13, 16, 19, 19, 16, 9, 15, 13, - 12, 19, 19, 15, 11, 14, 14, 10, 17, 17, 13, 8, 11, 13, 11, 14, 14, 12, 7, - 10, 14, 13, 12, 13, 11, 6, 8, 7, 11, 12, 9, 9, 11, 13, 7, 8, 10, 8, - 7, 9, 12, 7, 5, 8, 7, 6, 8, 10, 7, 4, 7, 6, 6, 8, 10, 8, 6, - 5, 5, 4, 6, 9, 9, 8, 8, 7, 5, 6, 8, 11, 9, 8, 7, 6, 5, 7, - 4, 0, 2, 4, 6, 9, 11, 4, 0, 2, 3, 5, 7, 10, 4, 0, 3, 2, 6, - 9, 10, 4, 1, 3, 2, 4, 5, 8, 4, 3, 5, 5, 5, 5, 7, 6, 6, 8, - 8, 6, 5, 6, 7, 9, 8, 8, 7, 5, 6, 36, 40, 42, 44, 44, 42, 39, 35, - 38, 42, 44, 45, 42, 38, 34, 37, 41, 44, 45, 42, 40, 33, 37, 41, 45, 46, 43, - 40, 33, 36, 40, 43, 47, 44, 39, 32, 35, 39, 43, 46, 44, 40, 30, 34, 38, 41, - 45, 44, 39, 34, 37, 40, 43, 41, 36, 34, 32, 35, 39, 42, 42, 37, 33, 31, 35, - 38, 40, 41, 37, 34, 31, 35, 37, 41, 41, 39, 34, 29, 35, 36, 40, 39, 39, 35, - 27, 33, 36, 39, 39, 38, 35, 24, 31, 35, 38, 37, 37, 35, 31, 34, 36, 35, 35, - 31, 24, 29, 33, 34, 35, 34, 31, 24, 27, 33, 34, 34, 32, 31, 26, 23, 33, 33, - 34, 33, 31, 27, 21, 31, 33, 33, 33, 29, 27, 18, 29, 32, 31, 31, 30, 28, 18, - 27, 30, 30, 31, 29, 25, 27, 29, 28, 28, 27, 22, 14, 22, 28, 27, 27, 25, 20, - 16, 19, 26, 27, 27, 25, 20, 18, 15, 24, 27, 26, 25, 20, 21, 17, 22, 25, 25, - 24, 19, 17, 17, 19, 24, 25, 23, 18, 14, 18, 16, 22, 22, 22, 18, 10, 14, 20, - 20, 20, 14, 8, 14, 11, 18, 19, 19, 14, 8, 15, 11, 14, 19, 18, 13, 7, 14, - 11, 11, 18, 18, 13, 7, 13, 13, 9, 16, 16, 12, 6, 9, 12, 11, 14, 14, 11, - 6, 7, 14, 13, 12, 12, 10, 6, 7, 6, 10, 11, 7, 5, 7, 10, 6, 7, 9, - 7, 5, 7, 9, 6, 3, 8, 6, 5, 7, 8, 6, 4, 7, 6, 4, 6, 7, 7, - 6, 5, 5, 6, 6, 7, 9, 8, 11, 11, 8, 6, 7, 11, 10, 12, 12, 10, 6, - 6, 3, 2, 0, 3, 4, 6, 8, 3, 2, 2, 2, 4, 5, 7, 3, 2, 3, 2, - 4, 6, 7, 3, 2, 6, 4, 4, 5, 6, 4, 5, 10, 11, 9, 6, 6, 6, 10, - 15, 16, 11, 7, 6, 9, 14, 17, 17, 13, 8, 6, 28, 32, 36, 38, 38, 36, 32, - 29, 31, 35, 38, 39, 36, 32, 27, 31, 34, 37, 39, 36, 33, 26, 30, 34, 37, 40, - 37, 34, 27, 30, 33, 36, 40, 38, 34, 26, 29, 32, 36, 39, 38, 34, 24, 27, 30, - 35, 37, 38, 34, 28, 30, 34, 36, 34, 30, 27, 26, 28, 32, 35, 34, 31, 27, 25, - 28, 32, 34, 34, 32, 28, 24, 28, 31, 35, 34, 32, 28, 24, 28, 31, 34, 34, 34, - 29, 23, 27, 29, 33, 33, 33, 29, 21, 25, 28, 31, 32, 31, 29, 26, 29, 29, 28, - 29, 25, 19, 25, 26, 28, 28, 28, 25, 19, 23, 26, 27, 28, 28, 25, 20, 19, 26, - 27, 28, 27, 26, 22, 17, 25, 27, 26, 26, 25, 22, 15, 25, 25, 25, 26, 24, 22, - 16, 22, 24, 24, 24, 24, 20, 22, 23, 22, 21, 21, 17, 8, 18, 22, 21, 21, 20, - 16, 10, 15, 21, 21, 21, 20, 16, 13, 12, 20, 21, 20, 19, 16, 16, 14, 18, 21, - 20, 19, 15, 12, 15, 16, 18, 18, 17, 15, 9, 16, 15, 16, 17, 16, 14, 6, 11, - 15, 15, 14, 10, 5, 8, 7, 14, 13, 13, 10, 5, 10, 8, 11, 12, 12, 10, 5, - 9, 7, 9, 12, 12, 10, 5, 8, 9, 7, 11, 11, 9, 6, 6, 10, 9, 10, 9, - 8, 6, 5, 13, 13, 13, 10, 8, 7, 5, 3, 6, 5, 4, 3, 4, 6, 3, 4, - 4, 3, 3, 4, 5, 3, 2, 2, 2, 3, 4, 6, 3, 2, 4, 4, 4, 5, 5, - 5, 6, 9, 9, 8, 7, 5, 7, 10, 16, 14, 10, 7, 6, 11, 15, 17, 15, 12, - 8, 6, 2, 4, 3, 0, 2, 3, 4, 2, 4, 4, 2, 2, 3, 5, 2, 4, 5, - 3, 2, 3, 4, 2, 6, 9, 7, 6, 5, 5, 5, 9, 13, 12, 11, 8, 6, 9, - 14, 18, 18, 13, 10, 7, 14, 18, 19, 19, 15, 11, 7, 24, 27, 30, 33, 32, 30, - 27, 24, 26, 29, 32, 33, 31, 27, 22, 25, 28, 31, 33, 31, 29, 21, 25, 28, 32, - 34, 32, 29, 22, 25, 27, 31, 35, 33, 29, 21, 24, 27, 30, 34, 33, 29, 19, 22, - 25, 29, 33, 33, 28, 21, 24, 28, 30, 29, 25, 23, 21, 24, 27, 30, 29, 25, 22, - 20, 22, 26, 29, 28, 27, 23, 20, 22, 26, 29, 28, 27, 24, 21, 23, 26, 29, 29, - 27, 23, 19, 21, 24, 28, 27, 27, 24, 16, 20, 23, 26, 26, 26, 24, 20, 22, 23, - 23, 23, 20, 15, 19, 22, 22, 23, 22, 20, 16, 19, 20, 22, 23, 22, 21, 17, 16, - 22, 23, 23, 23, 21, 18, 15, 21, 21, 21, 22, 21, 18, 13, 19, 20, 20, 21, 20, - 17, 17, 18, 19, 19, 19, 20, 17, 19, 17, 16, 17, 16, 13, 5, 16, 16, 16, 16, - 15, 12, 6, 13, 16, 15, 16, 15, 13, 9, 10, 16, 16, 15, 15, 13, 12, 11, 14, - 14, 14, 14, 12, 8, 12, 13, 13, 13, 13, 12, 6, 17, 18, 13, 12, 12, 11, 5, - 8, 10, 9, 9, 8, 3, 5, 5, 9, 8, 8, 7, 3, 6, 5, 8, 7, 7, 7, - 3, 5, 5, 6, 7, 7, 7, 5, 5, 6, 7, 7, 7, 8, 7, 5, 9, 12, 14, - 12, 9, 8, 6, 15, 18, 17, 13, 10, 8, 6, 2, 1, 1, 1, 2, 3, 3, 2, - 3, 2, 1, 1, 3, 4, 2, 3, 3, 3, 2, 3, 4, 2, 5, 7, 7, 6, 5, - 6, 5, 10, 13, 12, 11, 8, 6, 10, 15, 19, 17, 12, 9, 7, 16, 19, 21, 18, - 14, 10, 8, 4, 6, 4, 2, 0, 2, 3, 4, 6, 5, 3, 1, 2, 3, 4, 6, - 7, 5, 5, 3, 4, 4, 8, 12, 9, 8, 7, 7, 8, 12, 16, 15, 13, 10, 8, - 13, 16, 20, 21, 15, 11, 9, 18, 22, 21, 21, 17, 13, 9, 19, 23, 25, 29, 28, - 25, 22, 19, 21, 24, 27, 28, 26, 23, 17, 20, 24, 27, 30, 27, 24, 17, 20, 24, - 28, 30, 29, 25, 18, 20, 23, 27, 31, 28, 25, 16, 19, 22, 26, 29, 29, 25, 16, - 18, 22, 25, 28, 29, 26, 18, 20, 23, 25, 23, 21, 18, 16, 19, 23, 25, 25, 21, - 19, 15, 18, 21, 25, 24, 22, 20, 15, 19, 22, 25, 24, 23, 20, 16, 18, 21, 24, - 24, 23, 21, 14, 17, 20, 23, 23, 23, 20, 18, 18, 19, 22, 22, 22, 21, 15, 18, - 19, 19, 19, 16, 13, 15, 17, 18, 18, 18, 17, 13, 15, 16, 18, 18, 18, 18, 14, - 14, 17, 18, 18, 18, 18, 15, 12, 15, 17, 17, 17, 17, 15, 13, 15, 16, 17, 16, - 16, 15, 20, 19, 16, 15, 15, 15, 13, 15, 13, 12, 12, 12, 11, 2, 14, 12, 12, - 11, 11, 10, 3, 11, 11, 11, 12, 11, 11, 6, 7, 11, 11, 11, 11, 10, 9, 9, - 10, 10, 10, 10, 10, 6, 13, 14, 13, 11, 9, 9, 6, 19, 21, 16, 13, 10, 8, - 7, 6, 5, 5, 5, 4, 2, 3, 2, 4, 4, 3, 3, 2, 3, 2, 2, 2, 3, - 3, 3, 4, 2, 3, 5, 5, 6, 6, 6, 5, 10, 10, 10, 10, 8, 7, 11, 16, - 17, 15, 11, 9, 7, 18, 21, 20, 15, 13, 10, 8, 3, 4, 2, 2, 1, 2, 2, - 3, 4, 3, 2, 2, 2, 3, 3, 6, 4, 5, 5, 4, 4, 3, 8, 9, 9, 8, - 7, 7, 8, 12, 15, 14, 13, 10, 8, 13, 17, 20, 19, 14, 11, 8, 19, 22, 23, - 21, 16, 12, 9, 7, 9, 6, 3, 2, 0, 2, 7, 9, 7, 4, 3, 2, 2, 7, - 9, 9, 7, 6, 5, 5, 7, 11, 14, 12, 10, 9, 8, 10, 15, 18, 17, 15, 13, - 9, 15, 19, 22, 23, 17, 13, 10, 20, 23, 23, 24, 19, 15, 11, 15, 18, 21, 24, - 25, 22, 18, 14, 17, 20, 24, 25, 22, 20, 13, 16, 20, 23, 26, 24, 21, 12, 16, - 20, 23, 26, 24, 21, 13, 16, 19, 23, 27, 24, 21, 12, 16, 18, 22, 25, 24, 21, - 17, 16, 17, 21, 24, 24, 21, 13, 16, 19, 21, 21, 18, 15, 12, 15, 18, 20, 20, - 18, 15, 11, 14, 17, 20, 21, 19, 16, 10, 14, 18, 21, 21, 19, 17, 11, 14, 17, - 20, 20, 20, 17, 12, 13, 16, 19, 19, 19, 16, 19, 17, 16, 18, 18, 18, 17, 11, - 14, 15, 15, 16, 14, 10, 10, 13, 14, 14, 14, 13, 10, 9, 11, 13, 14, 14, 14, - 11, 9, 12, 14, 14, 14, 14, 12, 8, 11, 13, 13, 13, 13, 12, 14, 14, 14, 13, - 12, 12, 12, 22, 20, 16, 13, 11, 11, 11, 9, 9, 8, 8, 9, 9, 2, 8, 7, - 7, 7, 7, 7, 2, 6, 6, 7, 7, 7, 7, 3, 6, 6, 7, 7, 7, 7, 6, - 7, 8, 9, 9, 9, 7, 6, 14, 16, 14, 12, 10, 8, 6, 21, 22, 17, 13, 10, - 8, 7, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, - 4, 4, 3, 3, 2, 6, 6, 7, 7, 7, 6, 6, 11, 12, 11, 11, 9, 7, 13, - 17, 18, 15, 12, 10, 7, 20, 22, 21, 16, 13, 11, 8, 6, 5, 4, 3, 2, 1, - 2, 5, 7, 4, 3, 3, 2, 2, 6, 9, 6, 6, 5, 4, 4, 6, 10, 10, 10, - 9, 8, 7, 9, 14, 16, 15, 13, 11, 8, 15, 19, 22, 19, 15, 12, 9, 20, 23, - 24, 22, 16, 13, 10, 9, 11, 7, 4, 3, 2, 0, 10, 11, 9, 5, 3, 3, 3, - 9, 11, 12, 8, 7, 6, 5, 9, 13, 16, 13, 11, 10, 9, 12, 16, 20, 19, 16, - 13, 10, 17, 20, 24, 24, 18, 14, 11, 21, 25, 25, 25, 20, 16, 12, 32, 36, 39, - 42, 41, 39, 35, 31, 35, 37, 41, 41, 40, 35, 29, 33, 36, 39, 41, 39, 36, 29, - 32, 35, 39, 42, 40, 37, 29, 31, 35, 39, 42, 41, 37, 27, 31, 34, 38, 42, 40, - 36, 24, 28, 33, 37, 40, 41, 37, 30, 33, 36, 38, 38, 35, 31, 28, 31, 36, 38, - 37, 34, 32, 27, 31, 34, 37, 37, 35, 31, 25, 30, 34, 37, 36, 35, 33, 26, 29, - 33, 36, 36, 36, 33, 24, 29, 31, 35, 36, 35, 32, 21, 26, 30, 34, 34, 34, 32, - 27, 30, 31, 32, 33, 30, 24, 25, 29, 31, 32, 31, 30, 25, 25, 27, 28, 30, 31, - 30, 25, 21, 27, 28, 30, 29, 30, 26, 19, 26, 29, 30, 29, 28, 25, 15, 25, 26, - 28, 27, 27, 25, 16, 23, 24, 25, 27, 27, 25, 24, 24, 25, 25, 25, 22, 13, 21, - 23, 24, 24, 24, 21, 14, 17, 22, 22, 23, 22, 20, 15, 14, 22, 21, 22, 22, 20, - 18, 14, 19, 20, 21, 21, 19, 14, 15, 17, 19, 19, 19, 18, 11, 16, 14, 16, 18, - 18, 17, 8, 12, 16, 17, 17, 15, 10, 12, 9, 15, 15, 15, 14, 10, 13, 9, 13, - 13, 13, 12, 8, 11, 9, 10, 13, 13, 12, 9, 10, 10, 7, 11, 11, 10, 6, 8, - 10, 9, 8, 9, 9, 5, 8, 12, 11, 9, 7, 7, 4, 7, 4, 6, 6, 6, 7, - 9, 11, 4, 4, 4, 5, 6, 9, 10, 4, 2, 2, 3, 4, 7, 9, 4, 2, 1, - 1, 4, 6, 8, 5, 4, 4, 4, 4, 4, 7, 7, 6, 8, 6, 5, 4, 6, 8, - 9, 9, 7, 5, 4, 5, 0, 4, 3, 2, 4, 7, 9, 0, 4, 4, 2, 3, 7, - 9, 0, 4, 5, 2, 2, 6, 8, 0, 4, 5, 2, 2, 4, 6, 2, 4, 5, 5, - 5, 4, 5, 4, 6, 8, 8, 5, 5, 4, 8, 8, 9, 9, 6, 5, 4, 37, 41, - 45, 47, 47, 44, 41, 36, 40, 43, 47, 47, 44, 41, 35, 38, 43, 46, 47, 44, 41, - 33, 37, 41, 45, 48, 45, 42, 35, 37, 41, 45, 48, 46, 43, 33, 37, 40, 43, 47, - 46, 43, 31, 35, 39, 43, 46, 46, 43, 34, 39, 43, 44, 44, 39, 36, 34, 37, 42, - 44, 43, 41, 36, 33, 36, 40, 43, 43, 39, 36, 31, 36, 40, 43, 43, 41, 37, 30, - 36, 39, 42, 42, 42, 38, 28, 34, 37, 40, 40, 41, 37, 25, 32, 37, 40, 39, 39, - 37, 32, 36, 38, 37, 37, 34, 28, 31, 35, 37, 37, 38, 34, 28, 28, 33, 34, 36, - 36, 34, 28, 25, 34, 35, 34, 35, 34, 30, 23, 33, 35, 34, 35, 34, 29, 18, 30, - 32, 34, 34, 32, 30, 18, 28, 32, 31, 33, 32, 28, 29, 30, 31, 31, 30, 25, 16, - 25, 30, 30, 30, 28, 23, 18, 21, 28, 28, 29, 27, 22, 20, 17, 26, 28, 28, 27, - 23, 22, 18, 23, 27, 27, 27, 22, 18, 19, 20, 25, 25, 25, 21, 15, 18, 17, 22, - 23, 24, 21, 11, 16, 22, 23, 22, 17, 12, 16, 12, 20, 21, 21, 16, 11, 18, 13, - 16, 20, 19, 15, 9, 15, 12, 12, 19, 19, 15, 11, 14, 14, 10, 17, 17, 13, 8, - 11, 13, 11, 15, 15, 13, 7, 10, 14, 13, 12, 13, 11, 6, 9, 7, 11, 12, 9, - 9, 11, 13, 7, 8, 10, 8, 7, 10, 12, 7, 5, 8, 7, 6, 8, 10, 7, 4, - 7, 6, 6, 8, 10, 8, 6, 5, 5, 5, 6, 9, 9, 8, 7, 7, 5, 6, 8, - 11, 9, 8, 7, 6, 5, 7, 4, 0, 2, 4, 6, 9, 11, 4, 0, 2, 3, 5, - 7, 10, 4, 0, 3, 2, 5, 9, 10, 4, 1, 3, 2, 4, 5, 8, 4, 3, 5, - 5, 5, 5, 7, 6, 6, 8, 8, 6, 5, 6, 7, 8, 8, 8, 6, 5, 6, 39, - 41, 46, 47, 47, 45, 41, 37, 41, 43, 47, 46, 43, 40, 37, 39, 42, 46, 48, 45, - 42, 35, 38, 43, 46, 48, 46, 43, 36, 39, 43, 45, 49, 46, 44, 35, 38, 42, 45, - 48, 47, 43, 32, 35, 40, 43, 47, 47, 43, 36, 39, 43, 45, 43, 39, 36, 35, 38, - 42, 43, 44, 40, 35, 34, 37, 42, 44, 42, 40, 36, 32, 37, 41, 43, 42, 40, 37, - 31, 37, 40, 43, 43, 41, 37, 29, 35, 39, 42, 42, 40, 37, 25, 33, 38, 41, 40, - 39, 37, 35, 37, 37, 38, 38, 33, 26, 31, 36, 37, 37, 36, 33, 27, 29, 35, 37, - 37, 36, 33, 28, 25, 34, 36, 37, 36, 33, 30, 23, 34, 36, 36, 35, 32, 30, 19, - 31, 34, 35, 35, 32, 30, 19, 29, 33, 33, 33, 31, 27, 29, 31, 31, 31, 30, 24, - 16, 25, 30, 31, 30, 27, 22, 18, 21, 28, 29, 30, 27, 22, 20, 18, 26, 29, 28, - 28, 22, 23, 19, 23, 28, 28, 26, 21, 19, 19, 20, 26, 26, 26, 20, 16, 19, 17, - 24, 24, 24, 20, 12, 16, 23, 23, 22, 16, 10, 16, 13, 20, 22, 21, 15, 10, 17, - 13, 16, 21, 20, 15, 9, 16, 12, 13, 21, 19, 15, 9, 15, 14, 11, 19, 19, 13, - 7, 11, 15, 12, 16, 16, 12, 7, 9, 15, 14, 14, 15, 11, 7, 8, 7, 12, 13, - 8, 7, 9, 12, 8, 7, 12, 8, 6, 8, 10, 7, 4, 10, 7, 6, 8, 10, 7, - 5, 9, 7, 5, 7, 9, 9, 7, 7, 5, 6, 7, 8, 10, 9, 9, 10, 7, 6, - 7, 12, 10, 11, 11, 9, 6, 7, 4, 2, 2, 3, 5, 7, 9, 4, 2, 0, 3, - 5, 6, 9, 4, 2, 2, 2, 5, 8, 9, 4, 2, 5, 3, 4, 6, 8, 5, 4, - 9, 10, 8, 6, 7, 7, 8, 14, 14, 11, 7, 6, 8, 12, 15, 15, 12, 8, 6, - 31, 35, 38, 40, 41, 38, 34, 30, 34, 37, 40, 41, 37, 34, 29, 31, 36, 39, 41, - 39, 35, 28, 32, 36, 38, 42, 39, 36, 29, 32, 35, 39, 42, 40, 36, 28, 32, 34, - 38, 40, 40, 36, 25, 29, 33, 36, 40, 40, 35, 30, 33, 36, 38, 36, 32, 28, 28, - 31, 34, 37, 36, 32, 29, 27, 30, 34, 36, 36, 34, 30, 26, 30, 34, 36, 36, 34, - 30, 26, 30, 33, 36, 36, 35, 31, 24, 29, 32, 34, 35, 34, 30, 22, 26, 31, 34, - 34, 33, 30, 28, 30, 31, 31, 31, 27, 20, 26, 29, 29, 30, 29, 27, 21, 24, 29, - 29, 30, 30, 27, 22, 20, 28, 30, 30, 29, 27, 24, 18, 28, 29, 29, 29, 27, 23, - 16, 26, 28, 28, 28, 26, 23, 17, 24, 25, 26, 27, 26, 21, 24, 25, 24, 24, 22, - 18, 10, 20, 23, 23, 24, 22, 17, 12, 16, 22, 22, 22, 21, 16, 15, 13, 21, 22, - 22, 21, 17, 18, 14, 19, 22, 21, 20, 16, 14, 15, 17, 19, 20, 19, 16, 10, 17, - 15, 18, 18, 18, 16, 7, 12, 17, 16, 16, 11, 5, 11, 8, 15, 15, 15, 11, 6, - 12, 9, 12, 14, 14, 11, 5, 10, 9, 9, 14, 13, 11, 5, 10, 10, 8, 13, 12, - 10, 6, 7, 11, 10, 10, 10, 9, 5, 6, 13, 12, 11, 9, 8, 6, 5, 4, 7, - 7, 5, 4, 5, 7, 4, 5, 5, 5, 3, 5, 6, 4, 3, 4, 4, 4, 5, 6, - 4, 3, 3, 3, 4, 5, 5, 6, 5, 8, 8, 8, 6, 5, 8, 9, 14, 13, 10, - 7, 5, 10, 13, 16, 14, 11, 8, 5, 2, 3, 2, 2, 3, 4, 5, 2, 3, 3, - 0, 2, 4, 5, 2, 3, 4, 2, 2, 4, 5, 2, 5, 8, 6, 5, 5, 5, 4, - 8, 12, 12, 10, 8, 6, 7, 12, 17, 18, 13, 9, 6, 12, 17, 19, 18, 14, 10, - 7, 25, 29, 32, 35, 35, 31, 29, 24, 28, 30, 35, 35, 32, 28, 23, 26, 30, 33, - 35, 32, 30, 23, 26, 30, 33, 36, 33, 30, 24, 25, 29, 32, 36, 34, 30, 22, 25, - 28, 32, 35, 33, 30, 20, 23, 27, 31, 33, 34, 30, 24, 26, 30, 33, 30, 28, 23, - 23, 25, 28, 32, 31, 28, 24, 22, 23, 28, 31, 30, 27, 24, 21, 24, 27, 30, 30, - 28, 25, 21, 25, 27, 30, 29, 29, 25, 20, 23, 25, 29, 29, 29, 25, 17, 20, 24, - 27, 28, 27, 25, 22, 24, 25, 26, 26, 22, 17, 21, 22, 24, 25, 24, 23, 17, 20, - 22, 24, 24, 24, 22, 17, 17, 23, 24, 23, 24, 23, 18, 15, 22, 23, 22, 23, 22, - 18, 13, 20, 21, 21, 22, 21, 18, 15, 18, 19, 20, 20, 21, 17, 20, 19, 18, 18, - 19, 15, 7, 16, 18, 18, 17, 17, 14, 8, 14, 18, 17, 16, 17, 14, 10, 10, 17, - 17, 16, 16, 14, 13, 12, 16, 16, 15, 16, 13, 9, 12, 14, 14, 14, 14, 12, 6, - 15, 16, 12, 12, 13, 12, 5, 9, 11, 11, 11, 9, 4, 6, 5, 10, 9, 9, 8, - 3, 8, 5, 9, 8, 8, 8, 3, 6, 5, 7, 9, 8, 7, 4, 6, 7, 6, 7, - 7, 7, 6, 4, 9, 10, 12, 10, 8, 6, 5, 13, 16, 16, 11, 9, 7, 5, 2, - 2, 1, 2, 2, 3, 4, 2, 2, 1, 0, 2, 3, 4, 2, 2, 2, 2, 2, 3, - 4, 2, 4, 6, 6, 5, 5, 5, 4, 8, 11, 10, 9, 7, 5, 8, 13, 18, 15, - 11, 8, 6, 14, 18, 19, 17, 12, 9, 7, 4, 5, 3, 2, 1, 2, 3, 4, 5, - 4, 2, 0, 2, 4, 4, 5, 6, 4, 3, 2, 3, 4, 7, 10, 8, 7, 6, 6, - 7, 11, 14, 14, 11, 9, 7, 11, 15, 19, 19, 14, 10, 7, 16, 19, 20, 20, 16, - 12, 8, 21, 24, 27, 31, 32, 29, 25, 19, 23, 27, 30, 31, 28, 24, 18, 22, 26, - 29, 30, 28, 25, 18, 21, 24, 28, 31, 28, 25, 19, 21, 24, 27, 31, 29, 25, 17, - 20, 23, 26, 30, 29, 25, 15, 19, 22, 26, 29, 29, 26, 19, 21, 25, 29, 28, 25, - 21, 18, 20, 24, 28, 27, 24, 20, 17, 20, 22, 26, 25, 23, 21, 16, 20, 22, 25, - 25, 24, 21, 17, 19, 22, 24, 24, 24, 21, 15, 18, 21, 23, 24, 23, 21, 16, 16, - 19, 22, 22, 22, 21, 17, 19, 21, 22, 22, 20, 16, 16, 18, 19, 21, 21, 19, 14, - 16, 17, 19, 19, 19, 18, 15, 14, 18, 18, 18, 18, 18, 16, 13, 17, 18, 18, 17, - 18, 15, 11, 15, 17, 17, 17, 16, 15, 17, 16, 15, 15, 16, 16, 14, 16, 14, 14, - 14, 15, 14, 6, 14, 13, 13, 13, 13, 12, 5, 11, 12, 12, 12, 11, 11, 6, 8, - 12, 12, 12, 11, 11, 9, 9, 11, 11, 11, 10, 10, 6, 11, 11, 11, 9, 9, 9, - 4, 17, 18, 13, 10, 8, 8, 4, 7, 7, 6, 6, 7, 4, 5, 2, 5, 5, 5, - 5, 3, 5, 2, 4, 3, 3, 3, 2, 3, 2, 3, 3, 3, 4, 4, 4, 5, 8, - 8, 7, 8, 6, 4, 9, 13, 14, 12, 9, 7, 5, 16, 18, 17, 13, 10, 8, 5, - 2, 3, 2, 2, 2, 3, 4, 2, 4, 3, 2, 2, 2, 2, 2, 5, 4, 3, 2, - 2, 2, 2, 6, 7, 6, 6, 5, 5, 6, 10, 13, 11, 10, 8, 5, 11, 15, 18, - 16, 12, 9, 6, 16, 19, 19, 18, 13, 10, 7, 6, 8, 5, 3, 2, 2, 3, 6, - 7, 7, 4, 2, 0, 2, 6, 7, 8, 5, 4, 3, 3, 6, 9, 12, 9, 8, 7, - 6, 8, 12, 16, 15, 12, 10, 7, 13, 16, 20, 21, 15, 11, 8, 18, 21, 20, 21, - 16, 12, 9, 17, 20, 24, 28, 28, 25, 22, 16, 19, 23, 27, 28, 24, 20, 14, 17, - 21, 24, 26, 24, 20, 13, 17, 20, 23, 27, 24, 21, 14, 17, 20, 23, 27, 25, 21, - 12, 15, 19, 22, 26, 24, 21, 14, 14, 18, 21, 25, 24, 21, 14, 18, 22, 25, 24, - 21, 18, 13, 17, 20, 23, 23, 20, 16, 13, 15, 18, 21, 21, 19, 16, 12, 15, 18, - 20, 21, 19, 16, 12, 15, 18, 20, 20, 20, 17, 10, 13, 16, 19, 20, 19, 17, 16, - 15, 15, 18, 18, 18, 17, 13, 16, 17, 18, 19, 17, 13, 12, 14, 16, 16, 17, 15, - 11, 10, 13, 14, 14, 14, 14, 11, 10, 13, 14, 14, 14, 14, 12, 9, 12, 14, 13, - 13, 14, 12, 12, 12, 12, 12, 13, 12, 12, 18, 17, 13, 11, 11, 11, 11, 11, 10, - 10, 11, 12, 12, 5, 10, 9, 9, 9, 10, 10, 3, 8, 8, 8, 8, 7, 7, 3, - 5, 8, 7, 7, 7, 7, 5, 7, 7, 7, 6, 6, 6, 3, 12, 13, 11, 9, 7, - 6, 4, 18, 18, 14, 10, 8, 6, 4, 2, 2, 2, 3, 3, 4, 4, 1, 1, 0, - 1, 2, 2, 3, 1, 2, 2, 2, 1, 1, 2, 1, 5, 5, 4, 4, 4, 3, 5, - 10, 9, 8, 8, 6, 4, 11, 14, 14, 12, 10, 7, 5, 17, 19, 17, 13, 10, 8, - 5, 5, 5, 4, 3, 3, 3, 4, 5, 7, 4, 4, 3, 1, 2, 5, 8, 6, 4, - 3, 2, 2, 5, 9, 9, 7, 6, 6, 5, 9, 12, 14, 12, 10, 8, 5, 12, 16, - 19, 16, 12, 9, 6, 17, 19, 20, 18, 14, 10, 7, 9, 10, 7, 5, 3, 2, 3, - 10, 10, 9, 5, 4, 2, 0, 9, 10, 11, 7, 5, 4, 3, 10, 11, 14, 10, 8, - 7, 6, 10, 14, 17, 16, 13, 10, 8, 14, 17, 21, 20, 15, 11, 8, 18, 20, 22, - 22, 17, 12, 9, 32, 35, 38, 41, 41, 38, 36, 30, 34, 37, 41, 41, 39, 37, 29, - 32, 37, 40, 42, 39, 37, 28, 32, 36, 39, 42, 39, 37, 28, 31, 35, 39, 42, 41, - 36, 28, 30, 34, 38, 41, 40, 36, 25, 29, 33, 37, 40, 39, 37, 29, 33, 36, 39, - 38, 35, 32, 28, 32, 35, 39, 37, 35, 31, 27, 31, 34, 37, 37, 35, 31, 25, 30, - 33, 36, 36, 36, 33, 25, 30, 33, 36, 35, 36, 32, 24, 27, 31, 35, 36, 35, 33, - 21, 26, 30, 34, 34, 34, 32, 27, 31, 31, 32, 32, 30, 25, 26, 29, 31, 32, 32, - 30, 25, 24, 28, 30, 30, 30, 30, 24, 21, 28, 28, 30, 30, 29, 26, 18, 26, 28, - 29, 29, 29, 25, 15, 25, 27, 27, 28, 28, 25, 16, 22, 25, 26, 26, 27, 25, 24, - 25, 24, 25, 25, 23, 13, 20, 23, 24, 24, 24, 21, 14, 18, 22, 23, 22, 22, 20, - 15, 14, 21, 21, 22, 22, 20, 18, 14, 19, 20, 21, 21, 19, 14, 15, 17, 18, 19, - 19, 18, 11, 16, 14, 16, 17, 18, 17, 8, 12, 16, 17, 17, 15, 10, 13, 9, 15, - 15, 15, 13, 10, 14, 9, 13, 13, 13, 12, 8, 12, 9, 9, 12, 12, 12, 9, 10, - 10, 7, 11, 11, 10, 6, 8, 10, 9, 8, 8, 9, 5, 8, 12, 10, 9, 7, 7, - 4, 7, 4, 6, 6, 6, 7, 9, 11, 4, 4, 4, 5, 6, 9, 10, 4, 2, 2, - 3, 4, 7, 9, 4, 2, 1, 1, 3, 6, 8, 5, 4, 4, 4, 4, 4, 7, 7, - 6, 8, 6, 5, 4, 6, 9, 9, 9, 7, 5, 4, 6, 0, 4, 3, 2, 4, 7, - 9, 0, 4, 4, 2, 4, 6, 8, 0, 4, 5, 2, 2, 6, 8, 0, 4, 4, 2, - 2, 4, 6, 2, 4, 5, 5, 5, 4, 5, 4, 6, 8, 8, 6, 5, 4, 8, 8, - 9, 9, 6, 5, 4, 38, 41, 44, 47, 47, 44, 41, 37, 40, 43, 47, 47, 45, 42, - 35, 39, 42, 46, 47, 45, 42, 34, 37, 42, 45, 48, 46, 42, 34, 38, 41, 45, 49, - 46, 43, 34, 36, 41, 44, 48, 46, 42, 32, 35, 38, 42, 46, 46, 42, 35, 39, 43, - 44, 42, 39, 36, 34, 38, 41, 45, 43, 39, 36, 33, 36, 39, 43, 42, 40, 36, 31, - 36, 39, 43, 41, 40, 37, 31, 35, 39, 43, 41, 41, 37, 28, 34, 38, 41, 40, 40, - 37, 24, 31, 36, 39, 40, 39, 37, 33, 36, 38, 38, 37, 34, 27, 32, 34, 37, 38, - 37, 33, 28, 28, 33, 36, 35, 36, 34, 28, 25, 34, 35, 36, 35, 34, 30, 22, 33, - 35, 35, 35, 33, 30, 19, 31, 32, 33, 33, 32, 29, 19, 28, 31, 32, 33, 31, 28, - 29, 31, 30, 30, 29, 25, 16, 24, 29, 29, 29, 28, 24, 18, 21, 28, 29, 29, 27, - 23, 19, 17, 26, 27, 28, 28, 23, 22, 18, 23, 27, 26, 26, 22, 19, 19, 19, 25, - 25, 24, 22, 14, 19, 17, 23, 24, 24, 20, 11, 16, 22, 21, 22, 17, 12, 16, 13, - 20, 21, 20, 16, 12, 17, 12, 16, 20, 19, 16, 9, 15, 12, 12, 19, 19, 15, 10, - 14, 14, 10, 18, 17, 14, 8, 11, 14, 11, 15, 15, 12, 7, 10, 15, 13, 12, 13, - 11, 6, 9, 7, 11, 12, 9, 9, 10, 13, 7, 8, 10, 8, 7, 10, 12, 7, 5, - 8, 7, 6, 8, 10, 7, 5, 7, 6, 6, 8, 9, 8, 6, 6, 5, 5, 6, 9, - 9, 8, 7, 7, 5, 6, 8, 11, 9, 8, 7, 6, 5, 7, 4, 0, 2, 4, 6, - 9, 11, 4, 0, 2, 3, 5, 7, 10, 4, 0, 3, 2, 5, 9, 9, 4, 1, 3, - 2, 4, 5, 8, 4, 3, 5, 5, 5, 5, 7, 6, 6, 8, 8, 6, 5, 6, 7, - 9, 8, 8, 6, 5, 6, 41, 44, 47, 50, 50, 47, 43, 40, 43, 48, 50, 51, 47, - 44, 39, 42, 46, 48, 51, 46, 44, 37, 41, 45, 48, 51, 48, 45, 38, 41, 45, 49, - 51, 49, 45, 37, 40, 44, 47, 51, 49, 46, 34, 38, 42, 46, 49, 48, 44, 39, 42, - 46, 48, 46, 42, 38, 38, 41, 45, 48, 46, 42, 37, 37, 40, 43, 46, 45, 43, 39, - 33, 40, 43, 46, 46, 43, 39, 33, 40, 43, 45, 45, 44, 39, 30, 38, 40, 44, 44, - 43, 38, 27, 36, 40, 43, 42, 41, 39, 37, 40, 41, 40, 40, 37, 29, 34, 39, 39, - 41, 38, 36, 29, 31, 38, 40, 38, 38, 36, 30, 27, 37, 38, 40, 37, 36, 32, 25, - 35, 38, 38, 37, 35, 32, 21, 33, 36, 36, 36, 34, 32, 21, 30, 35, 35, 36, 33, - 29, 31, 34, 33, 34, 31, 27, 19, 26, 32, 34, 33, 31, 25, 20, 23, 30, 32, 31, - 30, 24, 22, 19, 27, 31, 32, 29, 23, 25, 20, 25, 31, 30, 28, 22, 21, 21, 22, - 29, 28, 27, 22, 17, 21, 18, 26, 27, 26, 21, 14, 18, 26, 26, 25, 18, 13, 19, - 14, 22, 25, 24, 17, 12, 20, 14, 18, 23, 23, 16, 10, 18, 14, 15, 22, 22, 15, - 10, 17, 15, 12, 21, 20, 14, 9, 13, 16, 13, 18, 18, 14, 8, 10, 16, 14, 15, - 17, 12, 8, 9, 9, 13, 15, 10, 9, 11, 15, 9, 9, 14, 10, 8, 10, 13, 9, - 5, 12, 8, 7, 9, 11, 9, 6, 11, 8, 7, 9, 10, 11, 8, 9, 6, 6, 7, - 9, 11, 9, 8, 8, 6, 7, 9, 12, 11, 9, 9, 8, 6, 7, 5, 3, 3, 5, - 7, 9, 12, 5, 3, 2, 4, 6, 8, 11, 5, 3, 0, 4, 7, 9, 11, 5, 3, - 3, 3, 4, 7, 9, 6, 4, 7, 8, 7, 6, 8, 7, 6, 10, 11, 8, 6, 7, - 9, 10, 11, 11, 9, 7, 6, 34, 38, 42, 44, 45, 41, 37, 32, 37, 41, 44, 44, - 41, 37, 31, 35, 39, 43, 43, 41, 36, 30, 33, 37, 40, 43, 40, 37, 30, 33, 37, - 40, 43, 40, 38, 29, 32, 35, 40, 42, 41, 36, 26, 31, 35, 38, 42, 41, 38, 32, - 35, 39, 43, 40, 36, 33, 31, 34, 38, 41, 40, 37, 32, 30, 32, 36, 39, 38, 35, - 30, 27, 31, 34, 37, 38, 35, 31, 27, 31, 34, 38, 37, 36, 31, 25, 30, 33, 36, - 37, 35, 31, 21, 27, 32, 35, 35, 34, 31, 29, 33, 34, 35, 33, 31, 25, 27, 31, - 33, 35, 33, 30, 24, 24, 30, 31, 32, 31, 29, 23, 21, 30, 30, 30, 30, 28, 24, - 19, 28, 30, 30, 29, 28, 24, 16, 26, 28, 28, 29, 26, 25, 16, 24, 27, 26, 28, - 26, 22, 23, 27, 26, 28, 27, 22, 15, 20, 25, 26, 26, 26, 21, 15, 17, 23, 24, - 24, 23, 18, 16, 14, 23, 23, 23, 21, 18, 19, 15, 19, 23, 22, 21, 17, 15, 15, - 17, 21, 21, 20, 16, 11, 16, 15, 19, 19, 20, 16, 7, 13, 19, 18, 19, 15, 9, - 15, 9, 17, 18, 17, 14, 8, 15, 9, 13, 16, 15, 12, 6, 12, 9, 10, 15, 14, - 11, 6, 10, 10, 8, 14, 13, 10, 5, 7, 11, 9, 11, 11, 9, 4, 5, 12, 11, - 9, 10, 8, 4, 5, 4, 9, 9, 8, 6, 8, 11, 4, 6, 8, 7, 5, 7, 9, - 4, 3, 5, 5, 3, 5, 6, 4, 3, 4, 4, 3, 4, 5, 6, 4, 5, 5, 6, - 4, 5, 7, 6, 11, 10, 7, 5, 5, 9, 11, 12, 12, 9, 6, 4, 2, 2, 2, - 3, 5, 7, 8, 2, 2, 2, 2, 4, 5, 7, 2, 2, 3, 0, 3, 5, 6, 2, - 3, 6, 4, 3, 3, 4, 3, 5, 9, 10, 8, 5, 4, 5, 9, 15, 15, 11, 7, - 4, 9, 14, 17, 17, 12, 8, 5, 27, 33, 36, 39, 39, 37, 33, 27, 30, 35, 38, - 40, 37, 32, 25, 29, 34, 37, 38, 34, 30, 25, 27, 32, 35, 37, 34, 32, 25, 27, - 30, 34, 37, 35, 31, 24, 26, 29, 33, 36, 34, 31, 21, 24, 28, 32, 35, 34, 32, - 26, 29, 34, 37, 35, 32, 28, 24, 29, 32, 35, 36, 32, 27, 24, 26, 30, 33, 33, - 30, 25, 23, 25, 28, 31, 31, 29, 26, 23, 25, 28, 31, 31, 28, 26, 21, 24, 27, - 30, 30, 29, 26, 18, 22, 25, 28, 29, 28, 26, 24, 26, 29, 30, 30, 27, 22, 22, - 25, 28, 28, 29, 26, 20, 21, 24, 26, 26, 26, 25, 18, 17, 24, 24, 24, 25, 24, - 19, 16, 23, 23, 23, 23, 22, 19, 13, 21, 22, 22, 22, 20, 19, 14, 19, 21, 21, - 21, 21, 17, 21, 22, 21, 22, 23, 20, 13, 17, 20, 21, 21, 21, 18, 12, 14, 19, - 19, 18, 19, 15, 12, 11, 19, 17, 17, 17, 14, 13, 12, 16, 16, 17, 16, 13, 10, - 13, 14, 15, 15, 15, 13, 7, 14, 13, 13, 13, 13, 13, 4, 9, 14, 14, 15, 13, - 9, 13, 6, 13, 12, 13, 12, 6, 12, 6, 10, 10, 10, 9, 4, 8, 6, 7, 9, - 9, 8, 4, 6, 7, 5, 8, 7, 7, 3, 4, 8, 7, 8, 7, 6, 3, 4, 10, - 11, 11, 8, 5, 4, 3, 2, 4, 5, 5, 5, 7, 9, 2, 2, 3, 4, 4, 5, - 7, 2, 0, 1, 1, 2, 3, 4, 2, 2, 3, 2, 2, 2, 3, 4, 5, 8, 7, - 6, 4, 3, 5, 9, 14, 12, 8, 5, 3, 10, 13, 16, 13, 9, 6, 3, 3, 6, - 4, 2, 5, 6, 7, 2, 5, 5, 2, 3, 4, 5, 3, 6, 7, 3, 0, 3, 4, - 2, 5, 7, 5, 4, 3, 3, 4, 7, 11, 11, 8, 6, 4, 7, 11, 15, 15, 11, - 7, 4, 12, 16, 16, 16, 12, 8, 5, 24, 29, 32, 36, 35, 32, 29, 23, 27, 31, - 35, 34, 31, 28, 21, 25, 29, 33, 34, 30, 26, 20, 22, 26, 30, 32, 29, 27, 19, - 22, 24, 28, 32, 30, 27, 18, 21, 23, 27, 31, 30, 27, 16, 19, 23, 26, 29, 30, - 26, 22, 25, 28, 33, 31, 28, 25, 20, 24, 28, 31, 31, 27, 24, 19, 22, 26, 30, - 29, 26, 22, 18, 20, 23, 26, 26, 25, 21, 18, 20, 22, 26, 26, 25, 22, 16, 19, - 22, 25, 24, 24, 22, 13, 17, 20, 23, 23, 24, 22, 19, 22, 24, 26, 26, 24, 20, - 18, 21, 23, 24, 25, 23, 18, 17, 20, 22, 21, 22, 21, 16, 15, 19, 19, 19, 20, - 19, 15, 13, 17, 19, 18, 18, 18, 15, 11, 16, 17, 17, 18, 17, 16, 13, 14, 15, - 16, 16, 17, 14, 17, 17, 17, 18, 19, 18, 10, 15, 16, 17, 17, 17, 15, 9, 11, - 15, 15, 15, 14, 13, 8, 8, 14, 13, 12, 12, 11, 10, 9, 12, 12, 11, 11, 10, - 6, 10, 10, 10, 10, 10, 9, 3, 13, 14, 10, 8, 9, 8, 3, 7, 9, 10, 10, - 11, 8, 10, 3, 7, 8, 9, 9, 5, 9, 3, 6, 6, 6, 6, 3, 5, 3, 4, - 4, 4, 3, 2, 3, 5, 5, 4, 4, 4, 3, 3, 7, 9, 10, 8, 6, 4, 2, - 11, 14, 13, 10, 7, 4, 2, 0, 2, 2, 3, 4, 6, 8, 0, 4, 3, 3, 3, - 4, 5, 0, 4, 3, 2, 1, 2, 3, 0, 5, 5, 3, 3, 2, 2, 3, 7, 9, - 8, 7, 4, 2, 7, 12, 15, 12, 9, 5, 3, 12, 15, 16, 14, 10, 7, 4, 6, - 9, 6, 3, 3, 5, 6, 6, 9, 8, 4, 2, 3, 4, 6, 9, 11, 5, 3, 0, - 3, 6, 7, 9, 6, 4, 4, 3, 6, 9, 12, 12, 9, 6, 4, 9, 13, 16, 16, - 11, 8, 4, 14, 17, 17, 17, 13, 9, 5, 20, 23, 27, 31, 30, 28, 24, 19, 22, - 26, 31, 31, 27, 24, 17, 21, 25, 28, 29, 26, 22, 16, 19, 22, 25, 27, 24, 21, - 14, 17, 20, 23, 27, 25, 22, 14, 16, 19, 23, 26, 25, 21, 11, 14, 18, 22, 25, - 25, 22, 17, 20, 25, 29, 28, 25, 21, 16, 20, 24, 28, 27, 23, 20, 15, 18, 22, - 24, 24, 22, 18, 14, 16, 19, 21, 21, 19, 17, 13, 16, 18, 20, 20, 21, 17, 11, - 14, 17, 20, 20, 20, 17, 12, 12, 16, 19, 19, 18, 17, 15, 18, 21, 22, 23, 21, - 16, 14, 17, 19, 20, 21, 20, 15, 13, 16, 18, 18, 18, 17, 13, 12, 14, 14, 14, - 15, 15, 12, 10, 13, 14, 14, 14, 14, 12, 9, 11, 12, 12, 13, 12, 12, 13, 12, - 11, 11, 11, 11, 11, 13, 13, 13, 14, 15, 15, 8, 11, 11, 12, 13, 13, 13, 7, - 9, 10, 11, 10, 10, 10, 6, 5, 9, 8, 7, 7, 7, 6, 7, 7, 7, 7, 6, - 6, 3, 9, 9, 8, 6, 5, 5, 2, 13, 13, 9, 7, 5, 4, 2, 4, 5, 5, - 6, 7, 7, 8, 1, 3, 4, 5, 5, 5, 6, 1, 1, 2, 2, 2, 2, 3, 1, - 3, 2, 1, 2, 1, 2, 3, 6, 6, 5, 5, 3, 2, 8, 11, 11, 9, 6, 4, - 2, 12, 14, 13, 10, 8, 6, 3, 5, 5, 4, 4, 4, 6, 7, 5, 7, 4, 4, - 4, 3, 4, 5, 7, 5, 4, 2, 1, 2, 5, 7, 6, 5, 3, 3, 2, 6, 9, - 11, 9, 7, 6, 3, 9, 12, 15, 13, 9, 6, 4, 13, 15, 16, 14, 10, 7, 4, - 8, 10, 7, 4, 4, 5, 5, 8, 10, 9, 5, 3, 3, 3, 8, 10, 11, 6, 4, - 3, 0, 8, 9, 11, 7, 5, 4, 3, 8, 10, 14, 13, 9, 7, 5, 11, 14, 17, - 16, 12, 8, 6, 14, 16, 17, 17, 13, 9, 6, 32, 35, 38, 42, 42, 39, 35, 31, - 35, 38, 41, 41, 39, 37, 29, 33, 37, 40, 41, 39, 37, 29, 31, 35, 38, 42, 39, - 37, 28, 31, 35, 39, 42, 40, 37, 27, 31, 35, 37, 41, 40, 36, 24, 28, 33, 36, - 41, 39, 36, 29, 33, 37, 39, 38, 34, 32, 29, 32, 35, 38, 37, 35, 31, 27, 30, - 33, 38, 37, 34, 32, 26, 29, 33, 36, 36, 35, 33, 26, 29, 33, 35, 36, 36, 33, - 23, 28, 31, 35, 35, 35, 33, 21, 25, 29, 33, 34, 34, 32, 27, 31, 32, 32, 33, - 30, 24, 26, 28, 32, 31, 32, 29, 25, 24, 28, 29, 30, 30, 29, 24, 21, 28, 28, - 29, 30, 30, 26, 19, 26, 29, 28, 29, 28, 26, 15, 24, 27, 27, 28, 27, 26, 16, - 22, 25, 25, 27, 26, 25, 24, 25, 25, 25, 25, 22, 13, 21, 23, 24, 24, 24, 21, - 14, 18, 22, 23, 23, 22, 20, 15, 13, 22, 22, 22, 23, 20, 17, 15, 20, 21, 21, - 21, 19, 14, 15, 17, 19, 19, 19, 18, 11, 16, 14, 16, 17, 18, 17, 8, 12, 17, - 16, 17, 14, 10, 13, 9, 15, 15, 15, 14, 10, 14, 9, 12, 13, 13, 13, 8, 12, - 9, 10, 13, 12, 12, 9, 10, 10, 7, 11, 11, 10, 6, 8, 10, 9, 8, 9, 9, - 5, 8, 12, 10, 9, 7, 7, 4, 7, 4, 6, 6, 6, 7, 9, 10, 4, 4, 4, - 5, 5, 9, 10, 4, 2, 2, 3, 4, 7, 9, 4, 2, 1, 1, 4, 6, 8, 5, - 4, 4, 4, 4, 4, 7, 7, 6, 8, 6, 4, 4, 6, 9, 9, 8, 7, 5, 4, - 5, 0, 4, 3, 2, 4, 7, 9, 0, 4, 4, 2, 4, 6, 8, 0, 4, 5, 2, - 2, 6, 8, 0, 4, 4, 2, 2, 4, 6, 2, 4, 6, 5, 5, 4, 5, 4, 6, - 8, 8, 6, 5, 4, 8, 8, 9, 9, 6, 5, 4, 38, 42, 46, 49, 49, 46, 42, - 37, 41, 46, 48, 50, 45, 42, 36, 39, 44, 47, 48, 45, 40, 34, 38, 41, 45, 48, - 44, 41, 34, 37, 41, 45, 48, 45, 41, 32, 37, 40, 43, 47, 46, 42, 30, 34, 39, - 43, 46, 46, 42, 36, 40, 44, 46, 44, 41, 37, 34, 38, 42, 45, 45, 40, 37, 33, - 37, 42, 43, 44, 41, 38, 30, 36, 39, 42, 40, 39, 37, 30, 35, 38, 42, 42, 40, - 36, 27, 33, 36, 40, 41, 39, 38, 24, 31, 35, 39, 39, 37, 37, 32, 36, 39, 39, - 39, 36, 29, 32, 35, 37, 39, 37, 35, 29, 28, 34, 36, 37, 36, 35, 28, 25, 34, - 33, 34, 35, 33, 29, 22, 32, 34, 34, 34, 33, 30, 18, 29, 31, 33, 33, 32, 29, - 17, 27, 30, 31, 32, 31, 27, 28, 31, 32, 31, 31, 27, 19, 24, 30, 31, 31, 30, - 25, 19, 20, 27, 29, 28, 28, 24, 21, 16, 26, 27, 27, 26, 22, 22, 17, 22, 26, - 26, 25, 22, 18, 18, 19, 24, 24, 24, 21, 14, 17, 15, 22, 23, 23, 20, 11, 15, - 22, 23, 24, 18, 14, 19, 12, 20, 22, 21, 18, 13, 19, 12, 16, 19, 19, 17, 10, - 16, 12, 12, 18, 18, 15, 10, 13, 13, 9, 17, 16, 13, 8, 10, 12, 10, 14, 14, - 12, 7, 10, 13, 12, 11, 12, 10, 6, 8, 7, 11, 13, 11, 9, 12, 15, 7, 7, - 11, 10, 8, 11, 13, 7, 5, 9, 8, 7, 8, 11, 7, 4, 7, 6, 7, 9, 9, - 7, 5, 5, 4, 4, 6, 8, 8, 7, 6, 6, 4, 5, 8, 10, 8, 8, 6, 5, - 4, 6, 4, 1, 2, 6, 8, 10, 13, 4, 1, 2, 5, 7, 9, 10, 4, 1, 3, - 3, 5, 7, 9, 4, 0, 3, 1, 3, 5, 7, 4, 2, 4, 4, 4, 4, 6, 5, - 5, 7, 7, 5, 4, 6, 7, 7, 7, 7, 5, 4, 5, 45, 49, 52, 55, 56, 52, - 48, 43, 47, 51, 55, 54, 51, 47, 41, 45, 50, 52, 53, 50, 46, 40, 44, 47, 51, - 52, 49, 46, 38, 41, 45, 49, 52, 50, 46, 37, 41, 44, 48, 51, 50, 46, 34, 39, - 43, 47, 50, 49, 47, 42, 45, 49, 53, 51, 48, 43, 40, 45, 49, 53, 51, 47, 42, - 37, 43, 47, 51, 49, 46, 40, 35, 40, 44, 48, 46, 45, 40, 33, 41, 44, 46, 45, - 45, 40, 30, 39, 42, 45, 45, 44, 40, 26, 36, 40, 44, 43, 42, 40, 38, 43, 45, - 46, 45, 42, 34, 34, 41, 44, 44, 44, 40, 34, 31, 40, 42, 41, 41, 39, 33, 28, - 37, 39, 39, 38, 36, 33, 24, 36, 38, 40, 38, 35, 33, 21, 32, 37, 37, 37, 34, - 33, 19, 30, 34, 35, 35, 34, 30, 31, 37, 38, 37, 36, 32, 25, 27, 34, 36, 35, - 35, 30, 25, 24, 31, 35, 34, 33, 27, 25, 20, 28, 31, 32, 30, 25, 26, 20, 25, - 31, 31, 29, 23, 22, 21, 21, 29, 29, 28, 23, 19, 20, 17, 26, 28, 27, 22, 14, - 18, 27, 29, 29, 23, 19, 25, 15, 23, 27, 27, 22, 16, 25, 15, 19, 25, 25, 20, - 13, 20, 15, 15, 23, 23, 17, 11, 17, 15, 12, 21, 21, 15, 10, 14, 16, 12, 18, - 19, 15, 8, 12, 15, 13, 14, 17, 13, 8, 12, 10, 14, 19, 15, 13, 16, 21, 10, - 10, 17, 13, 12, 14, 18, 10, 6, 15, 11, 9, 11, 14, 10, 5, 11, 8, 7, 10, - 11, 10, 6, 9, 6, 5, 8, 10, 10, 8, 6, 5, 4, 6, 10, 11, 9, 7, 5, - 4, 6, 8, 5, 3, 6, 9, 12, 14, 16, 5, 3, 5, 8, 10, 12, 14, 5, 3, - 3, 6, 7, 9, 11, 5, 3, 0, 3, 6, 10, 10, 5, 3, 3, 3, 3, 5, 8, - 6, 5, 5, 6, 4, 5, 7, 8, 6, 6, 6, 5, 4, 6, 38, 43, 47, 49, 51, - 47, 43, 36, 41, 43, 50, 49, 46, 41, 35, 39, 44, 46, 47, 45, 39, 34, 37, 40, - 44, 46, 42, 38, 31, 34, 38, 42, 44, 42, 38, 30, 34, 36, 40, 44, 43, 37, 28, - 31, 35, 39, 42, 42, 38, 34, 40, 44, 47, 45, 42, 38, 34, 38, 42, 46, 45, 41, - 37, 32, 36, 40, 43, 43, 39, 34, 31, 34, 37, 40, 39, 38, 33, 27, 32, 35, 38, - 38, 37, 33, 24, 32, 34, 37, 37, 36, 33, 20, 29, 33, 36, 36, 35, 34, 33, 36, - 38, 38, 39, 36, 30, 29, 34, 38, 39, 39, 35, 29, 26, 33, 36, 36, 36, 34, 27, - 23, 31, 32, 33, 33, 31, 26, 19, 29, 32, 32, 31, 29, 25, 15, 28, 30, 31, 31, - 28, 25, 15, 25, 28, 29, 29, 27, 24, 26, 30, 31, 31, 32, 28, 21, 22, 29, 30, - 31, 30, 25, 20, 18, 26, 28, 29, 27, 23, 20, 16, 22, 25, 25, 25, 19, 20, 14, - 19, 25, 24, 23, 17, 16, 15, 16, 22, 22, 21, 18, 12, 15, 13, 20, 20, 20, 17, - 9, 14, 22, 23, 24, 20, 15, 20, 10, 19, 21, 22, 18, 13, 21, 11, 14, 19, 19, - 16, 10, 16, 10, 9, 17, 16, 12, 7, 12, 10, 7, 15, 15, 11, 7, 9, 11, 8, - 12, 12, 10, 5, 7, 11, 9, 10, 11, 9, 4, 6, 5, 11, 14, 12, 11, 13, 17, - 5, 7, 12, 11, 10, 11, 14, 6, 3, 9, 8, 7, 8, 10, 5, 3, 6, 5, 4, - 5, 7, 5, 3, 4, 3, 2, 4, 6, 6, 5, 7, 6, 4, 3, 7, 8, 7, 8, - 8, 5, 3, 4, 2, 2, 4, 7, 9, 12, 13, 2, 2, 3, 6, 8, 9, 10, 2, - 2, 3, 4, 5, 6, 8, 2, 1, 3, 0, 3, 5, 6, 2, 1, 5, 6, 4, 3, - 5, 3, 5, 11, 11, 7, 3, 4, 5, 9, 12, 13, 8, 4, 3, 32, 37, 41, 44, - 43, 41, 38, 30, 35, 39, 44, 44, 41, 36, 30, 34, 39, 41, 42, 38, 34, 28, 32, - 35, 38, 41, 37, 32, 26, 29, 31, 35, 38, 36, 32, 24, 27, 30, 34, 38, 36, 33, - 22, 25, 29, 34, 36, 36, 32, 30, 35, 38, 41, 41, 37, 33, 30, 32, 36, 40, 38, - 36, 31, 27, 31, 35, 38, 37, 34, 30, 25, 29, 32, 35, 35, 32, 27, 23, 26, 30, - 32, 32, 31, 28, 21, 25, 28, 30, 31, 30, 27, 18, 23, 27, 30, 29, 29, 28, 27, - 31, 33, 34, 35, 33, 26, 25, 29, 31, 33, 33, 30, 24, 23, 28, 31, 30, 31, 29, - 23, 19, 26, 27, 26, 28, 26, 21, 15, 24, 25, 25, 25, 24, 21, 13, 23, 24, 23, - 23, 23, 21, 12, 21, 22, 22, 23, 23, 19, 22, 25, 26, 27, 27, 25, 18, 19, 24, - 24, 25, 25, 22, 17, 15, 22, 23, 23, 22, 19, 16, 12, 19, 19, 19, 20, 16, 16, - 11, 16, 18, 17, 17, 14, 12, 12, 13, 16, 16, 16, 13, 9, 12, 11, 15, 14, 15, - 13, 6, 10, 17, 18, 18, 17, 13, 18, 7, 16, 16, 17, 16, 10, 17, 7, 12, 15, - 14, 13, 8, 12, 7, 7, 11, 10, 10, 5, 8, 7, 4, 9, 9, 8, 4, 5, 7, - 6, 6, 7, 6, 3, 5, 9, 8, 7, 5, 5, 2, 4, 3, 8, 9, 9, 9, 11, - 15, 3, 6, 7, 8, 8, 9, 11, 3, 2, 5, 4, 6, 6, 7, 3, 1, 1, 1, - 3, 3, 4, 2, 2, 3, 3, 2, 2, 4, 4, 5, 9, 8, 4, 2, 5, 6, 9, - 11, 9, 6, 2, 3, 2, 4, 4, 6, 8, 10, 11, 2, 4, 4, 5, 7, 8, 8, - 2, 4, 5, 3, 4, 4, 5, 2, 3, 7, 3, 0, 3, 4, 1, 4, 7, 7, 5, - 2, 3, 3, 8, 11, 12, 7, 3, 2, 8, 12, 13, 12, 8, 4, 2, 27, 32, 36, - 39, 40, 36, 33, 27, 30, 35, 39, 38, 35, 32, 25, 29, 33, 37, 38, 34, 30, 25, - 26, 30, 34, 36, 32, 27, 21, 24, 27, 30, 34, 31, 27, 19, 22, 25, 28, 32, 31, - 28, 18, 20, 24, 27, 30, 31, 27, 26, 29, 34, 37, 35, 33, 28, 24, 27, 31, 35, - 36, 31, 28, 23, 26, 30, 33, 32, 29, 24, 21, 24, 28, 30, 29, 28, 23, 19, 21, - 24, 26, 26, 26, 22, 17, 20, 22, 25, 26, 25, 22, 14, 18, 22, 25, 24, 24, 22, - 23, 26, 28, 29, 31, 28, 24, 22, 25, 27, 28, 28, 27, 21, 20, 25, 25, 26, 26, - 25, 19, 17, 22, 22, 22, 22, 22, 17, 13, 19, 20, 19, 20, 19, 16, 10, 18, 19, - 19, 18, 18, 17, 10, 15, 17, 17, 18, 17, 15, 20, 21, 21, 22, 23, 22, 15, 17, - 20, 19, 21, 21, 20, 14, 13, 19, 19, 18, 18, 17, 13, 9, 16, 15, 15, 14, 13, - 12, 8, 13, 13, 12, 12, 11, 8, 9, 11, 11, 11, 11, 10, 6, 10, 8, 9, 9, - 10, 9, 4, 8, 13, 13, 14, 15, 12, 15, 5, 12, 12, 13, 13, 9, 13, 5, 10, - 10, 9, 10, 7, 9, 5, 5, 6, 6, 6, 3, 5, 4, 2, 4, 3, 3, 3, 3, - 5, 5, 5, 4, 2, 2, 4, 6, 7, 7, 5, 3, 1, 3, 2, 4, 6, 7, 8, - 10, 12, 2, 3, 5, 6, 7, 8, 9, 2, 3, 4, 4, 4, 5, 6, 2, 2, 2, - 2, 1, 2, 3, 2, 3, 6, 4, 3, 1, 3, 3, 7, 10, 8, 5, 2, 3, 6, - 9, 10, 9, 6, 3, 2, 4, 6, 5, 5, 7, 9, 10, 4, 6, 6, 5, 6, 7, - 7, 3, 5, 7, 3, 3, 4, 5, 4, 5, 10, 5, 3, 0, 3, 4, 6, 8, 8, - 5, 3, 1, 6, 9, 12, 11, 7, 4, 1, 9, 11, 12, 12, 8, 5, 2, 24, 27, - 32, 36, 36, 33, 29, 23, 26, 30, 34, 35, 32, 28, 21, 25, 29, 32, 33, 30, 26, - 20, 22, 26, 29, 32, 28, 23, 17, 19, 22, 26, 28, 26, 23, 15, 17, 20, 23, 27, - 26, 22, 14, 16, 19, 22, 26, 26, 22, 21, 25, 28, 33, 31, 29, 25, 20, 24, 28, - 31, 31, 27, 23, 19, 22, 26, 28, 28, 25, 22, 18, 20, 23, 25, 25, 24, 19, 15, - 17, 19, 21, 22, 22, 18, 13, 15, 18, 20, 20, 21, 18, 11, 14, 17, 20, 19, 19, - 18, 19, 22, 24, 25, 27, 25, 20, 18, 21, 23, 24, 24, 23, 18, 17, 20, 21, 22, - 22, 21, 17, 15, 17, 18, 18, 18, 18, 13, 10, 14, 15, 15, 15, 15, 13, 6, 13, - 14, 14, 14, 14, 13, 7, 12, 13, 12, 12, 12, 12, 17, 17, 17, 18, 19, 19, 13, - 15, 15, 16, 16, 17, 17, 11, 11, 14, 15, 14, 14, 13, 10, 7, 12, 11, 10, 10, - 10, 9, 5, 9, 8, 8, 7, 7, 6, 6, 7, 6, 6, 6, 6, 3, 7, 4, 5, - 5, 5, 5, 3, 7, 9, 9, 10, 11, 11, 13, 2, 7, 8, 9, 9, 8, 11, 2, - 6, 6, 5, 6, 6, 6, 2, 3, 3, 2, 2, 2, 3, 1, 2, 2, 2, 2, 0, - 2, 2, 5, 4, 3, 2, 1, 2, 3, 6, 6, 4, 3, 2, 1, 3, 4, 5, 7, - 8, 9, 11, 3, 4, 5, 6, 6, 7, 8, 3, 6, 4, 4, 4, 4, 5, 3, 5, - 4, 3, 2, 1, 2, 3, 6, 6, 5, 3, 2, 1, 5, 7, 9, 7, 4, 2, 0, - 6, 7, 9, 8, 5, 3, 1, 6, 7, 6, 5, 7, 8, 9, 6, 8, 7, 5, 6, - 6, 6, 6, 8, 9, 4, 3, 3, 3, 6, 8, 9, 6, 4, 2, 0, 6, 8, 10, - 8, 4, 3, 2, 7, 9, 11, 10, 6, 3, 2, 7, 9, 11, 10, 7, 4, 2, 33, - 38, 42, 45, 45, 42, 39, 33, 37, 41, 45, 45, 43, 37, 30, 35, 39, 42, 43, 41, - 38, 30, 33, 36, 40, 43, 39, 36, 27, 30, 34, 38, 41, 40, 36, 26, 30, 33, 36, - 40, 39, 35, 23, 27, 32, 36, 39, 38, 36, 31, 36, 39, 42, 41, 38, 35, 29, 33, - 38, 41, 41, 37, 33, 28, 32, 36, 40, 39, 37, 32, 27, 30, 34, 36, 36, 36, 31, - 25, 28, 32, 34, 35, 34, 30, 22, 27, 29, 33, 34, 33, 31, 20, 24, 28, 33, 32, - 33, 31, 28, 32, 35, 34, 36, 34, 28, 27, 30, 32, 35, 35, 32, 28, 24, 29, 32, - 33, 31, 32, 27, 21, 28, 28, 30, 29, 29, 25, 17, 25, 27, 28, 28, 28, 25, 14, - 24, 26, 26, 26, 27, 26, 14, 21, 24, 25, 24, 25, 24, 24, 26, 27, 28, 29, 26, - 17, 20, 25, 26, 28, 28, 25, 17, 17, 23, 25, 24, 24, 23, 18, 13, 20, 21, 21, - 21, 19, 18, 13, 18, 20, 19, 19, 18, 14, 14, 15, 17, 18, 18, 18, 10, 14, 12, - 15, 16, 17, 16, 9, 12, 18, 19, 20, 19, 14, 17, 9, 16, 17, 18, 17, 12, 17, - 8, 13, 15, 15, 15, 10, 14, 9, 8, 12, 12, 12, 8, 10, 8, 5, 10, 10, 9, - 7, 8, 9, 7, 7, 8, 8, 5, 10, 10, 8, 7, 6, 6, 3, 8, 4, 8, 9, - 9, 9, 12, 14, 4, 6, 7, 8, 9, 10, 13, 4, 2, 5, 5, 6, 8, 10, 4, - 2, 1, 1, 4, 6, 8, 4, 2, 2, 2, 2, 3, 8, 5, 4, 6, 4, 3, 2, - 6, 7, 7, 6, 5, 3, 2, 5, 2, 4, 4, 5, 8, 10, 12, 2, 4, 5, 4, - 7, 8, 10, 2, 4, 5, 3, 4, 6, 7, 2, 4, 5, 2, 1, 4, 7, 0, 4, - 5, 3, 3, 2, 5, 3, 4, 6, 6, 4, 3, 4, 5, 6, 6, 6, 4, 3, 2, - 41, 45, 50, 51, 52, 50, 46, 40, 43, 48, 51, 53, 48, 44, 37, 41, 46, 50, 51, - 48, 43, 36, 39, 43, 46, 50, 46, 41, 33, 36, 41, 44, 47, 45, 41, 32, 35, 39, - 42, 46, 45, 42, 28, 34, 37, 41, 45, 45, 41, 37, 41, 47, 49, 48, 44, 41, 35, - 41, 44, 49, 48, 44, 40, 33, 39, 43, 47, 44, 42, 38, 33, 37, 40, 44, 42, 41, - 36, 29, 34, 37, 40, 41, 39, 36, 25, 33, 36, 39, 40, 38, 36, 22, 30, 35, 38, - 39, 38, 36, 34, 39, 42, 42, 42, 39, 34, 32, 37, 40, 41, 42, 38, 32, 29, 36, - 37, 38, 39, 37, 31, 25, 33, 35, 35, 35, 34, 29, 20, 31, 33, 33, 34, 32, 30, - 16, 29, 31, 31, 32, 31, 29, 16, 26, 30, 30, 31, 30, 27, 28, 33, 34, 34, 34, - 32, 23, 24, 31, 32, 34, 33, 29, 23, 20, 29, 31, 30, 30, 27, 23, 17, 24, 27, - 27, 27, 24, 23, 15, 20, 25, 26, 25, 21, 19, 16, 18, 23, 23, 24, 20, 15, 16, - 14, 21, 22, 22, 20, 11, 16, 24, 25, 26, 23, 18, 24, 12, 21, 23, 24, 22, 16, - 23, 12, 17, 21, 21, 19, 13, 19, 12, 11, 18, 17, 15, 10, 14, 11, 8, 16, 15, - 13, 9, 11, 12, 9, 13, 13, 12, 8, 10, 12, 10, 11, 12, 11, 8, 9, 7, 13, - 15, 14, 14, 16, 20, 7, 9, 14, 13, 12, 14, 16, 7, 4, 11, 11, 9, 11, 13, - 7, 4, 7, 7, 6, 8, 10, 6, 4, 4, 4, 3, 8, 9, 7, 5, 4, 3, 2, - 5, 9, 8, 7, 5, 4, 2, 4, 8, 4, 3, 5, 9, 12, 14, 16, 4, 3, 4, - 8, 11, 12, 14, 4, 3, 4, 5, 7, 9, 11, 4, 2, 3, 1, 4, 7, 8, 4, - 0, 4, 3, 2, 4, 8, 3, 3, 4, 5, 3, 3, 7, 5, 5, 5, 5, 3, 2, - 5, 47, 50, 55, 58, 58, 55, 52, 45, 50, 53, 58, 57, 54, 50, 43, 48, 52, 54, - 56, 52, 48, 42, 45, 49, 51, 55, 51, 45, 39, 42, 45, 49, 52, 50, 45, 36, 40, - 43, 47, 50, 49, 45, 32, 38, 43, 46, 49, 51, 45, 42, 47, 51, 55, 54, 50, 47, - 42, 45, 51, 55, 54, 49, 44, 40, 44, 48, 53, 51, 47, 43, 36, 43, 47, 49, 48, - 46, 40, 32, 39, 42, 46, 46, 44, 39, 28, 36, 41, 45, 43, 44, 40, 24, 35, 40, - 44, 43, 41, 40, 38, 43, 47, 47, 48, 45, 38, 36, 43, 46, 48, 47, 43, 37, 32, - 40, 44, 44, 44, 43, 35, 28, 38, 40, 40, 40, 38, 34, 22, 34, 37, 38, 37, 36, - 33, 19, 32, 37, 36, 36, 35, 33, 18, 28, 34, 35, 35, 33, 31, 32, 39, 39, 42, - 40, 36, 30, 28, 36, 38, 39, 38, 34, 28, 24, 33, 37, 36, 35, 29, 28, 21, 28, - 33, 33, 33, 27, 27, 18, 23, 31, 30, 29, 23, 23, 19, 19, 28, 28, 28, 23, 20, - 18, 15, 25, 27, 27, 22, 15, 18, 28, 31, 31, 27, 23, 29, 16, 24, 30, 30, 26, - 20, 28, 16, 20, 27, 26, 23, 17, 23, 16, 14, 23, 23, 19, 13, 19, 14, 10, 20, - 20, 16, 11, 15, 14, 10, 16, 18, 15, 9, 12, 13, 11, 13, 17, 14, 9, 11, 11, - 15, 21, 18, 17, 20, 25, 10, 10, 19, 18, 16, 17, 21, 11, 6, 16, 15, 13, 14, - 17, 10, 6, 12, 12, 9, 11, 12, 9, 5, 7, 7, 7, 9, 11, 9, 7, 5, 4, - 4, 7, 11, 10, 8, 5, 3, 3, 8, 9, 6, 5, 10, 13, 15, 18, 20, 6, 5, - 9, 12, 14, 16, 17, 5, 5, 7, 9, 10, 12, 14, 5, 4, 3, 5, 7, 8, 10, - 5, 4, 0, 2, 4, 7, 9, 5, 3, 3, 4, 3, 6, 8, 6, 4, 4, 4, 3, - 4, 7, 44, 47, 51, 55, 56, 53, 48, 43, 46, 50, 54, 55, 52, 45, 40, 44, 49, - 51, 54, 48, 45, 40, 42, 46, 50, 52, 48, 42, 35, 39, 42, 45, 48, 45, 41, 32, - 37, 39, 42, 46, 45, 41, 29, 34, 39, 42, 45, 46, 41, 42, 45, 49, 53, 51, 47, - 44, 40, 44, 48, 51, 50, 46, 42, 36, 41, 45, 47, 47, 45, 40, 33, 39, 43, 46, - 46, 43, 37, 28, 35, 39, 42, 41, 40, 36, 25, 34, 37, 40, 40, 40, 37, 21, 32, - 36, 39, 39, 38, 36, 36, 42, 43, 44, 46, 42, 37, 33, 39, 42, 44, 43, 41, 33, - 29, 38, 40, 40, 41, 40, 33, 26, 35, 37, 37, 38, 36, 29, 20, 31, 34, 34, 34, - 32, 31, 16, 28, 31, 33, 33, 30, 30, 15, 24, 31, 31, 31, 30, 27, 30, 35, 36, - 37, 37, 35, 29, 25, 33, 34, 36, 36, 31, 26, 22, 30, 34, 34, 32, 28, 26, 17, - 25, 30, 29, 29, 24, 25, 16, 19, 26, 26, 24, 21, 21, 15, 16, 25, 25, 25, 20, - 17, 15, 12, 22, 23, 23, 20, 13, 16, 26, 28, 29, 25, 22, 28, 13, 22, 26, 28, - 25, 19, 27, 13, 17, 25, 24, 22, 15, 21, 13, 12, 21, 21, 18, 11, 17, 12, 7, - 17, 17, 14, 8, 13, 11, 8, 14, 15, 13, 7, 10, 11, 9, 10, 13, 12, 7, 9, - 9, 14, 18, 18, 17, 19, 24, 9, 9, 17, 17, 16, 16, 19, 9, 6, 15, 14, 12, - 13, 15, 8, 5, 10, 10, 9, 10, 10, 7, 4, 5, 6, 5, 7, 8, 6, 5, 3, - 3, 4, 6, 8, 7, 6, 3, 2, 3, 6, 7, 5, 5, 10, 13, 15, 18, 20, 5, - 5, 9, 12, 14, 15, 16, 5, 5, 8, 10, 11, 11, 13, 5, 4, 3, 6, 7, 8, - 8, 3, 3, 2, 0, 3, 5, 7, 3, 2, 4, 5, 2, 5, 6, 4, 4, 6, 6, - 2, 4, 6, 37, 42, 45, 48, 48, 46, 42, 36, 40, 43, 47, 48, 44, 40, 34, 37, - 42, 46, 46, 42, 38, 32, 36, 41, 43, 44, 41, 34, 29, 33, 36, 39, 40, 37, 35, - 27, 29, 33, 35, 39, 37, 33, 24, 27, 30, 35, 37, 39, 34, 34, 38, 41, 46, 45, - 42, 37, 34, 37, 40, 45, 44, 40, 35, 31, 35, 39, 42, 41, 38, 34, 29, 33, 36, - 39, 38, 36, 29, 25, 30, 32, 35, 35, 33, 29, 20, 27, 29, 32, 32, 32, 29, 15, - 26, 29, 32, 31, 31, 29, 31, 34, 37, 39, 40, 37, 30, 28, 34, 36, 37, 37, 35, - 29, 25, 32, 35, 35, 34, 34, 27, 21, 30, 31, 31, 31, 29, 25, 16, 25, 28, 28, - 27, 25, 24, 12, 23, 25, 25, 25, 24, 24, 11, 19, 25, 23, 24, 24, 21, 25, 29, - 30, 31, 31, 30, 24, 21, 28, 29, 30, 30, 27, 21, 18, 25, 27, 27, 27, 23, 20, - 15, 22, 24, 23, 23, 20, 19, 12, 15, 21, 21, 19, 15, 16, 11, 12, 19, 18, 18, - 15, 12, 11, 8, 17, 16, 16, 15, 9, 13, 21, 23, 23, 22, 19, 24, 9, 18, 21, - 22, 21, 15, 22, 10, 14, 19, 18, 17, 12, 17, 10, 8, 16, 15, 14, 8, 11, 8, - 4, 12, 11, 10, 5, 8, 7, 4, 9, 8, 8, 4, 6, 6, 5, 6, 7, 7, 4, - 5, 5, 11, 13, 14, 14, 16, 20, 5, 8, 12, 13, 13, 14, 16, 5, 4, 11, 10, - 10, 11, 11, 5, 3, 7, 6, 7, 7, 6, 3, 2, 2, 1, 3, 4, 5, 3, 2, - 3, 3, 2, 3, 5, 4, 3, 4, 4, 1, 3, 4, 5, 5, 9, 11, 13, 15, 16, - 5, 5, 8, 10, 12, 12, 13, 5, 5, 7, 8, 8, 9, 10, 5, 4, 3, 4, 5, - 6, 4, 3, 2, 4, 3, 0, 3, 4, 2, 3, 5, 5, 2, 2, 3, 2, 5, 6, - 6, 3, 1, 3, 32, 35, 39, 42, 42, 40, 37, 30, 34, 38, 42, 43, 39, 35, 29, - 31, 37, 40, 41, 37, 33, 28, 29, 33, 38, 39, 35, 28, 25, 27, 30, 33, 36, 33, - 29, 22, 23, 26, 30, 34, 32, 29, 20, 22, 25, 29, 32, 32, 28, 29, 33, 36, 40, - 39, 36, 32, 28, 31, 35, 38, 39, 34, 30, 26, 30, 34, 36, 35, 32, 28, 26, 26, - 30, 33, 33, 30, 24, 21, 23, 27, 30, 29, 28, 23, 17, 22, 24, 27, 27, 26, 24, - 14, 20, 23, 26, 26, 26, 24, 27, 30, 31, 32, 35, 31, 27, 25, 29, 31, 32, 31, - 29, 24, 22, 27, 29, 28, 29, 28, 22, 19, 26, 26, 25, 25, 25, 19, 13, 22, 22, - 22, 22, 20, 18, 9, 20, 20, 20, 19, 20, 19, 8, 17, 19, 18, 18, 19, 17, 22, - 25, 25, 25, 27, 26, 19, 18, 23, 24, 24, 25, 23, 17, 14, 22, 22, 22, 21, 19, - 16, 11, 18, 18, 18, 18, 16, 14, 9, 13, 15, 14, 14, 12, 11, 9, 10, 13, 13, - 12, 12, 8, 8, 6, 12, 11, 11, 11, 5, 10, 17, 17, 18, 18, 15, 19, 7, 15, - 15, 16, 16, 12, 17, 7, 12, 13, 13, 13, 9, 12, 7, 6, 10, 9, 9, 5, 8, - 5, 2, 6, 5, 5, 3, 5, 4, 2, 4, 3, 3, 3, 4, 4, 3, 2, 2, 2, - 2, 3, 3, 9, 9, 10, 11, 13, 16, 3, 7, 8, 9, 10, 11, 12, 3, 4, 7, - 7, 7, 8, 8, 3, 3, 4, 4, 4, 4, 3, 2, 1, 4, 3, 1, 2, 3, 1, - 3, 5, 4, 2, 2, 3, 2, 4, 5, 5, 3, 0, 2, 4, 5, 6, 8, 10, 12, - 13, 4, 5, 6, 8, 9, 10, 10, 4, 5, 6, 5, 6, 6, 7, 4, 4, 5, 3, - 2, 3, 3, 2, 4, 7, 5, 3, 0, 3, 3, 5, 7, 6, 3, 2, 2, 4, 6, - 7, 7, 4, 2, 2, 26, 30, 34, 38, 38, 34, 31, 24, 29, 32, 36, 37, 33, 29, - 23, 26, 31, 35, 35, 32, 28, 22, 25, 28, 31, 33, 29, 24, 19, 21, 24, 28, 30, - 28, 24, 17, 19, 22, 25, 29, 28, 25, 16, 17, 20, 24, 27, 28, 24, 23, 27, 31, - 35, 33, 31, 27, 22, 25, 30, 33, 33, 30, 26, 21, 24, 28, 30, 31, 28, 24, 20, - 21, 25, 27, 28, 26, 20, 17, 19, 21, 24, 24, 23, 20, 15, 17, 20, 22, 22, 22, - 20, 12, 16, 19, 21, 21, 21, 20, 22, 24, 27, 27, 29, 26, 22, 20, 23, 25, 26, - 26, 25, 20, 18, 22, 23, 23, 24, 23, 18, 16, 20, 20, 20, 20, 20, 15, 11, 16, - 17, 17, 17, 16, 15, 7, 16, 15, 15, 15, 15, 14, 7, 14, 14, 14, 14, 14, 14, - 18, 18, 19, 20, 22, 21, 14, 15, 18, 18, 19, 19, 19, 13, 12, 17, 17, 16, 16, - 15, 11, 8, 15, 13, 12, 13, 12, 10, 6, 10, 10, 9, 9, 9, 7, 6, 8, 8, - 8, 7, 8, 4, 7, 4, 7, 6, 6, 6, 3, 7, 11, 11, 12, 13, 12, 14, 4, - 9, 10, 10, 11, 10, 12, 4, 8, 8, 7, 7, 7, 8, 4, 5, 4, 4, 4, 4, - 4, 2, 1, 1, 1, 1, 2, 3, 2, 3, 4, 3, 2, 0, 3, 3, 4, 5, 3, - 3, 2, 2, 3, 5, 6, 8, 9, 11, 12, 3, 4, 6, 7, 7, 8, 9, 3, 4, - 4, 5, 5, 5, 6, 3, 3, 4, 3, 2, 2, 2, 1, 5, 6, 4, 3, 2, 2, - 3, 7, 8, 6, 4, 2, 2, 5, 7, 9, 8, 4, 3, 0, 5, 7, 6, 6, 8, - 9, 10, 5, 7, 7, 6, 7, 7, 7, 5, 7, 8, 4, 3, 4, 5, 5, 6, 8, - 5, 3, 1, 2, 5, 8, 10, 8, 4, 3, 0, 7, 9, 10, 9, 5, 3, 1, 8, - 9, 10, 10, 6, 4, 2, 36, 41, 47, 48, 47, 47, 42, 36, 39, 44, 48, 49, 45, - 41, 34, 38, 42, 45, 47, 44, 39, 32, 35, 39, 42, 45, 41, 36, 29, 33, 35, 39, - 41, 39, 37, 26, 29, 32, 37, 41, 39, 36, 23, 27, 32, 34, 38, 39, 35, 33, 38, - 42, 45, 44, 42, 39, 31, 37, 41, 45, 44, 40, 38, 31, 35, 40, 42, 42, 40, 35, - 29, 33, 36, 39, 38, 38, 31, 25, 28, 32, 36, 35, 35, 32, 22, 27, 30, 32, 34, - 34, 31, 18, 24, 28, 32, 33, 32, 31, 31, 36, 37, 38, 39, 37, 32, 29, 33, 35, - 37, 38, 36, 31, 26, 32, 36, 35, 35, 35, 30, 22, 29, 31, 31, 31, 31, 26, 17, - 26, 27, 28, 27, 27, 26, 13, 24, 26, 26, 26, 27, 26, 12, 21, 23, 25, 24, 25, - 24, 27, 29, 30, 31, 32, 31, 23, 21, 27, 29, 30, 29, 28, 22, 19, 25, 27, 26, - 27, 25, 22, 14, 21, 24, 23, 23, 22, 20, 13, 17, 20, 19, 20, 18, 16, 12, 13, - 17, 18, 18, 17, 12, 12, 10, 15, 16, 17, 17, 10, 13, 20, 22, 22, 22, 19, 23, - 10, 18, 20, 20, 21, 16, 21, 10, 15, 18, 18, 18, 13, 17, 10, 9, 14, 14, 14, - 10, 12, 8, 4, 10, 10, 10, 8, 9, 7, 5, 7, 7, 8, 6, 9, 8, 7, 5, - 5, 6, 6, 8, 5, 11, 12, 13, 15, 17, 20, 5, 8, 10, 11, 13, 14, 16, 5, - 5, 8, 8, 10, 12, 13, 5, 4, 4, 4, 6, 8, 8, 4, 3, 2, 1, 2, 6, - 8, 4, 2, 4, 3, 1, 5, 8, 5, 5, 4, 3, 2, 4, 6, 4, 6, 6, 9, - 13, 16, 17, 4, 6, 7, 7, 11, 13, 14, 5, 6, 7, 4, 8, 9, 11, 4, 5, - 6, 3, 3, 5, 7, 3, 3, 5, 3, 2, 3, 7, 0, 4, 5, 5, 2, 1, 5, - 3, 5, 5, 5, 3, 1, 4, 42, 48, 52, 54, 55, 52, 49, 41, 46, 50, 54, 53, - 50, 46, 40, 44, 48, 52, 53, 50, 45, 38, 41, 46, 50, 52, 47, 41, 35, 39, 41, - 46, 47, 46, 42, 31, 35, 37, 42, 46, 44, 41, 28, 33, 38, 41, 44, 44, 41, 39, - 45, 48, 53, 51, 47, 44, 39, 43, 47, 50, 50, 47, 42, 36, 43, 46, 49, 48, 44, - 40, 34, 39, 44, 45, 46, 42, 36, 29, 35, 38, 41, 41, 40, 37, 24, 33, 36, 39, - 39, 39, 36, 20, 31, 34, 38, 38, 37, 37, 36, 40, 43, 43, 46, 43, 37, 34, 39, - 42, 43, 43, 41, 36, 30, 39, 40, 41, 41, 39, 33, 25, 35, 37, 37, 37, 35, 30, - 20, 31, 33, 33, 33, 32, 31, 15, 28, 31, 31, 31, 31, 30, 15, 25, 29, 30, 30, - 30, 27, 30, 35, 37, 37, 38, 36, 28, 25, 33, 34, 36, 35, 32, 27, 21, 30, 34, - 32, 32, 29, 26, 18, 26, 30, 29, 30, 26, 25, 16, 19, 26, 25, 25, 21, 21, 15, - 16, 23, 24, 24, 21, 17, 15, 12, 21, 22, 22, 20, 13, 17, 25, 27, 29, 27, 23, - 29, 14, 22, 26, 27, 25, 20, 27, 13, 18, 23, 23, 22, 17, 21, 13, 12, 20, 20, - 18, 12, 16, 12, 7, 16, 16, 14, 9, 13, 11, 7, 13, 13, 13, 8, 10, 10, 8, - 10, 12, 11, 8, 9, 9, 15, 18, 19, 18, 21, 24, 9, 10, 17, 17, 17, 18, 20, - 9, 6, 14, 14, 14, 15, 16, 9, 5, 10, 10, 10, 11, 11, 7, 4, 5, 5, 5, - 8, 10, 6, 4, 2, 2, 4, 6, 10, 7, 5, 3, 2, 3, 7, 8, 6, 6, 9, - 14, 16, 19, 21, 6, 6, 8, 13, 15, 16, 18, 6, 6, 6, 10, 12, 13, 14, 6, - 5, 5, 5, 8, 9, 9, 4, 3, 3, 2, 3, 5, 9, 4, 0, 3, 4, 1, 6, - 7, 3, 3, 4, 4, 2, 4, 6, 49, 54, 58, 61, 61, 58, 53, 48, 51, 57, 60, - 60, 57, 53, 46, 50, 54, 57, 59, 54, 51, 44, 47, 51, 55, 56, 51, 46, 40, 44, - 47, 51, 53, 49, 46, 36, 41, 44, 46, 50, 50, 46, 32, 38, 42, 46, 49, 48, 47, - 45, 49, 54, 58, 56, 54, 48, 44, 48, 52, 58, 56, 52, 47, 41, 47, 51, 55, 54, - 50, 44, 38, 44, 48, 52, 50, 48, 41, 33, 42, 44, 48, 46, 46, 41, 27, 37, 41, - 44, 45, 43, 40, 23, 34, 39, 43, 42, 42, 41, 41, 46, 50, 50, 51, 49, 41, 38, - 45, 48, 50, 49, 46, 40, 33, 44, 46, 47, 46, 44, 37, 30, 40, 43, 43, 43, 41, - 34, 24, 34, 39, 39, 39, 35, 34, 19, 30, 36, 36, 36, 35, 35, 17, 26, 34, 35, - 34, 34, 32, 34, 42, 41, 43, 42, 41, 34, 29, 38, 41, 41, 40, 36, 33, 25, 34, - 39, 39, 36, 33, 31, 21, 29, 36, 35, 33, 28, 29, 19, 23, 31, 32, 29, 24, 26, - 18, 18, 28, 29, 27, 23, 22, 17, 14, 25, 26, 26, 23, 17, 20, 29, 33, 34, 30, - 28, 33, 17, 25, 32, 32, 29, 24, 31, 17, 21, 29, 30, 26, 20, 26, 17, 15, 25, - 26, 22, 15, 21, 15, 10, 20, 22, 17, 11, 17, 13, 9, 16, 19, 15, 10, 14, 13, - 9, 11, 17, 15, 9, 11, 12, 17, 24, 23, 22, 24, 30, 12, 12, 22, 22, 20, 21, - 25, 12, 9, 19, 19, 17, 18, 20, 12, 8, 14, 16, 13, 13, 14, 10, 6, 7, 11, - 7, 10, 12, 9, 5, 4, 6, 5, 8, 10, 8, 6, 4, 5, 5, 7, 10, 8, 7, - 16, 18, 20, 23, 24, 8, 8, 13, 17, 19, 20, 20, 8, 7, 11, 14, 16, 16, 17, - 8, 6, 5, 11, 11, 12, 10, 6, 4, 3, 4, 5, 7, 10, 5, 3, 0, 1, 3, - 6, 9, 5, 3, 2, 2, 3, 5, 8, 48, 52, 55, 59, 59, 57, 52, 47, 50, 55, - 59, 59, 56, 50, 44, 48, 52, 56, 58, 53, 49, 43, 46, 50, 53, 54, 51, 44, 38, - 44, 46, 49, 52, 49, 44, 34, 40, 43, 45, 50, 48, 43, 30, 37, 41, 44, 48, 47, - 43, 45, 51, 53, 56, 56, 51, 47, 44, 47, 53, 55, 56, 50, 45, 40, 47, 51, 54, - 52, 48, 44, 36, 43, 48, 50, 49, 44, 40, 32, 39, 45, 47, 44, 43, 39, 26, 36, - 40, 43, 42, 42, 39, 21, 33, 38, 42, 42, 41, 40, 40, 45, 47, 48, 50, 48, 40, - 37, 44, 48, 46, 49, 46, 38, 32, 42, 46, 45, 46, 43, 37, 28, 40, 42, 43, 41, - 40, 33, 23, 35, 37, 38, 36, 34, 33, 17, 29, 35, 35, 35, 34, 34, 16, 24, 33, - 33, 33, 32, 31, 32, 39, 40, 43, 42, 40, 34, 28, 38, 40, 41, 40, 36, 32, 24, - 33, 38, 38, 37, 33, 30, 20, 28, 34, 34, 33, 28, 28, 19, 21, 31, 30, 28, 24, - 25, 17, 17, 27, 27, 26, 22, 21, 16, 13, 23, 26, 26, 21, 17, 19, 29, 33, 34, - 30, 27, 33, 16, 24, 32, 32, 29, 24, 31, 16, 21, 29, 29, 26, 20, 26, 16, 15, - 24, 25, 22, 14, 20, 14, 10, 19, 21, 17, 10, 17, 12, 8, 14, 17, 15, 9, 13, - 12, 8, 10, 16, 14, 9, 11, 11, 17, 23, 23, 22, 24, 29, 12, 12, 21, 22, 21, - 21, 24, 12, 9, 19, 19, 17, 18, 20, 11, 7, 14, 15, 13, 12, 13, 10, 5, 7, - 10, 7, 9, 11, 8, 5, 4, 6, 5, 7, 10, 7, 5, 4, 4, 4, 7, 9, 8, - 8, 16, 18, 21, 23, 24, 8, 8, 14, 18, 20, 20, 20, 8, 8, 11, 16, 15, 15, - 16, 8, 7, 6, 11, 11, 11, 10, 6, 5, 4, 5, 5, 6, 9, 4, 4, 1, 0, - 3, 6, 8, 4, 3, 2, 2, 2, 5, 7, 41, 45, 48, 52, 51, 50, 45, 39, 42, - 46, 52, 51, 47, 43, 37, 41, 45, 49, 49, 46, 41, 36, 39, 41, 46, 47, 44, 36, - 33, 36, 38, 42, 43, 40, 37, 29, 32, 35, 39, 42, 41, 37, 25, 30, 34, 37, 40, - 41, 37, 37, 42, 45, 49, 48, 44, 40, 36, 41, 44, 47, 47, 42, 37, 33, 38, 43, - 45, 44, 42, 36, 31, 37, 39, 41, 41, 38, 32, 26, 33, 35, 38, 38, 35, 32, 21, - 30, 33, 35, 34, 34, 31, 16, 28, 31, 34, 34, 33, 32, 34, 39, 40, 43, 42, 40, - 33, 31, 37, 40, 41, 40, 37, 33, 26, 35, 38, 39, 37, 36, 30, 24, 32, 33, 34, - 34, 32, 26, 17, 27, 31, 30, 30, 27, 26, 13, 24, 29, 28, 27, 26, 27, 12, 20, - 27, 27, 27, 26, 24, 27, 33, 32, 34, 34, 33, 27, 22, 30, 33, 32, 32, 29, 24, - 20, 27, 31, 31, 30, 26, 23, 17, 23, 27, 27, 26, 21, 22, 13, 17, 24, 23, 21, - 18, 18, 12, 12, 21, 20, 19, 17, 15, 12, 9, 19, 19, 19, 17, 11, 15, 23, 26, - 26, 24, 21, 26, 11, 20, 24, 25, 23, 18, 24, 11, 15, 22, 22, 20, 15, 19, 11, - 10, 19, 18, 16, 10, 13, 9, 5, 14, 14, 12, 6, 10, 8, 4, 10, 11, 10, 5, - 8, 8, 5, 7, 9, 8, 5, 6, 7, 13, 16, 17, 16, 19, 23, 7, 9, 15, 15, - 15, 16, 18, 7, 5, 13, 12, 13, 13, 13, 7, 4, 10, 9, 9, 9, 8, 5, 2, - 4, 4, 4, 5, 6, 3, 2, 2, 1, 2, 4, 6, 4, 3, 2, 2, 2, 4, 5, - 6, 6, 11, 13, 15, 17, 18, 6, 6, 11, 13, 14, 15, 15, 6, 6, 8, 10, 11, - 11, 11, 5, 5, 4, 6, 7, 7, 6, 3, 3, 3, 2, 2, 3, 5, 2, 1, 3, - 3, 0, 3, 4, 2, 3, 4, 4, 2, 3, 4, 33, 38, 42, 46, 45, 43, 37, 32, - 36, 40, 45, 44, 41, 37, 31, 34, 39, 42, 43, 39, 34, 30, 32, 36, 39, 40, 37, - 31, 27, 29, 31, 36, 37, 35, 31, 23, 26, 29, 33, 36, 34, 31, 22, 25, 28, 30, - 34, 34, 31, 31, 34, 38, 42, 42, 37, 34, 30, 33, 38, 41, 40, 36, 32, 29, 32, - 36, 38, 38, 36, 28, 27, 29, 32, 36, 35, 32, 27, 22, 26, 30, 32, 31, 30, 26, - 18, 23, 26, 29, 29, 29, 26, 15, 23, 25, 28, 28, 28, 26, 28, 31, 35, 34, 37, - 34, 28, 26, 31, 31, 34, 34, 32, 26, 23, 30, 31, 31, 31, 30, 23, 19, 28, 28, - 28, 28, 26, 21, 14, 24, 24, 24, 23, 23, 21, 10, 21, 23, 21, 22, 22, 21, 10, - 19, 21, 20, 21, 21, 18, 24, 26, 27, 27, 29, 27, 21, 19, 25, 26, 27, 27, 24, - 18, 16, 23, 24, 24, 24, 21, 18, 12, 19, 21, 20, 21, 18, 17, 10, 14, 17, 17, - 16, 13, 13, 10, 10, 15, 15, 14, 13, 10, 9, 7, 14, 13, 13, 12, 6, 11, 18, - 19, 20, 20, 16, 21, 8, 16, 18, 18, 18, 13, 19, 8, 12, 15, 15, 15, 11, 14, - 8, 7, 12, 12, 11, 6, 9, 6, 2, 8, 8, 7, 4, 6, 5, 3, 6, 5, 5, - 3, 5, 5, 3, 4, 4, 3, 3, 4, 4, 10, 10, 11, 13, 14, 18, 4, 8, 10, - 10, 12, 12, 13, 4, 4, 9, 8, 9, 9, 9, 4, 3, 5, 5, 5, 5, 4, 2, - 2, 2, 2, 2, 3, 4, 2, 1, 5, 4, 2, 2, 4, 3, 3, 5, 4, 2, 2, - 3, 5, 5, 8, 10, 11, 13, 14, 5, 5, 7, 9, 10, 11, 11, 5, 5, 6, 7, - 7, 8, 8, 5, 4, 5, 3, 3, 4, 3, 3, 3, 7, 5, 2, 2, 3, 1, 5, - 6, 6, 3, 0, 3, 4, 6, 6, 6, 4, 2, 2, 27, 31, 35, 38, 39, 36, 33, - 25, 30, 34, 39, 38, 35, 30, 25, 29, 32, 36, 37, 34, 29, 24, 26, 29, 32, 36, - 31, 26, 21, 24, 26, 29, 33, 30, 26, 18, 20, 23, 27, 30, 30, 25, 17, 19, 22, - 25, 29, 29, 26, 25, 28, 33, 35, 35, 33, 29, 24, 28, 32, 35, 35, 32, 27, 23, - 26, 30, 32, 32, 30, 25, 22, 24, 27, 29, 29, 26, 21, 19, 20, 23, 26, 26, 25, - 21, 16, 18, 21, 24, 23, 24, 21, 13, 17, 20, 22, 23, 22, 21, 22, 26, 28, 29, - 31, 28, 23, 22, 24, 26, 28, 28, 27, 22, 20, 23, 25, 25, 25, 25, 19, 17, 22, - 22, 22, 22, 21, 16, 11, 18, 19, 18, 18, 17, 16, 8, 17, 17, 17, 17, 16, 16, - 8, 16, 16, 15, 15, 16, 14, 20, 21, 20, 22, 24, 22, 16, 16, 20, 20, 21, 21, - 20, 14, 13, 18, 18, 18, 17, 17, 13, 9, 16, 15, 14, 14, 14, 12, 7, 12, 11, - 11, 10, 10, 8, 7, 9, 10, 9, 9, 9, 5, 8, 5, 8, 8, 8, 8, 3, 8, - 13, 13, 14, 15, 13, 15, 5, 11, 12, 12, 13, 10, 14, 5, 10, 10, 9, 9, 8, - 9, 5, 5, 6, 6, 5, 4, 5, 3, 1, 2, 2, 2, 2, 3, 3, 2, 3, 2, - 1, 2, 3, 4, 3, 4, 3, 2, 0, 2, 3, 6, 7, 8, 9, 11, 13, 3, 5, - 7, 8, 8, 9, 10, 3, 4, 5, 5, 6, 6, 6, 3, 3, 3, 2, 2, 3, 3, - 1, 4, 5, 4, 3, 0, 2, 1, 5, 7, 5, 3, 1, 2, 3, 6, 7, 6, 4, - 2, 2, 4, 6, 6, 7, 9, 10, 11, 4, 6, 6, 6, 8, 8, 8, 4, 6, 7, - 4, 4, 4, 6, 4, 6, 7, 4, 2, 1, 2, 3, 7, 8, 6, 3, 2, 1, 5, - 7, 9, 8, 4, 3, 0, 6, 7, 9, 9, 5, 3, 2, 38, 44, 48, 51, 51, 48, - 46, 38, 42, 46, 50, 51, 48, 44, 37, 41, 45, 47, 49, 44, 41, 34, 38, 41, 45, - 47, 43, 36, 32, 34, 38, 42, 42, 38, 37, 28, 30, 33, 36, 41, 38, 37, 23, 26, - 32, 35, 39, 40, 36, 37, 39, 45, 49, 49, 44, 41, 36, 39, 43, 47, 48, 44, 39, - 34, 37, 42, 45, 44, 42, 36, 31, 36, 38, 41, 42, 38, 32, 27, 31, 35, 38, 36, - 36, 31, 22, 28, 31, 33, 34, 35, 32, 18, 25, 29, 32, 33, 33, 32, 34, 36, 40, - 41, 43, 41, 37, 31, 34, 39, 40, 40, 39, 34, 28, 35, 37, 37, 37, 37, 32, 23, - 33, 34, 34, 34, 32, 27, 18, 28, 29, 30, 29, 28, 27, 13, 24, 26, 26, 27, 27, - 27, 11, 21, 24, 24, 25, 25, 25, 28, 32, 33, 34, 36, 35, 27, 23, 30, 31, 34, - 33, 31, 25, 20, 28, 29, 30, 30, 28, 24, 16, 23, 26, 26, 26, 24, 23, 14, 17, - 22, 22, 21, 19, 18, 12, 13, 17, 19, 18, 18, 15, 11, 9, 16, 16, 17, 17, 11, - 15, 23, 25, 26, 27, 23, 27, 12, 20, 23, 25, 25, 21, 25, 12, 16, 21, 21, 21, - 17, 20, 12, 11, 17, 17, 17, 12, 14, 10, 5, 13, 12, 11, 8, 11, 7, 4, 8, - 8, 9, 7, 10, 7, 5, 5, 6, 7, 7, 9, 7, 14, 16, 17, 19, 22, 24, 8, - 11, 15, 16, 18, 19, 20, 8, 7, 13, 13, 15, 15, 16, 7, 6, 9, 9, 11, 10, - 9, 5, 4, 4, 4, 4, 7, 9, 5, 3, 3, 2, 3, 5, 8, 4, 2, 3, 3, - 1, 5, 7, 8, 7, 9, 14, 18, 20, 21, 7, 7, 9, 12, 16, 17, 18, 7, 7, - 9, 9, 12, 14, 14, 8, 6, 8, 5, 7, 9, 7, 5, 5, 6, 4, 2, 4, 8, - 3, 3, 5, 4, 2, 4, 6, 0, 4, 5, 5, 3, 3, 5, 45, 50, 54, 59, 58, - 56, 50, 44, 48, 52, 57, 58, 51, 48, 42, 46, 51, 55, 54, 52, 46, 41, 44, 46, - 51, 53, 48, 41, 36, 41, 44, 47, 48, 45, 41, 32, 37, 40, 42, 45, 46, 42, 28, - 33, 37, 42, 45, 46, 42, 42, 47, 50, 54, 54, 50, 46, 39, 44, 50, 53, 53, 49, - 45, 39, 43, 48, 51, 50, 46, 41, 35, 41, 45, 47, 46, 43, 36, 30, 37, 41, 43, - 41, 40, 37, 24, 33, 38, 38, 40, 40, 37, 19, 31, 35, 38, 39, 38, 36, 38, 43, - 46, 46, 48, 45, 41, 34, 41, 46, 46, 47, 44, 38, 31, 41, 42, 44, 43, 40, 36, - 27, 38, 39, 40, 38, 37, 32, 21, 33, 35, 35, 34, 32, 31, 16, 26, 32, 31, 32, - 30, 32, 15, 24, 29, 31, 31, 30, 29, 31, 38, 40, 39, 40, 39, 32, 27, 35, 37, - 39, 38, 35, 30, 24, 31, 37, 36, 35, 32, 29, 19, 27, 31, 32, 32, 27, 27, 17, - 21, 28, 27, 26, 22, 22, 16, 15, 24, 23, 23, 21, 19, 15, 12, 21, 22, 22, 21, - 15, 18, 28, 30, 31, 30, 27, 31, 15, 24, 29, 30, 29, 24, 30, 15, 19, 26, 27, - 25, 19, 24, 15, 14, 22, 23, 21, 14, 19, 13, 8, 18, 18, 15, 10, 15, 11, 6, - 12, 14, 13, 8, 12, 10, 7, 9, 12, 11, 8, 10, 11, 16, 21, 22, 22, 24, 29, - 11, 12, 20, 20, 21, 22, 24, 11, 8, 17, 17, 18, 18, 18, 10, 7, 13, 13, 13, - 12, 12, 8, 5, 7, 8, 6, 9, 10, 6, 5, 2, 3, 4, 7, 10, 5, 4, 2, - 1, 4, 7, 9, 8, 8, 14, 18, 21, 23, 24, 8, 8, 12, 17, 20, 21, 21, 8, - 8, 10, 14, 16, 16, 16, 9, 7, 6, 9, 12, 11, 9, 6, 5, 4, 4, 5, 6, - 9, 4, 3, 3, 3, 3, 5, 8, 4, 0, 3, 3, 2, 5, 7, 49, 54, 57, 61, - 61, 57, 54, 47, 52, 57, 60, 62, 56, 53, 46, 50, 55, 58, 58, 55, 50, 45, 49, - 52, 55, 57, 52, 46, 40, 45, 49, 52, 53, 50, 46, 35, 41, 44, 47, 50, 50, 46, - 31, 38, 43, 45, 50, 51, 45, 47, 49, 55, 59, 57, 54, 50, 44, 50, 55, 58, 57, - 52, 46, 41, 47, 53, 55, 54, 51, 44, 39, 46, 50, 51, 50, 48, 40, 32, 41, 45, - 47, 46, 45, 40, 27, 37, 41, 43, 44, 44, 41, 22, 34, 40, 44, 42, 41, 41, 41, - 49, 50, 52, 52, 49, 43, 37, 46, 50, 50, 50, 47, 41, 33, 42, 47, 47, 47, 44, - 38, 29, 41, 43, 44, 42, 41, 35, 23, 35, 39, 40, 37, 36, 35, 19, 29, 37, 36, - 37, 34, 36, 18, 26, 35, 35, 34, 33, 32, 33, 40, 43, 45, 43, 41, 35, 30, 38, - 41, 42, 42, 38, 34, 25, 35, 40, 40, 39, 33, 32, 22, 30, 36, 35, 35, 30, 30, - 20, 23, 31, 32, 30, 24, 26, 18, 18, 28, 29, 28, 23, 23, 18, 14, 24, 27, 26, - 23, 18, 21, 29, 34, 36, 33, 29, 34, 17, 26, 33, 34, 31, 25, 33, 17, 21, 30, - 30, 28, 21, 27, 17, 16, 25, 27, 23, 15, 21, 15, 10, 20, 23, 18, 11, 17, 13, - 9, 15, 19, 16, 10, 14, 13, 9, 11, 18, 15, 10, 12, 12, 17, 25, 24, 23, 26, - 31, 12, 13, 23, 23, 22, 22, 26, 12, 9, 20, 20, 19, 19, 21, 12, 8, 14, 16, - 14, 14, 14, 11, 6, 8, 11, 7, 9, 12, 9, 5, 4, 6, 5, 8, 11, 7, 5, - 4, 5, 4, 7, 10, 9, 8, 17, 19, 22, 24, 26, 9, 8, 15, 19, 20, 21, 21, - 9, 8, 11, 16, 16, 17, 17, 9, 7, 7, 13, 12, 12, 11, 6, 5, 4, 6, 6, - 7, 10, 5, 4, 2, 2, 3, 7, 9, 4, 3, 0, 0, 3, 5, 8, 49, 53, 57, - 61, 62, 59, 55, 48, 53, 57, 60, 61, 57, 52, 45, 51, 53, 58, 59, 56, 51, 44, - 47, 52, 55, 57, 52, 46, 42, 45, 48, 51, 54, 49, 45, 35, 41, 45, 47, 50, 49, - 45, 31, 38, 41, 46, 49, 50, 46, 46, 52, 55, 59, 57, 54, 50, 46, 50, 54, 57, - 55, 53, 48, 41, 48, 52, 56, 53, 50, 44, 38, 46, 50, 52, 50, 47, 42, 31, 41, - 46, 48, 45, 45, 40, 27, 37, 41, 43, 43, 43, 40, 22, 35, 40, 42, 43, 41, 41, - 41, 48, 50, 51, 51, 49, 42, 36, 46, 48, 50, 49, 46, 41, 33, 43, 47, 48, 46, - 45, 38, 30, 41, 44, 44, 44, 40, 35, 24, 34, 39, 40, 38, 36, 35, 19, 30, 36, - 36, 36, 35, 35, 17, 24, 34, 35, 35, 33, 32, 33, 41, 43, 44, 44, 41, 35, 29, - 38, 42, 43, 40, 38, 33, 26, 34, 40, 40, 39, 33, 31, 22, 30, 36, 36, 34, 29, - 30, 20, 23, 31, 32, 30, 24, 26, 19, 18, 28, 29, 27, 23, 22, 17, 14, 24, 27, - 27, 22, 18, 21, 31, 34, 35, 32, 29, 35, 17, 26, 33, 33, 30, 25, 33, 17, 21, - 30, 30, 28, 21, 27, 17, 16, 25, 27, 24, 15, 22, 15, 11, 20, 22, 17, 11, 17, - 14, 9, 15, 18, 16, 10, 14, 13, 9, 10, 17, 15, 9, 12, 13, 17, 25, 24, 23, - 25, 31, 13, 13, 22, 23, 22, 23, 26, 13, 9, 20, 20, 18, 19, 21, 12, 8, 14, - 16, 14, 13, 14, 10, 6, 8, 12, 7, 10, 12, 9, 5, 4, 7, 5, 8, 10, 7, - 6, 4, 5, 5, 8, 10, 9, 8, 17, 19, 21, 24, 25, 9, 8, 15, 18, 20, 21, - 22, 9, 8, 11, 17, 17, 17, 17, 9, 7, 6, 12, 12, 12, 11, 6, 5, 4, 6, - 6, 7, 10, 5, 4, 2, 2, 4, 6, 9, 5, 3, 0, 0, 3, 5, 8, 43, 47, - 51, 55, 55, 53, 49, 40, 45, 50, 53, 53, 50, 45, 39, 44, 47, 51, 52, 48, 43, - 39, 42, 46, 47, 49, 46, 39, 35, 38, 41, 45, 46, 43, 39, 30, 34, 37, 40, 44, - 43, 38, 27, 32, 36, 39, 42, 43, 40, 40, 43, 48, 51, 51, 47, 43, 39, 42, 47, - 50, 50, 47, 41, 36, 41, 45, 47, 48, 44, 39, 33, 38, 42, 44, 44, 40, 34, 27, - 36, 38, 42, 39, 38, 35, 22, 32, 35, 37, 36, 37, 34, 18, 29, 34, 37, 37, 35, - 34, 36, 40, 43, 44, 45, 42, 37, 32, 38, 42, 44, 42, 41, 33, 28, 38, 40, 40, - 40, 38, 33, 25, 35, 36, 36, 36, 34, 29, 19, 30, 33, 33, 32, 30, 29, 14, 26, - 30, 29, 30, 28, 29, 13, 21, 29, 28, 29, 28, 26, 28, 36, 36, 37, 37, 35, 29, - 24, 32, 35, 36, 35, 31, 27, 20, 30, 33, 33, 32, 28, 25, 17, 24, 29, 28, 28, - 24, 24, 15, 18, 25, 26, 24, 19, 20, 14, 14, 23, 22, 22, 19, 17, 13, 10, 20, - 21, 21, 18, 12, 16, 25, 28, 29, 26, 23, 28, 13, 21, 26, 27, 25, 19, 27, 13, - 17, 24, 24, 22, 16, 21, 13, 12, 20, 19, 18, 11, 16, 11, 7, 16, 16, 13, 7, - 12, 10, 5, 12, 13, 12, 6, 9, 9, 6, 8, 11, 10, 6, 8, 8, 14, 19, 19, - 18, 20, 24, 8, 10, 17, 18, 17, 17, 20, 8, 6, 14, 14, 14, 14, 15, 8, 5, - 11, 11, 10, 10, 10, 6, 3, 5, 6, 4, 6, 8, 4, 3, 2, 2, 3, 5, 7, - 4, 3, 2, 1, 3, 4, 6, 6, 6, 13, 15, 17, 19, 20, 6, 6, 12, 14, 16, - 16, 17, 6, 6, 9, 12, 12, 12, 13, 6, 5, 5, 8, 8, 8, 7, 4, 3, 3, - 2, 3, 4, 6, 3, 2, 3, 2, 2, 4, 5, 3, 2, 3, 3, 0, 4, 5, 36, - 40, 45, 47, 47, 44, 40, 34, 38, 42, 46, 46, 43, 38, 32, 36, 41, 44, 45, 42, - 36, 31, 34, 38, 40, 43, 39, 33, 29, 32, 33, 37, 39, 36, 32, 25, 27, 31, 33, - 37, 36, 33, 23, 26, 29, 33, 36, 37, 33, 33, 36, 41, 45, 43, 40, 35, 31, 35, - 39, 44, 43, 39, 35, 30, 33, 38, 41, 39, 36, 32, 29, 31, 34, 37, 37, 35, 29, - 24, 29, 31, 34, 32, 32, 29, 19, 26, 28, 31, 30, 32, 28, 15, 24, 27, 30, 30, - 29, 28, 31, 34, 36, 37, 37, 36, 30, 28, 32, 34, 36, 36, 35, 28, 25, 31, 34, - 34, 34, 31, 25, 20, 29, 29, 29, 30, 28, 23, 15, 24, 26, 26, 25, 24, 23, 11, - 21, 23, 23, 24, 23, 23, 10, 19, 24, 23, 22, 23, 20, 25, 29, 28, 30, 30, 29, - 23, 20, 27, 28, 29, 29, 26, 21, 17, 24, 27, 26, 26, 22, 19, 14, 20, 23, 22, - 22, 19, 18, 11, 15, 19, 19, 18, 14, 15, 11, 11, 17, 16, 16, 14, 11, 10, 7, - 16, 15, 15, 14, 8, 12, 20, 21, 22, 21, 18, 22, 9, 17, 20, 20, 20, 15, 21, - 9, 14, 18, 17, 17, 12, 15, 9, 8, 15, 14, 13, 7, 10, 7, 3, 10, 10, 9, - 5, 7, 6, 3, 8, 7, 7, 4, 5, 6, 4, 5, 6, 5, 4, 5, 5, 11, 12, - 13, 14, 16, 19, 5, 8, 11, 12, 13, 13, 15, 5, 5, 10, 9, 10, 10, 10, 5, - 3, 7, 6, 6, 6, 5, 3, 2, 1, 1, 2, 4, 4, 2, 2, 4, 3, 0, 3, - 5, 3, 2, 4, 4, 2, 2, 4, 5, 5, 9, 11, 13, 15, 15, 5, 5, 8, 10, - 12, 12, 12, 5, 5, 7, 8, 8, 9, 9, 5, 4, 4, 4, 4, 5, 4, 3, 2, - 4, 4, 1, 2, 4, 1, 4, 5, 5, 3, 2, 3, 2, 5, 5, 5, 3, 0, 3, - 29, 34, 38, 41, 41, 39, 34, 28, 31, 36, 40, 40, 37, 33, 27, 31, 34, 38, 39, - 36, 30, 26, 28, 31, 34, 37, 32, 27, 23, 25, 27, 31, 33, 31, 27, 20, 22, 25, - 28, 33, 31, 27, 19, 21, 23, 27, 30, 30, 28, 27, 30, 34, 38, 38, 34, 31, 26, - 29, 32, 37, 36, 34, 29, 25, 27, 32, 35, 33, 31, 26, 23, 25, 28, 31, 30, 28, - 23, 20, 23, 25, 28, 27, 26, 22, 17, 20, 23, 25, 25, 25, 23, 14, 19, 22, 24, - 24, 24, 24, 25, 28, 29, 31, 32, 30, 26, 23, 27, 28, 29, 30, 27, 23, 22, 25, - 28, 27, 27, 26, 21, 18, 23, 24, 23, 23, 23, 17, 12, 20, 20, 19, 20, 18, 17, - 8, 19, 19, 18, 18, 18, 17, 8, 16, 18, 17, 17, 18, 15, 21, 23, 23, 23, 25, - 24, 17, 18, 21, 22, 22, 22, 22, 15, 14, 20, 20, 19, 20, 18, 14, 10, 17, 17, - 16, 16, 15, 13, 8, 13, 13, 12, 12, 11, 10, 8, 9, 12, 11, 10, 10, 7, 8, - 6, 10, 9, 9, 9, 4, 9, 15, 15, 16, 17, 14, 17, 6, 13, 13, 14, 14, 11, - 15, 6, 11, 11, 11, 11, 8, 10, 6, 6, 8, 8, 7, 5, 6, 4, 2, 4, 4, - 3, 3, 4, 3, 2, 2, 2, 2, 3, 4, 4, 2, 3, 2, 1, 2, 3, 3, 7, - 8, 9, 10, 12, 14, 3, 6, 8, 9, 9, 10, 10, 3, 4, 6, 6, 6, 7, 7, - 3, 3, 3, 3, 3, 4, 3, 1, 3, 5, 3, 2, 2, 3, 1, 4, 6, 4, 3, - 0, 3, 2, 5, 6, 5, 3, 2, 2, 4, 6, 6, 8, 9, 11, 12, 4, 6, 6, - 7, 8, 9, 9, 4, 6, 6, 5, 5, 5, 6, 4, 4, 6, 3, 2, 2, 3, 2, - 5, 7, 6, 3, 2, 2, 4, 6, 8, 7, 4, 3, 2, 5, 7, 8, 8, 5, 3, - 0, -}; diff --git a/libwebp/extras/sharpyuv_risk_table.h b/libwebp/extras/sharpyuv_risk_table.h deleted file mode 100644 index 32f276e3..00000000 --- a/libwebp/extras/sharpyuv_risk_table.h +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2023 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Precomputed data for 420 risk estimation. - -#ifndef WEBP_EXTRAS_SHARPYUV_RISK_TABLE_H_ -#define WEBP_EXTRAS_SHARPYUV_RISK_TABLE_H_ - -#include "src/webp/types.h" - -extern const int kSharpYuvPrecomputedRiskYuvSampling; -// Table of precomputed risk scores when chroma subsampling images with two -// given colors. -// Since precomputing values for all possible YUV colors would create a huge -// table, the YUV space (i.e. [0, 255]^3) is reduced to -// [0, kSharpYuvPrecomputedRiskYuvSampling-1]^3 -// where 255 maps to kSharpYuvPrecomputedRiskYuvSampling-1. -// Table size: kSharpYuvPrecomputedRiskYuvSampling^6 bytes or 114 KiB -extern const uint8_t kSharpYuvPrecomputedRisk[]; - -#endif // WEBP_EXTRAS_SHARPYUV_RISK_TABLE_H_ diff --git a/libwebp/extras/vwebp_sdl.c b/libwebp/extras/vwebp_sdl.c deleted file mode 100644 index acf48909..00000000 --- a/libwebp/extras/vwebp_sdl.c +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2017 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Simple SDL-based WebP file viewer. -// Does not support animation, just static images. -// -// Press 'q' to exit. -// -// Author: James Zern (jzern@google.com) - -#include - -#ifdef HAVE_CONFIG_H -#include "webp/config.h" -#endif - -#if defined(WEBP_HAVE_SDL) - -#include "webp_to_sdl.h" -#include "webp/decode.h" -#include "imageio/imageio_util.h" -#include "../examples/unicode.h" - -#if defined(WEBP_HAVE_JUST_SDL_H) -#include -#else -#include -#endif - -static void ProcessEvents(void) { - int done = 0; - SDL_Event event; - while (!done && SDL_WaitEvent(&event)) { - switch (event.type) { - case SDL_KEYUP: - switch (event.key.keysym.sym) { - case SDLK_q: done = 1; break; - default: break; - } - break; - default: break; - } - } -} - -int main(int argc, char* argv[]) { - int c; - int ok = 0; - - INIT_WARGV(argc, argv); - - for (c = 1; c < argc; ++c) { - const char* file = NULL; - const uint8_t* webp = NULL; - size_t webp_size = 0; - if (!strcmp(argv[c], "-h")) { - printf("Usage: %s [-h] image.webp [more_files.webp...]\n", argv[0]); - FREE_WARGV_AND_RETURN(0); - } else { - file = (const char*)GET_WARGV(argv, c); - } - if (file == NULL) continue; - if (!ImgIoUtilReadFile(file, &webp, &webp_size)) { - WFPRINTF(stderr, "Error opening file: %s\n", (const W_CHAR*)file); - goto Error; - } - if (webp_size != (size_t)(int)webp_size) { - free((void*)webp); - fprintf(stderr, "File too large.\n"); - goto Error; - } - ok = WebPToSDL((const char*)webp, (int)webp_size); - free((void*)webp); - if (!ok) { - WFPRINTF(stderr, "Error decoding file %s\n", (const W_CHAR*)file); - goto Error; - } - ProcessEvents(); - } - ok = 1; - - Error: - SDL_Quit(); - FREE_WARGV_AND_RETURN(ok ? 0 : 1); -} - -#else // !WEBP_HAVE_SDL - -int main(int argc, const char* argv[]) { - fprintf(stderr, "SDL support not enabled in %s.\n", argv[0]); - (void)argc; - return 0; -} - -#endif diff --git a/libwebp/extras/webp_quality.c b/libwebp/extras/webp_quality.c deleted file mode 100644 index 0a3b25f1..00000000 --- a/libwebp/extras/webp_quality.c +++ /dev/null @@ -1,54 +0,0 @@ -// Simple tool to roughly evaluate the quality encoding of a webp bitstream -// -// Result is a *rough* estimation of the quality. You should just consider -// the bucket it's in (q > 80? > 50? > 20?) and not take it for face value. -/* - gcc -o webp_quality webp_quality.c -O3 -I../ -L. -L../imageio \ - -limageio_util -lwebpextras -lwebp -lm -lpthread -*/ - -#include -#include -#include - -#include "extras/extras.h" -#include "imageio/imageio_util.h" -#include "../examples/unicode.h" - -int main(int argc, const char* argv[]) { - int c; - int quiet = 0; - int ok = 1; - - INIT_WARGV(argc, argv); - - for (c = 1; ok && c < argc; ++c) { - if (!strcmp(argv[c], "-quiet")) { - quiet = 1; - } else if (!strcmp(argv[c], "-help") || !strcmp(argv[c], "-h")) { - printf("webp_quality [-h][-quiet] webp_files...\n"); - FREE_WARGV_AND_RETURN(0); - } else { - const char* const filename = (const char*)GET_WARGV(argv, c); - const uint8_t* data = NULL; - size_t data_size = 0; - int q; - ok = ImgIoUtilReadFile(filename, &data, &data_size); - if (!ok) break; - q = VP8EstimateQuality(data, data_size); - if (!quiet) WPRINTF("[%s] ", (const W_CHAR*)filename); - if (q < 0) { - fprintf(stderr, "Not a WebP file, or not a lossy WebP file.\n"); - ok = 0; - } else { - if (!quiet) { - printf("Estimated quality factor: %d\n", q); - } else { - printf("%d\n", q); // just print the number - } - } - free((void*)data); - } - } - FREE_WARGV_AND_RETURN(ok ? 0 : 1); -} diff --git a/libwebp/extras/webp_to_sdl.c b/libwebp/extras/webp_to_sdl.c deleted file mode 100644 index 971ffc88..00000000 --- a/libwebp/extras/webp_to_sdl.c +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2017 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Simple WebP-to-SDL wrapper. Useful for emscripten. -// -// Author: James Zern (jzern@google.com) - -#ifdef HAVE_CONFIG_H -#include "src/webp/config.h" -#endif - -#if defined(WEBP_HAVE_SDL) - -#include "webp_to_sdl.h" - -#include - -#include "src/webp/decode.h" - -#if defined(WEBP_HAVE_JUST_SDL_H) -#include -#else -#include -#endif - -static int init_ok = 0; -int WebPToSDL(const char* data, unsigned int data_size) { - int ok = 0; - VP8StatusCode status; - WebPBitstreamFeatures input; - uint8_t* output = NULL; - SDL_Window* window = NULL; - SDL_Renderer* renderer = NULL; - SDL_Texture* texture = NULL; - int width, height; - - if (!init_ok) { - SDL_Init(SDL_INIT_VIDEO); - init_ok = 1; - } - - status = WebPGetFeatures((uint8_t*)data, (size_t)data_size, &input); - if (status != VP8_STATUS_OK) goto Error; - width = input.width; - height = input.height; - - SDL_CreateWindowAndRenderer(width, height, 0, &window, &renderer); - if (window == NULL || renderer == NULL) { - fprintf(stderr, "Unable to create window or renderer!\n"); - goto Error; - } - SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, - "linear"); // make the scaled rendering look smoother. - SDL_RenderSetLogicalSize(renderer, width, height); - - texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ABGR8888, - SDL_TEXTUREACCESS_STREAMING, width, height); - if (texture == NULL) { - fprintf(stderr, "Unable to create %dx%d RGBA texture!\n", width, height); - goto Error; - } - -#if SDL_BYTEORDER == SDL_BIG_ENDIAN - output = WebPDecodeBGRA((const uint8_t*)data, (size_t)data_size, &width, - &height); -#else - output = WebPDecodeRGBA((const uint8_t*)data, (size_t)data_size, &width, - &height); -#endif - if (output == NULL) { - fprintf(stderr, "Error decoding image (%d)\n", status); - goto Error; - } - - SDL_UpdateTexture(texture, NULL, output, width * sizeof(uint32_t)); - SDL_RenderClear(renderer); - SDL_RenderCopy(renderer, texture, NULL, NULL); - SDL_RenderPresent(renderer); - ok = 1; - - Error: - // We should call SDL_DestroyWindow(window) but that makes .js fail. - SDL_DestroyRenderer(renderer); - SDL_DestroyTexture(texture); - WebPFree(output); - return ok; -} - -//------------------------------------------------------------------------------ - -#endif // WEBP_HAVE_SDL diff --git a/libwebp/extras/webp_to_sdl.h b/libwebp/extras/webp_to_sdl.h deleted file mode 100644 index 1534f2b4..00000000 --- a/libwebp/extras/webp_to_sdl.h +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2017 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Simple WebP-to-SDL wrapper. Useful for emscripten. -// -// Author: James Zern (jzern@google.com) - -#ifndef WEBP_EXTRAS_WEBP_TO_SDL_H_ -#define WEBP_EXTRAS_WEBP_TO_SDL_H_ - -// Exports the method WebPToSDL(const char* data, int data_size) which decodes -// a WebP bitstream into an RGBA SDL surface. -// Return false on failure. -extern int WebPToSDL(const char* data, unsigned int data_size); - -#endif // WEBP_EXTRAS_WEBP_TO_SDL_H_ diff --git a/libwebp/gradle.properties b/libwebp/gradle.properties deleted file mode 100644 index 28d39f5d..00000000 --- a/libwebp/gradle.properties +++ /dev/null @@ -1,14 +0,0 @@ -# Project-wide Gradle settings. - -# IDE (e.g. Android Studio) users: -# Gradle settings configured through the IDE *will override* -# any settings specified in this file. - -# For more details on how to configure your build environment visit -# http://www.gradle.org/docs/current/userguide/build_environment.html - -# Versions for gradle -BUILD_TOOLS_VERSION=23.0.3 -COMPILE_SDK_VERSION=23 -ANDROID_GRADLE_PLUGIN_VERSION=1.5.0 -GRADLE_DOWNLOAD_TASK_VERSION=2.1.0 diff --git a/libwebp/gradle/wrapper/gradle-wrapper.jar b/libwebp/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index f3d88b1c..00000000 Binary files a/libwebp/gradle/wrapper/gradle-wrapper.jar and /dev/null differ diff --git a/libwebp/gradle/wrapper/gradle-wrapper.properties b/libwebp/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 1b16c34a..00000000 --- a/libwebp/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-bin.zip -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/libwebp/gradlew b/libwebp/gradlew deleted file mode 100644 index 2fe81a7d..00000000 --- a/libwebp/gradlew +++ /dev/null @@ -1,183 +0,0 @@ -#!/usr/bin/env sh - -# -# Copyright 2015 the original author or authors. -# -# 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 -# -# https://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. -# - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn () { - echo "$*" -} - -die () { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=`expr $i + 1` - done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" - -exec "$JAVACMD" "$@" diff --git a/libwebp/gradlew.bat b/libwebp/gradlew.bat deleted file mode 100644 index 9618d8d9..00000000 --- a/libwebp/gradlew.bat +++ /dev/null @@ -1,100 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/libwebp/imageio/Android.mk b/libwebp/imageio/Android.mk deleted file mode 100644 index 1c8b8367..00000000 --- a/libwebp/imageio/Android.mk +++ /dev/null @@ -1,57 +0,0 @@ -# Ignore this file during non-NDK builds. -ifdef NDK_ROOT -LOCAL_PATH := $(call my-dir) - -################################################################################ -# libimageio_util - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - imageio_util.c \ - -LOCAL_CFLAGS := $(WEBP_CFLAGS) -LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src - -LOCAL_MODULE := imageio_util - -include $(BUILD_STATIC_LIBRARY) - -################################################################################ -# libimagedec - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - image_dec.c \ - jpegdec.c \ - metadata.c \ - pngdec.c \ - pnmdec.c \ - tiffdec.c \ - webpdec.c \ - -LOCAL_CFLAGS := $(WEBP_CFLAGS) -LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src -LOCAL_STATIC_LIBRARIES := imageio_util - -LOCAL_MODULE := imagedec - -include $(BUILD_STATIC_LIBRARY) - -################################################################################ -# libimageenc - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - image_enc.c \ - -LOCAL_CFLAGS := $(WEBP_CFLAGS) -LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src -LOCAL_STATIC_LIBRARIES := imageio_util - -LOCAL_MODULE := imageenc - -include $(BUILD_STATIC_LIBRARY) -endif # NDK_ROOT diff --git a/libwebp/imageio/Makefile.am b/libwebp/imageio/Makefile.am deleted file mode 100644 index 500ec7e3..00000000 --- a/libwebp/imageio/Makefile.am +++ /dev/null @@ -1,32 +0,0 @@ -AM_CPPFLAGS += -I$(top_builddir)/src -I$(top_srcdir)/src -noinst_LTLIBRARIES = -noinst_LTLIBRARIES += libimageio_util.la -if BUILD_DEMUX - noinst_LTLIBRARIES += libimagedec.la -endif -noinst_LTLIBRARIES += libimageenc.la - -noinst_HEADERS = -noinst_HEADERS += ../src/webp/decode.h -noinst_HEADERS += ../src/webp/types.h - -libimageio_util_la_SOURCES = -libimageio_util_la_SOURCES += imageio_util.c imageio_util.h - -libimagedec_la_SOURCES = -libimagedec_la_SOURCES += image_dec.c image_dec.h -libimagedec_la_SOURCES += jpegdec.c jpegdec.h -libimagedec_la_SOURCES += metadata.c metadata.h -libimagedec_la_SOURCES += pngdec.c pngdec.h -libimagedec_la_SOURCES += pnmdec.c pnmdec.h -libimagedec_la_SOURCES += tiffdec.c tiffdec.h -libimagedec_la_SOURCES += webpdec.c webpdec.h -libimagedec_la_SOURCES += wicdec.c wicdec.h -libimagedec_la_CPPFLAGS = $(JPEG_INCLUDES) $(PNG_INCLUDES) $(TIFF_INCLUDES) -libimagedec_la_CPPFLAGS += $(AM_CPPFLAGS) -libimagedec_la_LIBADD = ../src/demux/libwebpdemux.la - -libimageenc_la_SOURCES = -libimageenc_la_SOURCES += image_enc.c image_enc.h -libimageenc_la_CPPFLAGS = $(JPEG_INCLUDES) $(PNG_INCLUDES) $(TIFF_INCLUDES) -libimageenc_la_CPPFLAGS += $(AM_CPPFLAGS) diff --git a/libwebp/imageio/image_dec.c b/libwebp/imageio/image_dec.c deleted file mode 100644 index 5e003fab..00000000 --- a/libwebp/imageio/image_dec.c +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2016 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Generic image-type guessing. - -#include "./image_dec.h" - -const char* WebPGetEnabledInputFileFormats(void) { - return "WebP" -#ifdef WEBP_HAVE_JPEG - ", JPEG" -#endif -#ifdef WEBP_HAVE_PNG - ", PNG" -#endif - ", PNM (PGM, PPM, PAM)" -#ifdef WEBP_HAVE_TIFF - ", TIFF" -#endif -#ifdef HAVE_WINCODEC_H - ", Windows Imaging Component (WIC)" -#endif - ""; -} - -static WEBP_INLINE uint32_t GetBE32(const uint8_t buf[]) { - return ((uint32_t)buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; -} - -WebPInputFileFormat WebPGuessImageType(const uint8_t* const data, - size_t data_size) { - WebPInputFileFormat format = WEBP_UNSUPPORTED_FORMAT; - if (data != NULL && data_size >= 12) { - const uint32_t magic1 = GetBE32(data + 0); - const uint32_t magic2 = GetBE32(data + 8); - if (magic1 == 0x89504E47U) { - format = WEBP_PNG_FORMAT; - } else if (magic1 >= 0xFFD8FF00U && magic1 <= 0xFFD8FFFFU) { - format = WEBP_JPEG_FORMAT; - } else if (magic1 == 0x49492A00 || magic1 == 0x4D4D002A) { - format = WEBP_TIFF_FORMAT; - } else if (magic1 == 0x52494646 && magic2 == 0x57454250) { - format = WEBP_WEBP_FORMAT; - } else if (((magic1 >> 24) & 0xff) == 'P') { - const int type = (magic1 >> 16) & 0xff; - // we only support 'P5 -> P7' for now. - if (type >= '5' && type <= '7') format = WEBP_PNM_FORMAT; - } - } - return format; -} - -static int FailReader(const uint8_t* const data, size_t data_size, - struct WebPPicture* const pic, - int keep_alpha, struct Metadata* const metadata) { - (void)data; - (void)data_size; - (void)pic; - (void)keep_alpha; - (void)metadata; - return 0; -} - -WebPImageReader WebPGetImageReader(WebPInputFileFormat format) { - switch (format) { - case WEBP_PNG_FORMAT: return ReadPNG; - case WEBP_JPEG_FORMAT: return ReadJPEG; - case WEBP_TIFF_FORMAT: return ReadTIFF; - case WEBP_WEBP_FORMAT: return ReadWebP; - case WEBP_PNM_FORMAT: return ReadPNM; - default: return FailReader; - } -} - -WebPImageReader WebPGuessImageReader(const uint8_t* const data, - size_t data_size) { - return WebPGetImageReader(WebPGuessImageType(data, data_size)); -} diff --git a/libwebp/imageio/image_dec.h b/libwebp/imageio/image_dec.h deleted file mode 100644 index f09f564b..00000000 --- a/libwebp/imageio/image_dec.h +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2016 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// All-in-one library to decode PNG/JPEG/WebP/TIFF/WIC input images. -// -// Author: Skal (pascal.massimino@gmail.com) - -#ifndef WEBP_IMAGEIO_IMAGE_DEC_H_ -#define WEBP_IMAGEIO_IMAGE_DEC_H_ - -#include "webp/types.h" - -#ifdef HAVE_CONFIG_H -#include "webp/config.h" -#endif - -#include "./metadata.h" -#include "./jpegdec.h" -#include "./pngdec.h" -#include "./pnmdec.h" -#include "./tiffdec.h" -#include "./webpdec.h" -#include "./wicdec.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - WEBP_PNG_FORMAT = 0, - WEBP_JPEG_FORMAT, - WEBP_TIFF_FORMAT, - WEBP_WEBP_FORMAT, - WEBP_PNM_FORMAT, - WEBP_UNSUPPORTED_FORMAT -} WebPInputFileFormat; - -// Returns a comma separated list of enabled input formats. -const char* WebPGetEnabledInputFileFormats(void); - -// Try to infer the image format. 'data_size' should be larger than 12. -// Returns WEBP_UNSUPPORTED_FORMAT if format can't be guess safely. -WebPInputFileFormat WebPGuessImageType(const uint8_t* const data, - size_t data_size); - -// Signature for common image-reading functions (ReadPNG, ReadJPEG, ...) -typedef int (*WebPImageReader)(const uint8_t* const data, size_t data_size, - struct WebPPicture* const pic, - int keep_alpha, struct Metadata* const metadata); - -// Return the reader associated to a given file format. -WebPImageReader WebPGetImageReader(WebPInputFileFormat format); - -// This function is similar to WebPGuessImageType(), but returns a -// suitable reader function. The returned reader is never NULL, but -// unknown formats will return an always-failing valid reader. -WebPImageReader WebPGuessImageReader(const uint8_t* const data, - size_t data_size); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // WEBP_IMAGEIO_IMAGE_DEC_H_ diff --git a/libwebp/imageio/image_enc.c b/libwebp/imageio/image_enc.c deleted file mode 100644 index d58477f3..00000000 --- a/libwebp/imageio/image_enc.c +++ /dev/null @@ -1,638 +0,0 @@ -// Copyright 2016 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Save image - -#include "./image_enc.h" - -#include -#include - -#ifdef WEBP_HAVE_PNG -#include -#include // note: this must be included *after* png.h -#endif - -#ifdef HAVE_WINCODEC_H -#ifdef __MINGW32__ -#define INITGUID // Without this GUIDs are declared extern and fail to link -#endif -#define CINTERFACE -#define COBJMACROS -#define _WIN32_IE 0x500 // Workaround bug in shlwapi.h when compiling C++ - // code with COBJMACROS. -#include // CreateStreamOnHGlobal() -#include -#include -#include -#include -#endif - -#include "./imageio_util.h" -#include "../examples/unicode.h" - -//------------------------------------------------------------------------------ -// PNG - -#ifdef HAVE_WINCODEC_H - -#define IFS(fn) \ - do { \ - if (SUCCEEDED(hr)) { \ - hr = (fn); \ - if (FAILED(hr)) fprintf(stderr, #fn " failed %08lx\n", hr); \ - } \ - } while (0) - -#ifdef __cplusplus -#define MAKE_REFGUID(x) (x) -#else -#define MAKE_REFGUID(x) &(x) -#endif - -static HRESULT CreateOutputStream(const char* out_file_name, - int write_to_mem, IStream** stream) { - HRESULT hr = S_OK; - if (write_to_mem) { - // Output to a memory buffer. This is freed when 'stream' is released. - IFS(CreateStreamOnHGlobal(NULL, TRUE, stream)); - } else { - IFS(SHCreateStreamOnFile((const LPTSTR)out_file_name, - STGM_WRITE | STGM_CREATE, stream)); - } - if (FAILED(hr)) { - _ftprintf(stderr, _T("Error opening output file %s (%08lx)\n"), - (const LPTSTR)out_file_name, hr); - } - return hr; -} - -static HRESULT WriteUsingWIC(const char* out_file_name, int use_stdout, - REFGUID container_guid, - uint8_t* rgb, int stride, - uint32_t width, uint32_t height, int has_alpha) { - HRESULT hr = S_OK; - IWICImagingFactory* factory = NULL; - IWICBitmapFrameEncode* frame = NULL; - IWICBitmapEncoder* encoder = NULL; - IStream* stream = NULL; - WICPixelFormatGUID pixel_format = has_alpha ? GUID_WICPixelFormat32bppBGRA - : GUID_WICPixelFormat24bppBGR; - - if (out_file_name == NULL || rgb == NULL) return E_INVALIDARG; - - IFS(CoInitialize(NULL)); - IFS(CoCreateInstance(MAKE_REFGUID(CLSID_WICImagingFactory), NULL, - CLSCTX_INPROC_SERVER, - MAKE_REFGUID(IID_IWICImagingFactory), - (LPVOID*)&factory)); - if (hr == REGDB_E_CLASSNOTREG) { - fprintf(stderr, - "Couldn't access Windows Imaging Component (are you running " - "Windows XP SP3 or newer?). PNG support not available. " - "Use -ppm or -pgm for available PPM and PGM formats.\n"); - } - IFS(CreateOutputStream(out_file_name, use_stdout, &stream)); - IFS(IWICImagingFactory_CreateEncoder(factory, container_guid, NULL, - &encoder)); - IFS(IWICBitmapEncoder_Initialize(encoder, stream, - WICBitmapEncoderNoCache)); - IFS(IWICBitmapEncoder_CreateNewFrame(encoder, &frame, NULL)); - IFS(IWICBitmapFrameEncode_Initialize(frame, NULL)); - IFS(IWICBitmapFrameEncode_SetSize(frame, width, height)); - IFS(IWICBitmapFrameEncode_SetPixelFormat(frame, &pixel_format)); - IFS(IWICBitmapFrameEncode_WritePixels(frame, height, stride, - height * stride, rgb)); - IFS(IWICBitmapFrameEncode_Commit(frame)); - IFS(IWICBitmapEncoder_Commit(encoder)); - - if (SUCCEEDED(hr) && use_stdout) { - HGLOBAL image; - IFS(GetHGlobalFromStream(stream, &image)); - if (SUCCEEDED(hr)) { - HANDLE std_output = GetStdHandle(STD_OUTPUT_HANDLE); - DWORD mode; - const BOOL update_mode = GetConsoleMode(std_output, &mode); - const void* const image_mem = GlobalLock(image); - DWORD bytes_written = 0; - - // Clear output processing if necessary, then output the image. - if (update_mode) SetConsoleMode(std_output, 0); - if (!WriteFile(std_output, image_mem, (DWORD)GlobalSize(image), - &bytes_written, NULL) || - bytes_written != GlobalSize(image)) { - hr = E_FAIL; - } - if (update_mode) SetConsoleMode(std_output, mode); - GlobalUnlock(image); - } - } - - if (frame != NULL) IUnknown_Release(frame); - if (encoder != NULL) IUnknown_Release(encoder); - if (factory != NULL) IUnknown_Release(factory); - if (stream != NULL) IUnknown_Release(stream); - return hr; -} - -int WebPWritePNG(const char* out_file_name, int use_stdout, - const WebPDecBuffer* const buffer) { - const uint32_t width = buffer->width; - const uint32_t height = buffer->height; - uint8_t* const rgb = buffer->u.RGBA.rgba; - const int stride = buffer->u.RGBA.stride; - const int has_alpha = WebPIsAlphaMode(buffer->colorspace); - - return SUCCEEDED(WriteUsingWIC(out_file_name, use_stdout, - MAKE_REFGUID(GUID_ContainerFormatPng), - rgb, stride, width, height, has_alpha)); -} - -#elif defined(WEBP_HAVE_PNG) // !HAVE_WINCODEC_H -static void PNGAPI PNGErrorFunction(png_structp png, png_const_charp unused) { - (void)unused; // remove variable-unused warning - longjmp(png_jmpbuf(png), 1); -} - -int WebPWritePNG(FILE* out_file, const WebPDecBuffer* const buffer) { - volatile png_structp png; - volatile png_infop info; - - if (out_file == NULL || buffer == NULL) return 0; - - png = png_create_write_struct(PNG_LIBPNG_VER_STRING, - NULL, PNGErrorFunction, NULL); - if (png == NULL) { - return 0; - } - info = png_create_info_struct(png); - if (info == NULL) { - png_destroy_write_struct((png_structpp)&png, NULL); - return 0; - } - if (setjmp(png_jmpbuf(png))) { - png_destroy_write_struct((png_structpp)&png, (png_infopp)&info); - return 0; - } - png_init_io(png, out_file); - { - const uint32_t width = buffer->width; - const uint32_t height = buffer->height; - png_bytep row = buffer->u.RGBA.rgba; - const int stride = buffer->u.RGBA.stride; - const int has_alpha = WebPIsAlphaMode(buffer->colorspace); - uint32_t y; - - png_set_IHDR(png, info, width, height, 8, - has_alpha ? PNG_COLOR_TYPE_RGBA : PNG_COLOR_TYPE_RGB, - PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, - PNG_FILTER_TYPE_DEFAULT); - png_write_info(png, info); - for (y = 0; y < height; ++y) { - png_write_rows(png, &row, 1); - row += stride; - } - } - png_write_end(png, info); - png_destroy_write_struct((png_structpp)&png, (png_infopp)&info); - return 1; -} -#else // !HAVE_WINCODEC_H && !WEBP_HAVE_PNG -int WebPWritePNG(FILE* fout, const WebPDecBuffer* const buffer) { - if (fout == NULL || buffer == NULL) return 0; - - fprintf(stderr, "PNG support not compiled. Please install the libpng " - "development package before building.\n"); - fprintf(stderr, "You can run with -ppm flag to decode in PPM format.\n"); - return 0; -} -#endif - -//------------------------------------------------------------------------------ -// PPM / PAM - -static int WritePPMPAM(FILE* fout, const WebPDecBuffer* const buffer, - int alpha) { - if (fout == NULL || buffer == NULL) { - return 0; - } else { - const uint32_t width = buffer->width; - const uint32_t height = buffer->height; - const uint8_t* row = buffer->u.RGBA.rgba; - const int stride = buffer->u.RGBA.stride; - const size_t bytes_per_px = alpha ? 4 : 3; - uint32_t y; - - if (row == NULL) return 0; - - if (alpha) { - fprintf(fout, "P7\nWIDTH %u\nHEIGHT %u\nDEPTH 4\nMAXVAL 255\n" - "TUPLTYPE RGB_ALPHA\nENDHDR\n", width, height); - } else { - fprintf(fout, "P6\n%u %u\n255\n", width, height); - } - for (y = 0; y < height; ++y) { - if (fwrite(row, width, bytes_per_px, fout) != bytes_per_px) { - return 0; - } - row += stride; - } - } - return 1; -} - -int WebPWritePPM(FILE* fout, const WebPDecBuffer* const buffer) { - return WritePPMPAM(fout, buffer, 0); -} - -int WebPWritePAM(FILE* fout, const WebPDecBuffer* const buffer) { - return WritePPMPAM(fout, buffer, 1); -} - -//------------------------------------------------------------------------------ -// Raw PGM - -// Save 16b mode (RGBA4444, RGB565, ...) for debugging purpose. -int WebPWrite16bAsPGM(FILE* fout, const WebPDecBuffer* const buffer) { - uint32_t width, height; - uint8_t* rgba; - int stride; - const uint32_t bytes_per_px = 2; - uint32_t y; - - if (fout == NULL || buffer == NULL) return 0; - - width = buffer->width; - height = buffer->height; - rgba = buffer->u.RGBA.rgba; - stride = buffer->u.RGBA.stride; - - if (rgba == NULL) return 0; - - fprintf(fout, "P5\n%u %u\n255\n", width * bytes_per_px, height); - for (y = 0; y < height; ++y) { - if (fwrite(rgba, width, bytes_per_px, fout) != bytes_per_px) { - return 0; - } - rgba += stride; - } - return 1; -} - -//------------------------------------------------------------------------------ -// BMP (see https://en.wikipedia.org/wiki/BMP_file_format#Pixel_storage) - -static void PutLE16(uint8_t* const dst, uint32_t value) { - dst[0] = (value >> 0) & 0xff; - dst[1] = (value >> 8) & 0xff; -} - -static void PutLE32(uint8_t* const dst, uint32_t value) { - PutLE16(dst + 0, (value >> 0) & 0xffff); - PutLE16(dst + 2, (value >> 16) & 0xffff); -} - -#define BMP_HEADER_SIZE 54 -#define BMP_HEADER_ALPHA_EXTRA_SIZE 16 // for alpha info -int WebPWriteBMP(FILE* fout, const WebPDecBuffer* const buffer) { - int has_alpha, header_size; - uint32_t width, height; - uint8_t* rgba; - int stride; - uint32_t y; - uint32_t bytes_per_px, line_size, image_size, bmp_stride, total_size; - uint8_t bmp_header[BMP_HEADER_SIZE + BMP_HEADER_ALPHA_EXTRA_SIZE] = { 0 }; - - if (fout == NULL || buffer == NULL) return 0; - - has_alpha = WebPIsAlphaMode(buffer->colorspace); - header_size = BMP_HEADER_SIZE + (has_alpha ? BMP_HEADER_ALPHA_EXTRA_SIZE : 0); - width = buffer->width; - height = buffer->height; - rgba = buffer->u.RGBA.rgba; - stride = buffer->u.RGBA.stride; - bytes_per_px = has_alpha ? 4 : 3; - line_size = bytes_per_px * width; - bmp_stride = (line_size + 3) & ~3; // pad to 4 - image_size = bmp_stride * height; - total_size = image_size + header_size; - - if (rgba == NULL) return 0; - - // bitmap file header - PutLE16(bmp_header + 0, 0x4d42); // signature 'BM' - PutLE32(bmp_header + 2, total_size); // size including header - PutLE32(bmp_header + 6, 0); // reserved - PutLE32(bmp_header + 10, header_size); // offset to pixel array - // bitmap info header - PutLE32(bmp_header + 14, header_size - 14); // DIB header size - PutLE32(bmp_header + 18, width); // dimensions - PutLE32(bmp_header + 22, height); // no vertical flip - PutLE16(bmp_header + 26, 1); // number of planes - PutLE16(bmp_header + 28, bytes_per_px * 8); // bits per pixel - PutLE32(bmp_header + 30, has_alpha ? 3 : 0); // BI_BITFIELDS or BI_RGB - PutLE32(bmp_header + 34, image_size); - PutLE32(bmp_header + 38, 2400); // x pixels/meter - PutLE32(bmp_header + 42, 2400); // y pixels/meter - PutLE32(bmp_header + 46, 0); // number of palette colors - PutLE32(bmp_header + 50, 0); // important color count - if (has_alpha) { // BITMAPV3INFOHEADER complement - PutLE32(bmp_header + 54, 0x00ff0000); // red mask - PutLE32(bmp_header + 58, 0x0000ff00); // green mask - PutLE32(bmp_header + 62, 0x000000ff); // blue mask - PutLE32(bmp_header + 66, 0xff000000); // alpha mask - } - - // TODO(skal): color profile - - // write header - if (fwrite(bmp_header, header_size, 1, fout) != 1) { - return 0; - } - - // write pixel array, bottom to top - for (y = 0; y < height; ++y) { - const uint8_t* const src = &rgba[(uint64_t)(height - 1 - y) * stride]; - if (fwrite(src, line_size, 1, fout) != 1) { - return 0; - } - // write padding zeroes - if (bmp_stride != line_size) { - const uint8_t zeroes[3] = { 0 }; - if (fwrite(zeroes, bmp_stride - line_size, 1, fout) != 1) { - return 0; - } - } - } - return 1; -} -#undef BMP_HEADER_SIZE -#undef BMP_HEADER_ALPHA_EXTRA_SIZE - -//------------------------------------------------------------------------------ -// TIFF - -#define NUM_IFD_ENTRIES 15 -#define EXTRA_DATA_SIZE 16 -// 10b for signature/header + n * 12b entries + 4b for IFD terminator: -#define EXTRA_DATA_OFFSET (10 + 12 * NUM_IFD_ENTRIES + 4) -#define TIFF_HEADER_SIZE (EXTRA_DATA_OFFSET + EXTRA_DATA_SIZE) - -int WebPWriteTIFF(FILE* fout, const WebPDecBuffer* const buffer) { - int has_alpha; - uint32_t width, height; - uint8_t* rgba; - int stride; - uint8_t bytes_per_px = 0; - const uint8_t assoc_alpha = 0; - // For non-alpha case, we omit tag 0x152 (ExtraSamples). - const uint8_t num_ifd_entries = 0; - uint8_t tiff_header[TIFF_HEADER_SIZE] = { - 0x49, 0x49, 0x2a, 0x00, // little endian signature - 8, 0, 0, 0, // offset to the unique IFD that follows - // IFD (offset = 8). Entries must be written in increasing tag order. - num_ifd_entries, 0, // Number of entries in the IFD (12 bytes each). - 0x00, 0x01, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 10: Width (TBD) - 0x01, 0x01, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 22: Height (TBD) - 0x02, 0x01, 3, 0, bytes_per_px, 0, 0, 0, // 34: BitsPerSample: 8888 - EXTRA_DATA_OFFSET + 0, 0, 0, 0, - 0x03, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, // 46: Compression: none - 0x06, 0x01, 3, 0, 1, 0, 0, 0, 2, 0, 0, 0, // 58: Photometric: RGB - 0x11, 0x01, 4, 0, 1, 0, 0, 0, // 70: Strips offset: - TIFF_HEADER_SIZE, 0, 0, 0, // data follows header - 0x12, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, // 82: Orientation: topleft - 0x15, 0x01, 3, 0, 1, 0, 0, 0, // 94: SamplesPerPixels - bytes_per_px, 0, 0, 0, - 0x16, 0x01, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 106: Rows per strip (TBD) - 0x17, 0x01, 4, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 118: StripByteCount (TBD) - 0x1a, 0x01, 5, 0, 1, 0, 0, 0, // 130: X-resolution - EXTRA_DATA_OFFSET + 8, 0, 0, 0, - 0x1b, 0x01, 5, 0, 1, 0, 0, 0, // 142: Y-resolution - EXTRA_DATA_OFFSET + 8, 0, 0, 0, - 0x1c, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, // 154: PlanarConfiguration - 0x28, 0x01, 3, 0, 1, 0, 0, 0, 2, 0, 0, 0, // 166: ResolutionUnit (inch) - 0x52, 0x01, 3, 0, 1, 0, 0, 0, - assoc_alpha, 0, 0, 0, // 178: ExtraSamples: rgbA/RGBA - 0, 0, 0, 0, // 190: IFD terminator - // EXTRA_DATA_OFFSET: - 8, 0, 8, 0, 8, 0, 8, 0, // BitsPerSample - 72, 0, 0, 0, 1, 0, 0, 0 // 72 pixels/inch, for X/Y-resolution - }; - uint32_t y; - - if (fout == NULL || buffer == NULL) return 0; - - has_alpha = WebPIsAlphaMode(buffer->colorspace); - width = buffer->width; - height = buffer->height; - rgba = buffer->u.RGBA.rgba; - stride = buffer->u.RGBA.stride; - - if (rgba == NULL) return 0; - - // Update bytes_per_px, num_ifd_entries and assoc_alpha. - tiff_header[38] = tiff_header[102] = bytes_per_px = has_alpha ? 4 : 3; - tiff_header[8] = has_alpha ? NUM_IFD_ENTRIES : NUM_IFD_ENTRIES - 1; - tiff_header[186] = WebPIsPremultipliedMode(buffer->colorspace) ? 1 : 2; - - // Fill placeholders in IFD: - PutLE32(tiff_header + 10 + 8, width); - PutLE32(tiff_header + 22 + 8, height); - PutLE32(tiff_header + 106 + 8, height); - PutLE32(tiff_header + 118 + 8, width * bytes_per_px * height); - if (!has_alpha) PutLE32(tiff_header + 178, 0); // IFD terminator - - // write header - if (fwrite(tiff_header, sizeof(tiff_header), 1, fout) != 1) { - return 0; - } - // write pixel values - for (y = 0; y < height; ++y) { - if (fwrite(rgba, bytes_per_px, width, fout) != width) { - return 0; - } - rgba += stride; - } - - return 1; -} - -#undef TIFF_HEADER_SIZE -#undef EXTRA_DATA_OFFSET -#undef EXTRA_DATA_SIZE -#undef NUM_IFD_ENTRIES - -//------------------------------------------------------------------------------ -// Raw Alpha - -int WebPWriteAlphaPlane(FILE* fout, const WebPDecBuffer* const buffer) { - if (fout == NULL || buffer == NULL) { - return 0; - } else { - const uint32_t width = buffer->width; - const uint32_t height = buffer->height; - const uint8_t* a = buffer->u.YUVA.a; - const int a_stride = buffer->u.YUVA.a_stride; - uint32_t y; - - if (a == NULL) return 0; - - fprintf(fout, "P5\n%u %u\n255\n", width, height); - for (y = 0; y < height; ++y) { - if (fwrite(a, width, 1, fout) != 1) return 0; - a += a_stride; - } - return 1; - } -} - -//------------------------------------------------------------------------------ -// PGM with IMC4 layout - -int WebPWritePGM(FILE* fout, const WebPDecBuffer* const buffer) { - if (fout == NULL || buffer == NULL) { - return 0; - } else { - const int width = buffer->width; - const int height = buffer->height; - const WebPYUVABuffer* const yuv = &buffer->u.YUVA; - const uint8_t* src_y = yuv->y; - const uint8_t* src_u = yuv->u; - const uint8_t* src_v = yuv->v; - const uint8_t* src_a = yuv->a; - const int uv_width = (width + 1) / 2; - const int uv_height = (height + 1) / 2; - const int a_height = (src_a != NULL) ? height : 0; - int ok = 1; - int y; - - if (src_y == NULL || src_u == NULL || src_v == NULL) return 0; - - fprintf(fout, "P5\n%d %d\n255\n", - (width + 1) & ~1, height + uv_height + a_height); - for (y = 0; ok && y < height; ++y) { - ok &= (fwrite(src_y, width, 1, fout) == 1); - if (width & 1) fputc(0, fout); // padding byte - src_y += yuv->y_stride; - } - for (y = 0; ok && y < uv_height; ++y) { - ok &= (fwrite(src_u, uv_width, 1, fout) == 1); - ok &= (fwrite(src_v, uv_width, 1, fout) == 1); - src_u += yuv->u_stride; - src_v += yuv->v_stride; - } - for (y = 0; ok && y < a_height; ++y) { - ok &= (fwrite(src_a, width, 1, fout) == 1); - if (width & 1) fputc(0, fout); // padding byte - src_a += yuv->a_stride; - } - return ok; - } -} - -//------------------------------------------------------------------------------ -// Raw YUV(A) planes - -int WebPWriteYUV(FILE* fout, const WebPDecBuffer* const buffer) { - if (fout == NULL || buffer == NULL) { - return 0; - } else { - const int width = buffer->width; - const int height = buffer->height; - const WebPYUVABuffer* const yuv = &buffer->u.YUVA; - const uint8_t* src_y = yuv->y; - const uint8_t* src_u = yuv->u; - const uint8_t* src_v = yuv->v; - const uint8_t* src_a = yuv->a; - const int uv_width = (width + 1) / 2; - const int uv_height = (height + 1) / 2; - const int a_height = (src_a != NULL) ? height : 0; - int ok = 1; - int y; - - if (src_y == NULL || src_u == NULL || src_v == NULL) return 0; - - for (y = 0; ok && y < height; ++y) { - ok &= (fwrite(src_y, width, 1, fout) == 1); - src_y += yuv->y_stride; - } - for (y = 0; ok && y < uv_height; ++y) { - ok &= (fwrite(src_u, uv_width, 1, fout) == 1); - src_u += yuv->u_stride; - } - for (y = 0; ok && y < uv_height; ++y) { - ok &= (fwrite(src_v, uv_width, 1, fout) == 1); - src_v += yuv->v_stride; - } - for (y = 0; ok && y < a_height; ++y) { - ok &= (fwrite(src_a, width, 1, fout) == 1); - src_a += yuv->a_stride; - } - return ok; - } -} - -//------------------------------------------------------------------------------ -// Generic top-level call - -int WebPSaveImage(const WebPDecBuffer* const buffer, - WebPOutputFileFormat format, - const char* const out_file_name) { - FILE* fout = NULL; - int needs_open_file = 1; - const int use_stdout = - (out_file_name != NULL) && !WSTRCMP(out_file_name, "-"); - int ok = 1; - - if (buffer == NULL || out_file_name == NULL) return 0; - -#ifdef HAVE_WINCODEC_H - needs_open_file = (format != PNG); -#endif - - if (needs_open_file) { - fout = use_stdout ? ImgIoUtilSetBinaryMode(stdout) - : WFOPEN(out_file_name, "wb"); - if (fout == NULL) { - WFPRINTF(stderr, "Error opening output file %s\n", - (const W_CHAR*)out_file_name); - return 0; - } - } - - if (format == PNG || - format == RGBA || format == BGRA || format == ARGB || - format == rgbA || format == bgrA || format == Argb) { -#ifdef HAVE_WINCODEC_H - ok &= WebPWritePNG(out_file_name, use_stdout, buffer); -#else - ok &= WebPWritePNG(fout, buffer); -#endif - } else if (format == PAM) { - ok &= WebPWritePAM(fout, buffer); - } else if (format == PPM || format == RGB || format == BGR) { - ok &= WebPWritePPM(fout, buffer); - } else if (format == RGBA_4444 || format == RGB_565 || format == rgbA_4444) { - ok &= WebPWrite16bAsPGM(fout, buffer); - } else if (format == BMP) { - ok &= WebPWriteBMP(fout, buffer); - } else if (format == TIFF) { - ok &= WebPWriteTIFF(fout, buffer); - } else if (format == RAW_YUV) { - ok &= WebPWriteYUV(fout, buffer); - } else if (format == PGM || format == YUV || format == YUVA) { - ok &= WebPWritePGM(fout, buffer); - } else if (format == ALPHA_PLANE_ONLY) { - ok &= WebPWriteAlphaPlane(fout, buffer); - } - if (fout != NULL && fout != stdout) { - fclose(fout); - } - return ok; -} diff --git a/libwebp/imageio/image_enc.h b/libwebp/imageio/image_enc.h deleted file mode 100644 index d31e4bd3..00000000 --- a/libwebp/imageio/image_enc.h +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2016 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// All-in-one library to save PNG/JPEG/WebP/TIFF/WIC images. -// -// Author: Skal (pascal.massimino@gmail.com) - -#ifndef WEBP_IMAGEIO_IMAGE_ENC_H_ -#define WEBP_IMAGEIO_IMAGE_ENC_H_ - -#include - -#ifdef HAVE_CONFIG_H -#include "webp/config.h" -#endif - -#include "webp/types.h" -#include "webp/decode.h" - -#ifdef __cplusplus -extern "C" { -#endif - -// Output types -typedef enum { - PNG = 0, - PAM, - PPM, - PGM, - BMP, - TIFF, - RAW_YUV, - ALPHA_PLANE_ONLY, // this is for experimenting only - // forced colorspace output (for testing, mostly) - RGB, RGBA, BGR, BGRA, ARGB, - RGBA_4444, RGB_565, - rgbA, bgrA, Argb, rgbA_4444, - YUV, YUVA -} WebPOutputFileFormat; - -// General all-purpose call. -// Most formats expect a 'buffer' containing RGBA-like samples, except -// RAW_YUV, YUV and YUVA formats. -// If 'out_file_name' is "-", data is saved to stdout. -// Returns false if an error occurred, true otherwise. -int WebPSaveImage(const WebPDecBuffer* const buffer, - WebPOutputFileFormat format, const char* const out_file_name); - -// Save to PNG. -#ifdef HAVE_WINCODEC_H -int WebPWritePNG(const char* out_file_name, int use_stdout, - const struct WebPDecBuffer* const buffer); -#else -int WebPWritePNG(FILE* out_file, const WebPDecBuffer* const buffer); -#endif - -// Save to PPM format (RGB, no alpha) -int WebPWritePPM(FILE* fout, const struct WebPDecBuffer* const buffer); - -// Save to PAM format (= PPM + alpha) -int WebPWritePAM(FILE* fout, const struct WebPDecBuffer* const buffer); - -// Save 16b mode (RGBA4444, RGB565, ...) for debugging purposes. -int WebPWrite16bAsPGM(FILE* fout, const struct WebPDecBuffer* const buffer); - -// Save as BMP -int WebPWriteBMP(FILE* fout, const struct WebPDecBuffer* const buffer); - -// Save as TIFF -int WebPWriteTIFF(FILE* fout, const struct WebPDecBuffer* const buffer); - -// Save the ALPHA plane (only) as a PGM -int WebPWriteAlphaPlane(FILE* fout, const struct WebPDecBuffer* const buffer); - -// Save as YUV samples as PGM format (using IMC4 layout). -// See: https://www.fourcc.org/yuv.php#IMC4. -// (very convenient format for viewing the samples, esp. for odd dimensions). -int WebPWritePGM(FILE* fout, const struct WebPDecBuffer* const buffer); - -// Save YUV(A) planes sequentially (raw dump) -int WebPWriteYUV(FILE* fout, const struct WebPDecBuffer* const buffer); - -// Save 16b mode (RGBA4444, RGB565, ...) as PGM format, for debugging purposes. -int WebPWrite16bAsPGM(FILE* fout, const struct WebPDecBuffer* const buffer); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // WEBP_IMAGEIO_IMAGE_ENC_H_ diff --git a/libwebp/imageio/imageio_util.c b/libwebp/imageio/imageio_util.c deleted file mode 100644 index df37137e..00000000 --- a/libwebp/imageio/imageio_util.c +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright 2016 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Utility functions used by the image decoders. -// - -#include "./imageio_util.h" - -#if defined(_WIN32) -#include // for _O_BINARY -#include // for _setmode() -#endif -#include -#include -#include "../examples/unicode.h" - -// ----------------------------------------------------------------------------- -// File I/O - -FILE* ImgIoUtilSetBinaryMode(FILE* file) { -#if defined(_WIN32) - if (_setmode(_fileno(file), _O_BINARY) == -1) { - fprintf(stderr, "Failed to reopen file in O_BINARY mode.\n"); - return NULL; - } -#endif - return file; -} - -int ImgIoUtilReadFromStdin(const uint8_t** data, size_t* data_size) { - static const size_t kBlockSize = 16384; // default initial size - size_t max_size = 0; - size_t size = 0; - uint8_t* input = NULL; - - if (data == NULL || data_size == NULL) return 0; - *data = NULL; - *data_size = 0; - - if (!ImgIoUtilSetBinaryMode(stdin)) return 0; - - while (!feof(stdin)) { - // We double the buffer size each time and read as much as possible. - const size_t extra_size = (max_size == 0) ? kBlockSize : max_size; - // we allocate one extra byte for the \0 terminator - void* const new_data = realloc(input, max_size + extra_size + 1); - if (new_data == NULL) goto Error; - input = (uint8_t*)new_data; - max_size += extra_size; - size += fread(input + size, 1, extra_size, stdin); - if (size < max_size) break; - } - if (ferror(stdin)) goto Error; - if (input != NULL) input[size] = '\0'; // convenient 0-terminator - *data = input; - *data_size = size; - return 1; - - Error: - free(input); - fprintf(stderr, "Could not read from stdin\n"); - return 0; -} - -int ImgIoUtilReadFile(const char* const file_name, - const uint8_t** data, size_t* data_size) { - int ok; - uint8_t* file_data; - size_t file_size; - FILE* in; - const int from_stdin = (file_name == NULL) || !WSTRCMP(file_name, "-"); - - if (from_stdin) return ImgIoUtilReadFromStdin(data, data_size); - - if (data == NULL || data_size == NULL) return 0; - *data = NULL; - *data_size = 0; - - in = WFOPEN(file_name, "rb"); - if (in == NULL) { - WFPRINTF(stderr, "cannot open input file '%s'\n", (const W_CHAR*)file_name); - return 0; - } - fseek(in, 0, SEEK_END); - file_size = ftell(in); - fseek(in, 0, SEEK_SET); - // we allocate one extra byte for the \0 terminator - file_data = (uint8_t*)WebPMalloc(file_size + 1); - if (file_data == NULL) { - fclose(in); - WFPRINTF(stderr, "memory allocation failure when reading file %s\n", - (const W_CHAR*)file_name); - return 0; - } - ok = (fread(file_data, file_size, 1, in) == 1); - fclose(in); - - if (!ok) { - WFPRINTF(stderr, "Could not read %d bytes of data from file %s\n", - (int)file_size, (const W_CHAR*)file_name); - WebPFree(file_data); - return 0; - } - file_data[file_size] = '\0'; // convenient 0-terminator - *data = file_data; - *data_size = file_size; - return 1; -} - -// ----------------------------------------------------------------------------- - -int ImgIoUtilWriteFile(const char* const file_name, - const uint8_t* data, size_t data_size) { - int ok; - FILE* out; - const int to_stdout = (file_name == NULL) || !WSTRCMP(file_name, "-"); - - if (data == NULL) { - return 0; - } - out = to_stdout ? ImgIoUtilSetBinaryMode(stdout) : WFOPEN(file_name, "wb"); - if (out == NULL) { - WFPRINTF(stderr, "Error! Cannot open output file '%s'\n", - (const W_CHAR*)file_name); - return 0; - } - ok = (fwrite(data, data_size, 1, out) == 1); - if (out != stdout) fclose(out); - return ok; -} - -// ----------------------------------------------------------------------------- - -void ImgIoUtilCopyPlane(const uint8_t* src, int src_stride, - uint8_t* dst, int dst_stride, int width, int height) { - while (height-- > 0) { - memcpy(dst, src, width * sizeof(*dst)); - src += src_stride; - dst += dst_stride; - } -} - -// ----------------------------------------------------------------------------- - -int ImgIoUtilCheckSizeArgumentsOverflow(uint64_t stride, size_t height) { - const uint64_t total_size = stride * height; - int ok = (total_size == (size_t)total_size); - // check that 'stride' is representable as int: - ok = ok && ((uint64_t)(int)stride == stride); -#if defined(WEBP_MAX_IMAGE_SIZE) - ok = ok && (total_size <= (uint64_t)WEBP_MAX_IMAGE_SIZE); -#endif - return ok; -} - -// ----------------------------------------------------------------------------- diff --git a/libwebp/imageio/imageio_util.h b/libwebp/imageio/imageio_util.h deleted file mode 100644 index f135f566..00000000 --- a/libwebp/imageio/imageio_util.h +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2016 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Utility functions used by the image decoders. -// - -#ifndef WEBP_IMAGEIO_IMAGEIO_UTIL_H_ -#define WEBP_IMAGEIO_IMAGEIO_UTIL_H_ - -#include -#include "webp/types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -//------------------------------------------------------------------------------ -// File I/O - -// Reopen file in binary (O_BINARY) mode. -// Returns 'file' on success, NULL otherwise. -FILE* ImgIoUtilSetBinaryMode(FILE* file); - -// Allocates storage for entire file 'file_name' and returns contents and size -// in 'data' and 'data_size'. Returns 1 on success, 0 otherwise. '*data' should -// be deleted using WebPFree(). -// Note: for convenience, the data will be null-terminated with an extra byte -// (not accounted for in *data_size), in case the file is text and intended -// to be used as a C-string. -// If 'file_name' is NULL or equal to "-", input is read from stdin by calling -// the function ImgIoUtilReadFromStdin(). -int ImgIoUtilReadFile(const char* const file_name, - const uint8_t** data, size_t* data_size); - -// Same as ImgIoUtilReadFile(), but reads until EOF from stdin instead. -int ImgIoUtilReadFromStdin(const uint8_t** data, size_t* data_size); - -// Write a data segment into a file named 'file_name'. Returns true if ok. -// If 'file_name' is NULL or equal to "-", output is written to stdout. -int ImgIoUtilWriteFile(const char* const file_name, - const uint8_t* data, size_t data_size); - -//------------------------------------------------------------------------------ - -// Copy width x height pixels from 'src' to 'dst' honoring the strides. -void ImgIoUtilCopyPlane(const uint8_t* src, int src_stride, - uint8_t* dst, int dst_stride, int width, int height); - -//------------------------------------------------------------------------------ - -// Returns 0 in case of overflow, memory over-allocation or excessive dimension. -int ImgIoUtilCheckSizeArgumentsOverflow(uint64_t stride, size_t height); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // WEBP_IMAGEIO_IMAGEIO_UTIL_H_ diff --git a/libwebp/imageio/jpegdec.c b/libwebp/imageio/jpegdec.c deleted file mode 100644 index 74a4c09c..00000000 --- a/libwebp/imageio/jpegdec.c +++ /dev/null @@ -1,364 +0,0 @@ -// Copyright 2012 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// JPEG decode. - -#include "./jpegdec.h" - -#ifdef HAVE_CONFIG_H -#include "webp/config.h" -#endif - -#include - -#ifdef WEBP_HAVE_JPEG -#include -#include -#include -#include -#include - -#include "webp/encode.h" -#include "./imageio_util.h" -#include "./metadata.h" - -// ----------------------------------------------------------------------------- -// Metadata processing - -#ifndef JPEG_APP1 -# define JPEG_APP1 (JPEG_APP0 + 1) -#endif -#ifndef JPEG_APP2 -# define JPEG_APP2 (JPEG_APP0 + 2) -#endif - -typedef struct { - const uint8_t* data; - size_t data_length; - int seq; // this segment's sequence number [1, 255] for use in reassembly. -} ICCPSegment; - -static void SaveMetadataMarkers(j_decompress_ptr dinfo) { - const unsigned int max_marker_length = 0xffff; - jpeg_save_markers(dinfo, JPEG_APP1, max_marker_length); // Exif/XMP - jpeg_save_markers(dinfo, JPEG_APP2, max_marker_length); // ICC profile -} - -static int CompareICCPSegments(const void* a, const void* b) { - const ICCPSegment* s1 = (const ICCPSegment*)a; - const ICCPSegment* s2 = (const ICCPSegment*)b; - return s1->seq - s2->seq; -} - -// Extract ICC profile segments from the marker list in 'dinfo', reassembling -// and storing them in 'iccp'. -// Returns true on success and false for memory errors and corrupt profiles. -static int StoreICCP(j_decompress_ptr dinfo, MetadataPayload* const iccp) { - // ICC.1:2010-12 (4.3.0.0) Annex B.4 Embedding ICC Profiles in JPEG files - static const char kICCPSignature[] = "ICC_PROFILE"; - static const size_t kICCPSignatureLength = 12; // signature includes '\0' - static const size_t kICCPSkipLength = 14; // signature + seq & count - int expected_count = 0; - int actual_count = 0; - int seq_max = 0; - size_t total_size = 0; - ICCPSegment iccp_segments[255]; - jpeg_saved_marker_ptr marker; - - memset(iccp_segments, 0, sizeof(iccp_segments)); - for (marker = dinfo->marker_list; marker != NULL; marker = marker->next) { - if (marker->marker == JPEG_APP2 && - marker->data_length > kICCPSkipLength && - !memcmp(marker->data, kICCPSignature, kICCPSignatureLength)) { - // ICC_PROFILE\0; 'seq' starts at 1. - const int seq = marker->data[kICCPSignatureLength]; - const int count = marker->data[kICCPSignatureLength + 1]; - const size_t segment_size = marker->data_length - kICCPSkipLength; - ICCPSegment* segment; - - if (segment_size == 0 || count == 0 || seq == 0) { - fprintf(stderr, "[ICCP] size (%d) / count (%d) / sequence number (%d)" - " cannot be 0!\n", - (int)segment_size, seq, count); - return 0; - } - - if (expected_count == 0) { - expected_count = count; - } else if (expected_count != count) { - fprintf(stderr, "[ICCP] Inconsistent segment count (%d / %d)!\n", - expected_count, count); - return 0; - } - - segment = iccp_segments + seq - 1; - if (segment->data_length != 0) { - fprintf(stderr, "[ICCP] Duplicate segment number (%d)!\n" , seq); - return 0; - } - - segment->data = marker->data + kICCPSkipLength; - segment->data_length = segment_size; - segment->seq = seq; - total_size += segment_size; - if (seq > seq_max) seq_max = seq; - ++actual_count; - } - } - - if (actual_count == 0) return 1; - if (seq_max != actual_count) { - fprintf(stderr, "[ICCP] Discontinuous segments, expected: %d actual: %d!\n", - actual_count, seq_max); - return 0; - } - if (expected_count != actual_count) { - fprintf(stderr, "[ICCP] Segment count: %d does not match expected: %d!\n", - actual_count, expected_count); - return 0; - } - - // The segments may appear out of order in the file, sort them based on - // sequence number before assembling the payload. - qsort(iccp_segments, actual_count, sizeof(*iccp_segments), - CompareICCPSegments); - - iccp->bytes = (uint8_t*)malloc(total_size); - if (iccp->bytes == NULL) return 0; - iccp->size = total_size; - - { - int i; - size_t offset = 0; - for (i = 0; i < seq_max; ++i) { - memcpy(iccp->bytes + offset, - iccp_segments[i].data, iccp_segments[i].data_length); - offset += iccp_segments[i].data_length; - } - } - return 1; -} - -// Returns true on success and false for memory errors and corrupt profiles. -// The caller must use MetadataFree() on 'metadata' in all cases. -static int ExtractMetadataFromJPEG(j_decompress_ptr dinfo, - Metadata* const metadata) { - static const struct { - int marker; - const char* signature; - size_t signature_length; - size_t storage_offset; - } kJPEGMetadataMap[] = { - // Exif 2.2 Section 4.7.2 Interoperability Structure of APP1 ... - { JPEG_APP1, "Exif\0", 6, METADATA_OFFSET(exif) }, - // XMP Specification Part 3 Section 3 Embedding XMP Metadata ... #JPEG - // TODO(jzern) Add support for 'ExtendedXMP' - { JPEG_APP1, "http://ns.adobe.com/xap/1.0/", 29, METADATA_OFFSET(xmp) }, - { 0, NULL, 0, 0 }, - }; - jpeg_saved_marker_ptr marker; - // Treat ICC profiles separately as they may be segmented and out of order. - if (!StoreICCP(dinfo, &metadata->iccp)) return 0; - - for (marker = dinfo->marker_list; marker != NULL; marker = marker->next) { - int i; - for (i = 0; kJPEGMetadataMap[i].marker != 0; ++i) { - if (marker->marker == kJPEGMetadataMap[i].marker && - marker->data_length > kJPEGMetadataMap[i].signature_length && - !memcmp(marker->data, kJPEGMetadataMap[i].signature, - kJPEGMetadataMap[i].signature_length)) { - MetadataPayload* const payload = - (MetadataPayload*)((uint8_t*)metadata + - kJPEGMetadataMap[i].storage_offset); - - if (payload->bytes == NULL) { - const char* marker_data = (const char*)marker->data + - kJPEGMetadataMap[i].signature_length; - const size_t marker_data_length = - marker->data_length - kJPEGMetadataMap[i].signature_length; - if (!MetadataCopy(marker_data, marker_data_length, payload)) return 0; - } else { - fprintf(stderr, "Ignoring additional '%s' marker\n", - kJPEGMetadataMap[i].signature); - } - } - } - } - return 1; -} - -#undef JPEG_APP1 -#undef JPEG_APP2 - -// ----------------------------------------------------------------------------- -// JPEG decoding - -struct my_error_mgr { - struct jpeg_error_mgr pub; - jmp_buf setjmp_buffer; -}; - -static void my_error_exit(j_common_ptr dinfo) { - struct my_error_mgr* myerr = (struct my_error_mgr*)dinfo->err; - fprintf(stderr, "libjpeg error: "); - dinfo->err->output_message(dinfo); - longjmp(myerr->setjmp_buffer, 1); -} - -typedef struct { - struct jpeg_source_mgr pub; - const uint8_t* data; - size_t data_size; -} JPEGReadContext; - -static void ContextInit(j_decompress_ptr cinfo) { - JPEGReadContext* const ctx = (JPEGReadContext*)cinfo->src; - ctx->pub.next_input_byte = ctx->data; - ctx->pub.bytes_in_buffer = ctx->data_size; -} - -static boolean ContextFill(j_decompress_ptr cinfo) { - // we shouldn't get here. - ERREXIT(cinfo, JERR_FILE_READ); - return FALSE; -} - -static void ContextSkip(j_decompress_ptr cinfo, long jump_size) { - JPEGReadContext* const ctx = (JPEGReadContext*)cinfo->src; - size_t jump = (size_t)jump_size; - if (jump > ctx->pub.bytes_in_buffer) { // Don't overflow the buffer. - jump = ctx->pub.bytes_in_buffer; - } - ctx->pub.bytes_in_buffer -= jump; - ctx->pub.next_input_byte += jump; -} - -static void ContextTerm(j_decompress_ptr cinfo) { - (void)cinfo; -} - -static void ContextSetup(volatile struct jpeg_decompress_struct* const cinfo, - JPEGReadContext* const ctx) { - cinfo->src = (struct jpeg_source_mgr*)ctx; - ctx->pub.init_source = ContextInit; - ctx->pub.fill_input_buffer = ContextFill; - ctx->pub.skip_input_data = ContextSkip; - ctx->pub.resync_to_restart = jpeg_resync_to_restart; - ctx->pub.term_source = ContextTerm; - ctx->pub.bytes_in_buffer = 0; - ctx->pub.next_input_byte = NULL; -} - -int ReadJPEG(const uint8_t* const data, size_t data_size, - WebPPicture* const pic, int keep_alpha, - Metadata* const metadata) { - volatile int ok = 0; - int width, height; - int64_t stride; - volatile struct jpeg_decompress_struct dinfo; - struct my_error_mgr jerr; - uint8_t* volatile rgb = NULL; - JSAMPROW buffer[1]; - JPEGReadContext ctx; - - if (data == NULL || data_size == 0 || pic == NULL) return 0; - - (void)keep_alpha; - memset(&ctx, 0, sizeof(ctx)); - ctx.data = data; - ctx.data_size = data_size; - - memset((j_decompress_ptr)&dinfo, 0, sizeof(dinfo)); // for setjmp safety - dinfo.err = jpeg_std_error(&jerr.pub); - jerr.pub.error_exit = my_error_exit; - - if (setjmp(jerr.setjmp_buffer)) { - Error: - MetadataFree(metadata); - jpeg_destroy_decompress((j_decompress_ptr)&dinfo); - goto End; - } - - jpeg_create_decompress((j_decompress_ptr)&dinfo); - ContextSetup(&dinfo, &ctx); - if (metadata != NULL) SaveMetadataMarkers((j_decompress_ptr)&dinfo); - jpeg_read_header((j_decompress_ptr)&dinfo, TRUE); - - dinfo.out_color_space = JCS_RGB; - dinfo.do_fancy_upsampling = TRUE; - - jpeg_start_decompress((j_decompress_ptr)&dinfo); - - if (dinfo.output_components != 3) { - goto Error; - } - - width = dinfo.output_width; - height = dinfo.output_height; - stride = (int64_t)dinfo.output_width * dinfo.output_components * sizeof(*rgb); - - if (stride != (int)stride || - !ImgIoUtilCheckSizeArgumentsOverflow(stride, height)) { - goto Error; - } - - rgb = (uint8_t*)malloc((size_t)stride * height); - if (rgb == NULL) { - goto Error; - } - buffer[0] = (JSAMPLE*)rgb; - - while (dinfo.output_scanline < dinfo.output_height) { - if (jpeg_read_scanlines((j_decompress_ptr)&dinfo, buffer, 1) != 1) { - goto Error; - } - buffer[0] += stride; - } - - if (metadata != NULL) { - ok = ExtractMetadataFromJPEG((j_decompress_ptr)&dinfo, metadata); - if (!ok) { - fprintf(stderr, "Error extracting JPEG metadata!\n"); - goto Error; - } - } - - jpeg_finish_decompress((j_decompress_ptr)&dinfo); - jpeg_destroy_decompress((j_decompress_ptr)&dinfo); - - // WebP conversion. - pic->width = width; - pic->height = height; - ok = WebPPictureImportRGB(pic, rgb, (int)stride); - if (!ok) { - pic->width = 0; // WebPPictureImportRGB() barely touches 'pic' on failure. - pic->height = 0; // Just reset dimensions but keep any 'custom_ptr' etc. - MetadataFree(metadata); // In case the caller forgets to free it on error. - } - - End: - free(rgb); - return ok; -} -#else // !WEBP_HAVE_JPEG -int ReadJPEG(const uint8_t* const data, size_t data_size, - struct WebPPicture* const pic, int keep_alpha, - struct Metadata* const metadata) { - (void)data; - (void)data_size; - (void)pic; - (void)keep_alpha; - (void)metadata; - fprintf(stderr, "JPEG support not compiled. Please install the libjpeg " - "development package before building.\n"); - return 0; -} -#endif // WEBP_HAVE_JPEG - -// ----------------------------------------------------------------------------- diff --git a/libwebp/imageio/jpegdec.h b/libwebp/imageio/jpegdec.h deleted file mode 100644 index effc14f8..00000000 --- a/libwebp/imageio/jpegdec.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2012 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// JPEG decode. - -#ifndef WEBP_IMAGEIO_JPEGDEC_H_ -#define WEBP_IMAGEIO_JPEGDEC_H_ - -#include "webp/types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct Metadata; -struct WebPPicture; - -// Reads a JPEG from 'data', returning the decoded output in 'pic'. -// The output is RGB or YUV depending on pic->use_argb value. -// Returns true on success. -// 'keep_alpha' has no effect, but is kept for coherence with other signatures -// for image readers. -int ReadJPEG(const uint8_t* const data, size_t data_size, - struct WebPPicture* const pic, int keep_alpha, - struct Metadata* const metadata); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // WEBP_IMAGEIO_JPEGDEC_H_ diff --git a/libwebp/imageio/metadata.c b/libwebp/imageio/metadata.c deleted file mode 100644 index 936f2f4e..00000000 --- a/libwebp/imageio/metadata.c +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2012 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Metadata types and functions. -// - -#include "./metadata.h" - -#include -#include - -#include "webp/types.h" - -void MetadataInit(Metadata* const metadata) { - if (metadata == NULL) return; - memset(metadata, 0, sizeof(*metadata)); -} - -void MetadataPayloadDelete(MetadataPayload* const payload) { - if (payload == NULL) return; - free(payload->bytes); - payload->bytes = NULL; - payload->size = 0; -} - -void MetadataFree(Metadata* const metadata) { - if (metadata == NULL) return; - MetadataPayloadDelete(&metadata->exif); - MetadataPayloadDelete(&metadata->iccp); - MetadataPayloadDelete(&metadata->xmp); -} - -int MetadataCopy(const char* metadata, size_t metadata_len, - MetadataPayload* const payload) { - if (metadata == NULL || metadata_len == 0 || payload == NULL) return 0; - payload->bytes = (uint8_t*)malloc(metadata_len); - if (payload->bytes == NULL) return 0; - payload->size = metadata_len; - memcpy(payload->bytes, metadata, metadata_len); - return 1; -} - -// ----------------------------------------------------------------------------- diff --git a/libwebp/imageio/metadata.h b/libwebp/imageio/metadata.h deleted file mode 100644 index 1d5be91a..00000000 --- a/libwebp/imageio/metadata.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2012 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Metadata types and functions. -// - -#ifndef WEBP_IMAGEIO_METADATA_H_ -#define WEBP_IMAGEIO_METADATA_H_ - -#include "webp/types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct MetadataPayload { - uint8_t* bytes; - size_t size; -} MetadataPayload; - -typedef struct Metadata { - MetadataPayload exif; - MetadataPayload iccp; - MetadataPayload xmp; -} Metadata; - -#define METADATA_OFFSET(x) offsetof(Metadata, x) - -void MetadataInit(Metadata* const metadata); -void MetadataPayloadDelete(MetadataPayload* const payload); -void MetadataFree(Metadata* const metadata); - -// Stores 'metadata' to 'payload->bytes', returns false on allocation error. -int MetadataCopy(const char* metadata, size_t metadata_len, - MetadataPayload* const payload); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // WEBP_IMAGEIO_METADATA_H_ diff --git a/libwebp/imageio/pngdec.c b/libwebp/imageio/pngdec.c deleted file mode 100644 index cdd99883..00000000 --- a/libwebp/imageio/pngdec.c +++ /dev/null @@ -1,374 +0,0 @@ -// Copyright 2012 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// PNG decode. - -#include "./pngdec.h" - -#ifdef HAVE_CONFIG_H -#include "webp/config.h" -#endif - -#include - -#ifdef WEBP_HAVE_PNG -#ifndef PNG_USER_MEM_SUPPORTED -#define PNG_USER_MEM_SUPPORTED // for png_create_read_struct_2 -#endif -#include -#include // note: this must be included *after* png.h -#include -#include - -#include "webp/encode.h" -#include "./imageio_util.h" -#include "./metadata.h" - -#define LOCAL_PNG_VERSION ((PNG_LIBPNG_VER_MAJOR << 8) | PNG_LIBPNG_VER_MINOR) -#define LOCAL_PNG_PREREQ(maj, min) \ - (LOCAL_PNG_VERSION >= (((maj) << 8) | (min))) - -static void PNGAPI error_function(png_structp png, png_const_charp error) { - if (error != NULL) fprintf(stderr, "libpng error: %s\n", error); - longjmp(png_jmpbuf(png), 1); -} - -#if LOCAL_PNG_PREREQ(1,4) -typedef png_alloc_size_t LocalPngAllocSize; -#else -typedef png_size_t LocalPngAllocSize; -#endif - -static png_voidp MallocFunc(png_structp png_ptr, LocalPngAllocSize size) { - (void)png_ptr; - if (size != (size_t)size) return NULL; - if (!ImgIoUtilCheckSizeArgumentsOverflow(size, 1)) return NULL; - return (png_voidp)malloc((size_t)size); -} - -static void FreeFunc(png_structp png_ptr, png_voidp ptr) { - (void)png_ptr; - free(ptr); -} - -// Converts the NULL terminated 'hexstring' which contains 2-byte character -// representations of hex values to raw data. -// 'hexstring' may contain values consisting of [A-F][a-f][0-9] in pairs, -// e.g., 7af2..., separated by any number of newlines. -// 'expected_length' is the anticipated processed size. -// On success the raw buffer is returned with its length equivalent to -// 'expected_length'. NULL is returned if the processed length is less than -// 'expected_length' or any character aside from those above is encountered. -// The returned buffer must be freed by the caller. -static uint8_t* HexStringToBytes(const char* hexstring, - size_t expected_length) { - const char* src = hexstring; - size_t actual_length = 0; - uint8_t* const raw_data = (uint8_t*)malloc(expected_length); - uint8_t* dst; - - if (raw_data == NULL) return NULL; - - for (dst = raw_data; actual_length < expected_length && *src != '\0'; ++src) { - char* end; - char val[3]; - if (*src == '\n') continue; - val[0] = *src++; - val[1] = *src; - val[2] = '\0'; - *dst++ = (uint8_t)strtol(val, &end, 16); - if (end != val + 2) break; - ++actual_length; - } - - if (actual_length != expected_length) { - free(raw_data); - return NULL; - } - return raw_data; -} - -static int ProcessRawProfile(const char* profile, size_t profile_len, - MetadataPayload* const payload) { - const char* src = profile; - char* end; - int expected_length; - - if (profile == NULL || profile_len == 0) return 0; - - // ImageMagick formats 'raw profiles' as - // '\n\n(%8lu)\n\n'. - if (*src != '\n') { - fprintf(stderr, "Malformed raw profile, expected '\\n' got '\\x%.2X'\n", - *src); - return 0; - } - ++src; - // skip the profile name and extract the length. - while (*src != '\0' && *src++ != '\n') {} - expected_length = (int)strtol(src, &end, 10); - if (*end != '\n') { - fprintf(stderr, "Malformed raw profile, expected '\\n' got '\\x%.2X'\n", - *end); - return 0; - } - ++end; - - // 'end' now points to the profile payload. - payload->bytes = HexStringToBytes(end, expected_length); - if (payload->bytes == NULL) return 0; - payload->size = expected_length; - return 1; -} - -static const struct { - const char* name; - int (*process)(const char* profile, size_t profile_len, - MetadataPayload* const payload); - size_t storage_offset; -} kPNGMetadataMap[] = { - // https://exiftool.org/TagNames/PNG.html#TextualData - // See also: ExifTool on CPAN. - { "Raw profile type exif", ProcessRawProfile, METADATA_OFFSET(exif) }, - { "Raw profile type xmp", ProcessRawProfile, METADATA_OFFSET(xmp) }, - // Exiftool puts exif data in APP1 chunk, too. - { "Raw profile type APP1", ProcessRawProfile, METADATA_OFFSET(exif) }, - // XMP Specification Part 3, Section 3 #PNG - { "XML:com.adobe.xmp", MetadataCopy, METADATA_OFFSET(xmp) }, - { NULL, NULL, 0 }, -}; - -// Looks for metadata at both the beginning and end of the PNG file, giving -// preference to the head. -// Returns true on success. The caller must use MetadataFree() on 'metadata' in -// all cases. -static int ExtractMetadataFromPNG(png_structp png, - png_infop const head_info, - png_infop const end_info, - Metadata* const metadata) { - int p; - - for (p = 0; p < 2; ++p) { - png_infop const info = (p == 0) ? head_info : end_info; - png_textp text = NULL; - const png_uint_32 num = png_get_text(png, info, &text, NULL); - png_uint_32 i; - // Look for EXIF / XMP metadata. - for (i = 0; i < num; ++i, ++text) { - int j; - for (j = 0; kPNGMetadataMap[j].name != NULL; ++j) { - if (!strcmp(text->key, kPNGMetadataMap[j].name)) { - MetadataPayload* const payload = - (MetadataPayload*)((uint8_t*)metadata + - kPNGMetadataMap[j].storage_offset); - png_size_t text_length; - switch (text->compression) { -#ifdef PNG_iTXt_SUPPORTED - case PNG_ITXT_COMPRESSION_NONE: - case PNG_ITXT_COMPRESSION_zTXt: - text_length = text->itxt_length; - break; -#endif - case PNG_TEXT_COMPRESSION_NONE: - case PNG_TEXT_COMPRESSION_zTXt: - default: - text_length = text->text_length; - break; - } - if (payload->bytes != NULL) { - fprintf(stderr, "Ignoring additional '%s'\n", text->key); - } else if (!kPNGMetadataMap[j].process(text->text, text_length, - payload)) { - fprintf(stderr, "Failed to process: '%s'\n", text->key); - return 0; - } - break; - } - } - } - // Look for an ICC profile. - { - png_charp name; - int comp_type; -#if LOCAL_PNG_PREREQ(1,5) - png_bytep profile; -#else - png_charp profile; -#endif - png_uint_32 len; - - if (png_get_iCCP(png, info, - &name, &comp_type, &profile, &len) == PNG_INFO_iCCP) { - if (!MetadataCopy((const char*)profile, len, &metadata->iccp)) return 0; - } - } - } - return 1; -} - -typedef struct { - const uint8_t* data; - size_t data_size; - png_size_t offset; -} PNGReadContext; - -static void ReadFunc(png_structp png_ptr, png_bytep data, png_size_t length) { - PNGReadContext* const ctx = (PNGReadContext*)png_get_io_ptr(png_ptr); - if (ctx->data_size - ctx->offset < length) { - png_error(png_ptr, "ReadFunc: invalid read length (overflow)!"); - } - memcpy(data, ctx->data + ctx->offset, length); - ctx->offset += length; -} - -int ReadPNG(const uint8_t* const data, size_t data_size, - struct WebPPicture* const pic, - int keep_alpha, struct Metadata* const metadata) { - volatile png_structp png = NULL; - volatile png_infop info = NULL; - volatile png_infop end_info = NULL; - PNGReadContext context = { NULL, 0, 0 }; - int color_type, bit_depth, interlaced; - int num_channels; - int num_passes; - int p; - volatile int ok = 0; - png_uint_32 width, height, y; - int64_t stride; - uint8_t* volatile rgb = NULL; - - if (data == NULL || data_size == 0 || pic == NULL) return 0; - - context.data = data; - context.data_size = data_size; - - png = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL, - NULL, MallocFunc, FreeFunc); - if (png == NULL) goto End; - - png_set_error_fn(png, 0, error_function, NULL); - if (setjmp(png_jmpbuf(png))) { - Error: - MetadataFree(metadata); - goto End; - } - -#if LOCAL_PNG_PREREQ(1,5) || \ - (LOCAL_PNG_PREREQ(1,4) && PNG_LIBPNG_VER_RELEASE >= 1) - // If it looks like the bitstream is going to need more memory than libpng's - // internal limit (default: 8M), try to (reasonably) raise it. - if (data_size > png_get_chunk_malloc_max(png) && data_size < (1u << 24)) { - png_set_chunk_malloc_max(png, data_size); - } -#endif - - info = png_create_info_struct(png); - if (info == NULL) goto Error; - end_info = png_create_info_struct(png); - if (end_info == NULL) goto Error; - - png_set_read_fn(png, &context, ReadFunc); - png_read_info(png, info); - if (!png_get_IHDR(png, info, - &width, &height, &bit_depth, &color_type, &interlaced, - NULL, NULL)) goto Error; - - png_set_strip_16(png); - png_set_packing(png); - if (color_type == PNG_COLOR_TYPE_PALETTE) { - png_set_palette_to_rgb(png); - } - if (color_type == PNG_COLOR_TYPE_GRAY || - color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { - if (bit_depth < 8) { - png_set_expand_gray_1_2_4_to_8(png); - } - png_set_gray_to_rgb(png); - } - if (png_get_valid(png, info, PNG_INFO_tRNS)) { - png_set_tRNS_to_alpha(png); - } - - // Apply gamma correction if needed. - { - double image_gamma = 1 / 2.2, screen_gamma = 2.2; - int srgb_intent; - if (png_get_sRGB(png, info, &srgb_intent) || - png_get_gAMA(png, info, &image_gamma)) { - png_set_gamma(png, screen_gamma, image_gamma); - } - } - - if (!keep_alpha) { - png_set_strip_alpha(png); - } - - num_passes = png_set_interlace_handling(png); - png_read_update_info(png, info); - - num_channels = png_get_channels(png, info); - if (num_channels != 3 && num_channels != 4) { - goto Error; - } - stride = (int64_t)num_channels * width * sizeof(*rgb); - if (stride != (int)stride || - !ImgIoUtilCheckSizeArgumentsOverflow(stride, height)) { - goto Error; - } - - rgb = (uint8_t*)malloc((size_t)stride * height); - if (rgb == NULL) goto Error; - for (p = 0; p < num_passes; ++p) { - png_bytep row = rgb; - for (y = 0; y < height; ++y) { - png_read_rows(png, &row, NULL, 1); - row += stride; - } - } - png_read_end(png, end_info); - - if (metadata != NULL && - !ExtractMetadataFromPNG(png, info, end_info, metadata)) { - fprintf(stderr, "Error extracting PNG metadata!\n"); - goto Error; - } - - pic->width = (int)width; - pic->height = (int)height; - ok = (num_channels == 4) ? WebPPictureImportRGBA(pic, rgb, (int)stride) - : WebPPictureImportRGB(pic, rgb, (int)stride); - - if (!ok) { - goto Error; - } - - End: - if (png != NULL) { - png_destroy_read_struct((png_structpp)&png, - (png_infopp)&info, (png_infopp)&end_info); - } - free(rgb); - return ok; -} -#else // !WEBP_HAVE_PNG -int ReadPNG(const uint8_t* const data, size_t data_size, - struct WebPPicture* const pic, - int keep_alpha, struct Metadata* const metadata) { - (void)data; - (void)data_size; - (void)pic; - (void)keep_alpha; - (void)metadata; - fprintf(stderr, "PNG support not compiled. Please install the libpng " - "development package before building.\n"); - return 0; -} -#endif // WEBP_HAVE_PNG - -// ----------------------------------------------------------------------------- diff --git a/libwebp/imageio/pngdec.h b/libwebp/imageio/pngdec.h deleted file mode 100644 index e0a6122d..00000000 --- a/libwebp/imageio/pngdec.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2012 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// PNG decode. - -#ifndef WEBP_IMAGEIO_PNGDEC_H_ -#define WEBP_IMAGEIO_PNGDEC_H_ - -#include "webp/types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct Metadata; -struct WebPPicture; - -// Reads a PNG from 'data', returning the decoded output in 'pic'. -// Output is RGBA or YUVA, depending on pic->use_argb value. -// If 'keep_alpha' is true and the PNG has an alpha channel, the output is RGBA -// or YUVA. Otherwise, alpha channel is dropped and output is RGB or YUV. -// Returns true on success. -int ReadPNG(const uint8_t* const data, size_t data_size, - struct WebPPicture* const pic, - int keep_alpha, struct Metadata* const metadata); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // WEBP_IMAGEIO_PNGDEC_H_ diff --git a/libwebp/imageio/pnmdec.c b/libwebp/imageio/pnmdec.c deleted file mode 100644 index 0d592c32..00000000 --- a/libwebp/imageio/pnmdec.c +++ /dev/null @@ -1,301 +0,0 @@ -// Copyright 2017 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// (limited) PNM decoder - -#include "./pnmdec.h" - -#include -#include -#include -#include -#include - -#include "webp/encode.h" -#include "./imageio_util.h" - -#if defined(_MSC_VER) && _MSC_VER < 1900 -#define snprintf _snprintf -#endif - -typedef enum { - WIDTH_FLAG = 1 << 0, - HEIGHT_FLAG = 1 << 1, - DEPTH_FLAG = 1 << 2, - MAXVAL_FLAG = 1 << 3, - TUPLE_FLAG = 1 << 4, - ALL_NEEDED_FLAGS = WIDTH_FLAG | HEIGHT_FLAG | DEPTH_FLAG | MAXVAL_FLAG -} PNMFlags; - -typedef struct { - const uint8_t* data; - size_t data_size; - int width, height; - int bytes_per_px; - int depth; // 1 (grayscale), 2 (grayscale + alpha), 3 (rgb), 4 (rgba) - int max_value; - int type; // 5, 6 or 7 - int seen_flags; -} PNMInfo; - -// ----------------------------------------------------------------------------- -// PNM decoding - -#define MAX_LINE_SIZE 1024 -static const size_t kMinPNMHeaderSize = 3; - -static size_t ReadLine(const uint8_t* const data, size_t off, size_t data_size, - char out[MAX_LINE_SIZE + 1], size_t* const out_size) { - size_t i = 0; - *out_size = 0; - redo: - for (i = 0; i < MAX_LINE_SIZE && off < data_size; ++i) { - out[i] = data[off++]; - if (out[i] == '\n') break; - } - if (off < data_size) { - if (i == 0) goto redo; // empty line - if (out[0] == '#') goto redo; // skip comment - } - out[i] = 0; // safety sentinel - *out_size = i; - return off; -} - -static size_t FlagError(const char flag[]) { - fprintf(stderr, "PAM header error: flags '%s' already seen.\n", flag); - return 0; -} - -// inspired from http://netpbm.sourceforge.net/doc/pam.html -static size_t ReadPAMFields(PNMInfo* const info, size_t off) { - char out[MAX_LINE_SIZE + 1]; - size_t out_size; - int tmp; - int expected_depth = -1; - assert(info != NULL); - while (1) { - off = ReadLine(info->data, off, info->data_size, out, &out_size); - if (off == 0) return 0; - if (sscanf(out, "WIDTH %d", &tmp) == 1) { - if (info->seen_flags & WIDTH_FLAG) return FlagError("WIDTH"); - info->seen_flags |= WIDTH_FLAG; - info->width = tmp; - } else if (sscanf(out, "HEIGHT %d", &tmp) == 1) { - if (info->seen_flags & HEIGHT_FLAG) return FlagError("HEIGHT"); - info->seen_flags |= HEIGHT_FLAG; - info->height = tmp; - } else if (sscanf(out, "DEPTH %d", &tmp) == 1) { - if (info->seen_flags & DEPTH_FLAG) return FlagError("DEPTH"); - info->seen_flags |= DEPTH_FLAG; - info->depth = tmp; - } else if (sscanf(out, "MAXVAL %d", &tmp) == 1) { - if (info->seen_flags & MAXVAL_FLAG) return FlagError("MAXVAL"); - info->seen_flags |= MAXVAL_FLAG; - info->max_value = tmp; - } else if (!strcmp(out, "TUPLTYPE RGB_ALPHA")) { - expected_depth = 4; - info->seen_flags |= TUPLE_FLAG; - } else if (!strcmp(out, "TUPLTYPE RGB")) { - expected_depth = 3; - info->seen_flags |= TUPLE_FLAG; - } else if (!strcmp(out, "TUPLTYPE GRAYSCALE_ALPHA")) { - expected_depth = 2; - info->seen_flags |= TUPLE_FLAG; - } else if (!strcmp(out, "TUPLTYPE GRAYSCALE")) { - expected_depth = 1; - info->seen_flags |= TUPLE_FLAG; - } else if (!strcmp(out, "ENDHDR")) { - break; - } else { - static const char kEllipsis[] = " ..."; - const size_t kLen = strlen(kEllipsis) + 1; // +1 = trailing \0 - int i; - if (out_size > 20) snprintf(out + 20 - kLen, kLen, kEllipsis); - for (i = 0; i < (int)strlen(out); ++i) { - // isprint() might trigger a "char-subscripts" warning if given a char. - if (!isprint((int)out[i])) out[i] = ' '; - } - fprintf(stderr, "PAM header error: unrecognized entry [%s]\n", out); - return 0; - } - } - if (!(info->seen_flags & ALL_NEEDED_FLAGS)) { - fprintf(stderr, "PAM header error: missing tags%s%s%s%s\n", - (info->seen_flags & WIDTH_FLAG) ? "" : " WIDTH", - (info->seen_flags & HEIGHT_FLAG) ? "" : " HEIGHT", - (info->seen_flags & DEPTH_FLAG) ? "" : " DEPTH", - (info->seen_flags & MAXVAL_FLAG) ? "" : " MAXVAL"); - return 0; - } - if (expected_depth != -1 && info->depth != expected_depth) { - fprintf(stderr, "PAM header error: expected DEPTH %d but got DEPTH %d\n", - expected_depth, info->depth); - return 0; - } - return off; -} - -static size_t ReadHeader(PNMInfo* const info) { - size_t off = 0; - char out[MAX_LINE_SIZE + 1]; - size_t out_size; - if (info == NULL) return 0; - if (info->data == NULL || info->data_size < kMinPNMHeaderSize) return 0; - - info->width = info->height = 0; - info->type = -1; - info->seen_flags = 0; - info->bytes_per_px = 0; - info->depth = 0; - info->max_value = 0; - - off = ReadLine(info->data, off, info->data_size, out, &out_size); - if (off == 0 || sscanf(out, "P%d", &info->type) != 1) return 0; - if (info->type == 7) { - off = ReadPAMFields(info, off); - } else { - off = ReadLine(info->data, off, info->data_size, out, &out_size); - if (off == 0 || sscanf(out, "%d %d", &info->width, &info->height) != 2) { - return 0; - } - off = ReadLine(info->data, off, info->data_size, out, &out_size); - if (off == 0 || sscanf(out, "%d", &info->max_value) != 1) return 0; - - // finish initializing missing fields - info->depth = (info->type == 5) ? 1 : 3; - } - // perform some basic numerical validation - if (info->width <= 0 || info->height <= 0 || - info->type <= 0 || info->type >= 9 || - info->depth <= 0 || info->depth > 4 || - info->max_value <= 0 || info->max_value >= 65536) { - return 0; - } - info->bytes_per_px = info->depth * (info->max_value > 255 ? 2 : 1); - return off; -} - -int ReadPNM(const uint8_t* const data, size_t data_size, - WebPPicture* const pic, int keep_alpha, - struct Metadata* const metadata) { - int ok = 0; - int i, j; - uint64_t stride, pixel_bytes, sample_size, depth; - uint8_t* rgb = NULL, *tmp_rgb; - size_t offset; - PNMInfo info; - - info.data = data; - info.data_size = data_size; - offset = ReadHeader(&info); - if (offset == 0) { - fprintf(stderr, "Error parsing PNM header.\n"); - goto End; - } - - if (info.type < 5 || info.type > 7) { - fprintf(stderr, "Unsupported P%d PNM format.\n", info.type); - goto End; - } - - // Some basic validations. - if (pic == NULL) goto End; - if (info.width > WEBP_MAX_DIMENSION || info.height > WEBP_MAX_DIMENSION) { - fprintf(stderr, "Invalid %dx%d dimension for PNM\n", - info.width, info.height); - goto End; - } - - pixel_bytes = (uint64_t)info.width * info.height * info.bytes_per_px; - if (data_size < offset + pixel_bytes) { - fprintf(stderr, "Truncated PNM file (P%d).\n", info.type); - goto End; - } - sample_size = (info.max_value > 255) ? 2 : 1; - // final depth - depth = (info.depth == 1 || info.depth == 3 || !keep_alpha) ? 3 : 4; - stride = depth * info.width; - if (stride != (size_t)stride || - !ImgIoUtilCheckSizeArgumentsOverflow(stride, info.height)) { - goto End; - } - - rgb = (uint8_t*)malloc((size_t)stride * info.height); - if (rgb == NULL) goto End; - - // Convert input. - // We only optimize for the sample_size=1, max_value=255, depth=1 case. - tmp_rgb = rgb; - for (j = 0; j < info.height; ++j) { - const uint8_t* in = data + offset; - offset += info.bytes_per_px * info.width; - assert(offset <= data_size); - if (info.max_value == 255 && info.depth >= 3) { - // RGB or RGBA - if (info.depth == 3 || keep_alpha) { - memcpy(tmp_rgb, in, info.depth * info.width * sizeof(*in)); - } else { - assert(info.depth == 4 && !keep_alpha); - for (i = 0; i < info.width; ++i) { - tmp_rgb[3 * i + 0] = in[4 * i + 0]; - tmp_rgb[3 * i + 1] = in[4 * i + 1]; - tmp_rgb[3 * i + 2] = in[4 * i + 2]; - } - } - } else { - // Unoptimized case, we need to handle non-trivial operations: - // * convert 16b to 8b (if max_value > 255) - // * rescale to [0..255] range (if max_value != 255) - // * drop the alpha channel (if keep_alpha is false) - const uint32_t round = info.max_value / 2; - int k = 0; - for (i = 0; i < info.width * info.depth; ++i) { - uint32_t v = (sample_size == 2) ? 256u * in[2 * i + 0] + in[2 * i + 1] - : in[i]; - if (info.max_value != 255) v = (v * 255u + round) / info.max_value; - if (v > 255u) v = 255u; - if (info.depth > 2) { - if (!keep_alpha && info.depth == 4 && (i % 4) == 3) { - // skip alpha - } else { - tmp_rgb[k] = v; - k += 1; - } - } else if (info.depth == 1 || (i % 2) == 0) { - tmp_rgb[k + 0] = tmp_rgb[k + 1] = tmp_rgb[k + 2] = v; - k += 3; - } else if (keep_alpha && info.depth == 2) { - tmp_rgb[k] = v; - k += 1; - } else { - // skip alpha - } - } - } - tmp_rgb += stride; - } - - // WebP conversion. - pic->width = info.width; - pic->height = info.height; - ok = (depth == 4) ? WebPPictureImportRGBA(pic, rgb, (int)stride) - : WebPPictureImportRGB(pic, rgb, (int)stride); - if (!ok) goto End; - - ok = 1; - End: - free((void*)rgb); - - (void)metadata; - (void)keep_alpha; - return ok; -} - -// ----------------------------------------------------------------------------- diff --git a/libwebp/imageio/pnmdec.h b/libwebp/imageio/pnmdec.h deleted file mode 100644 index c4d5823e..00000000 --- a/libwebp/imageio/pnmdec.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2017 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// partial PNM format decoder (ppm/pgm) - -#ifndef WEBP_IMAGEIO_PNMDEC_H_ -#define WEBP_IMAGEIO_PNMDEC_H_ - -#include "webp/types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct Metadata; -struct WebPPicture; - -// Reads a PNM file from 'data', returning the decoded output in 'pic'. -// The output is RGB or YUV depending on pic->use_argb value. -// Returns true on success. -// 'metadata' has no effect, but is kept for coherence with other signatures -// for image readers. -int ReadPNM(const uint8_t* const data, size_t data_size, - struct WebPPicture* const pic, int keep_alpha, - struct Metadata* const metadata); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // WEBP_IMAGEIO_PNMDEC_H_ diff --git a/libwebp/imageio/tiffdec.c b/libwebp/imageio/tiffdec.c deleted file mode 100644 index d711fa4b..00000000 --- a/libwebp/imageio/tiffdec.c +++ /dev/null @@ -1,293 +0,0 @@ -// Copyright 2012 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// TIFF decode. - -#include "./tiffdec.h" - -#ifdef HAVE_CONFIG_H -#include "webp/config.h" -#endif - -#include -#include -#include - -#ifdef WEBP_HAVE_TIFF -#include - -#include "webp/encode.h" -#include "./imageio_util.h" -#include "./metadata.h" - -static const struct { - ttag_t tag; - size_t storage_offset; -} kTIFFMetadataMap[] = { - { TIFFTAG_ICCPROFILE, METADATA_OFFSET(iccp) }, - { TIFFTAG_XMLPACKET, METADATA_OFFSET(xmp) }, - { 0, 0 }, -}; - -// Returns true on success. The caller must use MetadataFree() on 'metadata' in -// all cases. -static int ExtractMetadataFromTIFF(TIFF* const tif, Metadata* const metadata) { - int i; - toff_t exif_ifd_offset; - - for (i = 0; kTIFFMetadataMap[i].tag != 0; ++i) { - MetadataPayload* const payload = - (MetadataPayload*)((uint8_t*)metadata + - kTIFFMetadataMap[i].storage_offset); - void* tag_data; - uint32_t tag_data_len; - - if (TIFFGetField(tif, kTIFFMetadataMap[i].tag, &tag_data_len, &tag_data) && - !MetadataCopy((const char*)tag_data, tag_data_len, payload)) { - return 0; - } - } - - // TODO(jzern): To extract the raw EXIF directory some parsing of it would be - // necessary to determine the overall size. In addition, value offsets in - // individual directory entries may need to be updated as, depending on the - // type, they are file based. - // Exif 2.2 Section 4.6.2 Tag Structure - // TIFF Revision 6.0 Part 1 Section 2 TIFF Structure #Image File Directory - if (TIFFGetField(tif, TIFFTAG_EXIFIFD, &exif_ifd_offset)) { - fprintf(stderr, "Warning: EXIF extraction from TIFF is unsupported.\n"); - } - return 1; -} - -// Ad-hoc structure to supply read-from-memory functionalities. -typedef struct { - const uint8_t* data; - toff_t size; - toff_t pos; -} MyData; - -static int MyClose(thandle_t opaque) { - (void)opaque; - return 0; -} - -static toff_t MySize(thandle_t opaque) { - const MyData* const my_data = (MyData*)opaque; - return my_data->size; -} - -static toff_t MySeek(thandle_t opaque, toff_t offset, int whence) { - MyData* const my_data = (MyData*)opaque; - offset += (whence == SEEK_CUR) ? my_data->pos - : (whence == SEEK_SET) ? 0 - : my_data->size; - if (offset > my_data->size) return (toff_t)-1; - my_data->pos = offset; - return offset; -} - -static int MyMapFile(thandle_t opaque, void** base, toff_t* size) { - (void)opaque; - (void)base; - (void)size; - return 0; -} -static void MyUnmapFile(thandle_t opaque, void* base, toff_t size) { - (void)opaque; - (void)base; - (void)size; -} - -static tsize_t MyRead(thandle_t opaque, void* dst, tsize_t size) { - MyData* const my_data = (MyData*)opaque; - if (my_data->pos + size > my_data->size) { - size = (tsize_t)(my_data->size - my_data->pos); - } - if (size > 0) { - memcpy(dst, my_data->data + my_data->pos, size); - my_data->pos += size; - } - return size; -} - -// Unmultiply Argb data. Taken from dsp/alpha_processing -// (we don't want to force a dependency to a libdspdec library). -#define MFIX 24 // 24bit fixed-point arithmetic -#define HALF ((1u << MFIX) >> 1) - -static uint32_t Unmult(uint8_t x, uint32_t mult) { - const uint32_t v = (x * mult + HALF) >> MFIX; - return (v > 255u) ? 255u : v; -} - -static WEBP_INLINE uint32_t GetScale(uint32_t a) { - return (255u << MFIX) / a; -} - -#undef MFIX -#undef HALF - -static void MultARGBRow(uint8_t* ptr, int width) { - int x; - for (x = 0; x < width; ++x, ptr += 4) { - const uint32_t alpha = ptr[3]; - if (alpha < 255) { - if (alpha == 0) { // alpha == 0 - ptr[0] = ptr[1] = ptr[2] = 0; - } else { - const uint32_t scale = GetScale(alpha); - ptr[0] = Unmult(ptr[0], scale); - ptr[1] = Unmult(ptr[1], scale); - ptr[2] = Unmult(ptr[2], scale); - } - } - } -} - -int ReadTIFF(const uint8_t* const data, size_t data_size, - WebPPicture* const pic, int keep_alpha, - Metadata* const metadata) { - MyData my_data = { data, (toff_t)data_size, 0 }; - TIFF* tif; - uint32_t image_width, image_height, tile_width, tile_height; - uint64_t stride; - uint16_t samples_per_px = 0; - uint16_t extra_samples = 0; - uint16_t* extra_samples_ptr = NULL; - uint32_t* raster; - int64_t alloc_size; - int ok = 0; - tdir_t dircount; - - if (data == NULL || data_size == 0 || data_size > INT_MAX || pic == NULL) { - return 0; - } - - tif = TIFFClientOpen("Memory", "r", &my_data, - MyRead, MyRead, MySeek, MyClose, - MySize, MyMapFile, MyUnmapFile); - if (tif == NULL) { - fprintf(stderr, "Error! Cannot parse TIFF file\n"); - return 0; - } - - dircount = TIFFNumberOfDirectories(tif); - if (dircount > 1) { - fprintf(stderr, "Warning: multi-directory TIFF files are not supported.\n" - "Only the first will be used, %d will be ignored.\n", - dircount - 1); - } - if (!TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &samples_per_px)) { - fprintf(stderr, "Error! Cannot retrieve TIFF samples-per-pixel info.\n"); - goto End; - } - if (!(samples_per_px == 1 || samples_per_px == 3 || samples_per_px == 4)) { - goto End; // not supported - } - - if (!(TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &image_width) && - TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &image_height))) { - fprintf(stderr, "Error! Cannot retrieve TIFF image dimensions.\n"); - goto End; - } - stride = (uint64_t)image_width * sizeof(*raster); - if (!ImgIoUtilCheckSizeArgumentsOverflow(stride, image_height)) { - fprintf(stderr, "Error! TIFF image dimension (%d x %d) is too large.\n", - image_width, image_height); - goto End; - } - - // According to spec, a tile can be bigger than the image. However it should - // be a multiple of 16 and not way too large, so check that it's not more - // than twice the image size, for dimensions above some arbitrary minimum - // 32. We also check that they respect WebP's dimension and memory limit. - // Note that a tile can be 6byte/px in some cases. Here we assume - // 4byte/px with sizeof(*raster), to be conservative. - if (TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tile_width) && - TIFFGetField(tif, TIFFTAG_TILELENGTH, &tile_height)) { - if ((tile_width > 32 && tile_width / 2 > image_width) || - (tile_height > 32 && tile_height / 2 > image_height) || - !ImgIoUtilCheckSizeArgumentsOverflow( - (uint64_t)tile_width * sizeof(*raster), tile_height)) { - fprintf(stderr, "Error! TIFF tile dimension (%d x %d) is too large.\n", - tile_width, tile_height); - goto End; - } - } - - if (samples_per_px > 3 && !TIFFGetField(tif, TIFFTAG_EXTRASAMPLES, - &extra_samples, &extra_samples_ptr)) { - fprintf(stderr, "Error! Cannot retrieve TIFF ExtraSamples info.\n"); - goto End; - } - - // _Tiffmalloc uses a signed type for size. - alloc_size = (int64_t)(stride * image_height); - if (alloc_size < 0 || alloc_size != (tsize_t)alloc_size) goto End; - - raster = (uint32_t*)_TIFFmalloc((tsize_t)alloc_size); - if (raster != NULL) { - if (TIFFReadRGBAImageOriented(tif, image_width, image_height, raster, - ORIENTATION_TOPLEFT, 1)) { - pic->width = image_width; - pic->height = image_height; - // TIFF data is ABGR -#ifdef WORDS_BIGENDIAN - TIFFSwabArrayOfLong(raster, image_width * image_height); -#endif - // if we have an alpha channel, we must un-multiply from rgbA to RGBA - if (extra_samples == 1 && extra_samples_ptr != NULL && - extra_samples_ptr[0] == EXTRASAMPLE_ASSOCALPHA) { - uint32_t y; - uint8_t* tmp = (uint8_t*)raster; - for (y = 0; y < image_height; ++y) { - MultARGBRow(tmp, image_width); - tmp += stride; - } - } - ok = keep_alpha - ? WebPPictureImportRGBA(pic, (const uint8_t*)raster, (int)stride) - : WebPPictureImportRGBX(pic, (const uint8_t*)raster, (int)stride); - } - _TIFFfree(raster); - } else { - fprintf(stderr, "Error allocating TIFF RGBA memory!\n"); - } - - if (ok) { - if (metadata != NULL) { - ok = ExtractMetadataFromTIFF(tif, metadata); - if (!ok) { - fprintf(stderr, "Error extracting TIFF metadata!\n"); - MetadataFree(metadata); - WebPPictureFree(pic); - } - } - } - End: - TIFFClose(tif); - return ok; -} -#else // !WEBP_HAVE_TIFF -int ReadTIFF(const uint8_t* const data, size_t data_size, - struct WebPPicture* const pic, int keep_alpha, - struct Metadata* const metadata) { - (void)data; - (void)data_size; - (void)pic; - (void)keep_alpha; - (void)metadata; - fprintf(stderr, "TIFF support not compiled. Please install the libtiff " - "development package before building.\n"); - return 0; -} -#endif // WEBP_HAVE_TIFF - -// ----------------------------------------------------------------------------- diff --git a/libwebp/imageio/tiffdec.h b/libwebp/imageio/tiffdec.h deleted file mode 100644 index 0c8beccd..00000000 --- a/libwebp/imageio/tiffdec.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2012 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// TIFF decode. - -#ifndef WEBP_IMAGEIO_TIFFDEC_H_ -#define WEBP_IMAGEIO_TIFFDEC_H_ - -#include "webp/types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct Metadata; -struct WebPPicture; - -// Reads a TIFF from 'data', returning the decoded output in 'pic'. -// Output is RGBA or YUVA, depending on pic->use_argb value. -// If 'keep_alpha' is true and the TIFF has an alpha channel, the output is RGBA -// or YUVA. Otherwise, alpha channel is dropped and output is RGB or YUV. -// Returns true on success. -int ReadTIFF(const uint8_t* const data, size_t data_size, - struct WebPPicture* const pic, int keep_alpha, - struct Metadata* const metadata); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // WEBP_IMAGEIO_TIFFDEC_H_ diff --git a/libwebp/imageio/webpdec.c b/libwebp/imageio/webpdec.c deleted file mode 100644 index aed60e14..00000000 --- a/libwebp/imageio/webpdec.c +++ /dev/null @@ -1,244 +0,0 @@ -// Copyright 2014 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// WebP decode. - -#ifdef HAVE_CONFIG_H -#include "webp/config.h" -#endif - -#include "./webpdec.h" - -#include -#include -#include - -#include "webp/decode.h" -#include "webp/demux.h" -#include "webp/encode.h" -#include "../examples/unicode.h" -#include "./imageio_util.h" -#include "./metadata.h" - -//------------------------------------------------------------------------------ -// WebP decoding - -static const char* const kStatusMessages[VP8_STATUS_NOT_ENOUGH_DATA + 1] = { - "OK", "OUT_OF_MEMORY", "INVALID_PARAM", "BITSTREAM_ERROR", - "UNSUPPORTED_FEATURE", "SUSPENDED", "USER_ABORT", "NOT_ENOUGH_DATA" -}; - -static void PrintAnimationWarning(const WebPDecoderConfig* const config) { - if (config->input.has_animation) { - fprintf(stderr, - "Error! Decoding of an animated WebP file is not supported.\n" - " Use webpmux to extract the individual frames or\n" - " vwebp to view this image.\n"); - } -} - -void PrintWebPError(const char* const in_file, int status) { - WFPRINTF(stderr, "Decoding of %s failed.\n", (const W_CHAR*)in_file); - fprintf(stderr, "Status: %d", status); - if (status >= VP8_STATUS_OK && status <= VP8_STATUS_NOT_ENOUGH_DATA) { - fprintf(stderr, "(%s)", kStatusMessages[status]); - } - fprintf(stderr, "\n"); -} - -int LoadWebP(const char* const in_file, - const uint8_t** data, size_t* data_size, - WebPBitstreamFeatures* bitstream) { - VP8StatusCode status; - WebPBitstreamFeatures local_features; - if (!ImgIoUtilReadFile(in_file, data, data_size)) return 0; - - if (bitstream == NULL) { - bitstream = &local_features; - } - - status = WebPGetFeatures(*data, *data_size, bitstream); - if (status != VP8_STATUS_OK) { - WebPFree((void*)*data); - *data = NULL; - *data_size = 0; - PrintWebPError(in_file, status); - return 0; - } - return 1; -} - -//------------------------------------------------------------------------------ - -VP8StatusCode DecodeWebP(const uint8_t* const data, size_t data_size, - WebPDecoderConfig* const config) { - if (config == NULL) return VP8_STATUS_INVALID_PARAM; - PrintAnimationWarning(config); - return WebPDecode(data, data_size, config); -} - -VP8StatusCode DecodeWebPIncremental( - const uint8_t* const data, size_t data_size, - WebPDecoderConfig* const config) { - VP8StatusCode status = VP8_STATUS_OK; - if (config == NULL) return VP8_STATUS_INVALID_PARAM; - - PrintAnimationWarning(config); - - // Decoding call. - { - WebPIDecoder* const idec = WebPIDecode(data, data_size, config); - if (idec == NULL) { - fprintf(stderr, "Failed during WebPIDecode().\n"); - return VP8_STATUS_OUT_OF_MEMORY; - } else { - status = WebPIUpdate(idec, data, data_size); - WebPIDelete(idec); - } - } - return status; -} - -// ----------------------------------------------------------------------------- -// Metadata - -static int ExtractMetadata(const uint8_t* const data, size_t data_size, - Metadata* const metadata) { - WebPData webp_data = { data, data_size }; - WebPDemuxer* const demux = WebPDemux(&webp_data); - WebPChunkIterator chunk_iter; - uint32_t flags; - - if (demux == NULL) return 0; - assert(metadata != NULL); - - flags = WebPDemuxGetI(demux, WEBP_FF_FORMAT_FLAGS); - - if ((flags & ICCP_FLAG) && WebPDemuxGetChunk(demux, "ICCP", 1, &chunk_iter)) { - MetadataCopy((const char*)chunk_iter.chunk.bytes, chunk_iter.chunk.size, - &metadata->iccp); - WebPDemuxReleaseChunkIterator(&chunk_iter); - } - if ((flags & EXIF_FLAG) && WebPDemuxGetChunk(demux, "EXIF", 1, &chunk_iter)) { - MetadataCopy((const char*)chunk_iter.chunk.bytes, chunk_iter.chunk.size, - &metadata->exif); - WebPDemuxReleaseChunkIterator(&chunk_iter); - } - if ((flags & XMP_FLAG) && WebPDemuxGetChunk(demux, "XMP ", 1, &chunk_iter)) { - MetadataCopy((const char*)chunk_iter.chunk.bytes, chunk_iter.chunk.size, - &metadata->xmp); - WebPDemuxReleaseChunkIterator(&chunk_iter); - } - WebPDemuxDelete(demux); - return 1; -} - -// ----------------------------------------------------------------------------- - -int ReadWebP(const uint8_t* const data, size_t data_size, - WebPPicture* const pic, - int keep_alpha, Metadata* const metadata) { - int ok = 0; - VP8StatusCode status = VP8_STATUS_OK; - WebPDecoderConfig config; - WebPDecBuffer* const output_buffer = &config.output; - WebPBitstreamFeatures* const bitstream = &config.input; - - if (data == NULL || data_size == 0 || pic == NULL) return 0; - - if (!WebPInitDecoderConfig(&config)) { - fprintf(stderr, "Library version mismatch!\n"); - return 0; - } - - status = WebPGetFeatures(data, data_size, bitstream); - if (status != VP8_STATUS_OK) { - PrintWebPError("input data", status); - return 0; - } - - do { - const int has_alpha = keep_alpha && bitstream->has_alpha; - uint64_t stride; - pic->width = bitstream->width; - pic->height = bitstream->height; - if (pic->use_argb) { - stride = (uint64_t)bitstream->width * 4; - } else { - stride = (uint64_t)bitstream->width * (has_alpha ? 5 : 3) / 2; - pic->colorspace = has_alpha ? WEBP_YUV420A : WEBP_YUV420; - } - - if (!ImgIoUtilCheckSizeArgumentsOverflow(stride, bitstream->height)) { - status = VP8_STATUS_OUT_OF_MEMORY; - break; - } - - ok = WebPPictureAlloc(pic); - if (!ok) { - status = VP8_STATUS_OUT_OF_MEMORY; - break; - } - if (pic->use_argb) { -#ifdef WORDS_BIGENDIAN - output_buffer->colorspace = MODE_ARGB; -#else - output_buffer->colorspace = MODE_BGRA; -#endif - output_buffer->u.RGBA.rgba = (uint8_t*)pic->argb; - output_buffer->u.RGBA.stride = pic->argb_stride * sizeof(uint32_t); - output_buffer->u.RGBA.size = output_buffer->u.RGBA.stride * pic->height; - } else { - output_buffer->colorspace = has_alpha ? MODE_YUVA : MODE_YUV; - output_buffer->u.YUVA.y = pic->y; - output_buffer->u.YUVA.u = pic->u; - output_buffer->u.YUVA.v = pic->v; - output_buffer->u.YUVA.a = has_alpha ? pic->a : NULL; - output_buffer->u.YUVA.y_stride = pic->y_stride; - output_buffer->u.YUVA.u_stride = pic->uv_stride; - output_buffer->u.YUVA.v_stride = pic->uv_stride; - output_buffer->u.YUVA.a_stride = has_alpha ? pic->a_stride : 0; - output_buffer->u.YUVA.y_size = pic->height * pic->y_stride; - output_buffer->u.YUVA.u_size = (pic->height + 1) / 2 * pic->uv_stride; - output_buffer->u.YUVA.v_size = (pic->height + 1) / 2 * pic->uv_stride; - output_buffer->u.YUVA.a_size = pic->height * pic->a_stride; - } - output_buffer->is_external_memory = 1; - - status = DecodeWebP(data, data_size, &config); - ok = (status == VP8_STATUS_OK); - if (ok && !keep_alpha && pic->use_argb) { - // Need to wipe out the alpha value, as requested. - int x, y; - uint32_t* argb = pic->argb; - for (y = 0; y < pic->height; ++y) { - for (x = 0; x < pic->width; ++x) argb[x] |= 0xff000000u; - argb += pic->argb_stride; - } - } - } while (0); // <- so we can 'break' out of the loop - - if (status != VP8_STATUS_OK) { - PrintWebPError("input data", status); - ok = 0; - } - - WebPFreeDecBuffer(output_buffer); - - if (ok && metadata != NULL) { - ok = ExtractMetadata(data, data_size, metadata); - if (!ok) { - PrintWebPError("metadata", VP8_STATUS_BITSTREAM_ERROR); - } - } - if (!ok) WebPPictureFree(pic); - return ok; -} - -// ----------------------------------------------------------------------------- diff --git a/libwebp/imageio/webpdec.h b/libwebp/imageio/webpdec.h deleted file mode 100644 index d329d41f..00000000 --- a/libwebp/imageio/webpdec.h +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2014 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// WebP decode. - -#ifndef WEBP_IMAGEIO_WEBPDEC_H_ -#define WEBP_IMAGEIO_WEBPDEC_H_ - -#include "webp/decode.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct Metadata; -struct WebPPicture; - -//------------------------------------------------------------------------------ -// WebP decoding - -// Prints an informative error message regarding decode failure of 'in_file'. -// 'status' is treated as a VP8StatusCode and if valid will be printed as a -// text string. -void PrintWebPError(const char* const in_file, int status); - -// Reads a WebP from 'in_file', returning the contents and size in 'data' and -// 'data_size'. If not NULL, 'bitstream' is populated using WebPGetFeatures(). -// Returns true on success. -int LoadWebP(const char* const in_file, - const uint8_t** data, size_t* data_size, - WebPBitstreamFeatures* bitstream); - -// Decodes the WebP contained in 'data'. -// 'config' is a structure previously initialized by WebPInitDecoderConfig(). -// 'config->output' should have the desired colorspace selected. -// Returns the decoder status. On success 'config->output' will contain the -// decoded picture. -VP8StatusCode DecodeWebP(const uint8_t* const data, size_t data_size, - WebPDecoderConfig* const config); - -// Same as DecodeWebP(), but using the incremental decoder. -VP8StatusCode DecodeWebPIncremental( - const uint8_t* const data, size_t data_size, - WebPDecoderConfig* const config); - -//------------------------------------------------------------------------------ - -// Decodes a WebP contained in 'data', returning the decoded output in 'pic'. -// Output is RGBA or YUVA, depending on pic->use_argb value. -// If 'keep_alpha' is true and the WebP has an alpha channel, the output is RGBA -// or YUVA. Otherwise, alpha channel is dropped and output is RGB or YUV. -// Returns true on success. -int ReadWebP(const uint8_t* const data, size_t data_size, - struct WebPPicture* const pic, - int keep_alpha, struct Metadata* const metadata); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // WEBP_IMAGEIO_WEBPDEC_H_ diff --git a/libwebp/imageio/wicdec.c b/libwebp/imageio/wicdec.c deleted file mode 100644 index 42001c6e..00000000 --- a/libwebp/imageio/wicdec.c +++ /dev/null @@ -1,413 +0,0 @@ -// Copyright 2013 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Windows Imaging Component (WIC) decode. - -#include "./wicdec.h" - -#ifdef HAVE_CONFIG_H -#include "webp/config.h" -#endif - -#include -#include -#include - -#ifdef HAVE_WINCODEC_H -#ifdef __MINGW32__ -#define INITGUID // Without this GUIDs are declared extern and fail to link -#endif -#define CINTERFACE -#define COBJMACROS -#define _WIN32_IE 0x500 // Workaround bug in shlwapi.h when compiling C++ - // code with COBJMACROS. -#include // CreateStreamOnHGlobal() -#include -#include -#include -#include - -#include "../examples/unicode.h" -#include "./imageio_util.h" -#include "./metadata.h" -#include "webp/encode.h" - -#define IFS(fn) \ - do { \ - if (SUCCEEDED(hr)) { \ - hr = (fn); \ - if (FAILED(hr)) fprintf(stderr, #fn " failed %08lx\n", hr); \ - } \ - } while (0) - -// modified version of DEFINE_GUID from guiddef.h. -#define WEBP_DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ - static const GUID name = \ - { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } - -#ifdef __cplusplus -#define MAKE_REFGUID(x) (x) -#else -#define MAKE_REFGUID(x) &(x) -#endif - -typedef struct WICFormatImporter { - const GUID* pixel_format; - int bytes_per_pixel; - int (*import)(WebPPicture* const, const uint8_t* const, int); -} WICFormatImporter; - -// From Microsoft SDK 7.0a -- wincodec.h -// Create local copies for compatibility when building against earlier -// versions of the SDK. -WEBP_DEFINE_GUID(GUID_WICPixelFormat24bppBGR_, - 0x6fddc324, 0x4e03, 0x4bfe, - 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0c); -WEBP_DEFINE_GUID(GUID_WICPixelFormat24bppRGB_, - 0x6fddc324, 0x4e03, 0x4bfe, - 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0d); -WEBP_DEFINE_GUID(GUID_WICPixelFormat32bppBGRA_, - 0x6fddc324, 0x4e03, 0x4bfe, - 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0f); -WEBP_DEFINE_GUID(GUID_WICPixelFormat32bppRGBA_, - 0xf5c7ad2d, 0x6a8d, 0x43dd, - 0xa7, 0xa8, 0xa2, 0x99, 0x35, 0x26, 0x1a, 0xe9); -WEBP_DEFINE_GUID(GUID_WICPixelFormat64bppBGRA_, - 0x1562ff7c, 0xd352, 0x46f9, - 0x97, 0x9e, 0x42, 0x97, 0x6b, 0x79, 0x22, 0x46); -WEBP_DEFINE_GUID(GUID_WICPixelFormat64bppRGBA_, - 0x6fddc324, 0x4e03, 0x4bfe, - 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x16); - -static HRESULT OpenInputStream(const char* filename, IStream** stream) { - HRESULT hr = S_OK; - if (!WSTRCMP(filename, "-")) { - const uint8_t* data = NULL; - size_t data_size = 0; - const int ok = ImgIoUtilReadFile(filename, &data, &data_size); - if (ok) { - HGLOBAL image = GlobalAlloc(GMEM_MOVEABLE, data_size); - if (image != NULL) { - void* const image_mem = GlobalLock(image); - if (image_mem != NULL) { - memcpy(image_mem, data, data_size); - GlobalUnlock(image); - IFS(CreateStreamOnHGlobal(image, TRUE, stream)); - } else { - hr = E_FAIL; - } - } else { - hr = E_OUTOFMEMORY; - } - free((void*)data); - } else { - hr = E_FAIL; - } - } else { - IFS(SHCreateStreamOnFile((const LPTSTR)filename, STGM_READ, stream)); - } - - if (FAILED(hr)) { - _ftprintf(stderr, _T("Error opening input file %s (%08lx)\n"), - (const LPTSTR)filename, hr); - } - return hr; -} - -// ----------------------------------------------------------------------------- -// Metadata processing - -// Stores the first non-zero sized color profile from 'frame' to 'iccp'. -// Returns an HRESULT to indicate success or failure. The caller is responsible -// for freeing 'iccp->bytes' in either case. -static HRESULT ExtractICCP(IWICImagingFactory* const factory, - IWICBitmapFrameDecode* const frame, - MetadataPayload* const iccp) { - HRESULT hr = S_OK; - UINT i, count; - IWICColorContext** color_contexts; - - IFS(IWICBitmapFrameDecode_GetColorContexts(frame, 0, NULL, &count)); - if (FAILED(hr) || count == 0) { - // Treat unsupported operation as a non-fatal error. See crbug.com/webp/506. - return (hr == WINCODEC_ERR_UNSUPPORTEDOPERATION) ? S_OK : hr; - } - - color_contexts = (IWICColorContext**)calloc(count, sizeof(*color_contexts)); - if (color_contexts == NULL) return E_OUTOFMEMORY; - for (i = 0; SUCCEEDED(hr) && i < count; ++i) { - IFS(IWICImagingFactory_CreateColorContext(factory, &color_contexts[i])); - } - - if (SUCCEEDED(hr)) { - UINT num_color_contexts; - IFS(IWICBitmapFrameDecode_GetColorContexts(frame, - count, color_contexts, - &num_color_contexts)); - assert(FAILED(hr) || num_color_contexts <= count); - for (i = 0; SUCCEEDED(hr) && i < num_color_contexts; ++i) { - WICColorContextType type; - IFS(IWICColorContext_GetType(color_contexts[i], &type)); - if (SUCCEEDED(hr) && type == WICColorContextProfile) { - UINT size; - IFS(IWICColorContext_GetProfileBytes(color_contexts[i], - 0, NULL, &size)); - if (SUCCEEDED(hr) && size > 0) { - iccp->bytes = (uint8_t*)malloc(size); - if (iccp->bytes == NULL) { - hr = E_OUTOFMEMORY; - break; - } - iccp->size = size; - IFS(IWICColorContext_GetProfileBytes(color_contexts[i], - (UINT)iccp->size, iccp->bytes, - &size)); - if (SUCCEEDED(hr) && size != iccp->size) { - fprintf(stderr, "Warning! ICC profile size (%u) != expected (%u)\n", - size, (uint32_t)iccp->size); - iccp->size = size; - } - break; - } - } - } - } - for (i = 0; i < count; ++i) { - if (color_contexts[i] != NULL) IUnknown_Release(color_contexts[i]); - } - free(color_contexts); - return hr; -} - -static HRESULT ExtractMetadata(IWICImagingFactory* const factory, - IWICBitmapFrameDecode* const frame, - Metadata* const metadata) { - // TODO(jzern): add XMP/EXIF extraction. - const HRESULT hr = ExtractICCP(factory, frame, &metadata->iccp); - if (FAILED(hr)) MetadataFree(metadata); - return hr; -} - -// ----------------------------------------------------------------------------- - -static int HasPalette(GUID pixel_format) { - return (IsEqualGUID(MAKE_REFGUID(pixel_format), - MAKE_REFGUID(GUID_WICPixelFormat1bppIndexed)) || - IsEqualGUID(MAKE_REFGUID(pixel_format), - MAKE_REFGUID(GUID_WICPixelFormat2bppIndexed)) || - IsEqualGUID(MAKE_REFGUID(pixel_format), - MAKE_REFGUID(GUID_WICPixelFormat4bppIndexed)) || - IsEqualGUID(MAKE_REFGUID(pixel_format), - MAKE_REFGUID(GUID_WICPixelFormat8bppIndexed))); -} - -static int HasAlpha(IWICImagingFactory* const factory, - IWICBitmapDecoder* const decoder, - IWICBitmapFrameDecode* const frame, - GUID pixel_format) { - int has_alpha; - if (HasPalette(pixel_format)) { - IWICPalette* frame_palette = NULL; - IWICPalette* global_palette = NULL; - BOOL frame_palette_has_alpha = FALSE; - BOOL global_palette_has_alpha = FALSE; - - // A palette may exist at the frame or container level, - // check IWICPalette::HasAlpha() for both if present. - if (SUCCEEDED(IWICImagingFactory_CreatePalette(factory, &frame_palette)) && - SUCCEEDED(IWICBitmapFrameDecode_CopyPalette(frame, frame_palette))) { - IWICPalette_HasAlpha(frame_palette, &frame_palette_has_alpha); - } - if (SUCCEEDED(IWICImagingFactory_CreatePalette(factory, &global_palette)) && - SUCCEEDED(IWICBitmapDecoder_CopyPalette(decoder, global_palette))) { - IWICPalette_HasAlpha(global_palette, &global_palette_has_alpha); - } - has_alpha = frame_palette_has_alpha || global_palette_has_alpha; - - if (frame_palette != NULL) IUnknown_Release(frame_palette); - if (global_palette != NULL) IUnknown_Release(global_palette); - } else { - has_alpha = IsEqualGUID(MAKE_REFGUID(pixel_format), - MAKE_REFGUID(GUID_WICPixelFormat32bppRGBA_)) || - IsEqualGUID(MAKE_REFGUID(pixel_format), - MAKE_REFGUID(GUID_WICPixelFormat32bppBGRA_)) || - IsEqualGUID(MAKE_REFGUID(pixel_format), - MAKE_REFGUID(GUID_WICPixelFormat64bppRGBA_)) || - IsEqualGUID(MAKE_REFGUID(pixel_format), - MAKE_REFGUID(GUID_WICPixelFormat64bppBGRA_)); - } - return has_alpha; -} - -int ReadPictureWithWIC(const char* const filename, - WebPPicture* const pic, int keep_alpha, - Metadata* const metadata) { - // From Microsoft SDK 6.0a -- ks.h - // Define a local copy to avoid link errors under mingw. - WEBP_DEFINE_GUID(GUID_NULL_, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - static const WICFormatImporter kAlphaFormatImporters[] = { - { &GUID_WICPixelFormat32bppBGRA_, 4, WebPPictureImportBGRA }, - { &GUID_WICPixelFormat32bppRGBA_, 4, WebPPictureImportRGBA }, - { NULL, 0, NULL }, - }; - static const WICFormatImporter kNonAlphaFormatImporters[] = { - { &GUID_WICPixelFormat24bppBGR_, 3, WebPPictureImportBGR }, - { &GUID_WICPixelFormat24bppRGB_, 3, WebPPictureImportRGB }, - { NULL, 0, NULL }, - }; - HRESULT hr = S_OK; - IWICBitmapFrameDecode* frame = NULL; - IWICFormatConverter* converter = NULL; - IWICImagingFactory* factory = NULL; - IWICBitmapDecoder* decoder = NULL; - IStream* stream = NULL; - UINT frame_count = 0; - UINT width = 0, height = 0; - BYTE* rgb = NULL; - WICPixelFormatGUID src_pixel_format = GUID_WICPixelFormatUndefined; - const WICFormatImporter* importer = NULL; - GUID src_container_format = GUID_NULL_; - // From Windows Kits\10\Include\10.0.19041.0\um\wincodec.h - WEBP_DEFINE_GUID(GUID_ContainerFormatWebp_, - 0xe094b0e2, 0x67f2, 0x45b3, - 0xb0, 0xea, 0x11, 0x53, 0x37, 0xca, 0x7c, 0xf3); - static const GUID* kAlphaContainers[] = { - &GUID_ContainerFormatBmp, - &GUID_ContainerFormatPng, - &GUID_ContainerFormatTiff, - &GUID_ContainerFormatWebp_, - NULL - }; - int has_alpha = 0; - int64_t stride; - - if (filename == NULL || pic == NULL) return 0; - - IFS(CoInitialize(NULL)); - IFS(CoCreateInstance(MAKE_REFGUID(CLSID_WICImagingFactory), NULL, - CLSCTX_INPROC_SERVER, - MAKE_REFGUID(IID_IWICImagingFactory), - (LPVOID*)&factory)); - if (hr == REGDB_E_CLASSNOTREG) { - fprintf(stderr, - "Couldn't access Windows Imaging Component (are you running " - "Windows XP SP3 or newer?). Most formats not available. " - "Use -s for the available YUV input.\n"); - } - // Prepare for image decoding. - IFS(OpenInputStream(filename, &stream)); - IFS(IWICImagingFactory_CreateDecoderFromStream( - factory, stream, NULL, - WICDecodeMetadataCacheOnDemand, &decoder)); - IFS(IWICBitmapDecoder_GetFrameCount(decoder, &frame_count)); - if (SUCCEEDED(hr)) { - if (frame_count == 0) { - fprintf(stderr, "No frame found in input file.\n"); - hr = E_FAIL; - } else if (frame_count > 1) { - // WIC will be tried before native WebP decoding so avoid duplicating the - // error message. - hr = E_FAIL; - } - } - IFS(IWICBitmapDecoder_GetFrame(decoder, 0, &frame)); - IFS(IWICBitmapFrameDecode_GetPixelFormat(frame, &src_pixel_format)); - IFS(IWICBitmapDecoder_GetContainerFormat(decoder, &src_container_format)); - - if (SUCCEEDED(hr) && keep_alpha) { - const GUID** guid; - for (guid = kAlphaContainers; *guid != NULL; ++guid) { - if (IsEqualGUID(MAKE_REFGUID(src_container_format), - MAKE_REFGUID(**guid))) { - has_alpha = HasAlpha(factory, decoder, frame, src_pixel_format); - break; - } - } - } - - // Prepare for pixel format conversion (if necessary). - IFS(IWICImagingFactory_CreateFormatConverter(factory, &converter)); - - for (importer = has_alpha ? kAlphaFormatImporters : kNonAlphaFormatImporters; - hr == S_OK && importer->import != NULL; ++importer) { - BOOL can_convert; - const HRESULT cchr = IWICFormatConverter_CanConvert( - converter, - MAKE_REFGUID(src_pixel_format), - MAKE_REFGUID(*importer->pixel_format), - &can_convert); - if (SUCCEEDED(cchr) && can_convert) break; - } - if (importer->import == NULL) hr = E_FAIL; - - IFS(IWICFormatConverter_Initialize(converter, (IWICBitmapSource*)frame, - importer->pixel_format, - WICBitmapDitherTypeNone, - NULL, 0.0, WICBitmapPaletteTypeCustom)); - - // Decode. - IFS(IWICFormatConverter_GetSize(converter, &width, &height)); - stride = (int64_t)importer->bytes_per_pixel * width * sizeof(*rgb); - if (stride != (int)stride || - !ImgIoUtilCheckSizeArgumentsOverflow(stride, height)) { - hr = E_FAIL; - } - - if (SUCCEEDED(hr)) { - rgb = (BYTE*)malloc((size_t)stride * height); - if (rgb == NULL) - hr = E_OUTOFMEMORY; - } - IFS(IWICFormatConverter_CopyPixels(converter, NULL, - (UINT)stride, (UINT)stride * height, rgb)); - - // WebP conversion. - if (SUCCEEDED(hr)) { - int ok; - pic->width = width; - pic->height = height; - pic->use_argb = 1; // For WIC, we always force to argb - ok = importer->import(pic, rgb, (int)stride); - if (!ok) hr = E_FAIL; - } - if (SUCCEEDED(hr)) { - if (metadata != NULL) { - hr = ExtractMetadata(factory, frame, metadata); - if (FAILED(hr)) { - fprintf(stderr, "Error extracting image metadata using WIC!\n"); - } - } - } - - // Cleanup. - if (converter != NULL) IUnknown_Release(converter); - if (frame != NULL) IUnknown_Release(frame); - if (decoder != NULL) IUnknown_Release(decoder); - if (factory != NULL) IUnknown_Release(factory); - if (stream != NULL) IUnknown_Release(stream); - free(rgb); - return SUCCEEDED(hr); -} -#else // !HAVE_WINCODEC_H -int ReadPictureWithWIC(const char* const filename, - struct WebPPicture* const pic, int keep_alpha, - struct Metadata* const metadata) { - (void)filename; - (void)pic; - (void)keep_alpha; - (void)metadata; - fprintf(stderr, "Windows Imaging Component (WIC) support not compiled. " - "Visual Studio and mingw-w64 builds support WIC. Make sure " - "wincodec.h detection is working correctly if using autoconf " - "and HAVE_WINCODEC_H is defined before building.\n"); - return 0; -} -#endif // HAVE_WINCODEC_H - -// ----------------------------------------------------------------------------- diff --git a/libwebp/imageio/wicdec.h b/libwebp/imageio/wicdec.h deleted file mode 100644 index d9eeca82..00000000 --- a/libwebp/imageio/wicdec.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2013 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Windows Imaging Component (WIC) decode. - -#ifndef WEBP_IMAGEIO_WICDEC_H_ -#define WEBP_IMAGEIO_WICDEC_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -struct Metadata; -struct WebPPicture; - -// Reads an image from 'filename', returning the decoded output in 'pic'. -// If 'keep_alpha' is true and the image has an alpha channel, the output is -// RGBA otherwise it will be RGB. pic->use_argb is always forced to true. -// Returns true on success. -int ReadPictureWithWIC(const char* const filename, - struct WebPPicture* const pic, int keep_alpha, - struct Metadata* const metadata); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // WEBP_IMAGEIO_WICDEC_H_ diff --git a/libwebp/infra/common.sh b/libwebp/infra/common.sh deleted file mode 100644 index b4892d54..00000000 --- a/libwebp/infra/common.sh +++ /dev/null @@ -1,106 +0,0 @@ -# Copyright (c) 2021, Google Inc. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# * Neither the name of Google nor the names of its contributors may -# be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -log_err() { - echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2 -} - -####################################### -# Create build directory. Build directory will be deleted if it exists. -# Arguments: -# None. -# Returns: -# mkdir result. -####################################### -make_build_dir() { - if [[ "$#" -ne 1 ]]; then - return 1 - fi - - local build_dir - build_dir="$1" - rm -rf "${build_dir}" - mkdir -p "${build_dir}" -} - -####################################### -# Cleanup files from the build directory. -# Globals: -# LIBWEBP_ROOT repository's root path. -# Arguments: -# $1 build directory. -####################################### -cleanup() { - # $1 is not completely removed to allow for binary artifacts to be - # extracted. - find "${1:?"Build directory not defined"}" \ - \( -name "*.[ao]" -o -name "*.l[ao]" \) -exec rm -f {} + -} - -####################################### -# Setup ccache for toolchain. -# Globals: -# PATH -# Arguments: -# None. -####################################### -setup_ccache() { - if [[ -x "$(command -v ccache)" ]]; then - export CCACHE_CPP2=yes - export PATH="/usr/lib/ccache:${PATH}" - fi -} - -####################################### -# Detects whether test block should be run in the current test shard. -# Globals: -# TEST_TOTAL_SHARDS: Valid range: [1, N]. Defaults to 1. -# TEST_SHARD_INDEX: Valid range: [0, TEST_TOTAL_SHARDS). Defaults to 0. -# libwebp_test_id: current test number; incremented with each call. -# Arguments: -# None -# Returns: -# true if the shard is active -# false if the shard is inactive -####################################### -shard_should_run() { - TEST_TOTAL_SHARDS=${TEST_TOTAL_SHARDS:=1} - TEST_SHARD_INDEX=${TEST_SHARD_INDEX:=0} - libwebp_test_id=${libwebp_test_id:=-1} - : $((libwebp_test_id += 1)) - - if [[ "${TEST_SHARD_INDEX}" -lt 0 || - "${TEST_SHARD_INDEX}" -ge "${TEST_TOTAL_SHARDS}" ]]; then - log_err "Invalid TEST_SHARD_INDEX (${TEST_SHARD_INDEX})!" \ - "Expected [0, ${TEST_TOTAL_SHARDS})." - fi - - [[ "$((libwebp_test_id % TEST_TOTAL_SHARDS))" -eq "${TEST_SHARD_INDEX}" ]] -} diff --git a/libwebp/infra/compile.sh b/libwebp/infra/compile.sh deleted file mode 100644 index 18e9ebee..00000000 --- a/libwebp/infra/compile.sh +++ /dev/null @@ -1,401 +0,0 @@ -#!/bin/bash -# Copyright (c) 2021, Google Inc. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# * Neither the name of Google nor the names of its contributors may -# be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -set -xe -LIBWEBP_ROOT="$(realpath "$(dirname "$0")/..")" -WORKSPACE=${WORKSPACE:-"$(mktemp -d -t webp.XXX)"} - -# shellcheck source=infra/common.sh -source "${LIBWEBP_ROOT}/infra/common.sh" - -usage() { - cat << EOF -Usage: compile.sh BUILD_TYPE TARGET -Options: -BUILD_TYPE supported build type: (shared, static, static-debug) -TARGET supported target platforms: - aarch64-linux-clang - aarch64-linux-gnu - arm-linux-gnueabi - arm-neon-linux-gnueabi - cmake - cmake-aarch64 - cmake-arm - cmake-clang - disable-near-lossless - disable-sse4.1 - disable-stats - force-aligned-32 - force-aligned-64 - gradle - i686-linux-asan - i686-linux-clang - i686-linux-gnu - i686-w64-mingw32 - mips2el-linux-gnu - mips32dspr2el-linux-gnu - mips32eb-linux-gnu - mips32el-linux-gnu - mips32r2el-linux-gnu - mips32r5el-linux-gnu - mips64r2el-linux-gnu - mips64r6el-linux-gnu - native - reduce-csp - reduce-size - reduce-size-disable-stats - visibility-default-gnu - visibility-hidden-clang - visibility-hidden-gnu - wasm - x86_64-linux-clang - x86_64-linux-gnu - x86_64-linux-msan - x86_64-w64-mingw32 -Environment variables: -WORKSPACE directory where the build is done -EOF -} - -################################################################################ -echo "Building libwebp in ${WORKSPACE}" - -if [[ ! -d "${WORKSPACE}" ]]; then - log_err "${WORKSPACE} directory does not exist" - exit 1 -fi - -BUILD_TYPE=${1:?"Build type not defined.$( - echo - usage -)"} -TARGET=${2:?"Target not defined.$( - echo - usage -)"} -readonly BUILD_DIR="${WORKSPACE}/build-${BUILD_TYPE}" - -trap 'cleanup ${BUILD_DIR}' EXIT -make_build_dir "${BUILD_DIR}" - -config_flags=() -case "${BUILD_TYPE}" in - shared*) ;; # Valid BUILD_TYPE but no setup required - static*) config_flags+=("--disable-shared") ;; - experimental) config_flags+=("--enable-experimental") ;; - *) - log_err "Invalid BUILD_TYPE" - usage - exit 1 - ;; -esac - -if grep -m 1 -q "enable-asserts" "${LIBWEBP_ROOT}/configure.ac"; then - config_flags+=("--enable-asserts") -fi - -case "${TARGET}" in - aarch64-linux-clang) - TARGET="aarch64-linux-gnu" - CC="clang" - CC="${CC} --target=aarch64-linux-gnu" - export CC - export CFLAGS="-isystem /usr/aarch64-linux-gnu/include" - ;; - arm-linux-gnueabi) - export CFLAGS="-O3 -march=armv7-a -mfloat-abi=softfp -ftree-vectorize" - ;; - arm-neon-linux-gnueabi) - TARGET="arm-linux-gnueabi" - CFLAGS="-O3 -march=armv7-a -mfpu=neon -mfloat-abi=softfp -ftree-vectorize" - export CFLAGS - ;; - mips2el-linux-gnu) - export CFLAGS="-EL -O2 -mips2" - TARGET="mipsel-linux-gnu" - ;; - mips32el-linux-gnu) - export CFLAGS="-EL -O2 -mips32" - TARGET="mipsel-linux-gnu" - ;; - mips32r2el-linux-gnu) - export CFLAGS="-EL -O2 -mips32r2" - TARGET="mipsel-linux-gnu" - ;; - mips32dspr2el-linux-gnu) - export CFLAGS="-EL -O2 -mdspr2" - TARGET="mipsel-linux-gnu" - ;; - mips32r5el-linux-gnu) - export CFLAGS="-EL -O2 -mips32r5 -mmsa" - TARGET="mipsel-linux-gnu" - ;; - mips32eb-linux-gnu) - export CFLAGS="-EB -O2 -mips32" - TARGET="mips-linux-gnu" - ;; - mips64r2el-linux-gnu) - export CFLAGS="-EL -O2 -mips64r2 -mabi=64" - TARGET="mips64el-linux-gnuabi64" - ;; - mips64r6el-linux-gnu) - export CFLAGS="-EL -O2 -mips64r6 -mabi=64 -mmsa" - TARGET="mips-img-linux-gnu" - ;; - i686-linux-gnu) - export CC="gcc -m32" - ;; - i686-linux-clang) - TARGET="i686-linux-gnu" - export CC="clang -m32" - ;; - i686-linux-asan) - TARGET="i686-linux-gnu" - export CC="clang -m32 -fsanitize=address" - ;; - i686-linux-msan) - TARGET="i686-linux-gnu" - export CC="clang -m32 -fsanitize=memory" - ;; - x86_64-linux-clang) - TARGET="x86_64-linux-gnu" - export CC=clang - ;; - x86_64-linux-msan) - TARGET="x86_64-linux-gnu" - export CC="clang -fsanitize=memory" - ;; - force-aligned-32) - config_flags+=("--enable-aligned") - TARGET="i686-linux-gnu" - export CC="gcc -m32" - ;; - force-aligned-64) - config_flags+=("--enable-aligned") - TARGET="x86_64-linux-gnu" - ;; - visibility-default-*) - export CFLAGS="-O2 -g -fvisibility=default" - TARGET="x86_64-linux-gnu" - ;; - visibility-hidden-*) - export CFLAGS="-O2 -g -fvisibility=hidden" - if [[ "${TARGET}" = "visibility-hidden-clang" ]]; then - export CC=clang - fi - TARGET="x86_64-linux-gnu" - ;; - disable-sse4.1) - grep "${TARGET}" "${LIBWEBP_ROOT}/configure.ac" || exit 0 - config_flags+=("--${TARGET}") - TARGET="x86_64-linux-gnu" - ;; - disable-near-lossless) - grep "${TARGET}" "${LIBWEBP_ROOT}/configure.ac" || exit 0 - config_flags+=("--${TARGET}") - TARGET="x86_64-linux-gnu" - ;; - disable-stats) - git -C "${LIBWEBP_ROOT}" grep WEBP_DISABLE_STATS || exit 0 - export CFLAGS="-O2 -g -DWEBP_DISABLE_STATS" - TARGET="x86_64-linux-gnu" - ;; - reduce-size) - git -C "${LIBWEBP_ROOT}" grep WEBP_REDUCE_SIZE || exit 0 - export CFLAGS="-O2 -g -DWEBP_REDUCE_SIZE" - TARGET="x86_64-linux-gnu" - ;; - reduce-size-disable-stats) - git -C "${LIBWEBP_ROOT}" grep -e WEBP_DISABLE_STATS -e WEBP_REDUCE_SIZE \ - || exit 0 - export CFLAGS="-O2 -g -DWEBP_DISABLE_STATS -DWEBP_REDUCE_SIZE" - TARGET="x86_64-linux-gnu" - ;; - reduce-csp) - git -C "${LIBWEBP_ROOT}" grep WEBP_REDUCE_CSP || exit 0 - export CFLAGS="-O2 -g -DWEBP_REDUCE_CSP" - TARGET="x86_64-linux-gnu" - ;; - x86_64-linux-gnu | *mingw32 | aarch64*) ;; # Default target configuration - # non-configure based builds - native) - setup_ccache - # exercise makefile.unix then quit - make -C "${LIBWEBP_ROOT}" -f makefile.unix -j all - for tgt in extras examples/anim_diff; do - grep -q -m 1 "${tgt}" "${LIBWEBP_ROOT}/makefile.unix" \ - && make -C "${LIBWEBP_ROOT}" -f makefile.unix -j "${tgt}" - done - [[ -d "${LIBWEBP_ROOT}/tests/fuzzer" ]] \ - && make -j -C "${LIBWEBP_ROOT}/tests/fuzzer" -f makefile.unix - exit 0 - ;; - cmake*) - setup_ccache - # exercise cmake then quit - opts=() - case "${TARGET}" in - cmake-clang) - opts+=("-DCMAKE_C_COMPILER=clang") - ;; - cmake-arm) - opts+=("-DCMAKE_C_COMPILER=arm-linux-gnueabi-gcc") - case "${GERRIT_BRANCH:-}" in - portable-intrinsics | 0.6.1) exit 0 ;; - *) ;; # Skip configuration - esac - ;; - cmake-aarch64) - opts+=("-DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc") - case "${GERRIT_BRANCH:-}" in - portable-intrinsics | 0.6.1) exit 0 ;; - *) ;; # Skip configuration - esac - ;; - *) ;; # Skip configuration - esac - case "${BUILD_TYPE}" in - static*) - opts+=("-DBUILD_SHARED_LIBS=OFF") - ;; - experimental) - opts+=("-DWEBP_EXPERIMENTAL_FEATURES=ON" "-DBUILD_SHARED_LIBS=ON") - ;; - *) - opts+=("-DBUILD_SHARED_LIBS=ON") - ;; - esac - case "${BUILD_TYPE}" in - *debug) opts+=("-DCMAKE_BUILD_TYPE=Debug") ;; - *) opts+=("-DCMAKE_BUILD_TYPE=RelWithDebInfo") ;; - esac - cd "${BUILD_DIR}" - opts+=("-DWEBP_BUILD_CWEBP=ON" "-DWEBP_BUILD_DWEBP=ON") - grep -m 1 -q WEBP_BUILD_GIF2WEBP "${LIBWEBP_ROOT}/CMakeLists.txt" \ - && opts+=("-DWEBP_BUILD_GIF2WEBP=ON") - grep -m 1 -q WEBP_BUILD_IMG2WEBP "${LIBWEBP_ROOT}/CMakeLists.txt" \ - && opts+=("-DWEBP_BUILD_IMG2WEBP=ON") - cmake "${opts[@]}" "${LIBWEBP_ROOT}" - make VERBOSE=1 -j - case "${BUILD_TYPE}" in - static) - mkdir -p examples - cp [cd]webp examples - ;; - *) ;; # Skip configuration. - esac - - grep "install" "${LIBWEBP_ROOT}/CMakeLists.txt" || exit 0 - - make DESTDIR="${BUILD_DIR}/webp-install" install/strip - mkdir tmp - cd tmp - cat > CMakeLists.txt << EOF -cmake_minimum_required(VERSION 2.8.7) - -project(libwebp C) - -find_package(WebP) -if (NOT WebP_FOUND) - message(FATAL_ERROR "WebP package not found") -endif () -message("WebP_FOUND: \${WebP_FOUND}") -message("WebP_INCLUDE_DIRS: \${WebP_INCLUDE_DIRS}") -message("WebP_LIBRARIES: \${WebP_LIBRARIES}") -message("WEBP_INCLUDE_DIRS: \${WEBP_INCLUDE_DIRS}") -message("WEBP_LIBRARIES: \${WEBP_LIBRARIES}") -EOF - cmake . "${opts[@]}" \ - "-DCMAKE_PREFIX_PATH=${BUILD_DIR}/webp-install/usr/local" - exit 0 - ;; - gradle) - setup_ccache - # exercise gradle then quit - [[ -f "${LIBWEBP_ROOT}/gradlew" ]] || exit 0 - - cd "${BUILD_DIR}" - # TODO -g / --gradle-user-home could be used if there's a race between jobs - "${LIBWEBP_ROOT}/gradlew" -p "${LIBWEBP_ROOT}" buildAllExecutables - exit 0 - ;; - wasm) - grep -m 1 -q WEBP_ENABLE_WASM "${LIBWEBP_ROOT}/CMakeLists.txt" || exit 0 - opts+=("-DCMAKE_C_COMPILER=clang" "-DWEBP_ENABLE_WASM=ON") - opts+=("-DWEBP_BUILD_CWEBP=ON" "-DWEBP_BUILD_DWEBP=ON") - case "${BUILD_TYPE}" in - *debug) opts+=("-DCMAKE_BUILD_TYPE=Debug") ;; - *) opts+=("-DCMAKE_BUILD_TYPE=RelWithDebInfo") ;; - esac - cd "${BUILD_DIR}" - cmake "${opts[@]}" "${LIBWEBP_ROOT}" - make VERBOSE=1 -j - mkdir examples - case "${BUILD_TYPE}" in - static) - mkdir -p examples - cp [cd]webp examples - ;; - *) ;; # Skip configuration - esac - exit 0 - ;; - *) - log_err "Invalid TARGET" - usage - exit 1 - ;; -esac - -case "${TARGET}" in - *mingw32) ;; # Skip configuration - *) - case "${TARGET}-${CC}" in - static-debug-gcc* | static-debug-) - CFLAGS="${CFLAGS} -fprofile-arcs -ftest-coverage -O0 -g" - CXXFLAGS="${CXXFLAGS} -fprofile-arcs -ftest-coverage -O0 -g" - export CFLAGS CXXFLAGS - ;; - *) ;; # This case should not be reached. - esac - ;; -esac - -setup_ccache - -cd "${LIBWEBP_ROOT}" -./autogen.sh - -cd "${BUILD_DIR}" -"${LIBWEBP_ROOT}/configure" \ - --host "${TARGET}" --build "$("${LIBWEBP_ROOT}/config.guess")" \ - --enable-everything "${config_flags[@]}" -make -j V=1 diff --git a/libwebp/infra/compile_android.sh b/libwebp/infra/compile_android.sh deleted file mode 100644 index 013b97cd..00000000 --- a/libwebp/infra/compile_android.sh +++ /dev/null @@ -1,224 +0,0 @@ -#!/bin/bash -# Copyright (c) 2021, Google Inc. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# * Neither the name of Google nor the names of its contributors may -# be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -set -xe -LIBWEBP_ROOT="$(realpath "$(dirname "$0")/..")" -readonly LIBWEBP_ROOT -readonly WORKSPACE=${WORKSPACE:-"$(mktemp -d -t webp.android.XXX)"} -# shellcheck source=infra/common.sh -source "${LIBWEBP_ROOT}/infra/common.sh" - -usage() { - cat << EOF -Usage: $(basename "$0") BUILD_TYPE APP_ABI -Options: -BUILD_TYPE supported build types: - static - static-debug - shared - shared-debug -APP_ABI supported application binary interfaces: - armeabi-v7a - arm64-v8a - x86 - x86_64 -Environment variables: -WORKSPACE directory where the build is done. -ANDROID_NDK_DIR directory where the android ndk tools are. -EOF -} - -################################################################################ -echo "Building libwebp for Android in ${WORKSPACE}" - -if [[ ! -d "${WORKSPACE}" ]]; then - log_err "${WORKSPACE} directory does not exist." - exit 1 -fi - -readonly BUILD_TYPE=${1:?"BUILD_TYPE is not defined.$( - echo - usage -)"} -readonly APP_ABI=${2:?"APP_ABI not defined.$( - echo - usage -)"} -readonly ANDROID_NDK_DIR=${ANDROID_NDK_DIR:?"ANDROID_NDK_DIR is not defined.$( - echo - usage -)"} -readonly BUILD_DIR="${WORKSPACE}/build-${BUILD_TYPE}" -readonly STANDALONE_ANDROID_DIR="${WORKSPACE}/android" - -if [[ ! -x "${ANDROID_NDK_DIR}/ndk-build" ]]; then - log_err "unable to find ndk-build in ANDROID_NDK_DIR: ${ANDROID_NDK_DIR}." - exit 1 -fi - -CFLAGS= -LDFLAGS= -opts=() -case "${BUILD_TYPE}" in - *debug) - readonly APP_OPTIM="debug" - CFLAGS="-O0 -g" - opts+=("--enable-asserts") - ;; - static* | shared*) - readonly APP_OPTIM="release" - CFLAGS="-O2 -g" - ;; - *) - usage - exit 1 - ;; -esac - -case "${BUILD_TYPE}" in - shared*) readonly SHARED="1" ;; - *) - readonly SHARED="0" - CFLAGS="${CFLAGS} -fPIE" - LDFLAGS="${LDFLAGS} -Wl,-pie" - opts+=("--disable-shared") - ;; -esac - -# Create a fresh build directory -make_build_dir "${BUILD_DIR}" -cd "${BUILD_DIR}" -ln -s "${LIBWEBP_ROOT}" jni - -"${ANDROID_NDK_DIR}/ndk-build" -j2 \ - APP_ABI="${APP_ABI}" \ - APP_OPTIM="${APP_OPTIM}" \ - ENABLE_SHARED="${SHARED}" - -cd "${LIBWEBP_ROOT}" -./autogen.sh - -case "${APP_ABI}" in - armeabi*) arch="arm" ;; - arm64*) arch="arm64" ;; - *) arch="${APP_ABI}" ;; -esac -# TODO(b/185520507): remove this and use the binaries from -# toolchains/llvm/prebuilt/ directly. -rm -rf "${STANDALONE_ANDROID_DIR}" -"${ANDROID_NDK_DIR}/build/tools/make_standalone_toolchain.py" \ - --api 24 --arch "${arch}" --stl gnustl --install-dir \ - "${STANDALONE_ANDROID_DIR}" -export PATH="${STANDALONE_ANDROID_DIR}/bin:${PATH}" - -rm -rf "${BUILD_DIR}" -make_build_dir "${BUILD_DIR}" -cd "${BUILD_DIR}" - -case "${arch}" in - arm) - host="arm-linux-androideabi" - case "${APP_ABI}" in - armeabi) ;; - armeabi-v7a) - CFLAGS="${CFLAGS} -march=armv7-a -mfpu=neon -mfloat-abi=softfp" - ;; - *) ;; # No configuration needed - esac - ;; - arm64) - host="aarch64-linux-android" - ;; - x86) - host="i686-linux-android" - ;; - x86_64) - host="x86_64-linux-android" - ;; - *) ;; # Skip configuration -esac - -setup_ccache -CC="clang" - -"${LIBWEBP_ROOT}/configure" --host "${host}" --build \ - "$("${LIBWEBP_ROOT}/config.guess")" CC="${CC}" CFLAGS="${CFLAGS}" \ - LDFLAGS="${LDFLAGS}" "${opts[@]}" -make -j - -if [[ "${GERRIT_REFSPEC:-}" = "refs/heads/portable-intrinsics" ]] \ - || [[ "${GERRIT_BRANCH:-}" = "portable-intrinsics" ]]; then - cd "${WORKSPACE}" - rm -rf build && mkdir build - cd build - standalone="${WORKSPACE}/android" - cmake ../libwebp \ - -DWEBP_BUILD_DWEBP=1 \ - -DCMAKE_C_COMPILER="${standalone}/bin/clang" \ - -DCMAKE_PREFIX_PATH="${standalone}/sysroot/usr/lib" \ - -DCMAKE_C_FLAGS=-fPIE \ - -DCMAKE_EXE_LINKER_FLAGS=-Wl,-pie \ - -DCMAKE_BUILD_TYPE=Release \ - -DWEBP_ENABLE_WASM=1 - make -j2 - - cd "${WORKSPACE}" - make_build_dir "${BUILD_DIR}" - cd "${BUILD_DIR}" - case "${APP_ABI}" in - armeabi-v7a | arm64*) - cmake "${LIBWEBP_ROOT}" \ - -DWEBP_BUILD_DWEBP=1 \ - -DCMAKE_C_COMPILER="${standalone}/bin/clang" \ - -DCMAKE_PREFIX_PATH="${standalone}/sysroot/usr/lib" \ - -DCMAKE_C_FLAGS='-fPIE -DENABLE_NEON_BUILTIN_MULHI_INT16X8' \ - -DCMAKE_EXE_LINKER_FLAGS=-Wl,-pie \ - -DCMAKE_BUILD_TYPE=Release \ - -DWEBP_ENABLE_WASM=1 - make -j2 - ;; - x86*) - cmake "${LIBWEBP_ROOT}" \ - -DWEBP_BUILD_DWEBP=1 \ - -DCMAKE_C_COMPILER="${standalone}/bin/clang" \ - -DCMAKE_PREFIX_PATH="${standalone}/sysroot/usr/lib" \ - -DCMAKE_C_FLAGS='-fPIE -DENABLE_X86_BUILTIN_MULHI_INT16X8' \ - -DCMAKE_EXE_LINKER_FLAGS=-Wl,-pie \ - -DCMAKE_BUILD_TYPE=Release \ - -DWEBP_ENABLE_WASM=1 - make -j2 - ;; - *) - log_err "APP_ABI not supported." - exit 1 - ;; - esac -fi diff --git a/libwebp/infra/compile_js.sh b/libwebp/infra/compile_js.sh deleted file mode 100644 index 6a13fe6a..00000000 --- a/libwebp/infra/compile_js.sh +++ /dev/null @@ -1,75 +0,0 @@ -#!/bin/bash -# Copyright (c) 2021, Google Inc. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# * Neither the name of Google nor the names of its contributors may -# be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -set -ex - -readonly WORKSPACE="${WORKSPACE:-"$(mktemp -d -t webp.js.XXX)"}" -readonly BUILD_DIR="${WORKSPACE}/webp_js/" -readonly LIBWEBP_ROOT="$(realpath "$(dirname "$0")/..")" - -# shellcheck source=infra/common.sh -source "${LIBWEBP_ROOT}/infra/common.sh" - -usage() { - cat << EOF -Usage: $(basename "$0") -Environment variables: -WORKSPACE directory where the build is done -EMSDK_DIR directory where emsdk is installed -EOF -} - -[[ -d "${EMSDK_DIR:?Not defined}" ]] \ - || (log_err "${EMSDK_DIR} is not a valid directory." && exit 1) - -# shellcheck source=/opt/emsdk/emsdk_env.sh -source "${EMSDK_DIR}/emsdk_env.sh" - -readonly EMSCRIPTEN=${EMSCRIPTEN:-"${EMSDK}/upstream/emscripten"} -readonly \ - EMSCRIPTEN_CMAKE_FILE="${EMSCRIPTEN}/cmake/Modules/Platform/Emscripten.cmake" -make_build_dir "${BUILD_DIR}" - -pushd "${BUILD_DIR}" -opts=("-GUnix Makefiles" "-DWEBP_BUILD_WEBP_JS=ON") -if [[ -z "$(command -v emcmake)" ]]; then - opts+=("-DCMAKE_TOOLCHAIN_FILE=${EMSCRIPTEN_CMAKE_FILE}") - cmake \ - "${opts[@]}" \ - "${LIBWEBP_ROOT}" - make -j -else - emcmake cmake \ - "${opts[@]}" \ - "${LIBWEBP_ROOT}" - emmake make -j -fi -popd diff --git a/libwebp/infra/run_static_analysis.sh b/libwebp/infra/run_static_analysis.sh deleted file mode 100644 index fa8445ca..00000000 --- a/libwebp/infra/run_static_analysis.sh +++ /dev/null @@ -1,98 +0,0 @@ -#!/bin/bash -# Copyright (c) 2021, Google Inc. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# * Neither the name of Google nor the names of its contributors may -# be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -set -xe - -LIBWEBP_ROOT="$(realpath "$(dirname "$0")/..")" -readonly LIBWEBP_ROOT -readonly WORKSPACE=${WORKSPACE:-"$(mktemp -d -t webp.scanbuild.XXX)"} - -# shellcheck source=infra/common.sh -source "${LIBWEBP_ROOT}/infra/common.sh" - -usage() { - cat << EOF -Usage: $(basename "$0") MODE -Options: -MODE supported scan modes: (shallow|deep) -Environment variables: -WORKSPACE directory where the build is done. -EOF -} - -####################################### -# Wrap clang-tools scan-build. -# Globals: -# OUTPUT_DIR target directory where scan-build report is generated. -# MODE scan-build mode -# Arguments: -# $* scan-build additional args. -# Returns: -# scan-build retcode -####################################### -scan_build() { - scan-build -o "${OUTPUT_DIR}" --use-analyzer="$(command -v clang)" \ - -analyzer-config mode="${MODE}" "$*" -} - -MODE=${1:?"MODE is not specified.$( - echo - usage -)"} - -readonly OUTPUT_DIR="${WORKSPACE}/output-${MODE}" -readonly BUILD_DIR="${WORKSPACE}/build" - -make_build_dir "${OUTPUT_DIR}" -make_build_dir "${BUILD_DIR}" - -cd "${LIBWEBP_ROOT}" -./autogen.sh - -cd "${BUILD_DIR}" -grep -m 1 -q 'enable-asserts' "${LIBWEBP_ROOT}/configure.ac" \ - && args='--enable-asserts' -scan_build "${LIBWEBP_ROOT}/configure" --enable-everything "${args}" -scan_build make -j4 - -index="$(find "${OUTPUT_DIR}" -name index.html)" -if [[ -f "${index}" ]]; then - mv "$(dirname "${index}")/"* "${OUTPUT_DIR}" -else - # make a empty report to wipe out any old bug reports. - cat << EOT > "${OUTPUT_DIR}/index.html" - - -No bugs reported. - - -EOT -fi diff --git a/libwebp/iosbuild.sh b/libwebp/iosbuild.sh deleted file mode 100644 index d0fb5572..00000000 --- a/libwebp/iosbuild.sh +++ /dev/null @@ -1,178 +0,0 @@ -#!/bin/bash -# -# This script generates 'WebP.framework' and 'WebPDecoder.framework', -# 'WebPDemux.framework' and 'WebPMux.framework'. -# An iOS app can decode WebP images by including 'WebPDecoder.framework' and -# both encode and decode WebP images by including 'WebP.framework'. -# -# Run ./iosbuild.sh to generate the frameworks under the current directory -# (the previous build will be erased if it exists). -# -# This script is inspired by the build script written by Carson McDonald. -# (https://www.ioncannon.net/programming/1483/using-webp-to-reduce-native-ios-app-size/). - -set -e - -# Set this variable based on the desired minimum deployment target. -readonly IOS_MIN_VERSION=6.0 - -# Extract the latest SDK version from the final field of the form: iphoneosX.Y -readonly SDK=$(xcodebuild -showsdks \ - | grep iphoneos | sort | tail -n 1 | awk '{print substr($NF, 9)}' -) -# Extract Xcode version. -readonly XCODE=$(xcodebuild -version | grep Xcode | cut -d " " -f2) -if [[ -z "${XCODE}" ]]; then - echo "Xcode not available" - exit 1 -fi - -readonly OLDPATH=${PATH} - -# Add iPhoneOS-V6 to the list of platforms below if you need armv6 support. -# Note that iPhoneOS-V6 support is not available with the iOS6 SDK. -PLATFORMS="iPhoneSimulator iPhoneSimulator64" -PLATFORMS+=" iPhoneOS-V7 iPhoneOS-V7s iPhoneOS-V7-arm64" -readonly PLATFORMS -readonly SRCDIR=$(dirname $0) -readonly TOPDIR=$(pwd) -readonly BUILDDIR="${TOPDIR}/iosbuild" -readonly TARGETDIR="${TOPDIR}/WebP.framework" -readonly DECTARGETDIR="${TOPDIR}/WebPDecoder.framework" -readonly MUXTARGETDIR="${TOPDIR}/WebPMux.framework" -readonly DEMUXTARGETDIR="${TOPDIR}/WebPDemux.framework" -readonly SHARPYUVTARGETDIR="${TOPDIR}/SharpYuv.framework" -readonly DEVELOPER=$(xcode-select --print-path) -readonly PLATFORMSROOT="${DEVELOPER}/Platforms" -readonly LIPO=$(xcrun -sdk iphoneos${SDK} -find lipo) -LIBLIST='' -DECLIBLIST='' -MUXLIBLIST='' -DEMUXLIBLIST='' - -if [[ -z "${SDK}" ]]; then - echo "iOS SDK not available" - exit 1 -elif [[ ${SDK%%.*} -gt 8 ]]; then - EXTRA_CFLAGS="-fembed-bitcode" -elif [[ ${SDK%%.*} -le 6 ]]; then - echo "You need iOS SDK version 6.0 or above" - exit 1 -fi - -echo "Xcode Version: ${XCODE}" -echo "iOS SDK Version: ${SDK}" - -if [[ -e "${BUILDDIR}" || -e "${TARGETDIR}" || -e "${DECTARGETDIR}" \ - || -e "${MUXTARGETDIR}" || -e "${DEMUXTARGETDIR}" \ - || -e "${SHARPYUVTARGETDIR}" ]]; then - cat << EOF -WARNING: The following directories will be deleted: -WARNING: ${BUILDDIR} -WARNING: ${TARGETDIR} -WARNING: ${DECTARGETDIR} -WARNING: ${MUXTARGETDIR} -WARNING: ${DEMUXTARGETDIR} -WARNING: ${SHARPYUVTARGETDIR} -WARNING: The build will continue in 5 seconds... -EOF - sleep 5 -fi -rm -rf ${BUILDDIR} ${TARGETDIR} ${DECTARGETDIR} \ - ${MUXTARGETDIR} ${DEMUXTARGETDIR} ${SHARPYUVTARGETDIR} -mkdir -p ${BUILDDIR} ${TARGETDIR}/Headers/ ${DECTARGETDIR}/Headers/ \ - ${MUXTARGETDIR}/Headers/ ${DEMUXTARGETDIR}/Headers/ \ - ${SHARPYUVTARGETDIR}/Headers/ - -if [[ ! -e ${SRCDIR}/configure ]]; then - if ! (cd ${SRCDIR} && sh autogen.sh); then - cat << EOF -Error creating configure script! -This script requires the autoconf/automake and libtool to build. MacPorts can -be used to obtain these: -https://www.macports.org/install.php -EOF - exit 1 - fi -fi - -for PLATFORM in ${PLATFORMS}; do - ARCH2="" - if [[ "${PLATFORM}" == "iPhoneOS-V7-arm64" ]]; then - PLATFORM="iPhoneOS" - ARCH="aarch64" - ARCH2="arm64" - elif [[ "${PLATFORM}" == "iPhoneOS-V7s" ]]; then - PLATFORM="iPhoneOS" - ARCH="armv7s" - elif [[ "${PLATFORM}" == "iPhoneOS-V7" ]]; then - PLATFORM="iPhoneOS" - ARCH="armv7" - elif [[ "${PLATFORM}" == "iPhoneOS-V6" ]]; then - PLATFORM="iPhoneOS" - ARCH="armv6" - elif [[ "${PLATFORM}" == "iPhoneSimulator64" ]]; then - PLATFORM="iPhoneSimulator" - ARCH="x86_64" - else - ARCH="i386" - fi - - ROOTDIR="${BUILDDIR}/${PLATFORM}-${SDK}-${ARCH}" - mkdir -p "${ROOTDIR}" - - DEVROOT="${DEVELOPER}/Toolchains/XcodeDefault.xctoolchain" - SDKROOT="${PLATFORMSROOT}/" - SDKROOT+="${PLATFORM}.platform/Developer/SDKs/${PLATFORM}${SDK}.sdk/" - CFLAGS="-arch ${ARCH2:-${ARCH}} -pipe -isysroot ${SDKROOT} -O3 -DNDEBUG" - CFLAGS+=" -miphoneos-version-min=${IOS_MIN_VERSION} ${EXTRA_CFLAGS}" - - set -x - export PATH="${DEVROOT}/usr/bin:${OLDPATH}" - ${SRCDIR}/configure --host=${ARCH}-apple-darwin --prefix=${ROOTDIR} \ - --build=$(${SRCDIR}/config.guess) \ - --disable-shared --enable-static \ - --enable-libwebpdecoder --enable-swap-16bit-csp \ - --enable-libwebpmux \ - CFLAGS="${CFLAGS}" - set +x - - # Build only the libraries, skip the examples. - make V=0 -C sharpyuv install - make V=0 -C src install - - LIBLIST+=" ${ROOTDIR}/lib/libwebp.a" - DECLIBLIST+=" ${ROOTDIR}/lib/libwebpdecoder.a" - MUXLIBLIST+=" ${ROOTDIR}/lib/libwebpmux.a" - DEMUXLIBLIST+=" ${ROOTDIR}/lib/libwebpdemux.a" - SHARPYUVLIBLIST+=" ${ROOTDIR}/lib/libsharpyuv.a" - - make clean - - export PATH=${OLDPATH} -done - -echo "LIBLIST = ${LIBLIST}" -cp -a ${SRCDIR}/src/webp/{decode,encode,types}.h ${TARGETDIR}/Headers/ -${LIPO} -create ${LIBLIST} -output ${TARGETDIR}/WebP - -echo "DECLIBLIST = ${DECLIBLIST}" -cp -a ${SRCDIR}/src/webp/{decode,types}.h ${DECTARGETDIR}/Headers/ -${LIPO} -create ${DECLIBLIST} -output ${DECTARGETDIR}/WebPDecoder - -echo "MUXLIBLIST = ${MUXLIBLIST}" -cp -a ${SRCDIR}/src/webp/{types,mux,mux_types}.h \ - ${MUXTARGETDIR}/Headers/ -${LIPO} -create ${MUXLIBLIST} -output ${MUXTARGETDIR}/WebPMux - -echo "DEMUXLIBLIST = ${DEMUXLIBLIST}" -cp -a ${SRCDIR}/src/webp/{decode,types,mux_types,demux}.h \ - ${DEMUXTARGETDIR}/Headers/ -${LIPO} -create ${DEMUXLIBLIST} -output ${DEMUXTARGETDIR}/WebPDemux - -echo "SHARPYUVLIBLIST = ${SHARPYUVLIBLIST}" -cp -a ${SRCDIR}/sharpyuv/{sharpyuv,sharpyuv_csp}.h \ - ${SHARPYUVTARGETDIR}/Headers/ -${LIPO} -create ${SHARPYUVLIBLIST} -output ${SHARPYUVTARGETDIR}/SharpYuv - -echo "SUCCESS" diff --git a/libwebp/m4/ax_pthread.m4 b/libwebp/m4/ax_pthread.m4 deleted file mode 100644 index d383ad5c..00000000 --- a/libwebp/m4/ax_pthread.m4 +++ /dev/null @@ -1,332 +0,0 @@ -# =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_pthread.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) -# -# DESCRIPTION -# -# This macro figures out how to build C programs using POSIX threads. It -# sets the PTHREAD_LIBS output variable to the threads library and linker -# flags, and the PTHREAD_CFLAGS output variable to any special C compiler -# flags that are needed. (The user can also force certain compiler -# flags/libs to be tested by setting these environment variables.) -# -# Also sets PTHREAD_CC to any special C compiler that is needed for -# multi-threaded programs (defaults to the value of CC otherwise). (This -# is necessary on AIX to use the special cc_r compiler alias.) -# -# NOTE: You are assumed to not only compile your program with these flags, -# but also link it with them as well. e.g. you should link with -# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS -# -# If you are only building threads programs, you may wish to use these -# variables in your default LIBS, CFLAGS, and CC: -# -# LIBS="$PTHREAD_LIBS $LIBS" -# CFLAGS="$CFLAGS $PTHREAD_CFLAGS" -# CC="$PTHREAD_CC" -# -# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant -# has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name -# (e.g. PTHREAD_CREATE_UNDETACHED on AIX). -# -# Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the -# PTHREAD_PRIO_INHERIT symbol is defined when compiling with -# PTHREAD_CFLAGS. -# -# ACTION-IF-FOUND is a list of shell commands to run if a threads library -# is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it -# is not found. If ACTION-IF-FOUND is not specified, the default action -# will define HAVE_PTHREAD. -# -# Please let the authors know if this macro fails on any platform, or if -# you have any other suggestions or comments. This macro was based on work -# by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help -# from M. Frigo), as well as ac_pthread and hb_pthread macros posted by -# Alejandro Forero Cuervo to the autoconf macro repository. We are also -# grateful for the helpful feedback of numerous users. -# -# Updated for Autoconf 2.68 by Daniel Richard G. -# -# LICENSE -# -# Copyright (c) 2008 Steven G. Johnson -# Copyright (c) 2011 Daniel Richard G. -# -# This program is free software: you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the -# Free Software Foundation, either version 3 of the License, or (at your -# option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General -# Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program. If not, see . -# -# As a special exception, the respective Autoconf Macro's copyright owner -# gives unlimited permission to copy, distribute and modify the configure -# scripts that are the output of Autoconf when processing the Macro. You -# need not follow the terms of the GNU General Public License when using -# or distributing such scripts, even though portions of the text of the -# Macro appear in them. The GNU General Public License (GPL) does govern -# all other use of the material that constitutes the Autoconf Macro. -# -# This special exception to the GPL applies to versions of the Autoconf -# Macro released by the Autoconf Archive. When you make and distribute a -# modified version of the Autoconf Macro, you may extend this special -# exception to the GPL to apply to your modified version as well. - -#serial 21 - -AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) -AC_DEFUN([AX_PTHREAD], [ -AC_REQUIRE([AC_CANONICAL_HOST]) -AC_LANG_PUSH([C]) -ax_pthread_ok=no - -# We used to check for pthread.h first, but this fails if pthread.h -# requires special compiler flags (e.g. on True64 or Sequent). -# It gets checked for in the link test anyway. - -# First of all, check if the user has set any of the PTHREAD_LIBS, -# etcetera environment variables, and if threads linking works using -# them: -if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then - save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - save_LIBS="$LIBS" - LIBS="$PTHREAD_LIBS $LIBS" - AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) - AC_TRY_LINK_FUNC([pthread_join], [ax_pthread_ok=yes]) - AC_MSG_RESULT([$ax_pthread_ok]) - if test x"$ax_pthread_ok" = xno; then - PTHREAD_LIBS="" - PTHREAD_CFLAGS="" - fi - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" -fi - -# We must check for the threads library under a number of different -# names; the ordering is very important because some systems -# (e.g. DEC) have both -lpthread and -lpthreads, where one of the -# libraries is broken (non-POSIX). - -# Create a list of thread flags to try. Items starting with a "-" are -# C compiler flags, and other items are library names, except for "none" -# which indicates that we try without any flags at all, and "pthread-config" -# which is a program returning the flags for the Pth emulation library. - -ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" - -# The ordering *is* (sometimes) important. Some notes on the -# individual items follow: - -# pthreads: AIX (must check this before -lpthread) -# none: in case threads are in libc; should be tried before -Kthread and -# other compiler flags to prevent continual compiler warnings -# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) -# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) -# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) -# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) -# -pthreads: Solaris/gcc -# -mthreads: Mingw32/gcc, Lynx/gcc -# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it -# doesn't hurt to check since this sometimes defines pthreads too; -# also defines -D_REENTRANT) -# ... -mt is also the pthreads flag for HP/aCC -# pthread: Linux, etcetera -# --thread-safe: KAI C++ -# pthread-config: use pthread-config program (for GNU Pth library) - -case ${host_os} in - solaris*) - - # On Solaris (at least, for some versions), libc contains stubbed - # (non-functional) versions of the pthreads routines, so link-based - # tests will erroneously succeed. (We need to link with -pthreads/-mt/ - # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather - # a function called by this macro, so we could check for that, but - # who knows whether they'll stub that too in a future libc.) So, - # we'll just look for -pthreads and -lpthread first: - - ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags" - ;; - - darwin*) - ax_pthread_flags="-pthread $ax_pthread_flags" - ;; -esac - -# Clang doesn't consider unrecognized options an error unless we specify -# -Werror. We throw in some extra Clang-specific options to ensure that -# this doesn't happen for GCC, which also accepts -Werror. - -AC_MSG_CHECKING([if compiler needs -Werror to reject unknown flags]) -save_CFLAGS="$CFLAGS" -ax_pthread_extra_flags="-Werror" -CFLAGS="$CFLAGS $ax_pthread_extra_flags -Wunknown-warning-option -Wsizeof-array-argument" -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([int foo(void);],[foo()])], - [AC_MSG_RESULT([yes])], - [ax_pthread_extra_flags= - AC_MSG_RESULT([no])]) -CFLAGS="$save_CFLAGS" - -if test x"$ax_pthread_ok" = xno; then -for flag in $ax_pthread_flags; do - - case $flag in - none) - AC_MSG_CHECKING([whether pthreads work without any flags]) - ;; - - -*) - AC_MSG_CHECKING([whether pthreads work with $flag]) - PTHREAD_CFLAGS="$flag" - ;; - - pthread-config) - AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no]) - if test x"$ax_pthread_config" = xno; then continue; fi - PTHREAD_CFLAGS="`pthread-config --cflags`" - PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" - ;; - - *) - AC_MSG_CHECKING([for the pthreads library -l$flag]) - PTHREAD_LIBS="-l$flag" - ;; - esac - - save_LIBS="$LIBS" - save_CFLAGS="$CFLAGS" - LIBS="$PTHREAD_LIBS $LIBS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS $ax_pthread_extra_flags" - - # Check for various functions. We must include pthread.h, - # since some functions may be macros. (On the Sequent, we - # need a special flag -Kthread to make this header compile.) - # We check for pthread_join because it is in -lpthread on IRIX - # while pthread_create is in libc. We check for pthread_attr_init - # due to DEC craziness with -lpthreads. We check for - # pthread_cleanup_push because it is one of the few pthread - # functions on Solaris that doesn't have a non-functional libc stub. - # We try pthread_create on general principles. - AC_LINK_IFELSE([AC_LANG_PROGRAM([#include - static void routine(void *a) { a = 0; } - static void *start_routine(void *a) { return a; }], - [pthread_t th; pthread_attr_t attr; - pthread_create(&th, 0, start_routine, 0); - pthread_join(th, 0); - pthread_attr_init(&attr); - pthread_cleanup_push(routine, 0); - pthread_cleanup_pop(0) /* ; */])], - [ax_pthread_ok=yes], - []) - - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" - - AC_MSG_RESULT([$ax_pthread_ok]) - if test "x$ax_pthread_ok" = xyes; then - break; - fi - - PTHREAD_LIBS="" - PTHREAD_CFLAGS="" -done -fi - -# Various other checks: -if test "x$ax_pthread_ok" = xyes; then - save_LIBS="$LIBS" - LIBS="$PTHREAD_LIBS $LIBS" - save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - - # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. - AC_MSG_CHECKING([for joinable pthread attribute]) - attr_name=unknown - for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do - AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], - [int attr = $attr; return attr /* ; */])], - [attr_name=$attr; break], - []) - done - AC_MSG_RESULT([$attr_name]) - if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then - AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], [$attr_name], - [Define to necessary symbol if this constant - uses a non-standard name on your system.]) - fi - - AC_MSG_CHECKING([if more special flags are required for pthreads]) - flag=no - case ${host_os} in - aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";; - osf* | hpux*) flag="-D_REENTRANT";; - solaris*) - if test "$GCC" = "yes"; then - flag="-D_REENTRANT" - else - # TODO: What about Clang on Solaris? - flag="-mt -D_REENTRANT" - fi - ;; - esac - AC_MSG_RESULT([$flag]) - if test "x$flag" != xno; then - PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" - fi - - AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], - [ax_cv_PTHREAD_PRIO_INHERIT], [ - AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], - [[int i = PTHREAD_PRIO_INHERIT;]])], - [ax_cv_PTHREAD_PRIO_INHERIT=yes], - [ax_cv_PTHREAD_PRIO_INHERIT=no]) - ]) - AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"], - [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])]) - - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" - - # More AIX lossage: compile with *_r variant - if test "x$GCC" != xyes; then - case $host_os in - aix*) - AS_CASE(["x/$CC"], - [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6], - [#handle absolute path differently from PATH based program lookup - AS_CASE(["x$CC"], - [x/*], - [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])], - [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])]) - ;; - esac - fi -fi - -test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" - -AC_SUBST([PTHREAD_LIBS]) -AC_SUBST([PTHREAD_CFLAGS]) -AC_SUBST([PTHREAD_CC]) - -# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: -if test x"$ax_pthread_ok" = xyes; then - ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1]) - : -else - ax_pthread_ok=no - $2 -fi -AC_LANG_POP -])dnl AX_PTHREAD diff --git a/libwebp/makefile.unix b/libwebp/makefile.unix deleted file mode 100644 index 70f97ff2..00000000 --- a/libwebp/makefile.unix +++ /dev/null @@ -1,539 +0,0 @@ -# This makefile is a simpler alternative to the autoconf-based build -# system, for simple local building of the libraries and tools. -# It will not install the libraries system-wide, but just create the 'cwebp' -# and 'dwebp' tools in the examples/ directory, along with the static -# libraries 'src/libwebp.a', 'src/libwebpdecoder.a', 'src/mux/libwebpmux.a', -# 'src/demux/libwebpdemux.a', 'extras/libwebpextras.a' and -# 'sharpyuv/libsharpyuv.a'. -# -# To build the library and examples, use: -# make -f makefile.unix -# from this top directory. - -#### Customizable part #### - -# These flags assume you have libpng, libjpeg, libtiff and libgif installed. If -# not, either follow the install instructions below or just comment out the next -# four lines. -EXTRA_FLAGS= -DWEBP_HAVE_PNG -DWEBP_HAVE_JPEG -DWEBP_HAVE_TIFF -DWEBP_LIBS= -lpng -lz -CWEBP_LIBS= $(DWEBP_LIBS) -ljpeg -ltiff -GIF_LIBS = -lgif - -ifeq ($(strip $(shell uname)), Darwin) - # Work around a problem linking tables marked as common symbols, - # cf., src/enc/yuv.[hc] - # Failure observed with: gcc 4.2.1 and 4.0.1. - EXTRA_FLAGS += -fno-common - EXTRA_FLAGS += -DHAVE_GLUT_GLUT_H - EXTRA_FLAGS += -Wno-deprecated-declarations - EXTRA_FLAGS += -I/opt/local/include - EXTRA_LIBS += -L/opt/local/lib - GL_LIBS = -framework GLUT -framework OpenGL -else - EXTRA_FLAGS += -I/usr/local/include - EXTRA_LIBS += -L/usr/local/lib - GL_LIBS = -lglut -lGL -endif - -# SDL flags: use sdl-config if it exists -SDL_CONFIG = $(shell sdl2-config --version 2> /dev/null) -ifneq ($(SDL_CONFIG),) - SDL_LIBS = $(shell sdl2-config --libs) - SDL_FLAGS = $(shell sdl2-config --cflags) -else - # use best-guess - SDL_LIBS = -lSDL2 - SDL_FLAGS = -endif - -# To install libraries on Mac OS X: -# 1. Install MacPorts (https://www.macports.org/install.php) -# 2. Run "sudo port install jpeg" -# 3. Run "sudo port install libpng" -# 4. Run "sudo port install tiff" -# 5. Run "sudo port install giflib" - -# To install libraries on Linux: -# 1. Run "sudo apt-get install libjpeg62-dev" -# 2. Run "sudo apt-get install libpng12-dev" -# 3. Run "sudo apt-get install libtiff4-dev" -# 4. Run "sudo apt-get install libgif-dev" - -# Uncomment for build for 32bit platform -# Alternatively, you can just use the command -# 'make -f makefile.unix EXTRA_FLAGS=-m32' to that effect. -# EXTRA_FLAGS += -m32 - -# Extra flags to enable byte swap for 16 bit colorspaces. -# EXTRA_FLAGS += -DWEBP_SWAP_16BIT_CSP=1 - -# Extra flags to enable multi-threading -EXTRA_FLAGS += -DWEBP_USE_THREAD -EXTRA_LIBS += -lpthread - -# Control symbol visibility. Comment out if your compiler doesn't support it. -EXTRA_FLAGS += -fvisibility=hidden - -# Extra flags to emulate C89 strictness with the full ANSI -EXTRA_FLAGS += -Wextra -Wold-style-definition -EXTRA_FLAGS += -Wmissing-prototypes -EXTRA_FLAGS += -Wmissing-declarations -EXTRA_FLAGS += -Wdeclaration-after-statement -EXTRA_FLAGS += -Wshadow -EXTRA_FLAGS += -Wformat-security -Wformat-nonliteral -# EXTRA_FLAGS += -Wvla - -# SSE4.1-specific flags: -ifeq ($(HAVE_SSE41), 1) -EXTRA_FLAGS += -DWEBP_HAVE_SSE41 -src/dsp/%_sse41.o: EXTRA_FLAGS += -msse4.1 -endif - -# NEON-specific flags: -# EXTRA_FLAGS += -march=armv7-a -mfloat-abi=hard -mfpu=neon -mtune=cortex-a8 -# -> seems to make the overall lib slower: -fno-split-wide-types - -# MIPS (MSA) 32-bit build specific flags for mips32r5 (p5600): -# EXTRA_FLAGS += -mips32r5 -mabi=32 -mtune=p5600 -mmsa -mfp64 -# EXTRA_FLAGS += -msched-weight -mload-store-pairs - -# MIPS (MSA) 64-bit build specific flags for mips64r6 (i6400): -# EXTRA_FLAGS += -mips64r6 -mabi=64 -mtune=i6400 -mmsa -mfp64 -# EXTRA_FLAGS += -msched-weight -mload-store-pairs - -#### Nothing should normally be changed below this line #### - -AR = ar -ARFLAGS = r -CPPFLAGS = -I. -Isrc/ -Wall -ifeq ($(DEBUG), 1) - CFLAGS = -g -else - CFLAGS = -O3 -DNDEBUG -endif -CFLAGS += $(EXTRA_FLAGS) -CC = gcc -INSTALL = install -GROFF = /usr/bin/groff -COL = /usr/bin/col -LDFLAGS = $(EXTRA_LIBS) $(EXTRA_FLAGS) -lm - -ifdef BITTRACE -CFLAGS += -DBITTRACE=$(BITTRACE) -endif - -ANIM_UTIL_OBJS = \ - examples/anim_util.o \ - -SHARPYUV_OBJS = \ - sharpyuv/sharpyuv.o \ - sharpyuv/sharpyuv_cpu.o \ - sharpyuv/sharpyuv_csp.o \ - sharpyuv/sharpyuv_dsp.o \ - sharpyuv/sharpyuv_gamma.o \ - sharpyuv/sharpyuv_neon.o \ - sharpyuv/sharpyuv_sse2.o \ - -DEC_OBJS = \ - src/dec/alpha_dec.o \ - src/dec/buffer_dec.o \ - src/dec/frame_dec.o \ - src/dec/idec_dec.o \ - src/dec/io_dec.o \ - src/dec/quant_dec.o \ - src/dec/tree_dec.o \ - src/dec/vp8_dec.o \ - src/dec/vp8l_dec.o \ - src/dec/webp_dec.o \ - -DEMUX_OBJS = \ - src/demux/anim_decode.o \ - src/demux/demux.o \ - -DSP_DEC_OBJS = \ - src/dsp/alpha_processing.o \ - src/dsp/alpha_processing_mips_dsp_r2.o \ - src/dsp/alpha_processing_neon.o \ - src/dsp/alpha_processing_sse2.o \ - src/dsp/alpha_processing_sse41.o \ - src/dsp/cpu.o \ - src/dsp/dec.o \ - src/dsp/dec_clip_tables.o \ - src/dsp/dec_mips32.o \ - src/dsp/dec_mips_dsp_r2.o \ - src/dsp/dec_msa.o \ - src/dsp/dec_neon.o \ - src/dsp/dec_sse2.o \ - src/dsp/dec_sse41.o \ - src/dsp/filters.o \ - src/dsp/filters_mips_dsp_r2.o \ - src/dsp/filters_msa.o \ - src/dsp/filters_neon.o \ - src/dsp/filters_sse2.o \ - src/dsp/lossless.o \ - src/dsp/lossless_mips_dsp_r2.o \ - src/dsp/lossless_msa.o \ - src/dsp/lossless_neon.o \ - src/dsp/lossless_sse2.o \ - src/dsp/lossless_sse41.o \ - src/dsp/rescaler.o \ - src/dsp/rescaler_mips32.o \ - src/dsp/rescaler_mips_dsp_r2.o \ - src/dsp/rescaler_msa.o \ - src/dsp/rescaler_neon.o \ - src/dsp/rescaler_sse2.o \ - src/dsp/upsampling.o \ - src/dsp/upsampling_mips_dsp_r2.o \ - src/dsp/upsampling_msa.o \ - src/dsp/upsampling_neon.o \ - src/dsp/upsampling_sse2.o \ - src/dsp/upsampling_sse41.o \ - src/dsp/yuv.o \ - src/dsp/yuv_mips32.o \ - src/dsp/yuv_mips_dsp_r2.o \ - src/dsp/yuv_neon.o \ - src/dsp/yuv_sse2.o \ - src/dsp/yuv_sse41.o \ - -DSP_ENC_OBJS = \ - src/dsp/cost.o \ - src/dsp/cost_mips32.o \ - src/dsp/cost_mips_dsp_r2.o \ - src/dsp/cost_neon.o \ - src/dsp/cost_sse2.o \ - src/dsp/enc.o \ - src/dsp/enc_mips32.o \ - src/dsp/enc_mips_dsp_r2.o \ - src/dsp/enc_msa.o \ - src/dsp/enc_neon.o \ - src/dsp/enc_sse2.o \ - src/dsp/enc_sse41.o \ - src/dsp/lossless_enc.o \ - src/dsp/lossless_enc_mips32.o \ - src/dsp/lossless_enc_mips_dsp_r2.o \ - src/dsp/lossless_enc_msa.o \ - src/dsp/lossless_enc_neon.o \ - src/dsp/lossless_enc_sse2.o \ - src/dsp/lossless_enc_sse41.o \ - src/dsp/ssim.o \ - src/dsp/ssim_sse2.o \ - -ENC_OBJS = \ - src/enc/alpha_enc.o \ - src/enc/analysis_enc.o \ - src/enc/backward_references_cost_enc.o \ - src/enc/backward_references_enc.o \ - src/enc/config_enc.o \ - src/enc/cost_enc.o \ - src/enc/filter_enc.o \ - src/enc/frame_enc.o \ - src/enc/histogram_enc.o \ - src/enc/iterator_enc.o \ - src/enc/near_lossless_enc.o \ - src/enc/picture_enc.o \ - src/enc/picture_csp_enc.o \ - src/enc/picture_psnr_enc.o \ - src/enc/picture_rescale_enc.o \ - src/enc/picture_tools_enc.o \ - src/enc/predictor_enc.o \ - src/enc/quant_enc.o \ - src/enc/syntax_enc.o \ - src/enc/token_enc.o \ - src/enc/tree_enc.o \ - src/enc/vp8l_enc.o \ - src/enc/webp_enc.o \ - -EX_FORMAT_DEC_OBJS = \ - imageio/image_dec.o \ - imageio/jpegdec.o \ - imageio/metadata.o \ - imageio/pngdec.o \ - imageio/pnmdec.o \ - imageio/tiffdec.o \ - imageio/webpdec.o \ - -EX_FORMAT_ENC_OBJS = \ - imageio/image_enc.o \ - -EX_UTIL_OBJS = \ - examples/example_util.o \ - -GIFDEC_OBJS = \ - examples/gifdec.o \ - -IMAGE_UTIL_OBJS = \ - imageio/imageio_util.o \ - -MUX_OBJS = \ - src/mux/anim_encode.o \ - src/mux/muxedit.o \ - src/mux/muxinternal.o \ - src/mux/muxread.o \ - -UTILS_DEC_OBJS = \ - src/utils/bit_reader_utils.o \ - src/utils/color_cache_utils.o \ - src/utils/filters_utils.o \ - src/utils/huffman_utils.o \ - src/utils/palette.o \ - src/utils/quant_levels_dec_utils.o \ - src/utils/random_utils.o \ - src/utils/rescaler_utils.o \ - src/utils/thread_utils.o \ - src/utils/utils.o \ - -UTILS_ENC_OBJS = \ - src/utils/bit_writer_utils.o \ - src/utils/huffman_encode_utils.o \ - src/utils/quant_levels_utils.o \ - -EXTRA_OBJS = \ - extras/extras.o \ - extras/quality_estimate.o \ - extras/sharpyuv_risk_table.o \ - -LIBWEBPDECODER_OBJS = $(DEC_OBJS) $(DSP_DEC_OBJS) $(UTILS_DEC_OBJS) -LIBWEBP_OBJS = $(LIBWEBPDECODER_OBJS) $(ENC_OBJS) \ - $(DSP_ENC_OBJS) $(UTILS_ENC_OBJS) -LIBWEBPMUX_OBJS = $(MUX_OBJS) -LIBWEBPDEMUX_OBJS = $(DEMUX_OBJS) -LIBWEBPEXTRA_OBJS = $(EXTRA_OBJS) -LIBSHARPYUV_OBJS = $(SHARPYUV_OBJS) - -HDRS_INSTALLED = \ - src/webp/decode.h \ - src/webp/demux.h \ - src/webp/encode.h \ - src/webp/mux.h \ - src/webp/mux_types.h \ - src/webp/types.h \ - -SHARPYUV_HDRS_INSTALLED = \ - sharpyuv/sharpyuv.h \ - sharpyuv/sharpyuv_cpu.h \ - sharpyuv/sharpyuv_csp.h \ - -HDRS = \ - src/dec/alphai_dec.h \ - src/dec/common_dec.h \ - src/dec/vp8_dec.h \ - src/dec/vp8i_dec.h \ - src/dec/vp8li_dec.h \ - src/dec/webpi_dec.h \ - src/dsp/common_sse2.h \ - src/dsp/cpu.h \ - src/dsp/dsp.h \ - src/dsp/lossless.h \ - src/dsp/lossless_common.h \ - src/dsp/mips_macro.h \ - src/dsp/msa_macro.h \ - src/dsp/neon.h \ - src/dsp/yuv.h \ - src/enc/backward_references_enc.h \ - src/enc/cost_enc.h \ - src/enc/histogram_enc.h \ - src/enc/vp8i_enc.h \ - src/enc/vp8li_enc.h \ - src/mux/animi.h \ - src/mux/muxi.h \ - src/utils/bit_reader_utils.h \ - src/utils/bit_reader_inl_utils.h \ - src/utils/bit_writer_utils.h \ - src/utils/color_cache_utils.h \ - src/utils/endian_inl_utils.h \ - src/utils/filters_utils.h \ - src/utils/huffman_utils.h \ - src/utils/huffman_encode_utils.h \ - src/utils/palette.h \ - src/utils/quant_levels_utils.h \ - src/utils/quant_levels_dec_utils.h \ - src/utils/random_utils.h \ - src/utils/rescaler_utils.h \ - src/utils/thread_utils.h \ - src/utils/utils.h \ - src/webp/format_constants.h \ - $(HDRS_INSTALLED) \ - $(SHARPYUV_HDRS_INSTALLED) \ - -OUT_LIBS = examples/libexample_util.a -OUT_LIBS += imageio/libimageio_util.a -OUT_LIBS += imageio/libimagedec.a -OUT_LIBS += imageio/libimageenc.a -OUT_LIBS += src/libwebpdecoder.a -OUT_LIBS += src/libwebp.a -OUT_LIBS += sharpyuv/libsharpyuv.a -EXTRA_LIB = extras/libwebpextras.a -OUT_EXAMPLES = examples/cwebp examples/dwebp -EXTRA_EXAMPLES = examples/gif2webp examples/vwebp examples/webpmux \ - examples/anim_diff examples/anim_dump \ - examples/img2webp examples/webpinfo -OTHER_EXAMPLES = extras/get_disto extras/webp_quality extras/vwebp_sdl - -OUTPUT = $(OUT_LIBS) $(OUT_EXAMPLES) -ifeq ($(MAKECMDGOALS),clean) - OUTPUT += $(EXTRA_EXAMPLES) $(OTHER_EXAMPLES) - OUTPUT += src/demux/libwebpdemux.a src/mux/libwebpmux.a $(EXTRA_LIB) - OUTPUT += examples/libgifdec.a examples/libanim_util.a -endif - -ex: $(OUT_EXAMPLES) -all: ex $(EXTRA_EXAMPLES) $(OTHER_EXAMPLES) -extras: $(EXTRA_LIB) - -$(EX_FORMAT_DEC_OBJS): %.o: %.h - -# special dependencies: -# tree_dec.c/vp8_dec.c/bit_reader_utils.c <-> -# bit_reader_inl_utils.h, endian_inl_utils.h -# bit_writer_utils.c <-> endian_inl_utils.h -src/dec/tree_dec.o: src/utils/bit_reader_inl_utils.h -src/dec/tree_dec.o: src/utils/endian_inl_utils.h -src/dec/vp8_dec.o: src/utils/bit_reader_inl_utils.h src/utils/endian_inl_utils.h -src/utils/bit_reader_utils.o: src/utils/bit_reader_inl_utils.h -src/utils/bit_reader_utils.o: src/utils/endian_inl_utils.h -src/utils/bit_writer_utils.o: src/utils/endian_inl_utils.h - -%.o: %.c $(HDRS) - $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ - -examples/libanim_util.a: $(ANIM_UTIL_OBJS) -examples/libexample_util.a: $(EX_UTIL_OBJS) -examples/libgifdec.a: $(GIFDEC_OBJS) -extras/libwebpextras.a: $(LIBWEBPEXTRA_OBJS) -imageio/libimagedec.a: $(EX_FORMAT_DEC_OBJS) -imageio/libimageenc.a: $(EX_FORMAT_ENC_OBJS) -imageio/libimageio_util.a: $(IMAGE_UTIL_OBJS) -src/libwebpdecoder.a: $(LIBWEBPDECODER_OBJS) -src/libwebp.a: $(LIBWEBP_OBJS) -src/mux/libwebpmux.a: $(LIBWEBPMUX_OBJS) -src/demux/libwebpdemux.a: $(LIBWEBPDEMUX_OBJS) -sharpyuv/libsharpyuv.a: $(LIBSHARPYUV_OBJS) - -%.a: - $(AR) $(ARFLAGS) $@ $^ - -examples/anim_diff: examples/anim_diff.o $(ANIM_UTIL_OBJS) $(GIFDEC_OBJS) -examples/anim_dump: examples/anim_dump.o $(ANIM_UTIL_OBJS) $(GIFDEC_OBJS) -examples/cwebp: examples/cwebp.o -examples/dwebp: examples/dwebp.o -examples/gif2webp: examples/gif2webp.o $(GIFDEC_OBJS) -examples/vwebp: examples/vwebp.o -examples/webpmux: examples/webpmux.o -examples/img2webp: examples/img2webp.o -examples/webpinfo: examples/webpinfo.o - -examples/anim_diff: examples/libanim_util.a examples/libgifdec.a -examples/anim_diff: src/demux/libwebpdemux.a examples/libexample_util.a -examples/anim_diff: imageio/libimageio_util.a src/libwebp.a -examples/anim_diff: sharpyuv/libsharpyuv.a -examples/anim_diff: override EXTRA_LIBS += $(GIF_LIBS) -examples/anim_diff: EXTRA_FLAGS += -DWEBP_HAVE_GIF -examples/anim_dump: examples/libanim_util.a examples/libgifdec.a -examples/anim_dump: src/demux/libwebpdemux.a -examples/anim_dump: examples/libexample_util.a -examples/anim_dump: imageio/libimageio_util.a -examples/anim_dump: imageio/libimageenc.a -examples/anim_dump: src/libwebp.a -examples/anim_dump: sharpyuv/libsharpyuv.a -examples/anim_dump: override EXTRA_LIBS += $(GIF_LIBS) $(DWEBP_LIBS) -examples/cwebp: examples/libexample_util.a -examples/cwebp: imageio/libimagedec.a -examples/cwebp: src/demux/libwebpdemux.a -examples/cwebp: imageio/libimageio_util.a -examples/cwebp: src/libwebp.a -examples/cwebp: sharpyuv/libsharpyuv.a -examples/cwebp: override EXTRA_LIBS += $(CWEBP_LIBS) -examples/dwebp: examples/libexample_util.a -examples/dwebp: imageio/libimagedec.a -examples/dwebp: src/demux/libwebpdemux.a -examples/dwebp: imageio/libimageenc.a -examples/dwebp: imageio/libimageio_util.a -examples/dwebp: src/libwebp.a -examples/dwebp: sharpyuv/libsharpyuv.a -examples/dwebp: override EXTRA_LIBS += $(DWEBP_LIBS) -examples/gif2webp: examples/libexample_util.a imageio/libimageio_util.a -examples/gif2webp: examples/libgifdec.a src/mux/libwebpmux.a src/libwebp.a -examples/gif2webp: sharpyuv/libsharpyuv.a -examples/gif2webp: override EXTRA_LIBS += $(GIF_LIBS) -examples/gif2webp: EXTRA_FLAGS += -DWEBP_HAVE_GIF -examples/vwebp: examples/libexample_util.a src/demux/libwebpdemux.a -examples/vwebp: imageio/libimageio_util.a src/libwebp.a -examples/vwebp: sharpyuv/libsharpyuv.a -examples/vwebp: override EXTRA_LIBS += $(GL_LIBS) -examples/vwebp: EXTRA_FLAGS += -DWEBP_HAVE_GL -examples/webpmux: examples/libexample_util.a imageio/libimageio_util.a -examples/webpmux: src/mux/libwebpmux.a src/libwebpdecoder.a -examples/img2webp: examples/libexample_util.a imageio/libimageio_util.a -examples/img2webp: imageio/libimagedec.a -examples/img2webp: src/demux/libwebpdemux.a -examples/img2webp: src/mux/libwebpmux.a -examples/img2webp: src/libwebp.a -examples/img2webp: sharpyuv/libsharpyuv.a -examples/img2webp: override EXTRA_LIBS += $(CWEBP_LIBS) -examples/webpinfo: examples/libexample_util.a imageio/libimageio_util.a -examples/webpinfo: src/libwebpdecoder.a - -extras/get_disto: extras/get_disto.o -extras/get_disto: imageio/libimagedec.a -extras/get_disto: src/demux/libwebpdemux.a -extras/get_disto: imageio/libimageio_util.a -extras/get_disto: src/libwebp.a -extras/get_disto: sharpyuv/libsharpyuv.a -extras/get_disto: override EXTRA_LIBS += $(CWEBP_LIBS) - -extras/webp_quality: extras/webp_quality.o -extras/webp_quality: imageio/libimageio_util.a -extras/webp_quality: $(EXTRA_LIB) src/libwebp.a -extras/webp_quality: sharpyuv/libsharpyuv.a - -extras/vwebp_sdl: extras/vwebp_sdl.o -extras/vwebp_sdl: extras/webp_to_sdl.o -extras/vwebp_sdl: imageio/libimageio_util.a -extras/vwebp_sdl: src/libwebp.a -extras/vwebp_sdl: sharpyuv/libsharpyuv.a -extras/vwebp_sdl: EXTRA_FLAGS += -DWEBP_HAVE_SDL $(SDL_FLAGS) -extras/vwebp_sdl: override EXTRA_LIBS += $(SDL_LIBS) - -$(OUT_EXAMPLES) $(EXTRA_EXAMPLES) $(OTHER_EXAMPLES): - $(CC) -o $@ $^ $(LDFLAGS) - -dist: DESTDIR := dist -dist: OUT_EXAMPLES += $(EXTRA_EXAMPLES) -dist: all - $(INSTALL) -m755 -d $(DESTDIR)/include/webp \ - $(DESTDIR)/include/webp/sharpyuv \ - $(DESTDIR)/bin $(DESTDIR)/doc $(DESTDIR)/lib - $(INSTALL) -m755 -s $(OUT_EXAMPLES) $(DESTDIR)/bin - $(INSTALL) -m644 $(HDRS_INSTALLED) $(DESTDIR)/include/webp - $(INSTALL) -m644 $(SHARPYUV_HDRS_INSTALLED) $(DESTDIR)/include/webp/sharpyuv - $(INSTALL) -m644 src/libwebp.a $(DESTDIR)/lib - $(INSTALL) -m644 src/demux/libwebpdemux.a $(DESTDIR)/lib - $(INSTALL) -m644 src/mux/libwebpmux.a $(DESTDIR)/lib - $(INSTALL) -m644 sharpyuv/libsharpyuv.a $(DESTDIR)/lib - umask 022; \ - for m in man/[cdv]webp.1 man/gif2webp.1 man/webpmux.1 \ - man/img2webp.1 man/webpinfo.1; do \ - basenam=$$(basename $$m .1); \ - $(GROFF) -t -e -man -T ascii $$m \ - | $(COL) -bx >$(DESTDIR)/doc/$${basenam}.txt; \ - $(GROFF) -t -e -man -T html $$m \ - | $(COL) -bx >$(DESTDIR)/doc/$${basenam}.html; \ - done - -clean: - $(RM) $(OUTPUT) *~ \ - examples/*.o examples/*~ \ - extras/*.o extras/*~ \ - imageio/*.o imageio/*~ \ - sharpyuv/*.o sharpyuv/*~ \ - src/dec/*.o src/dec/*~ \ - src/demux/*.o src/demux/*~ \ - src/dsp/*.o src/dsp/*~ \ - src/enc/*.o src/enc/*~ \ - src/mux/*.o src/mux/*~ \ - src/utils/*.o src/utils/*~ \ - src/webp/*~ man/*~ doc/*~ swig/*~ \ - -.PHONY: all clean dist ex -.SUFFIXES: diff --git a/libwebp/man/Makefile.am b/libwebp/man/Makefile.am deleted file mode 100644 index 57e2483f..00000000 --- a/libwebp/man/Makefile.am +++ /dev/null @@ -1,17 +0,0 @@ -man_MANS = cwebp.1 dwebp.1 -if BUILD_MUX - man_MANS += webpmux.1 -endif -if BUILD_GIF2WEBP - man_MANS += gif2webp.1 -endif -if BUILD_IMG2WEBP - man_MANS += img2webp.1 -endif -if BUILD_VWEBP - man_MANS += vwebp.1 -endif -if BUILD_WEBPINFO - man_MANS += webpinfo.1 -endif -EXTRA_DIST = $(man_MANS) diff --git a/libwebp/man/cwebp.1 b/libwebp/man/cwebp.1 deleted file mode 100644 index 28de4c94..00000000 --- a/libwebp/man/cwebp.1 +++ /dev/null @@ -1,328 +0,0 @@ -.\" Hey, EMACS: -*- nroff -*- -.TH CWEBP 1 "March 17, 2022" -.SH NAME -cwebp \- compress an image file to a WebP file -.SH SYNOPSIS -.B cwebp -.RI [ options ] " input_file \-o output_file.webp -.br -.SH DESCRIPTION -This manual page documents the -.B cwebp -command. -.PP -\fBcwebp\fP compresses an image using the WebP format. -Input format can be either PNG, JPEG, TIFF, WebP or raw Y'CbCr samples. -Note: Animated PNG and WebP files are not supported. -.SH OPTIONS -The basic options are: -.TP -.BI \-o " string -Specify the name of the output WebP file. If omitted, \fBcwebp\fP will -perform compression but only report statistics. -Using "\-" as output name will direct output to 'stdout'. -.TP -.BI \-\- " string -Explicitly specify the input file. This option is useful if the input -file starts with a '\-' for instance. This option must appear \fBlast\fP. -Any other options afterward will be ignored. -.TP -.B \-h, \-help -A short usage summary. -.TP -.B \-H, \-longhelp -A summary of all the possible options. -.TP -.B \-version -Print the version number (as major.minor.revision) and exit. -.TP -.B \-lossless -Encode the image without any loss. For images with fully transparent area, -the invisible pixel values (R/G/B or Y/U/V) will be preserved only if the -\-exact option is used. -.TP -.BI \-near_lossless " int -Specify the level of near\-lossless image preprocessing. This option adjusts -pixel values to help compressibility, but has minimal impact on the visual -quality. It triggers lossless compression mode automatically. The range is 0 -(maximum preprocessing) to 100 (no preprocessing, the default). The typical -value is around 60. Note that lossy with \fB\-q 100\fP can at times yield -better results. -.TP -.BI \-q " float -Specify the compression factor for RGB channels between 0 and 100. The default -is 75. -.br -In case of lossy compression (default), a small factor produces a smaller file -with lower quality. Best quality is achieved by using a value of 100. -.br -In case of lossless compression (specified by the \fB\-lossless\fP option), a -small factor enables faster compression speed, but produces a larger file. -Maximum compression is achieved by using a value of 100. -.TP -.BI \-z " int -Switch on \fBlossless\fP compression mode with the specified level between 0 -and 9, with level 0 being the fastest, 9 being the slowest. Fast mode -produces larger file size than slower ones. A good default is \fB\-z 6\fP. -This option is actually a shortcut for some predefined settings for quality -and method. If options \fB\-q\fP or \fB\-m\fP are subsequently used, they will -invalidate the effect of this option. -.TP -.BI \-alpha_q " int -Specify the compression factor for alpha compression between 0 and 100. -Lossless compression of alpha is achieved using a value of 100, while the lower -values result in a lossy compression. The default is 100. -.TP -.BI \-preset " string -Specify a set of pre\-defined parameters to suit a particular type of -source material. Possible values are: \fBdefault\fP, \fBphoto\fP, -\fBpicture\fP, \fBdrawing\fP, \fBicon\fP, \fBtext\fP. Since -\fB\-preset\fP overwrites the other parameters' values (except the -\fB\-q\fP one), this option should preferably appear first in the -order of the arguments. -.TP -.BI \-m " int -Specify the compression method to use. This parameter controls the -trade off between encoding speed and the compressed file size and quality. -Possible values range from 0 to 6. Default value is 4. -When higher values are used, the encoder will spend more time inspecting -additional encoding possibilities and decide on the quality gain. -Lower value can result in faster processing time at the expense of -larger file size and lower compression quality. -.TP -.BI \-crop " x_position y_position width height -Crop the source to a rectangle with top\-left corner at coordinates -(\fBx_position\fP, \fBy_position\fP) and size \fBwidth\fP x \fBheight\fP. -This cropping area must be fully contained within the source rectangle. -Note: the cropping is applied \fIbefore\fP any scaling. -.TP -.BI \-resize " width height -Resize the source to a rectangle with size \fBwidth\fP x \fBheight\fP. -If either (but not both) of the \fBwidth\fP or \fBheight\fP parameters is 0, -the value will be calculated preserving the aspect\-ratio. Note: scaling -is applied \fIafter\fP cropping. -.TP -.B \-mt -Use multi\-threading for encoding, if possible. -.TP -.B \-low_memory -Reduce memory usage of lossy encoding by saving four times the compressed -size (typically). This will make the encoding slower and the output slightly -different in size and distortion. This flag is only effective for methods -3 and up, and is off by default. Note that leaving this flag off will have -some side effects on the bitstream: it forces certain bitstream features -like number of partitions (forced to 1). Note that a more detailed report -of bitstream size is printed by \fBcwebp\fP when using this option. - -.SS LOSSY OPTIONS -These options are only effective when doing lossy encoding (the default, with -or without alpha). - -.TP -.BI \-size " int -Specify a target size (in bytes) to try and reach for the compressed output. -The compressor will make several passes of partial encoding in order to get as -close as possible to this target. If both \fB\-size\fP and \fB\-psnr\fP -are used, \fB\-size\fP value will prevail. -.TP -.BI \-psnr " float -Specify a target PSNR (in dB) to try and reach for the compressed output. -The compressor will make several passes of partial encoding in order to get as -close as possible to this target. If both \fB\-size\fP and \fB\-psnr\fP -are used, \fB\-size\fP value will prevail. -.TP -.BI \-pass " int -Set a maximum number of passes to use during the dichotomy used by -options \fB\-size\fP or \fB\-psnr\fP. Maximum value is 10, default is 1. -If options \fB\-size\fP or \fB\-psnr\fP were used, but \fB\-pass\fP wasn't -specified, a default value of '6' passes will be used. -.TP -.BI \-qrange " int int -Specifies the permissible interval for the quality factor. This is particularly -useful when using multi-pass (\fB\-size\fP or \fB\-psnr\fP options). -Default is 0 100. -If the quality factor is outside this range, it will be clamped. -If the minimum value must be less or equal to the maximum one. -.TP -.B \-af -Turns auto\-filter on. This algorithm will spend additional time optimizing -the filtering strength to reach a well\-balanced quality. -.TP -.B \-jpeg_like -Change the internal parameter mapping to better match the expected size -of JPEG compression. This flag will generally produce an output file of -similar size to its JPEG equivalent (for the same \fB\-q\fP setting), but -with less visual distortion. - -.TP -Advanced options: - -.TP -.BI \-f " int -Specify the strength of the deblocking filter, between 0 (no filtering) -and 100 (maximum filtering). A value of 0 will turn off any filtering. -Higher value will increase the strength of the filtering process applied -after decoding the picture. The higher the value the smoother the picture will -appear. Typical values are usually in the range of 20 to 50. -.TP -.BI \-sharpness " int -Specify the sharpness of the filtering (if used). -Range is 0 (sharpest) to 7 (least sharp). Default is 0. -.TP -.B \-strong -Use strong filtering (if filtering is being used thanks to the -\fB\-f\fP option). Strong filtering is on by default. -.TP -.B \-nostrong -Disable strong filtering (if filtering is being used thanks to the -\fB\-f\fP option) and use simple filtering instead. -.TP -.B \-sharp_yuv -Use more accurate and sharper RGB->YUV conversion if needed. Note that this -process is slower than the default 'fast' RGB->YUV conversion. -.TP -.BI \-sns " int -Specify the amplitude of the spatial noise shaping. Spatial noise shaping -(or \fBsns\fP for short) refers to a general collection of built\-in algorithms -used to decide which area of the picture should use relatively less bits, -and where else to better transfer these bits. The possible range goes from -0 (algorithm is off) to 100 (the maximal effect). The default value is 50. -.TP -.BI \-segments " int -Change the number of partitions to use during the segmentation of the -sns algorithm. Segments should be in range 1 to 4. Default value is 4. -This option has no effect for methods 3 and up, unless \fB\-low_memory\fP -is used. -.TP -.BI \-partition_limit " int -Degrade quality by limiting the number of bits used by some macroblocks. -Range is 0 (no degradation, the default) to 100 (full degradation). -Useful values are usually around 30\-70 for moderately large images. -In the VP8 format, the so\-called control partition has a limit of 512k and -is used to store the following information: whether the macroblock is skipped, -which segment it belongs to, whether it is coded as intra 4x4 or intra 16x16 -mode, and finally the prediction modes to use for each of the sub\-blocks. -For a very large image, 512k only leaves room to few bits per 16x16 macroblock. -The absolute minimum is 4 bits per macroblock. Skip, segment, and mode -information can use up almost all these 4 bits (although the case is unlikely), -which is problematic for very large images. The partition_limit factor controls -how frequently the most bit\-costly mode (intra 4x4) will be used. This is -useful in case the 512k limit is reached and the following message is displayed: -\fIError code: 6 (PARTITION0_OVERFLOW: Partition #0 is too big to fit 512k)\fP. -If using \fB\-partition_limit\fP is not enough to meet the 512k constraint, one -should use less segments in order to save more header bits per macroblock. -See the \fB\-segments\fP option. - -.SS LOGGING OPTIONS -These options control the level of output: -.TP -.B \-v -Print extra information (encoding time in particular). -.TP -.B \-print_psnr -Compute and report average PSNR (Peak\-Signal\-To\-Noise ratio). -.TP -.B \-print_ssim -Compute and report average SSIM (structural similarity -metric, see https://en.wikipedia.org/wiki/SSIM for additional details). -.TP -.B \-print_lsim -Compute and report local similarity metric (sum of lowest error amongst the -collocated pixel neighbors). -.TP -.B \-progress -Report encoding progress in percent. -.TP -.B \-quiet -Do not print anything. -.TP -.B \-short -Only print brief information (output file size and PSNR) for testing purposes. -.TP -.BI \-map " int -Output additional ASCII\-map of encoding information. Possible map values -range from 1 to 6. This is only meant to help debugging. - -.SS ADDITIONAL OPTIONS -More advanced options are: -.TP -.BI \-s " width height -Specify that the input file actually consists of raw Y'CbCr samples following -the ITU\-R BT.601 recommendation, in 4:2:0 linear format. -The luma plane has size \fBwidth\fP x \fBheight\fP. -.TP -.BI \-pre " int -Specify some preprocessing steps. Using a value of '2' will trigger -quality\-dependent pseudo\-random dithering during RGBA\->YUVA conversion -(lossy compression only). -.TP -.BI \-alpha_filter " string -Specify the predictive filtering method for the alpha plane. One of 'none', -\&'fast' or 'best', in increasing complexity and slowness order. Default is -\&'fast'. Internally, alpha filtering is performed using four possible -predictions (none, horizontal, vertical, gradient). The 'best' mode will try -each mode in turn and pick the one which gives the smaller size. The 'fast' -mode will just try to form an a priori guess without testing all modes. -.TP -.BI \-alpha_method " int -Specify the algorithm used for alpha compression: 0 or 1. Algorithm 0 denotes -no compression, 1 uses WebP lossless format for compression. The default is 1. -.TP -.B \-exact -Preserve RGB values in transparent area. The default is off, to help -compressibility. -.TP -.BI \-blend_alpha " int -This option blends the alpha channel (if present) with the source using the -background color specified in hexadecimal as 0xrrggbb. The alpha channel is -afterward reset to the opaque value 255. -.TP -.B \-noalpha -Using this option will discard the alpha channel. -.TP -.BI \-hint " string -Specify the hint about input image type. Possible values are: -\fBphoto\fP, \fBpicture\fP or \fBgraph\fP. -.TP -.BI \-metadata " string -A comma separated list of metadata to copy from the input to the output if -present. -Valid values: \fBall\fP, \fBnone\fP, \fBexif\fP, \fBicc\fP, \fBxmp\fP. -The default is \fBnone\fP. - -Note: each input format may not support all combinations. -.TP -.B \-noasm -Disable all assembly optimizations. - -.SH BUGS -Please report all bugs to the issue tracker: -https://bugs.chromium.org/p/webp -.br -Patches welcome! See this page to get started: -https://www.webmproject.org/code/contribute/submitting\-patches/ - -.SH EXAMPLES -cwebp \-q 50 -lossless picture.png \-o picture_lossless.webp -.br -cwebp \-q 70 picture_with_alpha.png \-o picture_with_alpha.webp -.br -cwebp \-sns 70 \-f 50 \-size 60000 picture.png \-o picture.webp -.br -cwebp \-o picture.webp \-\- \-\-\-picture.png - -.SH AUTHORS -\fBcwebp\fP is a part of libwebp and was written by the WebP team. -.br -The latest source tree is available at -https://chromium.googlesource.com/webm/libwebp -.PP -This manual page was written by Pascal Massimino , -for the Debian project (and may be used by others). - -.SH SEE ALSO -.BR dwebp (1), -.BR gif2webp (1) -.br -Please refer to https://developers.google.com/speed/webp/ for additional -information. diff --git a/libwebp/man/dwebp.1 b/libwebp/man/dwebp.1 deleted file mode 100644 index e718aba7..00000000 --- a/libwebp/man/dwebp.1 +++ /dev/null @@ -1,150 +0,0 @@ -.\" Hey, EMACS: -*- nroff -*- -.TH DWEBP 1 "November 17, 2021" -.SH NAME -dwebp \- decompress a WebP file to an image file -.SH SYNOPSIS -.B dwebp -.RI [ options ] " input_file.webp -.br -.SH DESCRIPTION -This manual page documents the -.B dwebp -command. -.PP -\fBdwebp\fP decompresses WebP files into PNG, PAM, PPM or PGM images. -Note: Animated WebP files are not supported. -.SH OPTIONS -The basic options are: -.TP -.B \-h -Print usage summary. -.TP -.B \-version -Print the version number (as major.minor.revision) and exit. -.TP -.BI \-o " string -Specify the name of the output file (as PNG format by default). -Using "-" as output name will direct output to 'stdout'. -.TP -.BI \-\- " string -Explicitly specify the input file. This option is useful if the input -file starts with an '\-' for instance. This option must appear \fBlast\fP. -Any other options afterward will be ignored. If the input file is "\-", -the data will be read from \fIstdin\fP instead of a file. -.TP -.B \-bmp -Change the output format to uncompressed BMP. -.TP -.B \-tiff -Change the output format to uncompressed TIFF. -.TP -.B \-pam -Change the output format to PAM (retains alpha). -.TP -.B \-ppm -Change the output format to PPM (discards alpha). -.TP -.B \-pgm -Change the output format to PGM. The output consists of luma/chroma -samples instead of RGB, using the IMC4 layout. This option is mainly -for verification and debugging purposes. -.TP -.B \-yuv -Change the output format to raw YUV. The output consists of -luma/chroma-U/chroma-V samples instead of RGB, saved sequentially as -individual planes. This option is mainly for verification and debugging -purposes. -.TP -.B \-nofancy -Don't use the fancy upscaler for YUV420. This may lead to jaggy -edges (especially the red ones), but should be faster. -.TP -.B \-nofilter -Don't use the in-loop filtering process even if it is required by -the bitstream. This may produce visible blocks on the non-compliant output, -but it will make the decoding faster. -.TP -.BI \-dither " strength -Specify a dithering \fBstrength\fP between 0 and 100. Dithering is a -post-processing effect applied to chroma components in lossy compression. -It helps by smoothing gradients and avoiding banding artifacts. -.TP -.BI \-alpha_dither -If the compressed file contains a transparency plane that was quantized -during compression, this flag will allow dithering the reconstructed plane -in order to generate smoother transparency gradients. -.TP -.B \-nodither -Disable all dithering (default). -.TP -.B \-mt -Use multi-threading for decoding, if possible. -.TP -.BI \-crop " x_position y_position width height -Crop the decoded picture to a rectangle with top-left corner at coordinates -(\fBx_position\fP, \fBy_position\fP) and size \fBwidth\fP x \fBheight\fP. -This cropping area must be fully contained within the source rectangle. -The top-left corner will be snapped to even coordinates if needed. -This option is meant to reduce the memory needed for cropping large images. -Note: the cropping is applied \fIbefore\fP any scaling. -.TP -.B \-flip -Flip decoded image vertically (can be useful for OpenGL textures for instance). -.TP -\fB\-resize\fR, \fB\-scale\fI width height\fR -Rescale the decoded picture to dimension \fBwidth\fP x \fBheight\fP. This -option is mostly intended to reducing the memory needed to decode large images, -when only a small version is needed (thumbnail, preview, etc.). Note: scaling -is applied \fIafter\fP cropping. -If either (but not both) of the \fBwidth\fP or \fBheight\fP parameters is 0, -the value will be calculated preserving the aspect-ratio. -.TP -.B \-quiet -Do not print anything. -.TP -.B \-v -Print extra information (decoding time in particular). -.TP -.B \-noasm -Disable all assembly optimizations. - -.SH BUGS -Please report all bugs to the issue tracker: -https://bugs.chromium.org/p/webp -.br -Patches welcome! See this page to get started: -https://www.webmproject.org/code/contribute/submitting\-patches/ - -.SH EXAMPLES -dwebp picture.webp \-o output.png -.br -dwebp picture.webp \-ppm \-o output.ppm -.br -dwebp \-o output.ppm \-\- \-\-\-picture.webp -.br -cat picture.webp | dwebp \-o \- \-\- \- > output.ppm - -.SH AUTHORS -\fBdwebp\fP is a part of libwebp and was written by the WebP team. -.br -The latest source tree is available at -https://chromium.googlesource.com/webm/libwebp -.PP -This manual page was written by Pascal Massimino , -for the Debian project (and may be used by others). - -.SH SEE ALSO -.BR cwebp (1), -.BR gif2webp (1), -.BR webpmux (1) -.br -Please refer to https://developers.google.com/speed/webp/ for additional -information. -.SS Output file format details -PAM: http://netpbm.sourceforge.net/doc/pam.html -.br -PGM: http://netpbm.sourceforge.net/doc/pgm.html -.br -PPM: http://netpbm.sourceforge.net/doc/ppm.html -.br -PNG: http://www.libpng.org/pub/png/png-sitemap.html#info diff --git a/libwebp/man/gif2webp.1 b/libwebp/man/gif2webp.1 deleted file mode 100644 index 3bf43bcc..00000000 --- a/libwebp/man/gif2webp.1 +++ /dev/null @@ -1,164 +0,0 @@ -.\" Hey, EMACS: -*- nroff -*- -.TH GIF2WEBP 1 "November 17, 2021" -.SH NAME -gif2webp \- Convert a GIF image to WebP -.SH SYNOPSIS -.B gif2webp -.RI [ options ] " input_file.gif \-o output_file.webp -.br -.SH DESCRIPTION -This manual page documents the -.B gif2webp -command. -.PP -\fBgif2webp\fP converts a GIF image to a WebP image. -.SH OPTIONS -The basic options are: -.TP -.BI \-o " string -Specify the name of the output WebP file. If omitted, \fBgif2webp\fP will -perform conversion but only report statistics. -Using "\-" as output name will direct output to 'stdout'. -.TP -.BI \-\- " string -Explicitly specify the input file. This option is useful if the input -file starts with an '\-' for instance. This option must appear \fBlast\fP. -Any other options afterward will be ignored. If the input file is "\-", -the data will be read from \fIstdin\fP instead of a file. -.TP -.B \-h, \-help -Usage information. -.TP -.B \-version -Print the version number (as major.minor.revision) and exit. -.TP -.B \-lossy -Encode the image using lossy compression. -.TP -.B \-mixed -Mixed compression mode: optimize compression of the image by picking either -lossy or lossless compression for each frame heuristically. -.TP -.BI \-q " float -Specify the compression factor for RGB channels between 0 and 100. The default -is 75. -.br -In case of lossless compression (default), a small factor enables faster -compression speed, but produces a larger file. Maximum compression is achieved -by using a value of 100. -.br -In case of lossy compression (specified by the \-lossy option), a small factor -produces a smaller file with lower quality. Best quality is achieved by using a -value of 100. -.TP -.BI \-m " int -Specify the compression method to use. This parameter controls the -trade off between encoding speed and the compressed file size and quality. -Possible values range from 0 to 6. Default value is 4. -When higher values are used, the encoder will spend more time inspecting -additional encoding possibilities and decide on the quality gain. -Lower value can result is faster processing time at the expense of -larger file size and lower compression quality. -.TP -.BI \-min_size -Encode image to achieve smallest size. This disables key frame insertion and -picks the dispose method resulting in the smallest output for each frame. It -uses lossless compression by default, but can be combined with \-q, \-m, -\-lossy or \-mixed options. -.TP -.BI \-kmin " int -.TP -.BI \-kmax " int -Specify the minimum and maximum distance between consecutive key frames -(independently decodable frames) in the output animation. The tool will insert -some key frames into the output animation as needed so that this criteria is -satisfied. -.br -A 'kmax' value of 0 will turn off insertion of key frames. A 'kmax' value of 1 -will result in all frames being key frames. 'kmin' value is not taken into -account in both these special cases. -Typical values are in the range 3 to 30. Default values are kmin = 9, -kmax = 17 for lossless compression and kmin = 3, kmax = 5 for lossy compression. -.br -These two options are relevant only for animated images with large number of -frames (>50). -.br -When lower values are used, more frames will be converted to key frames. This -may lead to smaller number of frames required to decode a frame on average, -thereby improving the decoding performance. But this may lead to slightly bigger -file sizes. -Higher values may lead to worse decoding performance, but smaller file sizes. -.br -Some restrictions: -.br -(i) kmin < kmax, -.br -(ii) kmin >= kmax / 2 + 1 and -.br -(iii) kmax - kmin <= 30. -.br -If any of these restrictions are not met, they will be enforced automatically. -.TP -.BI \-metadata " string -A comma separated list of metadata to copy from the input to the output if -present. -Valid values: \fBall\fP, \fBnone\fP, \fBicc\fP, \fBxmp\fP. -The default is \fBxmp\fP. -.TP -.BI \-f " int -For lossy encoding only (specified by the \-lossy option). Specify the strength -of the deblocking filter, between 0 (no filtering) and 100 (maximum filtering). -A value of 0 will turn off any filtering. Higher value will increase the -strength of the filtering process applied after decoding the picture. The higher -the value the smoother the picture will appear. Typical values are usually in -the range of 20 to 50. -.TP -.B \-mt -Use multi-threading for encoding, if possible. -.TP -.B \-loop_compatibility -If enabled, handle the loop information in a compatible fashion for Chrome -version prior to M62 (inclusive) and Firefox. -.TP -.B \-v -Print extra information. -.TP -.B \-quiet -Do not print anything. - -.SH BUGS -Please report all bugs to the issue tracker: -https://bugs.chromium.org/p/webp -.br -Patches welcome! See this page to get started: -https://www.webmproject.org/code/contribute/submitting\-patches/ - -.SH EXAMPLES -gif2webp picture.gif \-o picture.webp -.br -gif2webp \-q 70 picture.gif \-o picture.webp -.br -gif2webp \-lossy \-m 3 picture.gif \-o picture_lossy.webp -.br -gif2webp \-lossy \-f 50 picture.gif \-o picture.webp -.br -gif2webp \-q 70 \-o picture.webp \-\- \-\-\-picture.gif -.br -cat picture.gif | gif2webp \-o \- \-\- \- > output.webp - -.SH AUTHORS -\fBgif2webp\fP is a part of libwebp and was written by the WebP team. -.br -The latest source tree is available at -https://chromium.googlesource.com/webm/libwebp -.PP -This manual page was written by Urvang Joshi , for the -Debian project (and may be used by others). - -.SH SEE ALSO -.BR cwebp (1), -.BR dwebp (1), -.BR webpmux (1) -.br -Please refer to https://developers.google.com/speed/webp/ for additional -information. diff --git a/libwebp/man/img2webp.1 b/libwebp/man/img2webp.1 deleted file mode 100644 index fc493e12..00000000 --- a/libwebp/man/img2webp.1 +++ /dev/null @@ -1,117 +0,0 @@ -.\" Hey, EMACS: -*- nroff -*- -.TH IMG2WEBP 1 "March 17, 2023" -.SH NAME -img2webp \- create animated WebP file from a sequence of input images. -.SH SYNOPSIS -.B img2webp -[file_options] [[frame_options] frame_file]... [\-o webp_file] -.br -.B img2webp argument_file_name -.br -.SH DESCRIPTION -This manual page documents the -.B img2webp -command. -.PP -\fBimg2webp\fP compresses a sequence of images using the animated WebP format. -Input images can either be PNG, JPEG, TIFF or WebP. -If a single file name (not starting with the character '\-') is supplied as -the argument, the command line arguments are actually tokenized from this file. -This allows for easy scripting or using a large number of arguments. -.SH FILE-LEVEL OPTIONS -The file-level options are applied at the beginning of the compression process, -before the input frames are read. -.TP -.BI \-o " string -Specify the name of the output WebP file. -.TP -.BI \-min_size -Encode images to achieve smallest size. This disables key frame insertion and -picks the parameters resulting in the smallest output for each frame. It uses -lossless compression by default, but can be combined with \-q, \-m, \-lossy or -\-mixed options. -.TP -.BI \-kmin " int -.TP -.BI \-kmax " int -Specify the minimum and maximum distance between consecutive key frames -(independently decodable frames) in the output animation. The tool will insert -some key frames into the output animation as needed so that this criteria is -satisfied. -.br -.B \-mixed -Mixed compression mode: optimize compression of the image by picking either -lossy or lossless compression for each frame heuristically. This global -option disables the local option \fB-lossy\fP and \fB-lossless\fP . -.TP -.BI \-near_lossless " int -Specify the level of near\-lossless image preprocessing. This option adjusts -pixel values to help compressibility, but has minimal impact on the visual -quality. It triggers lossless compression mode automatically. The range is 0 -(maximum preprocessing) to 100 (no preprocessing, the default). The typical -value is around 60. Note that lossy with \fB\-q 100\fP can at times yield -better results. -.TP -.B \-sharp_yuv -Use more accurate and sharper RGB->YUV conversion if needed. Note that this -process is slower than the default 'fast' RGB->YUV conversion. -.TP -.BI \-loop " int -Specifies the number of times the animation should loop. Using '0' -means 'loop indefinitely'. -.TP -.BI \-v -Be more verbose. -.TP -.B \-h, \-help -A short usage summary. -.TP -.B \-version -Print the version numbers of the relevant libraries used. - -.SH PER-FRAME OPTIONS -The per-frame options are applied for the images following as arguments in the -command line. They can be modified any number of times preceding each particular -input image. -.TP -.BI \-d " int -Specify the image duration in milliseconds. -.TP -.B \-lossless, \-lossy -Compress the next image(s) using lossless or lossy compression mode. The -default mode is lossless. -.TP -.BI \-q " float -Specify the compression factor between 0 and 100. The default is 75. -.TP -.BI \-m " int -Specify the compression method to use. This parameter controls the -trade off between encoding speed and the compressed file size and quality. -Possible values range from 0 to 6. Default value is 4. - -.SH EXAMPLE -img2webp -loop 2 in0.png -lossy in1.jpg -d 80 in2.tiff -o out.webp -.br - -.SH BUGS -Please report all bugs to the issue tracker: -https://bugs.chromium.org/p/webp -.br -Patches welcome! See this page to get started: -https://www.webmproject.org/code/contribute/submitting\-patches/ - -.SH AUTHORS -\fBimg2webp\fP is a part of libwebp and was written by the WebP team. -.br -The latest source tree is available at -https://chromium.googlesource.com/webm/libwebp -.PP -This manual page was written by Pascal Massimino , -for the Debian project (and may be used by others). - -.SH SEE ALSO -.BR webpmux (1), -.BR gif2webp (1) -.br -Please refer to https://developers.google.com/speed/webp/ for additional -information. diff --git a/libwebp/man/vwebp.1 b/libwebp/man/vwebp.1 deleted file mode 100644 index fa48db6d..00000000 --- a/libwebp/man/vwebp.1 +++ /dev/null @@ -1,101 +0,0 @@ -.\" Hey, EMACS: -*- nroff -*- -.TH VWEBP 1 "November 17, 2021" -.SH NAME -vwebp \- decompress a WebP file and display it in a window -.SH SYNOPSIS -.B vwebp -.RI [ options ] " input_file.webp -.br -.SH DESCRIPTION -This manual page documents the -.B vwebp -command. -.PP -\fBvwebp\fP decompresses a WebP file and displays it in a window using OpenGL. -.SH OPTIONS -.TP -.B \-h -Print usage summary. -.TP -.B \-version -Print version number and exit. -.TP -.B \-noicc -Don't use the ICC profile if present. -.TP -.B \-nofancy -Don't use the fancy YUV420 upscaler. -.TP -.B \-nofilter -Disable in-loop filtering. -.TP -.BI \-dither " strength -Specify a dithering \fBstrength\fP between 0 and 100. Dithering is a -post-processing effect applied to chroma components in lossy compression. -It helps by smoothing gradients and avoiding banding artifacts. Default: 50. -.TP -.BI \-noalphadither -By default, quantized transparency planes are dithered during decompression, -to smooth the gradients. This flag will prevent this dithering. -.TP -.B \-usebgcolor -Fill transparent areas with the bitstream's own background color instead of -checkerboard only. Default is white for non-animated images. -.TP -.B \-mt -Use multi-threading for decoding, if possible. -.TP -.B \-info -Display image information on top of the decoded image. -.TP -.BI \-\- " string -Explicitly specify the input file. This option is useful if the input -file starts with an '\-' for instance. This option must appear \fBlast\fP. -Any other options afterward will be ignored. If the input file is "\-", -the data will be read from \fIstdin\fP instead of a file. -.TP - -.SH KEYBOARD SHORTCUTS -.TP -.B 'c' -Toggle use of color profile. -.TP -.B 'b' -Toggle display of background color. -.TP -.B 'i' -Overlay file information. -.TP -.B 'd' -Disable blending and disposal process, for debugging purposes. -.TP -.B 'q' / 'Q' / ESC -Quit. - -.SH BUGS -Please report all bugs to the issue tracker: -https://bugs.chromium.org/p/webp -.br -Patches welcome! See this page to get started: -https://www.webmproject.org/code/contribute/submitting\-patches/ - -.SH EXAMPLES -vwebp picture.webp -.br -vwebp picture.webp -mt -dither 0 -.br -vwebp \-\- \-\-\-picture.webp - -.SH AUTHORS -\fBvwebp\fP is a part of libwebp and was written by the WebP team. -.br -The latest source tree is available at -https://chromium.googlesource.com/webm/libwebp -.PP -This manual page was written for the Debian project (and may be used by others). - -.SH SEE ALSO -.BR dwebp (1) -.br -Please refer to https://developers.google.com/speed/webp/ for additional -information. diff --git a/libwebp/man/webpinfo.1 b/libwebp/man/webpinfo.1 deleted file mode 100644 index 35d6d92f..00000000 --- a/libwebp/man/webpinfo.1 +++ /dev/null @@ -1,80 +0,0 @@ -.\" Hey, EMACS: -*- nroff -*- -.TH WEBPINFO 1 "November 17, 2021" -.SH NAME -webpinfo \- print out the chunk level structure of WebP files -along with basic integrity checks. -.SH SYNOPSIS -.B webpinfo -.I OPTIONS -.I INPUT -.br -.B webpinfo [\-h|\-help|\-H|\-longhelp] -.br - -.SH DESCRIPTION -This manual page documents the -.B webpinfo -command. -.PP -\fBwebpinfo\fP can be used to print out the chunk level structure and bitstream -header information of WebP files. It can also check if the files are of valid -WebP format. - -.SH OPTIONS -.TP -.B \-version -Print the version number (as major.minor.revision) and exit. -.TP -.B \-quiet -Do not show chunk parsing information. -.TP -.B \-diag -Show parsing error diagnosis. -.TP -.B \-summary -Show chunk stats summary. -.TP -.BI \-bitstream_info -Parse bitstream header. -.TP -.B \-h, \-help -A short usage summary. -.TP -.B \-H, \-longhelp -Detailed usage instructions. - -.SH INPUT -Input files in WebP format. Input files must come last, following -options (if any). There can be multiple input files. - -.SH BUGS -Please report all bugs to the issue tracker: -https://bugs.chromium.org/p/webp -.br -Patches welcome! See this page to get started: -https://www.webmproject.org/code/contribute/submitting\-patches/ - -.SH EXAMPLES -.br -webpinfo \-h -.br -webpinfo \-diag \-summary input_file.webp -.br -webpinfo \-bitstream_info input_file_1.webp input_file_2.webp -.br -webpinfo *.webp - -.SH AUTHORS -\fBwebpinfo\fP is a part of libwebp and was written by the WebP team. -.br -The latest source tree is available at -https://chromium.googlesource.com/webm/libwebp -.PP -This manual page was written by Hui Su , -for the Debian project (and may be used by others). - -.SH SEE ALSO -.BR webpmux (1) -.br -Please refer to https://developers.google.com/speed/webp/ for additional -information. diff --git a/libwebp/man/webpmux.1 b/libwebp/man/webpmux.1 deleted file mode 100644 index 07e87389..00000000 --- a/libwebp/man/webpmux.1 +++ /dev/null @@ -1,271 +0,0 @@ -.\" Hey, EMACS: -*- nroff -*- -.TH WEBPMUX 1 "November 17, 2021" -.SH NAME -webpmux \- create animated WebP files from non\-animated WebP images, extract -frames from animated WebP images, and manage XMP/EXIF metadata and ICC profile. -.SH SYNOPSIS -.B webpmux \-get -.I GET_OPTIONS -.I INPUT -.B \-o -.I OUTPUT -.br -.B webpmux \-set -.I SET_OPTIONS -.I INPUT -.B \-o -.I OUTPUT -.br -.B webpmux \-strip -.I STRIP_OPTIONS -.I INPUT -.B \-o -.I OUTPUT -.br -.B webpmux \-frame -.I FRAME_OPTIONS -.B [ \-frame ... ] [ \-loop -.I LOOP_COUNT -.B ] -.br -.RS 8 -.B [ \-bgcolor -.I BACKGROUND_COLOR -.B ] \-o -.I OUTPUT -.RE -.br -.B webpmux \-duration -.I DURATION OPTIONS -.B [ \-duration ... ] -.I INPUT -.B \-o -.I OUTPUT -.br -.B webpmux \-info -.I INPUT -.br -.B webpmux [\-h|\-help] -.br -.B webpmux \-version -.br -.B webpmux argument_file_name -.SH DESCRIPTION -This manual page documents the -.B webpmux -command. -.PP -\fBwebpmux\fP can be used to create/extract from animated WebP files, as well as -to add/extract/strip XMP/EXIF metadata and ICC profile. -If a single file name (not starting with the character '\-') is supplied as -the argument, the command line arguments are actually tokenized from this file. -This allows for easy scripting or using a large number of arguments. -.SH OPTIONS -.SS GET_OPTIONS (\-get): -.TP -.B icc -Get ICC profile. -.TP -.B exif -Get EXIF metadata. -.TP -.B xmp -Get XMP metadata. -.TP -.BI frame " n -Get nth frame from an animated image. (n = 0 has a special meaning: last frame). - -.SS SET_OPTIONS (\-set) -.TP -.BI loop " loop_count -Set loop count on an animated file. -.P -Where: 'loop_count' must be in range [0, 65535]. -.TP -.BI bgcolor " A,R,G,B -Set the background color of the canvas on an animated file. -.P -where: 'A', 'R', 'G' and 'B' are integers in the range 0 to 255 specifying the -Alpha, Red, Green and Blue component values respectively. -.TP -.BI icc " file.icc -Set ICC profile. -.P -Where: 'file.icc' contains the ICC profile to be set. -.TP -.BI exif " file.exif -Set EXIF metadata. -.P -Where: 'file.exif' contains the EXIF metadata to be set. -.TP -.BI xmp " file.xmp -Set XMP metadata. -.P -Where: 'file.xmp' contains the XMP metadata to be set. - -.SS STRIP_OPTIONS (\-strip) -.TP -.B icc -Strip ICC profile. -.TP -.B exif -Strip EXIF metadata. -.TP -.B xmp -Strip XMP metadata. - -.SS DURATION_OPTIONS (\-duration) -Amend the duration of a specific interval of frames. This option is only -effective on animated WebP and has no effect on a single-frame file. -.TP -.I duration[,start[,end]] -Where: -.br -.B duration -is the duration for the interval in milliseconds (mandatory). -Must be non-negative. -.br -.B start -is the starting frame index of the interval (optional). -.br -.B end -is the ending frame index (inclusive) of the interval (optional). -.TP -The three typical usages of this option are: -.br -.B -duration d - set the duration to 'd' for the whole animation. -.br -.B -duration d,f - set the duration of frame 'f' to 'd'. -.br -.B -duration d,start,end - set the duration to 'd' for the whole [start,end] interval. -.TP -.P -Note that the frames outside of the [start, end] interval will remain untouched. -The 'end' value '0' has the special meaning 'last frame of the animation'. -.TP -.I Reminder: -frame indexing starts at '1'. -.br - -.SS FRAME_OPTIONS (\-frame) -Create an animated WebP file from multiple (non\-animated) WebP images. -.TP -.I file_i +di[+xi+yi[+mi[bi]]] -Where: 'file_i' is the i'th frame (WebP format), 'xi','yi' specify the image -offset for this frame, 'di' is the pause duration before next frame, 'mi' is -the dispose method for this frame (0 for NONE or 1 for BACKGROUND) and 'bi' is -the blending method for this frame (+b for BLEND or \-b for NO_BLEND). -Argument 'bi' can be omitted and will default to +b (BLEND). -Also, 'mi' can be omitted if 'bi' is omitted and will default to 0 (NONE). -Finally, if 'mi' and 'bi' are omitted then 'xi' and 'yi' can be omitted and will -default to +0+0. -.TP -.BI \-loop " n -Loop the frames n number of times. 0 indicates the frames should loop forever. -Valid range is 0 to 65535 [Default: 0 (infinite)]. -.TP -.BI \-bgcolor " A,R,G,B -Background color of the canvas. -.br -where: 'A', 'R', 'G' and 'B' are integers in the range 0 to 255 specifying the -Alpha, Red, Green and Blue component values respectively -[Default: 255,255,255,255]. - -.SS INPUT -.TP -Input file in WebP format. - -.SS OUTPUT (\-o) -.TP -Output file in WebP format. - -.SS Note: -.TP -The nature of EXIF, XMP and ICC data is not checked and is assumed to be valid. - -.SH BUGS -Please report all bugs to the issue tracker: -https://bugs.chromium.org/p/webp -.br -Patches welcome! See this page to get started: -https://www.webmproject.org/code/contribute/submitting\-patches/ - -.SH EXAMPLES -.P -Add ICC profile: -.br -webpmux \-set icc image_profile.icc in.webp \-o icc_container.webp -.P -Extract ICC profile: -.br -webpmux \-get icc icc_container.webp \-o image_profile.icc -.P -Strip ICC profile: -.br -webpmux \-strip icc icc_container.webp \-o without_icc.webp -.P -Add XMP metadata: -.br -webpmux \-set xmp image_metadata.xmp in.webp \-o xmp_container.webp -.P -Extract XMP metadata: -.br -webpmux \-get xmp xmp_container.webp \-o image_metadata.xmp -.P -Strip XMP metadata: -.br -webpmux \-strip xmp xmp_container.webp \-o without_xmp.webp -.P -Add EXIF metadata: -.br -webpmux \-set exif image_metadata.exif in.webp \-o exif_container.webp -.P -Extract EXIF metadata: -.br -webpmux \-get exif exif_container.webp \-o image_metadata.exif -.P -Strip EXIF metadata: -.br -webpmux \-strip exif exif_container.webp \-o without_exif.webp -.P -Create an animated WebP file from 3 (non\-animated) WebP images: -.br -webpmux \-frame 1.webp +100 \-frame 2.webp +100+50+50 -.br -.RS 8 -\-frame 3.webp +100+50+50+1+b \-loop 10 \-bgcolor 255,255,255,255 -.br -\-o anim_container.webp -.RE -.P -Get the 2nd frame from an animated WebP file: -.br -webpmux \-get frame 2 anim_container.webp \-o frame_2.webp -.P -Using \-get/\-set/\-strip with input file name starting with '\-': -.br -webpmux \-set icc image_profile.icc \-o icc_container.webp \-\- \-\-\-in.webp -.br -webpmux \-get icc \-o image_profile.icc \-\- \-\-\-icc_container.webp -.br -webpmux \-strip icc \-o without_icc.webp \-\- \-\-\-icc_container.webp - -.SH AUTHORS -\fBwebpmux\fP is a part of libwebp and was written by the WebP team. -.br -The latest source tree is available at -https://chromium.googlesource.com/webm/libwebp -.PP -This manual page was written by Vikas Arora , -for the Debian project (and may be used by others). - -.SH SEE ALSO -.BR cwebp (1), -.BR dwebp (1), -.BR gif2webp (1) -.br -Please refer to https://developers.google.com/speed/webp/ for additional -information. diff --git a/libwebp/sharpyuv/Makefile.am b/libwebp/sharpyuv/Makefile.am deleted file mode 100644 index 8d9ba7ca..00000000 --- a/libwebp/sharpyuv/Makefile.am +++ /dev/null @@ -1,41 +0,0 @@ -AM_CPPFLAGS += -I$(top_builddir) -I$(top_srcdir) -AM_CPPFLAGS += -I$(top_builddir)/src -I$(top_srcdir)/src - -lib_LTLIBRARIES = libsharpyuv.la - -noinst_LTLIBRARIES = -noinst_LTLIBRARIES += libsharpyuv_sse2.la -noinst_LTLIBRARIES += libsharpyuv_neon.la - -libsharpyuvinclude_HEADERS = -libsharpyuvinclude_HEADERS += sharpyuv.h -libsharpyuvinclude_HEADERS += sharpyuv_csp.h -noinst_HEADERS = -noinst_HEADERS += ../src/dsp/cpu.c -noinst_HEADERS += ../src/dsp/cpu.h -noinst_HEADERS += ../src/webp/types.h - -libsharpyuv_sse2_la_SOURCES = -libsharpyuv_sse2_la_SOURCES += sharpyuv_sse2.c -libsharpyuv_sse2_la_CPPFLAGS = $(libsharpyuv_la_CPPFLAGS) -libsharpyuv_sse2_la_CFLAGS = $(AM_CFLAGS) $(SSE2_FLAGS) - -libsharpyuv_neon_la_SOURCES = -libsharpyuv_neon_la_SOURCES += sharpyuv_neon.c -libsharpyuv_neon_la_CPPFLAGS = $(libsharpyuv_la_CPPFLAGS) -libsharpyuv_neon_la_CFLAGS = $(AM_CFLAGS) $(NEON_FLAGS) - -libsharpyuv_la_SOURCES = -libsharpyuv_la_SOURCES += sharpyuv_cpu.c sharpyuv_cpu.h -libsharpyuv_la_SOURCES += sharpyuv_csp.c sharpyuv_csp.h -libsharpyuv_la_SOURCES += sharpyuv_dsp.c sharpyuv_dsp.h -libsharpyuv_la_SOURCES += sharpyuv_gamma.c sharpyuv_gamma.h -libsharpyuv_la_SOURCES += sharpyuv.c sharpyuv.h - -libsharpyuv_la_CPPFLAGS = $(AM_CPPFLAGS) -libsharpyuv_la_LDFLAGS = -no-undefined -version-info 0:1:0 -lm -libsharpyuv_la_LIBADD = -libsharpyuv_la_LIBADD += libsharpyuv_sse2.la -libsharpyuv_la_LIBADD += libsharpyuv_neon.la -libsharpyuvincludedir = $(includedir)/webp/sharpyuv -pkgconfig_DATA = libsharpyuv.pc diff --git a/libwebp/sharpyuv/libsharpyuv.pc.in b/libwebp/sharpyuv/libsharpyuv.pc.in deleted file mode 100644 index 0fb565a6..00000000 --- a/libwebp/sharpyuv/libsharpyuv.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@/webp - -Name: libsharpyuv -Description: Library for sharp RGB to YUV conversion -Version: @PACKAGE_VERSION@ -Cflags: -I${includedir} -Libs: -L${libdir} -l@webp_libname_prefix@sharpyuv -Libs.private: -lm @PTHREAD_CFLAGS@ @PTHREAD_LIBS@ diff --git a/libwebp/sharpyuv/libsharpyuv.rc b/libwebp/sharpyuv/libsharpyuv.rc deleted file mode 100644 index 49c338a3..00000000 --- a/libwebp/sharpyuv/libsharpyuv.rc +++ /dev/null @@ -1,41 +0,0 @@ -#define APSTUDIO_READONLY_SYMBOLS -#include "winres.h" -#undef APSTUDIO_READONLY_SYMBOLS - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US - -VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,0,2,1 - PRODUCTVERSION 0,0,2,1 - FILEFLAGSMASK 0x3fL -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x40004L - FILETYPE 0x2L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "CompanyName", "Google, Inc." - VALUE "FileDescription", "libsharpyuv DLL" - VALUE "FileVersion", "0.2.1" - VALUE "InternalName", "libsharpyuv.dll" - VALUE "LegalCopyright", "Copyright (C) 2023" - VALUE "OriginalFilename", "libsharpyuv.dll" - VALUE "ProductName", "SharpYuv Library" - VALUE "ProductVersion", "0.2.1" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - -#endif // English (United States) resources diff --git a/libwebp/sharpyuv/sharpyuv.c b/libwebp/sharpyuv/sharpyuv.c deleted file mode 100644 index 7cbf668f..00000000 --- a/libwebp/sharpyuv/sharpyuv.c +++ /dev/null @@ -1,574 +0,0 @@ -// Copyright 2022 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Sharp RGB to YUV conversion. -// -// Author: Skal (pascal.massimino@gmail.com) - -#include "sharpyuv/sharpyuv.h" - -#include -#include -#include -#include -#include - -#include "src/webp/types.h" -#include "sharpyuv/sharpyuv_cpu.h" -#include "sharpyuv/sharpyuv_dsp.h" -#include "sharpyuv/sharpyuv_gamma.h" - -//------------------------------------------------------------------------------ - -int SharpYuvGetVersion(void) { - return SHARPYUV_VERSION; -} - -//------------------------------------------------------------------------------ -// Sharp RGB->YUV conversion - -static const int kNumIterations = 4; - -#define YUV_FIX 16 // fixed-point precision for RGB->YUV -static const int kYuvHalf = 1 << (YUV_FIX - 1); - -// Max bit depth so that intermediate calculations fit in 16 bits. -static const int kMaxBitDepth = 14; - -// Returns the precision shift to use based on the input rgb_bit_depth. -static int GetPrecisionShift(int rgb_bit_depth) { - // Try to add 2 bits of precision if it fits in kMaxBitDepth. Otherwise remove - // bits if needed. - return ((rgb_bit_depth + 2) <= kMaxBitDepth) ? 2 - : (kMaxBitDepth - rgb_bit_depth); -} - -typedef int16_t fixed_t; // signed type with extra precision for UV -typedef uint16_t fixed_y_t; // unsigned type with extra precision for W - -//------------------------------------------------------------------------------ - -static uint8_t clip_8b(fixed_t v) { - return (!(v & ~0xff)) ? (uint8_t)v : (v < 0) ? 0u : 255u; -} - -static uint16_t clip(fixed_t v, int max) { - return (v < 0) ? 0 : (v > max) ? max : (uint16_t)v; -} - -static fixed_y_t clip_bit_depth(int y, int bit_depth) { - const int max = (1 << bit_depth) - 1; - return (!(y & ~max)) ? (fixed_y_t)y : (y < 0) ? 0 : max; -} - -//------------------------------------------------------------------------------ - -static int RGBToGray(int64_t r, int64_t g, int64_t b) { - const int64_t luma = 13933 * r + 46871 * g + 4732 * b + kYuvHalf; - return (int)(luma >> YUV_FIX); -} - -static uint32_t ScaleDown(uint16_t a, uint16_t b, uint16_t c, uint16_t d, - int rgb_bit_depth, - SharpYuvTransferFunctionType transfer_type) { - const int bit_depth = rgb_bit_depth + GetPrecisionShift(rgb_bit_depth); - const uint32_t A = SharpYuvGammaToLinear(a, bit_depth, transfer_type); - const uint32_t B = SharpYuvGammaToLinear(b, bit_depth, transfer_type); - const uint32_t C = SharpYuvGammaToLinear(c, bit_depth, transfer_type); - const uint32_t D = SharpYuvGammaToLinear(d, bit_depth, transfer_type); - return SharpYuvLinearToGamma((A + B + C + D + 2) >> 2, bit_depth, - transfer_type); -} - -static WEBP_INLINE void UpdateW(const fixed_y_t* src, fixed_y_t* dst, int w, - int rgb_bit_depth, - SharpYuvTransferFunctionType transfer_type) { - const int bit_depth = rgb_bit_depth + GetPrecisionShift(rgb_bit_depth); - int i = 0; - do { - const uint32_t R = - SharpYuvGammaToLinear(src[0 * w + i], bit_depth, transfer_type); - const uint32_t G = - SharpYuvGammaToLinear(src[1 * w + i], bit_depth, transfer_type); - const uint32_t B = - SharpYuvGammaToLinear(src[2 * w + i], bit_depth, transfer_type); - const uint32_t Y = RGBToGray(R, G, B); - dst[i] = (fixed_y_t)SharpYuvLinearToGamma(Y, bit_depth, transfer_type); - } while (++i < w); -} - -static void UpdateChroma(const fixed_y_t* src1, const fixed_y_t* src2, - fixed_t* dst, int uv_w, int rgb_bit_depth, - SharpYuvTransferFunctionType transfer_type) { - int i = 0; - do { - const int r = - ScaleDown(src1[0 * uv_w + 0], src1[0 * uv_w + 1], src2[0 * uv_w + 0], - src2[0 * uv_w + 1], rgb_bit_depth, transfer_type); - const int g = - ScaleDown(src1[2 * uv_w + 0], src1[2 * uv_w + 1], src2[2 * uv_w + 0], - src2[2 * uv_w + 1], rgb_bit_depth, transfer_type); - const int b = - ScaleDown(src1[4 * uv_w + 0], src1[4 * uv_w + 1], src2[4 * uv_w + 0], - src2[4 * uv_w + 1], rgb_bit_depth, transfer_type); - const int W = RGBToGray(r, g, b); - dst[0 * uv_w] = (fixed_t)(r - W); - dst[1 * uv_w] = (fixed_t)(g - W); - dst[2 * uv_w] = (fixed_t)(b - W); - dst += 1; - src1 += 2; - src2 += 2; - } while (++i < uv_w); -} - -static void StoreGray(const fixed_y_t* rgb, fixed_y_t* y, int w) { - int i = 0; - assert(w > 0); - do { - y[i] = RGBToGray(rgb[0 * w + i], rgb[1 * w + i], rgb[2 * w + i]); - } while (++i < w); -} - -//------------------------------------------------------------------------------ - -static WEBP_INLINE fixed_y_t Filter2(int A, int B, int W0, int bit_depth) { - const int v0 = (A * 3 + B + 2) >> 2; - return clip_bit_depth(v0 + W0, bit_depth); -} - -//------------------------------------------------------------------------------ - -static WEBP_INLINE int Shift(int v, int shift) { - return (shift >= 0) ? (v << shift) : (v >> -shift); -} - -static void ImportOneRow(const uint8_t* const r_ptr, - const uint8_t* const g_ptr, - const uint8_t* const b_ptr, - int rgb_step, - int rgb_bit_depth, - int pic_width, - fixed_y_t* const dst) { - // Convert the rgb_step from a number of bytes to a number of uint8_t or - // uint16_t values depending the bit depth. - const int step = (rgb_bit_depth > 8) ? rgb_step / 2 : rgb_step; - int i = 0; - const int w = (pic_width + 1) & ~1; - do { - const int off = i * step; - const int shift = GetPrecisionShift(rgb_bit_depth); - if (rgb_bit_depth == 8) { - dst[i + 0 * w] = Shift(r_ptr[off], shift); - dst[i + 1 * w] = Shift(g_ptr[off], shift); - dst[i + 2 * w] = Shift(b_ptr[off], shift); - } else { - dst[i + 0 * w] = Shift(((uint16_t*)r_ptr)[off], shift); - dst[i + 1 * w] = Shift(((uint16_t*)g_ptr)[off], shift); - dst[i + 2 * w] = Shift(((uint16_t*)b_ptr)[off], shift); - } - } while (++i < pic_width); - if (pic_width & 1) { // replicate rightmost pixel - dst[pic_width + 0 * w] = dst[pic_width + 0 * w - 1]; - dst[pic_width + 1 * w] = dst[pic_width + 1 * w - 1]; - dst[pic_width + 2 * w] = dst[pic_width + 2 * w - 1]; - } -} - -static void InterpolateTwoRows(const fixed_y_t* const best_y, - const fixed_t* prev_uv, - const fixed_t* cur_uv, - const fixed_t* next_uv, - int w, - fixed_y_t* out1, - fixed_y_t* out2, - int rgb_bit_depth) { - const int uv_w = w >> 1; - const int len = (w - 1) >> 1; // length to filter - int k = 3; - const int bit_depth = rgb_bit_depth + GetPrecisionShift(rgb_bit_depth); - while (k-- > 0) { // process each R/G/B segments in turn - // special boundary case for i==0 - out1[0] = Filter2(cur_uv[0], prev_uv[0], best_y[0], bit_depth); - out2[0] = Filter2(cur_uv[0], next_uv[0], best_y[w], bit_depth); - - SharpYuvFilterRow(cur_uv, prev_uv, len, best_y + 0 + 1, out1 + 1, - bit_depth); - SharpYuvFilterRow(cur_uv, next_uv, len, best_y + w + 1, out2 + 1, - bit_depth); - - // special boundary case for i == w - 1 when w is even - if (!(w & 1)) { - out1[w - 1] = Filter2(cur_uv[uv_w - 1], prev_uv[uv_w - 1], - best_y[w - 1 + 0], bit_depth); - out2[w - 1] = Filter2(cur_uv[uv_w - 1], next_uv[uv_w - 1], - best_y[w - 1 + w], bit_depth); - } - out1 += w; - out2 += w; - prev_uv += uv_w; - cur_uv += uv_w; - next_uv += uv_w; - } -} - -static WEBP_INLINE int RGBToYUVComponent(int r, int g, int b, - const int coeffs[4], int sfix) { - const int srounder = 1 << (YUV_FIX + sfix - 1); - const int luma = coeffs[0] * r + coeffs[1] * g + coeffs[2] * b + - coeffs[3] + srounder; - return (luma >> (YUV_FIX + sfix)); -} - -static int ConvertWRGBToYUV(const fixed_y_t* best_y, const fixed_t* best_uv, - uint8_t* y_ptr, int y_stride, uint8_t* u_ptr, - int u_stride, uint8_t* v_ptr, int v_stride, - int rgb_bit_depth, - int yuv_bit_depth, int width, int height, - const SharpYuvConversionMatrix* yuv_matrix) { - int i, j; - const fixed_t* const best_uv_base = best_uv; - const int w = (width + 1) & ~1; - const int h = (height + 1) & ~1; - const int uv_w = w >> 1; - const int uv_h = h >> 1; - const int sfix = GetPrecisionShift(rgb_bit_depth); - const int yuv_max = (1 << yuv_bit_depth) - 1; - - best_uv = best_uv_base; - j = 0; - do { - i = 0; - do { - const int off = (i >> 1); - const int W = best_y[i]; - const int r = best_uv[off + 0 * uv_w] + W; - const int g = best_uv[off + 1 * uv_w] + W; - const int b = best_uv[off + 2 * uv_w] + W; - const int y = RGBToYUVComponent(r, g, b, yuv_matrix->rgb_to_y, sfix); - if (yuv_bit_depth <= 8) { - y_ptr[i] = clip_8b(y); - } else { - ((uint16_t*)y_ptr)[i] = clip(y, yuv_max); - } - } while (++i < width); - best_y += w; - best_uv += (j & 1) * 3 * uv_w; - y_ptr += y_stride; - } while (++j < height); - - best_uv = best_uv_base; - j = 0; - do { - i = 0; - do { - // Note r, g and b values here are off by W, but a constant offset on all - // 3 components doesn't change the value of u and v with a YCbCr matrix. - const int r = best_uv[i + 0 * uv_w]; - const int g = best_uv[i + 1 * uv_w]; - const int b = best_uv[i + 2 * uv_w]; - const int u = RGBToYUVComponent(r, g, b, yuv_matrix->rgb_to_u, sfix); - const int v = RGBToYUVComponent(r, g, b, yuv_matrix->rgb_to_v, sfix); - if (yuv_bit_depth <= 8) { - u_ptr[i] = clip_8b(u); - v_ptr[i] = clip_8b(v); - } else { - ((uint16_t*)u_ptr)[i] = clip(u, yuv_max); - ((uint16_t*)v_ptr)[i] = clip(v, yuv_max); - } - } while (++i < uv_w); - best_uv += 3 * uv_w; - u_ptr += u_stride; - v_ptr += v_stride; - } while (++j < uv_h); - return 1; -} - -//------------------------------------------------------------------------------ -// Main function - -static void* SafeMalloc(uint64_t nmemb, size_t size) { - const uint64_t total_size = nmemb * (uint64_t)size; - if (total_size != (size_t)total_size) return NULL; - return malloc((size_t)total_size); -} - -#define SAFE_ALLOC(W, H, T) ((T*)SafeMalloc((uint64_t)(W) * (H), sizeof(T))) - -static int DoSharpArgbToYuv(const uint8_t* r_ptr, const uint8_t* g_ptr, - const uint8_t* b_ptr, int rgb_step, int rgb_stride, - int rgb_bit_depth, uint8_t* y_ptr, int y_stride, - uint8_t* u_ptr, int u_stride, uint8_t* v_ptr, - int v_stride, int yuv_bit_depth, int width, - int height, - const SharpYuvConversionMatrix* yuv_matrix, - SharpYuvTransferFunctionType transfer_type) { - // we expand the right/bottom border if needed - const int w = (width + 1) & ~1; - const int h = (height + 1) & ~1; - const int uv_w = w >> 1; - const int uv_h = h >> 1; - const int y_bit_depth = rgb_bit_depth + GetPrecisionShift(rgb_bit_depth); - uint64_t prev_diff_y_sum = ~0; - int j, iter; - - // TODO(skal): allocate one big memory chunk. But for now, it's easier - // for valgrind debugging to have several chunks. - fixed_y_t* const tmp_buffer = SAFE_ALLOC(w * 3, 2, fixed_y_t); // scratch - fixed_y_t* const best_y_base = SAFE_ALLOC(w, h, fixed_y_t); - fixed_y_t* const target_y_base = SAFE_ALLOC(w, h, fixed_y_t); - fixed_y_t* const best_rgb_y = SAFE_ALLOC(w, 2, fixed_y_t); - fixed_t* const best_uv_base = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t); - fixed_t* const target_uv_base = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t); - fixed_t* const best_rgb_uv = SAFE_ALLOC(uv_w * 3, 1, fixed_t); - fixed_y_t* best_y = best_y_base; - fixed_y_t* target_y = target_y_base; - fixed_t* best_uv = best_uv_base; - fixed_t* target_uv = target_uv_base; - const uint64_t diff_y_threshold = (uint64_t)(3.0 * w * h); - int ok; - assert(w > 0); - assert(h > 0); - - if (best_y_base == NULL || best_uv_base == NULL || - target_y_base == NULL || target_uv_base == NULL || - best_rgb_y == NULL || best_rgb_uv == NULL || - tmp_buffer == NULL) { - ok = 0; - goto End; - } - - // Import RGB samples to W/RGB representation. - for (j = 0; j < height; j += 2) { - const int is_last_row = (j == height - 1); - fixed_y_t* const src1 = tmp_buffer + 0 * w; - fixed_y_t* const src2 = tmp_buffer + 3 * w; - - // prepare two rows of input - ImportOneRow(r_ptr, g_ptr, b_ptr, rgb_step, rgb_bit_depth, width, - src1); - if (!is_last_row) { - ImportOneRow(r_ptr + rgb_stride, g_ptr + rgb_stride, b_ptr + rgb_stride, - rgb_step, rgb_bit_depth, width, src2); - } else { - memcpy(src2, src1, 3 * w * sizeof(*src2)); - } - StoreGray(src1, best_y + 0, w); - StoreGray(src2, best_y + w, w); - - UpdateW(src1, target_y, w, rgb_bit_depth, transfer_type); - UpdateW(src2, target_y + w, w, rgb_bit_depth, transfer_type); - UpdateChroma(src1, src2, target_uv, uv_w, rgb_bit_depth, transfer_type); - memcpy(best_uv, target_uv, 3 * uv_w * sizeof(*best_uv)); - best_y += 2 * w; - best_uv += 3 * uv_w; - target_y += 2 * w; - target_uv += 3 * uv_w; - r_ptr += 2 * rgb_stride; - g_ptr += 2 * rgb_stride; - b_ptr += 2 * rgb_stride; - } - - // Iterate and resolve clipping conflicts. - for (iter = 0; iter < kNumIterations; ++iter) { - const fixed_t* cur_uv = best_uv_base; - const fixed_t* prev_uv = best_uv_base; - uint64_t diff_y_sum = 0; - - best_y = best_y_base; - best_uv = best_uv_base; - target_y = target_y_base; - target_uv = target_uv_base; - j = 0; - do { - fixed_y_t* const src1 = tmp_buffer + 0 * w; - fixed_y_t* const src2 = tmp_buffer + 3 * w; - { - const fixed_t* const next_uv = cur_uv + ((j < h - 2) ? 3 * uv_w : 0); - InterpolateTwoRows(best_y, prev_uv, cur_uv, next_uv, w, - src1, src2, rgb_bit_depth); - prev_uv = cur_uv; - cur_uv = next_uv; - } - - UpdateW(src1, best_rgb_y + 0 * w, w, rgb_bit_depth, transfer_type); - UpdateW(src2, best_rgb_y + 1 * w, w, rgb_bit_depth, transfer_type); - UpdateChroma(src1, src2, best_rgb_uv, uv_w, rgb_bit_depth, transfer_type); - - // update two rows of Y and one row of RGB - diff_y_sum += - SharpYuvUpdateY(target_y, best_rgb_y, best_y, 2 * w, y_bit_depth); - SharpYuvUpdateRGB(target_uv, best_rgb_uv, best_uv, 3 * uv_w); - - best_y += 2 * w; - best_uv += 3 * uv_w; - target_y += 2 * w; - target_uv += 3 * uv_w; - j += 2; - } while (j < h); - // test exit condition - if (iter > 0) { - if (diff_y_sum < diff_y_threshold) break; - if (diff_y_sum > prev_diff_y_sum) break; - } - prev_diff_y_sum = diff_y_sum; - } - - // final reconstruction - ok = ConvertWRGBToYUV(best_y_base, best_uv_base, y_ptr, y_stride, u_ptr, - u_stride, v_ptr, v_stride, rgb_bit_depth, yuv_bit_depth, - width, height, yuv_matrix); - - End: - free(best_y_base); - free(best_uv_base); - free(target_y_base); - free(target_uv_base); - free(best_rgb_y); - free(best_rgb_uv); - free(tmp_buffer); - return ok; -} - -#undef SAFE_ALLOC - -#if defined(WEBP_USE_THREAD) && !defined(_WIN32) -#include // NOLINT - -#define LOCK_ACCESS \ - static pthread_mutex_t sharpyuv_lock = PTHREAD_MUTEX_INITIALIZER; \ - if (pthread_mutex_lock(&sharpyuv_lock)) return -#define UNLOCK_ACCESS_AND_RETURN \ - do { \ - (void)pthread_mutex_unlock(&sharpyuv_lock); \ - return; \ - } while (0) -#else // !(defined(WEBP_USE_THREAD) && !defined(_WIN32)) -#define LOCK_ACCESS do {} while (0) -#define UNLOCK_ACCESS_AND_RETURN return -#endif // defined(WEBP_USE_THREAD) && !defined(_WIN32) - -// Hidden exported init function. -// By default SharpYuvConvert calls it with SharpYuvGetCPUInfo. If needed, -// users can declare it as extern and call it with an alternate VP8CPUInfo -// function. -extern VP8CPUInfo SharpYuvGetCPUInfo; -SHARPYUV_EXTERN void SharpYuvInit(VP8CPUInfo cpu_info_func); -void SharpYuvInit(VP8CPUInfo cpu_info_func) { - static volatile VP8CPUInfo sharpyuv_last_cpuinfo_used = - (VP8CPUInfo)&sharpyuv_last_cpuinfo_used; - LOCK_ACCESS; - // Only update SharpYuvGetCPUInfo when called from external code to avoid a - // race on reading the value in SharpYuvConvert(). - if (cpu_info_func != (VP8CPUInfo)&SharpYuvGetCPUInfo) { - SharpYuvGetCPUInfo = cpu_info_func; - } - if (sharpyuv_last_cpuinfo_used == SharpYuvGetCPUInfo) { - UNLOCK_ACCESS_AND_RETURN; - } - - SharpYuvInitDsp(); - SharpYuvInitGammaTables(); - - sharpyuv_last_cpuinfo_used = SharpYuvGetCPUInfo; - UNLOCK_ACCESS_AND_RETURN; -} - -int SharpYuvConvert(const void* r_ptr, const void* g_ptr, const void* b_ptr, - int rgb_step, int rgb_stride, int rgb_bit_depth, - void* y_ptr, int y_stride, void* u_ptr, int u_stride, - void* v_ptr, int v_stride, int yuv_bit_depth, int width, - int height, const SharpYuvConversionMatrix* yuv_matrix) { - SharpYuvOptions options; - options.yuv_matrix = yuv_matrix; - options.transfer_type = kSharpYuvTransferFunctionSrgb; - return SharpYuvConvertWithOptions( - r_ptr, g_ptr, b_ptr, rgb_step, rgb_stride, rgb_bit_depth, y_ptr, y_stride, - u_ptr, u_stride, v_ptr, v_stride, yuv_bit_depth, width, height, &options); -} - -int SharpYuvOptionsInitInternal(const SharpYuvConversionMatrix* yuv_matrix, - SharpYuvOptions* options, int version) { - const int major = (version >> 24); - const int minor = (version >> 16) & 0xff; - if (options == NULL || yuv_matrix == NULL || - (major == SHARPYUV_VERSION_MAJOR && major == 0 && - minor != SHARPYUV_VERSION_MINOR) || - (major != SHARPYUV_VERSION_MAJOR)) { - return 0; - } - options->yuv_matrix = yuv_matrix; - options->transfer_type = kSharpYuvTransferFunctionSrgb; - return 1; -} - -int SharpYuvConvertWithOptions(const void* r_ptr, const void* g_ptr, - const void* b_ptr, int rgb_step, int rgb_stride, - int rgb_bit_depth, void* y_ptr, int y_stride, - void* u_ptr, int u_stride, void* v_ptr, - int v_stride, int yuv_bit_depth, int width, - int height, const SharpYuvOptions* options) { - const SharpYuvConversionMatrix* yuv_matrix = options->yuv_matrix; - SharpYuvTransferFunctionType transfer_type = options->transfer_type; - SharpYuvConversionMatrix scaled_matrix; - const int rgb_max = (1 << rgb_bit_depth) - 1; - const int rgb_round = 1 << (rgb_bit_depth - 1); - const int yuv_max = (1 << yuv_bit_depth) - 1; - const int sfix = GetPrecisionShift(rgb_bit_depth); - - if (width < 1 || height < 1 || width == INT_MAX || height == INT_MAX || - r_ptr == NULL || g_ptr == NULL || b_ptr == NULL || y_ptr == NULL || - u_ptr == NULL || v_ptr == NULL) { - return 0; - } - if (rgb_bit_depth != 8 && rgb_bit_depth != 10 && rgb_bit_depth != 12 && - rgb_bit_depth != 16) { - return 0; - } - if (yuv_bit_depth != 8 && yuv_bit_depth != 10 && yuv_bit_depth != 12) { - return 0; - } - if (rgb_bit_depth > 8 && (rgb_step % 2 != 0 || rgb_stride % 2 != 0)) { - // Step/stride should be even for uint16_t buffers. - return 0; - } - if (yuv_bit_depth > 8 && - (y_stride % 2 != 0 || u_stride % 2 != 0 || v_stride % 2 != 0)) { - // Stride should be even for uint16_t buffers. - return 0; - } - // The address of the function pointer is used to avoid a read race. - SharpYuvInit((VP8CPUInfo)&SharpYuvGetCPUInfo); - - // Add scaling factor to go from rgb_bit_depth to yuv_bit_depth, to the - // rgb->yuv conversion matrix. - if (rgb_bit_depth == yuv_bit_depth) { - memcpy(&scaled_matrix, yuv_matrix, sizeof(scaled_matrix)); - } else { - int i; - for (i = 0; i < 3; ++i) { - scaled_matrix.rgb_to_y[i] = - (yuv_matrix->rgb_to_y[i] * yuv_max + rgb_round) / rgb_max; - scaled_matrix.rgb_to_u[i] = - (yuv_matrix->rgb_to_u[i] * yuv_max + rgb_round) / rgb_max; - scaled_matrix.rgb_to_v[i] = - (yuv_matrix->rgb_to_v[i] * yuv_max + rgb_round) / rgb_max; - } - } - // Also incorporate precision change scaling. - scaled_matrix.rgb_to_y[3] = Shift(yuv_matrix->rgb_to_y[3], sfix); - scaled_matrix.rgb_to_u[3] = Shift(yuv_matrix->rgb_to_u[3], sfix); - scaled_matrix.rgb_to_v[3] = Shift(yuv_matrix->rgb_to_v[3], sfix); - - return DoSharpArgbToYuv(r_ptr, g_ptr, b_ptr, rgb_step, rgb_stride, - rgb_bit_depth, y_ptr, y_stride, u_ptr, u_stride, - v_ptr, v_stride, yuv_bit_depth, width, height, - &scaled_matrix, transfer_type); -} - -//------------------------------------------------------------------------------ diff --git a/libwebp/sharpyuv/sharpyuv.h b/libwebp/sharpyuv/sharpyuv.h deleted file mode 100644 index fe958915..00000000 --- a/libwebp/sharpyuv/sharpyuv.h +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright 2022 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Sharp RGB to YUV conversion. - -#ifndef WEBP_SHARPYUV_SHARPYUV_H_ -#define WEBP_SHARPYUV_SHARPYUV_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef SHARPYUV_EXTERN -#ifdef WEBP_EXTERN -#define SHARPYUV_EXTERN WEBP_EXTERN -#else -// This explicitly marks library functions and allows for changing the -// signature for e.g., Windows DLL builds. -#if defined(_WIN32) && defined(WEBP_DLL) -#define SHARPYUV_EXTERN __declspec(dllexport) -#elif defined(__GNUC__) && __GNUC__ >= 4 -#define SHARPYUV_EXTERN extern __attribute__((visibility("default"))) -#else -#define SHARPYUV_EXTERN extern -#endif /* defined(_WIN32) && defined(WEBP_DLL) */ -#endif /* WEBP_EXTERN */ -#endif /* SHARPYUV_EXTERN */ - -#ifndef SHARPYUV_INLINE -#ifdef WEBP_INLINE -#define SHARPYUV_INLINE WEBP_INLINE -#else -#ifndef _MSC_VER -#if defined(__cplusplus) || !defined(__STRICT_ANSI__) || \ - (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) -#define SHARPYUV_INLINE inline -#else -#define SHARPYUV_INLINE -#endif -#else -#define SHARPYUV_INLINE __forceinline -#endif /* _MSC_VER */ -#endif /* WEBP_INLINE */ -#endif /* SHARPYUV_INLINE */ - -// SharpYUV API version following the convention from semver.org -#define SHARPYUV_VERSION_MAJOR 0 -#define SHARPYUV_VERSION_MINOR 4 -#define SHARPYUV_VERSION_PATCH 0 -// Version as a uint32_t. The major number is the high 8 bits. -// The minor number is the middle 8 bits. The patch number is the low 16 bits. -#define SHARPYUV_MAKE_VERSION(MAJOR, MINOR, PATCH) \ - (((MAJOR) << 24) | ((MINOR) << 16) | (PATCH)) -#define SHARPYUV_VERSION \ - SHARPYUV_MAKE_VERSION(SHARPYUV_VERSION_MAJOR, SHARPYUV_VERSION_MINOR, \ - SHARPYUV_VERSION_PATCH) - -// Returns the library's version number, packed in hexadecimal. See -// SHARPYUV_VERSION. -SHARPYUV_EXTERN int SharpYuvGetVersion(void); - -// RGB to YUV conversion matrix, in 16 bit fixed point. -// y = rgb_to_y[0] * r + rgb_to_y[1] * g + rgb_to_y[2] * b + rgb_to_y[3] -// u = rgb_to_u[0] * r + rgb_to_u[1] * g + rgb_to_u[2] * b + rgb_to_u[3] -// v = rgb_to_v[0] * r + rgb_to_v[1] * g + rgb_to_v[2] * b + rgb_to_v[3] -// Then y, u and v values are divided by 1<<16 and rounded. -typedef struct { - int rgb_to_y[4]; - int rgb_to_u[4]; - int rgb_to_v[4]; -} SharpYuvConversionMatrix; - -typedef struct SharpYuvOptions SharpYuvOptions; - -// Enums for transfer functions, as defined in H.273, -// https://www.itu.int/rec/T-REC-H.273-202107-I/en -typedef enum SharpYuvTransferFunctionType { - // 0 is reserved - kSharpYuvTransferFunctionBt709 = 1, - // 2 is unspecified - // 3 is reserved - kSharpYuvTransferFunctionBt470M = 4, - kSharpYuvTransferFunctionBt470Bg = 5, - kSharpYuvTransferFunctionBt601 = 6, - kSharpYuvTransferFunctionSmpte240 = 7, - kSharpYuvTransferFunctionLinear = 8, - kSharpYuvTransferFunctionLog100 = 9, - kSharpYuvTransferFunctionLog100_Sqrt10 = 10, - kSharpYuvTransferFunctionIec61966 = 11, - kSharpYuvTransferFunctionBt1361 = 12, - kSharpYuvTransferFunctionSrgb = 13, - kSharpYuvTransferFunctionBt2020_10Bit = 14, - kSharpYuvTransferFunctionBt2020_12Bit = 15, - kSharpYuvTransferFunctionSmpte2084 = 16, // PQ - kSharpYuvTransferFunctionSmpte428 = 17, - kSharpYuvTransferFunctionHlg = 18, - kSharpYuvTransferFunctionNum -} SharpYuvTransferFunctionType; - -// Converts RGB to YUV420 using a downsampling algorithm that minimizes -// artefacts caused by chroma subsampling. -// This is slower than standard downsampling (averaging of 4 UV values). -// Assumes that the image will be upsampled using a bilinear filter. If nearest -// neighbor is used instead, the upsampled image might look worse than with -// standard downsampling. -// r_ptr, g_ptr, b_ptr: pointers to the source r, g and b channels. Should point -// to uint8_t buffers if rgb_bit_depth is 8, or uint16_t buffers otherwise. -// rgb_step: distance in bytes between two horizontally adjacent pixels on the -// r, g and b channels. If rgb_bit_depth is > 8, it should be a -// multiple of 2. -// rgb_stride: distance in bytes between two vertically adjacent pixels on the -// r, g, and b channels. If rgb_bit_depth is > 8, it should be a -// multiple of 2. -// rgb_bit_depth: number of bits for each r/g/b value. One of: 8, 10, 12, 16. -// Note: 16 bit input is truncated to 14 bits before conversion to yuv. -// yuv_bit_depth: number of bits for each y/u/v value. One of: 8, 10, 12. -// y_ptr, u_ptr, v_ptr: pointers to the destination y, u and v channels. Should -// point to uint8_t buffers if yuv_bit_depth is 8, or uint16_t buffers -// otherwise. -// y_stride, u_stride, v_stride: distance in bytes between two vertically -// adjacent pixels on the y, u and v channels. If yuv_bit_depth > 8, they -// should be multiples of 2. -// width, height: width and height of the image in pixels -// This function calls SharpYuvConvertWithOptions with a default transfer -// function of kSharpYuvTransferFunctionSrgb. -SHARPYUV_EXTERN int SharpYuvConvert(const void* r_ptr, const void* g_ptr, - const void* b_ptr, int rgb_step, - int rgb_stride, int rgb_bit_depth, - void* y_ptr, int y_stride, void* u_ptr, - int u_stride, void* v_ptr, int v_stride, - int yuv_bit_depth, int width, int height, - const SharpYuvConversionMatrix* yuv_matrix); - -struct SharpYuvOptions { - // This matrix cannot be NULL and can be initialized by - // SharpYuvComputeConversionMatrix. - const SharpYuvConversionMatrix* yuv_matrix; - SharpYuvTransferFunctionType transfer_type; -}; - -// Internal, version-checked, entry point -SHARPYUV_EXTERN int SharpYuvOptionsInitInternal(const SharpYuvConversionMatrix*, - SharpYuvOptions*, int); - -// Should always be called, to initialize a fresh SharpYuvOptions -// structure before modification. SharpYuvOptionsInit() must have succeeded -// before using the 'options' object. -static SHARPYUV_INLINE int SharpYuvOptionsInit( - const SharpYuvConversionMatrix* yuv_matrix, SharpYuvOptions* options) { - return SharpYuvOptionsInitInternal(yuv_matrix, options, SHARPYUV_VERSION); -} - -SHARPYUV_EXTERN int SharpYuvConvertWithOptions( - const void* r_ptr, const void* g_ptr, const void* b_ptr, int rgb_step, - int rgb_stride, int rgb_bit_depth, void* y_ptr, int y_stride, void* u_ptr, - int u_stride, void* v_ptr, int v_stride, int yuv_bit_depth, int width, - int height, const SharpYuvOptions* options); - -// TODO(b/194336375): Add YUV444 to YUV420 conversion. Maybe also add 422 -// support (it's rarely used in practice, especially for images). - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // WEBP_SHARPYUV_SHARPYUV_H_ diff --git a/libwebp/sharpyuv/sharpyuv_cpu.c b/libwebp/sharpyuv/sharpyuv_cpu.c deleted file mode 100644 index 29425a0c..00000000 --- a/libwebp/sharpyuv/sharpyuv_cpu.c +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2022 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -#include "sharpyuv/sharpyuv_cpu.h" - -// Include src/dsp/cpu.c to create SharpYuvGetCPUInfo from VP8GetCPUInfo. The -// function pointer is renamed in sharpyuv_cpu.h. -#include "src/dsp/cpu.c" diff --git a/libwebp/sharpyuv/sharpyuv_cpu.h b/libwebp/sharpyuv/sharpyuv_cpu.h deleted file mode 100644 index 176ca3eb..00000000 --- a/libwebp/sharpyuv/sharpyuv_cpu.h +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2022 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -#ifndef WEBP_SHARPYUV_SHARPYUV_CPU_H_ -#define WEBP_SHARPYUV_SHARPYUV_CPU_H_ - -#include "sharpyuv/sharpyuv.h" - -// Avoid exporting SharpYuvGetCPUInfo in shared object / DLL builds. -// SharpYuvInit() replaces the use of the function pointer. -#undef WEBP_EXTERN -#define WEBP_EXTERN extern -#define VP8GetCPUInfo SharpYuvGetCPUInfo -#include "src/dsp/cpu.h" - -#endif // WEBP_SHARPYUV_SHARPYUV_CPU_H_ diff --git a/libwebp/sharpyuv/sharpyuv_csp.c b/libwebp/sharpyuv/sharpyuv_csp.c deleted file mode 100644 index 0ad22be9..00000000 --- a/libwebp/sharpyuv/sharpyuv_csp.c +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2022 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Colorspace utilities. - -#include "sharpyuv/sharpyuv_csp.h" - -#include -#include -#include - -static int ToFixed16(float f) { return (int)floor(f * (1 << 16) + 0.5f); } - -void SharpYuvComputeConversionMatrix(const SharpYuvColorSpace* yuv_color_space, - SharpYuvConversionMatrix* matrix) { - const float kr = yuv_color_space->kr; - const float kb = yuv_color_space->kb; - const float kg = 1.0f - kr - kb; - const float cr = 0.5f / (1.0f - kb); - const float cb = 0.5f / (1.0f - kr); - - const int shift = yuv_color_space->bit_depth - 8; - - const float denom = (float)((1 << yuv_color_space->bit_depth) - 1); - float scale_y = 1.0f; - float add_y = 0.0f; - float scale_u = cr; - float scale_v = cb; - float add_uv = (float)(128 << shift); - assert(yuv_color_space->bit_depth >= 8); - - if (yuv_color_space->range == kSharpYuvRangeLimited) { - scale_y *= (219 << shift) / denom; - scale_u *= (224 << shift) / denom; - scale_v *= (224 << shift) / denom; - add_y = (float)(16 << shift); - } - - matrix->rgb_to_y[0] = ToFixed16(kr * scale_y); - matrix->rgb_to_y[1] = ToFixed16(kg * scale_y); - matrix->rgb_to_y[2] = ToFixed16(kb * scale_y); - matrix->rgb_to_y[3] = ToFixed16(add_y); - - matrix->rgb_to_u[0] = ToFixed16(-kr * scale_u); - matrix->rgb_to_u[1] = ToFixed16(-kg * scale_u); - matrix->rgb_to_u[2] = ToFixed16((1 - kb) * scale_u); - matrix->rgb_to_u[3] = ToFixed16(add_uv); - - matrix->rgb_to_v[0] = ToFixed16((1 - kr) * scale_v); - matrix->rgb_to_v[1] = ToFixed16(-kg * scale_v); - matrix->rgb_to_v[2] = ToFixed16(-kb * scale_v); - matrix->rgb_to_v[3] = ToFixed16(add_uv); -} - -// Matrices are in YUV_FIX fixed point precision. -// WebP's matrix, similar but not identical to kRec601LimitedMatrix. -static const SharpYuvConversionMatrix kWebpMatrix = { - {16839, 33059, 6420, 16 << 16}, - {-9719, -19081, 28800, 128 << 16}, - {28800, -24116, -4684, 128 << 16}, -}; -// Kr=0.2990f Kb=0.1140f bits=8 range=kSharpYuvRangeLimited -static const SharpYuvConversionMatrix kRec601LimitedMatrix = { - {16829, 33039, 6416, 16 << 16}, - {-9714, -19071, 28784, 128 << 16}, - {28784, -24103, -4681, 128 << 16}, -}; -// Kr=0.2990f Kb=0.1140f bits=8 range=kSharpYuvRangeFull -static const SharpYuvConversionMatrix kRec601FullMatrix = { - {19595, 38470, 7471, 0}, - {-11058, -21710, 32768, 128 << 16}, - {32768, -27439, -5329, 128 << 16}, -}; -// Kr=0.2126f Kb=0.0722f bits=8 range=kSharpYuvRangeLimited -static const SharpYuvConversionMatrix kRec709LimitedMatrix = { - {11966, 40254, 4064, 16 << 16}, - {-6596, -22189, 28784, 128 << 16}, - {28784, -26145, -2639, 128 << 16}, -}; -// Kr=0.2126f Kb=0.0722f bits=8 range=kSharpYuvRangeFull -static const SharpYuvConversionMatrix kRec709FullMatrix = { - {13933, 46871, 4732, 0}, - {-7509, -25259, 32768, 128 << 16}, - {32768, -29763, -3005, 128 << 16}, -}; - -const SharpYuvConversionMatrix* SharpYuvGetConversionMatrix( - SharpYuvMatrixType matrix_type) { - switch (matrix_type) { - case kSharpYuvMatrixWebp: - return &kWebpMatrix; - case kSharpYuvMatrixRec601Limited: - return &kRec601LimitedMatrix; - case kSharpYuvMatrixRec601Full: - return &kRec601FullMatrix; - case kSharpYuvMatrixRec709Limited: - return &kRec709LimitedMatrix; - case kSharpYuvMatrixRec709Full: - return &kRec709FullMatrix; - case kSharpYuvMatrixNum: - return NULL; - } - return NULL; -} diff --git a/libwebp/sharpyuv/sharpyuv_csp.h b/libwebp/sharpyuv/sharpyuv_csp.h deleted file mode 100644 index 3214e3ac..00000000 --- a/libwebp/sharpyuv/sharpyuv_csp.h +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2022 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Colorspace utilities. - -#ifndef WEBP_SHARPYUV_SHARPYUV_CSP_H_ -#define WEBP_SHARPYUV_SHARPYUV_CSP_H_ - -#include "sharpyuv/sharpyuv.h" - -#ifdef __cplusplus -extern "C" { -#endif - -// Range of YUV values. -typedef enum { - kSharpYuvRangeFull, // YUV values between [0;255] (for 8 bit) - kSharpYuvRangeLimited // Y in [16;235], YUV in [16;240] (for 8 bit) -} SharpYuvRange; - -// Constants that define a YUV color space. -typedef struct { - // Kr and Kb are defined such that: - // Y = Kr * r + Kg * g + Kb * b where Kg = 1 - Kr - Kb. - float kr; - float kb; - int bit_depth; // 8, 10 or 12 - SharpYuvRange range; -} SharpYuvColorSpace; - -// Fills in 'matrix' for the given YUVColorSpace. -SHARPYUV_EXTERN void SharpYuvComputeConversionMatrix( - const SharpYuvColorSpace* yuv_color_space, - SharpYuvConversionMatrix* matrix); - -// Enums for precomputed conversion matrices. -typedef enum { - kSharpYuvMatrixWebp = 0, - kSharpYuvMatrixRec601Limited, - kSharpYuvMatrixRec601Full, - kSharpYuvMatrixRec709Limited, - kSharpYuvMatrixRec709Full, - kSharpYuvMatrixNum -} SharpYuvMatrixType; - -// Returns a pointer to a matrix for one of the predefined colorspaces. -SHARPYUV_EXTERN const SharpYuvConversionMatrix* SharpYuvGetConversionMatrix( - SharpYuvMatrixType matrix_type); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // WEBP_SHARPYUV_SHARPYUV_CSP_H_ diff --git a/libwebp/sharpyuv/sharpyuv_dsp.c b/libwebp/sharpyuv/sharpyuv_dsp.c deleted file mode 100644 index 94a40ec6..00000000 --- a/libwebp/sharpyuv/sharpyuv_dsp.c +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2022 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Speed-critical functions for Sharp YUV. -// -// Author: Skal (pascal.massimino@gmail.com) - -#include "sharpyuv/sharpyuv_dsp.h" - -#include -#include - -#include "sharpyuv/sharpyuv_cpu.h" -#include "src/webp/types.h" - -//----------------------------------------------------------------------------- - -#if !WEBP_NEON_OMIT_C_CODE -static uint16_t clip(int v, int max) { - return (v < 0) ? 0 : (v > max) ? max : (uint16_t)v; -} - -static uint64_t SharpYuvUpdateY_C(const uint16_t* ref, const uint16_t* src, - uint16_t* dst, int len, int bit_depth) { - uint64_t diff = 0; - int i; - const int max_y = (1 << bit_depth) - 1; - for (i = 0; i < len; ++i) { - const int diff_y = ref[i] - src[i]; - const int new_y = (int)dst[i] + diff_y; - dst[i] = clip(new_y, max_y); - diff += (uint64_t)abs(diff_y); - } - return diff; -} - -static void SharpYuvUpdateRGB_C(const int16_t* ref, const int16_t* src, - int16_t* dst, int len) { - int i; - for (i = 0; i < len; ++i) { - const int diff_uv = ref[i] - src[i]; - dst[i] += diff_uv; - } -} - -static void SharpYuvFilterRow_C(const int16_t* A, const int16_t* B, int len, - const uint16_t* best_y, uint16_t* out, - int bit_depth) { - int i; - const int max_y = (1 << bit_depth) - 1; - for (i = 0; i < len; ++i, ++A, ++B) { - const int v0 = (A[0] * 9 + A[1] * 3 + B[0] * 3 + B[1] + 8) >> 4; - const int v1 = (A[1] * 9 + A[0] * 3 + B[1] * 3 + B[0] + 8) >> 4; - out[2 * i + 0] = clip(best_y[2 * i + 0] + v0, max_y); - out[2 * i + 1] = clip(best_y[2 * i + 1] + v1, max_y); - } -} -#endif // !WEBP_NEON_OMIT_C_CODE - -//----------------------------------------------------------------------------- - -uint64_t (*SharpYuvUpdateY)(const uint16_t* src, const uint16_t* ref, - uint16_t* dst, int len, int bit_depth); -void (*SharpYuvUpdateRGB)(const int16_t* src, const int16_t* ref, int16_t* dst, - int len); -void (*SharpYuvFilterRow)(const int16_t* A, const int16_t* B, int len, - const uint16_t* best_y, uint16_t* out, int bit_depth); - -extern VP8CPUInfo SharpYuvGetCPUInfo; -extern void InitSharpYuvSSE2(void); -extern void InitSharpYuvNEON(void); - -void SharpYuvInitDsp(void) { -#if !WEBP_NEON_OMIT_C_CODE - SharpYuvUpdateY = SharpYuvUpdateY_C; - SharpYuvUpdateRGB = SharpYuvUpdateRGB_C; - SharpYuvFilterRow = SharpYuvFilterRow_C; -#endif - - if (SharpYuvGetCPUInfo != NULL) { -#if defined(WEBP_HAVE_SSE2) - if (SharpYuvGetCPUInfo(kSSE2)) { - InitSharpYuvSSE2(); - } -#endif // WEBP_HAVE_SSE2 - } - -#if defined(WEBP_HAVE_NEON) - if (WEBP_NEON_OMIT_C_CODE || - (SharpYuvGetCPUInfo != NULL && SharpYuvGetCPUInfo(kNEON))) { - InitSharpYuvNEON(); - } -#endif // WEBP_HAVE_NEON - - assert(SharpYuvUpdateY != NULL); - assert(SharpYuvUpdateRGB != NULL); - assert(SharpYuvFilterRow != NULL); -} diff --git a/libwebp/sharpyuv/sharpyuv_dsp.h b/libwebp/sharpyuv/sharpyuv_dsp.h deleted file mode 100644 index 805fbadb..00000000 --- a/libwebp/sharpyuv/sharpyuv_dsp.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2022 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Speed-critical functions for Sharp YUV. - -#ifndef WEBP_SHARPYUV_SHARPYUV_DSP_H_ -#define WEBP_SHARPYUV_SHARPYUV_DSP_H_ - -#include "sharpyuv/sharpyuv_cpu.h" -#include "src/webp/types.h" - -extern uint64_t (*SharpYuvUpdateY)(const uint16_t* src, const uint16_t* ref, - uint16_t* dst, int len, int bit_depth); -extern void (*SharpYuvUpdateRGB)(const int16_t* src, const int16_t* ref, - int16_t* dst, int len); -extern void (*SharpYuvFilterRow)(const int16_t* A, const int16_t* B, int len, - const uint16_t* best_y, uint16_t* out, - int bit_depth); - -void SharpYuvInitDsp(void); - -#endif // WEBP_SHARPYUV_SHARPYUV_DSP_H_ diff --git a/libwebp/sharpyuv/sharpyuv_gamma.c b/libwebp/sharpyuv/sharpyuv_gamma.c deleted file mode 100644 index 09028428..00000000 --- a/libwebp/sharpyuv/sharpyuv_gamma.c +++ /dev/null @@ -1,419 +0,0 @@ -// Copyright 2022 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Gamma correction utilities. - -#include "sharpyuv/sharpyuv_gamma.h" - -#include -#include -#include - -#include "src/webp/types.h" - -// Gamma correction compensates loss of resolution during chroma subsampling. -// Size of pre-computed table for converting from gamma to linear. -#define GAMMA_TO_LINEAR_TAB_BITS 10 -#define GAMMA_TO_LINEAR_TAB_SIZE (1 << GAMMA_TO_LINEAR_TAB_BITS) -static uint32_t kGammaToLinearTabS[GAMMA_TO_LINEAR_TAB_SIZE + 2]; -#define LINEAR_TO_GAMMA_TAB_BITS 9 -#define LINEAR_TO_GAMMA_TAB_SIZE (1 << LINEAR_TO_GAMMA_TAB_BITS) -static uint32_t kLinearToGammaTabS[LINEAR_TO_GAMMA_TAB_SIZE + 2]; - -static const double kGammaF = 1. / 0.45; -#define GAMMA_TO_LINEAR_BITS 16 - -static volatile int kGammaTablesSOk = 0; -void SharpYuvInitGammaTables(void) { - assert(GAMMA_TO_LINEAR_BITS <= 16); - if (!kGammaTablesSOk) { - int v; - const double a = 0.09929682680944; - const double thresh = 0.018053968510807; - const double final_scale = 1 << GAMMA_TO_LINEAR_BITS; - // Precompute gamma to linear table. - { - const double norm = 1. / GAMMA_TO_LINEAR_TAB_SIZE; - const double a_rec = 1. / (1. + a); - for (v = 0; v <= GAMMA_TO_LINEAR_TAB_SIZE; ++v) { - const double g = norm * v; - double value; - if (g <= thresh * 4.5) { - value = g / 4.5; - } else { - value = pow(a_rec * (g + a), kGammaF); - } - kGammaToLinearTabS[v] = (uint32_t)(value * final_scale + .5); - } - // to prevent small rounding errors to cause read-overflow: - kGammaToLinearTabS[GAMMA_TO_LINEAR_TAB_SIZE + 1] = - kGammaToLinearTabS[GAMMA_TO_LINEAR_TAB_SIZE]; - } - // Precompute linear to gamma table. - { - const double scale = 1. / LINEAR_TO_GAMMA_TAB_SIZE; - for (v = 0; v <= LINEAR_TO_GAMMA_TAB_SIZE; ++v) { - const double g = scale * v; - double value; - if (g <= thresh) { - value = 4.5 * g; - } else { - value = (1. + a) * pow(g, 1. / kGammaF) - a; - } - kLinearToGammaTabS[v] = - (uint32_t)(final_scale * value + 0.5); - } - // to prevent small rounding errors to cause read-overflow: - kLinearToGammaTabS[LINEAR_TO_GAMMA_TAB_SIZE + 1] = - kLinearToGammaTabS[LINEAR_TO_GAMMA_TAB_SIZE]; - } - kGammaTablesSOk = 1; - } -} - -static WEBP_INLINE int Shift(int v, int shift) { - return (shift >= 0) ? (v << shift) : (v >> -shift); -} - -static WEBP_INLINE uint32_t FixedPointInterpolation(int v, uint32_t* tab, - int tab_pos_shift_right, - int tab_value_shift) { - const uint32_t tab_pos = Shift(v, -tab_pos_shift_right); - // fractional part, in 'tab_pos_shift' fixed-point precision - const uint32_t x = v - (tab_pos << tab_pos_shift_right); // fractional part - // v0 / v1 are in kGammaToLinearBits fixed-point precision (range [0..1]) - const uint32_t v0 = Shift(tab[tab_pos + 0], tab_value_shift); - const uint32_t v1 = Shift(tab[tab_pos + 1], tab_value_shift); - // Final interpolation. - const uint32_t v2 = (v1 - v0) * x; // note: v1 >= v0. - const int half = - (tab_pos_shift_right > 0) ? 1 << (tab_pos_shift_right - 1) : 0; - const uint32_t result = v0 + ((v2 + half) >> tab_pos_shift_right); - return result; -} - -static uint32_t ToLinearSrgb(uint16_t v, int bit_depth) { - const int shift = GAMMA_TO_LINEAR_TAB_BITS - bit_depth; - if (shift > 0) { - return kGammaToLinearTabS[v << shift]; - } - return FixedPointInterpolation(v, kGammaToLinearTabS, -shift, 0); -} - -static uint16_t FromLinearSrgb(uint32_t value, int bit_depth) { - return FixedPointInterpolation( - value, kLinearToGammaTabS, - (GAMMA_TO_LINEAR_BITS - LINEAR_TO_GAMMA_TAB_BITS), - bit_depth - GAMMA_TO_LINEAR_BITS); -} - -//////////////////////////////////////////////////////////////////////////////// - -#define CLAMP(x, low, high) \ - (((x) < (low)) ? (low) : (((high) < (x)) ? (high) : (x))) -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) -#define MAX(a, b) (((a) > (b)) ? (a) : (b)) - -static WEBP_INLINE float Roundf(float x) { - if (x < 0) - return (float)ceil((double)(x - 0.5f)); - else - return (float)floor((double)(x + 0.5f)); -} - -static WEBP_INLINE float Powf(float base, float exp) { - return (float)pow((double)base, (double)exp); -} - -static WEBP_INLINE float Log10f(float x) { return (float)log10((double)x); } - -static float ToLinear709(float gamma) { - if (gamma < 0.f) { - return 0.f; - } else if (gamma < 4.5f * 0.018053968510807f) { - return gamma / 4.5f; - } else if (gamma < 1.f) { - return Powf((gamma + 0.09929682680944f) / 1.09929682680944f, 1.f / 0.45f); - } - return 1.f; -} - -static float FromLinear709(float linear) { - if (linear < 0.f) { - return 0.f; - } else if (linear < 0.018053968510807f) { - return linear * 4.5f; - } else if (linear < 1.f) { - return 1.09929682680944f * Powf(linear, 0.45f) - 0.09929682680944f; - } - return 1.f; -} - -static float ToLinear470M(float gamma) { - return Powf(CLAMP(gamma, 0.f, 1.f), 2.2f); -} - -static float FromLinear470M(float linear) { - return Powf(CLAMP(linear, 0.f, 1.f), 1.f / 2.2f); -} - -static float ToLinear470Bg(float gamma) { - return Powf(CLAMP(gamma, 0.f, 1.f), 2.8f); -} - -static float FromLinear470Bg(float linear) { - return Powf(CLAMP(linear, 0.f, 1.f), 1.f / 2.8f); -} - -static float ToLinearSmpte240(float gamma) { - if (gamma < 0.f) { - return 0.f; - } else if (gamma < 4.f * 0.022821585529445f) { - return gamma / 4.f; - } else if (gamma < 1.f) { - return Powf((gamma + 0.111572195921731f) / 1.111572195921731f, 1.f / 0.45f); - } - return 1.f; -} - -static float FromLinearSmpte240(float linear) { - if (linear < 0.f) { - return 0.f; - } else if (linear < 0.022821585529445f) { - return linear * 4.f; - } else if (linear < 1.f) { - return 1.111572195921731f * Powf(linear, 0.45f) - 0.111572195921731f; - } - return 1.f; -} - -static float ToLinearLog100(float gamma) { - // The function is non-bijective so choose the middle of [0, 0.01]. - const float mid_interval = 0.01f / 2.f; - return (gamma <= 0.0f) ? mid_interval - : Powf(10.0f, 2.f * (MIN(gamma, 1.f) - 1.0f)); -} - -static float FromLinearLog100(float linear) { - return (linear < 0.01f) ? 0.0f : 1.0f + Log10f(MIN(linear, 1.f)) / 2.0f; -} - -static float ToLinearLog100Sqrt10(float gamma) { - // The function is non-bijective so choose the middle of [0, 0.00316227766f[. - const float mid_interval = 0.00316227766f / 2.f; - return (gamma <= 0.0f) ? mid_interval - : Powf(10.0f, 2.5f * (MIN(gamma, 1.f) - 1.0f)); -} - -static float FromLinearLog100Sqrt10(float linear) { - return (linear < 0.00316227766f) ? 0.0f - : 1.0f + Log10f(MIN(linear, 1.f)) / 2.5f; -} - -static float ToLinearIec61966(float gamma) { - if (gamma <= -4.5f * 0.018053968510807f) { - return Powf((-gamma + 0.09929682680944f) / -1.09929682680944f, 1.f / 0.45f); - } else if (gamma < 4.5f * 0.018053968510807f) { - return gamma / 4.5f; - } - return Powf((gamma + 0.09929682680944f) / 1.09929682680944f, 1.f / 0.45f); -} - -static float FromLinearIec61966(float linear) { - if (linear <= -0.018053968510807f) { - return -1.09929682680944f * Powf(-linear, 0.45f) + 0.09929682680944f; - } else if (linear < 0.018053968510807f) { - return linear * 4.5f; - } - return 1.09929682680944f * Powf(linear, 0.45f) - 0.09929682680944f; -} - -static float ToLinearBt1361(float gamma) { - if (gamma < -0.25f) { - return -0.25f; - } else if (gamma < 0.f) { - return Powf((gamma - 0.02482420670236f) / -0.27482420670236f, 1.f / 0.45f) / - -4.f; - } else if (gamma < 4.5f * 0.018053968510807f) { - return gamma / 4.5f; - } else if (gamma < 1.f) { - return Powf((gamma + 0.09929682680944f) / 1.09929682680944f, 1.f / 0.45f); - } - return 1.f; -} - -static float FromLinearBt1361(float linear) { - if (linear < -0.25f) { - return -0.25f; - } else if (linear < 0.f) { - return -0.27482420670236f * Powf(-4.f * linear, 0.45f) + 0.02482420670236f; - } else if (linear < 0.018053968510807f) { - return linear * 4.5f; - } else if (linear < 1.f) { - return 1.09929682680944f * Powf(linear, 0.45f) - 0.09929682680944f; - } - return 1.f; -} - -static float ToLinearPq(float gamma) { - if (gamma > 0.f) { - const float pow_gamma = Powf(gamma, 32.f / 2523.f); - const float num = MAX(pow_gamma - 107.f / 128.f, 0.0f); - const float den = MAX(2413.f / 128.f - 2392.f / 128.f * pow_gamma, FLT_MIN); - return Powf(num / den, 4096.f / 653.f); - } - return 0.f; -} - -static float FromLinearPq(float linear) { - if (linear > 0.f) { - const float pow_linear = Powf(linear, 653.f / 4096.f); - const float num = 107.f / 128.f + 2413.f / 128.f * pow_linear; - const float den = 1.0f + 2392.f / 128.f * pow_linear; - return Powf(num / den, 2523.f / 32.f); - } - return 0.f; -} - -static float ToLinearSmpte428(float gamma) { - return Powf(MAX(gamma, 0.f), 2.6f) / 0.91655527974030934f; -} - -static float FromLinearSmpte428(float linear) { - return Powf(0.91655527974030934f * MAX(linear, 0.f), 1.f / 2.6f); -} - -// Conversion in BT.2100 requires RGB info. Simplify to gamma correction here. -static float ToLinearHlg(float gamma) { - if (gamma < 0.f) { - return 0.f; - } else if (gamma <= 0.5f) { - return Powf((gamma * gamma) * (1.f / 3.f), 1.2f); - } - return Powf((expf((gamma - 0.55991073f) / 0.17883277f) + 0.28466892f) / 12.0f, - 1.2f); -} - -static float FromLinearHlg(float linear) { - linear = Powf(linear, 1.f / 1.2f); - if (linear < 0.f) { - return 0.f; - } else if (linear <= (1.f / 12.f)) { - return sqrtf(3.f * linear); - } - return 0.17883277f * logf(12.f * linear - 0.28466892f) + 0.55991073f; -} - -uint32_t SharpYuvGammaToLinear(uint16_t v, int bit_depth, - SharpYuvTransferFunctionType transfer_type) { - float v_float, linear; - if (transfer_type == kSharpYuvTransferFunctionSrgb) { - return ToLinearSrgb(v, bit_depth); - } - v_float = (float)v / ((1 << bit_depth) - 1); - switch (transfer_type) { - case kSharpYuvTransferFunctionBt709: - case kSharpYuvTransferFunctionBt601: - case kSharpYuvTransferFunctionBt2020_10Bit: - case kSharpYuvTransferFunctionBt2020_12Bit: - linear = ToLinear709(v_float); - break; - case kSharpYuvTransferFunctionBt470M: - linear = ToLinear470M(v_float); - break; - case kSharpYuvTransferFunctionBt470Bg: - linear = ToLinear470Bg(v_float); - break; - case kSharpYuvTransferFunctionSmpte240: - linear = ToLinearSmpte240(v_float); - break; - case kSharpYuvTransferFunctionLinear: - return v; - case kSharpYuvTransferFunctionLog100: - linear = ToLinearLog100(v_float); - break; - case kSharpYuvTransferFunctionLog100_Sqrt10: - linear = ToLinearLog100Sqrt10(v_float); - break; - case kSharpYuvTransferFunctionIec61966: - linear = ToLinearIec61966(v_float); - break; - case kSharpYuvTransferFunctionBt1361: - linear = ToLinearBt1361(v_float); - break; - case kSharpYuvTransferFunctionSmpte2084: - linear = ToLinearPq(v_float); - break; - case kSharpYuvTransferFunctionSmpte428: - linear = ToLinearSmpte428(v_float); - break; - case kSharpYuvTransferFunctionHlg: - linear = ToLinearHlg(v_float); - break; - default: - assert(0); - linear = 0; - break; - } - return (uint32_t)Roundf(linear * ((1 << 16) - 1)); -} - -uint16_t SharpYuvLinearToGamma(uint32_t v, int bit_depth, - SharpYuvTransferFunctionType transfer_type) { - float v_float, linear; - if (transfer_type == kSharpYuvTransferFunctionSrgb) { - return FromLinearSrgb(v, bit_depth); - } - v_float = (float)v / ((1 << 16) - 1); - switch (transfer_type) { - case kSharpYuvTransferFunctionBt709: - case kSharpYuvTransferFunctionBt601: - case kSharpYuvTransferFunctionBt2020_10Bit: - case kSharpYuvTransferFunctionBt2020_12Bit: - linear = FromLinear709(v_float); - break; - case kSharpYuvTransferFunctionBt470M: - linear = FromLinear470M(v_float); - break; - case kSharpYuvTransferFunctionBt470Bg: - linear = FromLinear470Bg(v_float); - break; - case kSharpYuvTransferFunctionSmpte240: - linear = FromLinearSmpte240(v_float); - break; - case kSharpYuvTransferFunctionLinear: - return v; - case kSharpYuvTransferFunctionLog100: - linear = FromLinearLog100(v_float); - break; - case kSharpYuvTransferFunctionLog100_Sqrt10: - linear = FromLinearLog100Sqrt10(v_float); - break; - case kSharpYuvTransferFunctionIec61966: - linear = FromLinearIec61966(v_float); - break; - case kSharpYuvTransferFunctionBt1361: - linear = FromLinearBt1361(v_float); - break; - case kSharpYuvTransferFunctionSmpte2084: - linear = FromLinearPq(v_float); - break; - case kSharpYuvTransferFunctionSmpte428: - linear = FromLinearSmpte428(v_float); - break; - case kSharpYuvTransferFunctionHlg: - linear = FromLinearHlg(v_float); - break; - default: - assert(0); - linear = 0; - break; - } - return (uint16_t)Roundf(linear * ((1 << bit_depth) - 1)); -} diff --git a/libwebp/sharpyuv/sharpyuv_gamma.h b/libwebp/sharpyuv/sharpyuv_gamma.h deleted file mode 100644 index b8ba7e98..00000000 --- a/libwebp/sharpyuv/sharpyuv_gamma.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2022 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Gamma correction utilities. - -#ifndef WEBP_SHARPYUV_SHARPYUV_GAMMA_H_ -#define WEBP_SHARPYUV_SHARPYUV_GAMMA_H_ - -#include "sharpyuv/sharpyuv.h" -#include "src/webp/types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -// Initializes precomputed tables. Must be called once before calling -// SharpYuvGammaToLinear or SharpYuvLinearToGamma. -void SharpYuvInitGammaTables(void); - -// Converts a 'bit_depth'-bit gamma color value to a 16-bit linear value. -uint32_t SharpYuvGammaToLinear(uint16_t v, int bit_depth, - SharpYuvTransferFunctionType transfer_type); - -// Converts a 16-bit linear color value to a 'bit_depth'-bit gamma value. -uint16_t SharpYuvLinearToGamma(uint32_t value, int bit_depth, - SharpYuvTransferFunctionType transfer_type); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // WEBP_SHARPYUV_SHARPYUV_GAMMA_H_ diff --git a/libwebp/sharpyuv/sharpyuv_neon.c b/libwebp/sharpyuv/sharpyuv_neon.c deleted file mode 100644 index 58409148..00000000 --- a/libwebp/sharpyuv/sharpyuv_neon.c +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright 2022 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Speed-critical functions for Sharp YUV. -// -// Author: Skal (pascal.massimino@gmail.com) - -#include "sharpyuv/sharpyuv_dsp.h" - -#if defined(WEBP_USE_NEON) -#include -#include -#include - -static uint16_t clip_NEON(int v, int max) { - return (v < 0) ? 0 : (v > max) ? max : (uint16_t)v; -} - -static uint64_t SharpYuvUpdateY_NEON(const uint16_t* ref, const uint16_t* src, - uint16_t* dst, int len, int bit_depth) { - const int max_y = (1 << bit_depth) - 1; - int i; - const int16x8_t zero = vdupq_n_s16(0); - const int16x8_t max = vdupq_n_s16(max_y); - uint64x2_t sum = vdupq_n_u64(0); - uint64_t diff; - - for (i = 0; i + 8 <= len; i += 8) { - const int16x8_t A = vreinterpretq_s16_u16(vld1q_u16(ref + i)); - const int16x8_t B = vreinterpretq_s16_u16(vld1q_u16(src + i)); - const int16x8_t C = vreinterpretq_s16_u16(vld1q_u16(dst + i)); - const int16x8_t D = vsubq_s16(A, B); // diff_y - const int16x8_t F = vaddq_s16(C, D); // new_y - const uint16x8_t H = - vreinterpretq_u16_s16(vmaxq_s16(vminq_s16(F, max), zero)); - const int16x8_t I = vabsq_s16(D); // abs(diff_y) - vst1q_u16(dst + i, H); - sum = vpadalq_u32(sum, vpaddlq_u16(vreinterpretq_u16_s16(I))); - } - diff = vgetq_lane_u64(sum, 0) + vgetq_lane_u64(sum, 1); - for (; i < len; ++i) { - const int diff_y = ref[i] - src[i]; - const int new_y = (int)(dst[i]) + diff_y; - dst[i] = clip_NEON(new_y, max_y); - diff += (uint64_t)(abs(diff_y)); - } - return diff; -} - -static void SharpYuvUpdateRGB_NEON(const int16_t* ref, const int16_t* src, - int16_t* dst, int len) { - int i; - for (i = 0; i + 8 <= len; i += 8) { - const int16x8_t A = vld1q_s16(ref + i); - const int16x8_t B = vld1q_s16(src + i); - const int16x8_t C = vld1q_s16(dst + i); - const int16x8_t D = vsubq_s16(A, B); // diff_uv - const int16x8_t E = vaddq_s16(C, D); // new_uv - vst1q_s16(dst + i, E); - } - for (; i < len; ++i) { - const int diff_uv = ref[i] - src[i]; - dst[i] += diff_uv; - } -} - -static void SharpYuvFilterRow16_NEON(const int16_t* A, const int16_t* B, - int len, const uint16_t* best_y, - uint16_t* out, int bit_depth) { - const int max_y = (1 << bit_depth) - 1; - int i; - const int16x8_t max = vdupq_n_s16(max_y); - const int16x8_t zero = vdupq_n_s16(0); - for (i = 0; i + 8 <= len; i += 8) { - const int16x8_t a0 = vld1q_s16(A + i + 0); - const int16x8_t a1 = vld1q_s16(A + i + 1); - const int16x8_t b0 = vld1q_s16(B + i + 0); - const int16x8_t b1 = vld1q_s16(B + i + 1); - const int16x8_t a0b1 = vaddq_s16(a0, b1); - const int16x8_t a1b0 = vaddq_s16(a1, b0); - const int16x8_t a0a1b0b1 = vaddq_s16(a0b1, a1b0); // A0+A1+B0+B1 - const int16x8_t a0b1_2 = vaddq_s16(a0b1, a0b1); // 2*(A0+B1) - const int16x8_t a1b0_2 = vaddq_s16(a1b0, a1b0); // 2*(A1+B0) - const int16x8_t c0 = vshrq_n_s16(vaddq_s16(a0b1_2, a0a1b0b1), 3); - const int16x8_t c1 = vshrq_n_s16(vaddq_s16(a1b0_2, a0a1b0b1), 3); - const int16x8_t e0 = vrhaddq_s16(c1, a0); - const int16x8_t e1 = vrhaddq_s16(c0, a1); - const int16x8x2_t f = vzipq_s16(e0, e1); - const int16x8_t g0 = vreinterpretq_s16_u16(vld1q_u16(best_y + 2 * i + 0)); - const int16x8_t g1 = vreinterpretq_s16_u16(vld1q_u16(best_y + 2 * i + 8)); - const int16x8_t h0 = vaddq_s16(g0, f.val[0]); - const int16x8_t h1 = vaddq_s16(g1, f.val[1]); - const int16x8_t i0 = vmaxq_s16(vminq_s16(h0, max), zero); - const int16x8_t i1 = vmaxq_s16(vminq_s16(h1, max), zero); - vst1q_u16(out + 2 * i + 0, vreinterpretq_u16_s16(i0)); - vst1q_u16(out + 2 * i + 8, vreinterpretq_u16_s16(i1)); - } - for (; i < len; ++i) { - const int a0b1 = A[i + 0] + B[i + 1]; - const int a1b0 = A[i + 1] + B[i + 0]; - const int a0a1b0b1 = a0b1 + a1b0 + 8; - const int v0 = (8 * A[i + 0] + 2 * a1b0 + a0a1b0b1) >> 4; - const int v1 = (8 * A[i + 1] + 2 * a0b1 + a0a1b0b1) >> 4; - out[2 * i + 0] = clip_NEON(best_y[2 * i + 0] + v0, max_y); - out[2 * i + 1] = clip_NEON(best_y[2 * i + 1] + v1, max_y); - } -} - -static void SharpYuvFilterRow32_NEON(const int16_t* A, const int16_t* B, - int len, const uint16_t* best_y, - uint16_t* out, int bit_depth) { - const int max_y = (1 << bit_depth) - 1; - int i; - const uint16x8_t max = vdupq_n_u16(max_y); - for (i = 0; i + 4 <= len; i += 4) { - const int16x4_t a0 = vld1_s16(A + i + 0); - const int16x4_t a1 = vld1_s16(A + i + 1); - const int16x4_t b0 = vld1_s16(B + i + 0); - const int16x4_t b1 = vld1_s16(B + i + 1); - const int32x4_t a0b1 = vaddl_s16(a0, b1); - const int32x4_t a1b0 = vaddl_s16(a1, b0); - const int32x4_t a0a1b0b1 = vaddq_s32(a0b1, a1b0); // A0+A1+B0+B1 - const int32x4_t a0b1_2 = vaddq_s32(a0b1, a0b1); // 2*(A0+B1) - const int32x4_t a1b0_2 = vaddq_s32(a1b0, a1b0); // 2*(A1+B0) - const int32x4_t c0 = vshrq_n_s32(vaddq_s32(a0b1_2, a0a1b0b1), 3); - const int32x4_t c1 = vshrq_n_s32(vaddq_s32(a1b0_2, a0a1b0b1), 3); - const int32x4_t e0 = vrhaddq_s32(c1, vmovl_s16(a0)); - const int32x4_t e1 = vrhaddq_s32(c0, vmovl_s16(a1)); - const int32x4x2_t f = vzipq_s32(e0, e1); - - const int16x8_t g = vreinterpretq_s16_u16(vld1q_u16(best_y + 2 * i)); - const int32x4_t h0 = vaddw_s16(f.val[0], vget_low_s16(g)); - const int32x4_t h1 = vaddw_s16(f.val[1], vget_high_s16(g)); - const uint16x8_t i_16 = vcombine_u16(vqmovun_s32(h0), vqmovun_s32(h1)); - const uint16x8_t i_clamped = vminq_u16(i_16, max); - vst1q_u16(out + 2 * i + 0, i_clamped); - } - for (; i < len; ++i) { - const int a0b1 = A[i + 0] + B[i + 1]; - const int a1b0 = A[i + 1] + B[i + 0]; - const int a0a1b0b1 = a0b1 + a1b0 + 8; - const int v0 = (8 * A[i + 0] + 2 * a1b0 + a0a1b0b1) >> 4; - const int v1 = (8 * A[i + 1] + 2 * a0b1 + a0a1b0b1) >> 4; - out[2 * i + 0] = clip_NEON(best_y[2 * i + 0] + v0, max_y); - out[2 * i + 1] = clip_NEON(best_y[2 * i + 1] + v1, max_y); - } -} - -static void SharpYuvFilterRow_NEON(const int16_t* A, const int16_t* B, int len, - const uint16_t* best_y, uint16_t* out, - int bit_depth) { - if (bit_depth <= 10) { - SharpYuvFilterRow16_NEON(A, B, len, best_y, out, bit_depth); - } else { - SharpYuvFilterRow32_NEON(A, B, len, best_y, out, bit_depth); - } -} - -//------------------------------------------------------------------------------ - -extern void InitSharpYuvNEON(void); - -WEBP_TSAN_IGNORE_FUNCTION void InitSharpYuvNEON(void) { - SharpYuvUpdateY = SharpYuvUpdateY_NEON; - SharpYuvUpdateRGB = SharpYuvUpdateRGB_NEON; - SharpYuvFilterRow = SharpYuvFilterRow_NEON; -} - -#else // !WEBP_USE_NEON - -extern void InitSharpYuvNEON(void); - -void InitSharpYuvNEON(void) {} - -#endif // WEBP_USE_NEON diff --git a/libwebp/sharpyuv/sharpyuv_sse2.c b/libwebp/sharpyuv/sharpyuv_sse2.c deleted file mode 100644 index 9744d1bb..00000000 --- a/libwebp/sharpyuv/sharpyuv_sse2.c +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright 2022 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Speed-critical functions for Sharp YUV. -// -// Author: Skal (pascal.massimino@gmail.com) - -#include "sharpyuv/sharpyuv_dsp.h" - -#if defined(WEBP_USE_SSE2) -#include -#include - -static uint16_t clip_SSE2(int v, int max) { - return (v < 0) ? 0 : (v > max) ? max : (uint16_t)v; -} - -static uint64_t SharpYuvUpdateY_SSE2(const uint16_t* ref, const uint16_t* src, - uint16_t* dst, int len, int bit_depth) { - const int max_y = (1 << bit_depth) - 1; - uint64_t diff = 0; - uint32_t tmp[4]; - int i; - const __m128i zero = _mm_setzero_si128(); - const __m128i max = _mm_set1_epi16(max_y); - const __m128i one = _mm_set1_epi16(1); - __m128i sum = zero; - - for (i = 0; i + 8 <= len; i += 8) { - const __m128i A = _mm_loadu_si128((const __m128i*)(ref + i)); - const __m128i B = _mm_loadu_si128((const __m128i*)(src + i)); - const __m128i C = _mm_loadu_si128((const __m128i*)(dst + i)); - const __m128i D = _mm_sub_epi16(A, B); // diff_y - const __m128i E = _mm_cmpgt_epi16(zero, D); // sign (-1 or 0) - const __m128i F = _mm_add_epi16(C, D); // new_y - const __m128i G = _mm_or_si128(E, one); // -1 or 1 - const __m128i H = _mm_max_epi16(_mm_min_epi16(F, max), zero); - const __m128i I = _mm_madd_epi16(D, G); // sum(abs(...)) - _mm_storeu_si128((__m128i*)(dst + i), H); - sum = _mm_add_epi32(sum, I); - } - _mm_storeu_si128((__m128i*)tmp, sum); - diff = tmp[3] + tmp[2] + tmp[1] + tmp[0]; - for (; i < len; ++i) { - const int diff_y = ref[i] - src[i]; - const int new_y = (int)dst[i] + diff_y; - dst[i] = clip_SSE2(new_y, max_y); - diff += (uint64_t)abs(diff_y); - } - return diff; -} - -static void SharpYuvUpdateRGB_SSE2(const int16_t* ref, const int16_t* src, - int16_t* dst, int len) { - int i = 0; - for (i = 0; i + 8 <= len; i += 8) { - const __m128i A = _mm_loadu_si128((const __m128i*)(ref + i)); - const __m128i B = _mm_loadu_si128((const __m128i*)(src + i)); - const __m128i C = _mm_loadu_si128((const __m128i*)(dst + i)); - const __m128i D = _mm_sub_epi16(A, B); // diff_uv - const __m128i E = _mm_add_epi16(C, D); // new_uv - _mm_storeu_si128((__m128i*)(dst + i), E); - } - for (; i < len; ++i) { - const int diff_uv = ref[i] - src[i]; - dst[i] += diff_uv; - } -} - -static void SharpYuvFilterRow16_SSE2(const int16_t* A, const int16_t* B, - int len, const uint16_t* best_y, - uint16_t* out, int bit_depth) { - const int max_y = (1 << bit_depth) - 1; - int i; - const __m128i kCst8 = _mm_set1_epi16(8); - const __m128i max = _mm_set1_epi16(max_y); - const __m128i zero = _mm_setzero_si128(); - for (i = 0; i + 8 <= len; i += 8) { - const __m128i a0 = _mm_loadu_si128((const __m128i*)(A + i + 0)); - const __m128i a1 = _mm_loadu_si128((const __m128i*)(A + i + 1)); - const __m128i b0 = _mm_loadu_si128((const __m128i*)(B + i + 0)); - const __m128i b1 = _mm_loadu_si128((const __m128i*)(B + i + 1)); - const __m128i a0b1 = _mm_add_epi16(a0, b1); - const __m128i a1b0 = _mm_add_epi16(a1, b0); - const __m128i a0a1b0b1 = _mm_add_epi16(a0b1, a1b0); // A0+A1+B0+B1 - const __m128i a0a1b0b1_8 = _mm_add_epi16(a0a1b0b1, kCst8); - const __m128i a0b1_2 = _mm_add_epi16(a0b1, a0b1); // 2*(A0+B1) - const __m128i a1b0_2 = _mm_add_epi16(a1b0, a1b0); // 2*(A1+B0) - const __m128i c0 = _mm_srai_epi16(_mm_add_epi16(a0b1_2, a0a1b0b1_8), 3); - const __m128i c1 = _mm_srai_epi16(_mm_add_epi16(a1b0_2, a0a1b0b1_8), 3); - const __m128i d0 = _mm_add_epi16(c1, a0); - const __m128i d1 = _mm_add_epi16(c0, a1); - const __m128i e0 = _mm_srai_epi16(d0, 1); - const __m128i e1 = _mm_srai_epi16(d1, 1); - const __m128i f0 = _mm_unpacklo_epi16(e0, e1); - const __m128i f1 = _mm_unpackhi_epi16(e0, e1); - const __m128i g0 = _mm_loadu_si128((const __m128i*)(best_y + 2 * i + 0)); - const __m128i g1 = _mm_loadu_si128((const __m128i*)(best_y + 2 * i + 8)); - const __m128i h0 = _mm_add_epi16(g0, f0); - const __m128i h1 = _mm_add_epi16(g1, f1); - const __m128i i0 = _mm_max_epi16(_mm_min_epi16(h0, max), zero); - const __m128i i1 = _mm_max_epi16(_mm_min_epi16(h1, max), zero); - _mm_storeu_si128((__m128i*)(out + 2 * i + 0), i0); - _mm_storeu_si128((__m128i*)(out + 2 * i + 8), i1); - } - for (; i < len; ++i) { - // (9 * A0 + 3 * A1 + 3 * B0 + B1 + 8) >> 4 = - // = (8 * A0 + 2 * (A1 + B0) + (A0 + A1 + B0 + B1 + 8)) >> 4 - // We reuse the common sub-expressions. - const int a0b1 = A[i + 0] + B[i + 1]; - const int a1b0 = A[i + 1] + B[i + 0]; - const int a0a1b0b1 = a0b1 + a1b0 + 8; - const int v0 = (8 * A[i + 0] + 2 * a1b0 + a0a1b0b1) >> 4; - const int v1 = (8 * A[i + 1] + 2 * a0b1 + a0a1b0b1) >> 4; - out[2 * i + 0] = clip_SSE2(best_y[2 * i + 0] + v0, max_y); - out[2 * i + 1] = clip_SSE2(best_y[2 * i + 1] + v1, max_y); - } -} - -static WEBP_INLINE __m128i s16_to_s32(__m128i in) { - return _mm_srai_epi32(_mm_unpacklo_epi16(in, in), 16); -} - -static void SharpYuvFilterRow32_SSE2(const int16_t* A, const int16_t* B, - int len, const uint16_t* best_y, - uint16_t* out, int bit_depth) { - const int max_y = (1 << bit_depth) - 1; - int i; - const __m128i kCst8 = _mm_set1_epi32(8); - const __m128i max = _mm_set1_epi16(max_y); - const __m128i zero = _mm_setzero_si128(); - for (i = 0; i + 4 <= len; i += 4) { - const __m128i a0 = s16_to_s32(_mm_loadl_epi64((const __m128i*)(A + i + 0))); - const __m128i a1 = s16_to_s32(_mm_loadl_epi64((const __m128i*)(A + i + 1))); - const __m128i b0 = s16_to_s32(_mm_loadl_epi64((const __m128i*)(B + i + 0))); - const __m128i b1 = s16_to_s32(_mm_loadl_epi64((const __m128i*)(B + i + 1))); - const __m128i a0b1 = _mm_add_epi32(a0, b1); - const __m128i a1b0 = _mm_add_epi32(a1, b0); - const __m128i a0a1b0b1 = _mm_add_epi32(a0b1, a1b0); // A0+A1+B0+B1 - const __m128i a0a1b0b1_8 = _mm_add_epi32(a0a1b0b1, kCst8); - const __m128i a0b1_2 = _mm_add_epi32(a0b1, a0b1); // 2*(A0+B1) - const __m128i a1b0_2 = _mm_add_epi32(a1b0, a1b0); // 2*(A1+B0) - const __m128i c0 = _mm_srai_epi32(_mm_add_epi32(a0b1_2, a0a1b0b1_8), 3); - const __m128i c1 = _mm_srai_epi32(_mm_add_epi32(a1b0_2, a0a1b0b1_8), 3); - const __m128i d0 = _mm_add_epi32(c1, a0); - const __m128i d1 = _mm_add_epi32(c0, a1); - const __m128i e0 = _mm_srai_epi32(d0, 1); - const __m128i e1 = _mm_srai_epi32(d1, 1); - const __m128i f0 = _mm_unpacklo_epi32(e0, e1); - const __m128i f1 = _mm_unpackhi_epi32(e0, e1); - const __m128i g = _mm_loadu_si128((const __m128i*)(best_y + 2 * i + 0)); - const __m128i h_16 = _mm_add_epi16(g, _mm_packs_epi32(f0, f1)); - const __m128i final = _mm_max_epi16(_mm_min_epi16(h_16, max), zero); - _mm_storeu_si128((__m128i*)(out + 2 * i + 0), final); - } - for (; i < len; ++i) { - // (9 * A0 + 3 * A1 + 3 * B0 + B1 + 8) >> 4 = - // = (8 * A0 + 2 * (A1 + B0) + (A0 + A1 + B0 + B1 + 8)) >> 4 - // We reuse the common sub-expressions. - const int a0b1 = A[i + 0] + B[i + 1]; - const int a1b0 = A[i + 1] + B[i + 0]; - const int a0a1b0b1 = a0b1 + a1b0 + 8; - const int v0 = (8 * A[i + 0] + 2 * a1b0 + a0a1b0b1) >> 4; - const int v1 = (8 * A[i + 1] + 2 * a0b1 + a0a1b0b1) >> 4; - out[2 * i + 0] = clip_SSE2(best_y[2 * i + 0] + v0, max_y); - out[2 * i + 1] = clip_SSE2(best_y[2 * i + 1] + v1, max_y); - } -} - -static void SharpYuvFilterRow_SSE2(const int16_t* A, const int16_t* B, int len, - const uint16_t* best_y, uint16_t* out, - int bit_depth) { - if (bit_depth <= 10) { - SharpYuvFilterRow16_SSE2(A, B, len, best_y, out, bit_depth); - } else { - SharpYuvFilterRow32_SSE2(A, B, len, best_y, out, bit_depth); - } -} - -//------------------------------------------------------------------------------ - -extern void InitSharpYuvSSE2(void); - -WEBP_TSAN_IGNORE_FUNCTION void InitSharpYuvSSE2(void) { - SharpYuvUpdateY = SharpYuvUpdateY_SSE2; - SharpYuvUpdateRGB = SharpYuvUpdateRGB_SSE2; - SharpYuvFilterRow = SharpYuvFilterRow_SSE2; -} -#else // !WEBP_USE_SSE2 - -extern void InitSharpYuvSSE2(void); - -void InitSharpYuvSSE2(void) {} - -#endif // WEBP_USE_SSE2 diff --git a/libwebp/src/Makefile.am b/libwebp/src/Makefile.am deleted file mode 100644 index bc4a320a..00000000 --- a/libwebp/src/Makefile.am +++ /dev/null @@ -1,55 +0,0 @@ -# The mux and demux libraries depend on libwebp, thus the '.' to force -# the build order so it's available to them. -SUBDIRS = dec enc dsp utils . -if BUILD_MUX - SUBDIRS += mux -endif -if BUILD_DEMUX - SUBDIRS += demux -endif - -lib_LTLIBRARIES = libwebp.la - -if BUILD_LIBWEBPDECODER - lib_LTLIBRARIES += libwebpdecoder.la -endif - -common_HEADERS = -common_HEADERS += webp/decode.h -common_HEADERS += webp/types.h -commondir = $(includedir)/webp - -libwebp_la_SOURCES = -libwebpinclude_HEADERS = -libwebpinclude_HEADERS += webp/encode.h - -noinst_HEADERS = -noinst_HEADERS += webp/format_constants.h - -libwebp_la_LIBADD = -libwebp_la_LIBADD += dec/libwebpdecode.la -libwebp_la_LIBADD += dsp/libwebpdsp.la -libwebp_la_LIBADD += enc/libwebpencode.la -libwebp_la_LIBADD += utils/libwebputils.la - -# Use '-no-undefined' to declare that libwebp does not depend on any libraries -# other than the ones listed on the command line, i.e., after linking, it will -# not have unresolved symbols. Some platforms (Windows among them) require all -# symbols in shared libraries to be resolved at library creation. -libwebp_la_LDFLAGS = -no-undefined -version-info 8:8:1 -libwebpincludedir = $(includedir)/webp -pkgconfig_DATA = libwebp.pc - -if BUILD_LIBWEBPDECODER - libwebpdecoder_la_SOURCES = - - libwebpdecoder_la_LIBADD = - libwebpdecoder_la_LIBADD += dec/libwebpdecode.la - libwebpdecoder_la_LIBADD += dsp/libwebpdspdecode.la - libwebpdecoder_la_LIBADD += utils/libwebputilsdecode.la - - libwebpdecoder_la_LDFLAGS = -no-undefined -version-info 4:8:1 - pkgconfig_DATA += libwebpdecoder.pc -endif - -${pkgconfig_DATA}: ${top_builddir}/config.status diff --git a/libwebp/src/dec/Makefile.am b/libwebp/src/dec/Makefile.am deleted file mode 100644 index f8c6398d..00000000 --- a/libwebp/src/dec/Makefile.am +++ /dev/null @@ -1,29 +0,0 @@ -AM_CPPFLAGS += -I$(top_builddir) -I$(top_srcdir) -noinst_LTLIBRARIES = libwebpdecode.la - -libwebpdecode_la_SOURCES = -libwebpdecode_la_SOURCES += alpha_dec.c -libwebpdecode_la_SOURCES += alphai_dec.h -libwebpdecode_la_SOURCES += buffer_dec.c -libwebpdecode_la_SOURCES += common_dec.h -libwebpdecode_la_SOURCES += vp8_dec.h -libwebpdecode_la_SOURCES += frame_dec.c -libwebpdecode_la_SOURCES += idec_dec.c -libwebpdecode_la_SOURCES += io_dec.c -libwebpdecode_la_SOURCES += quant_dec.c -libwebpdecode_la_SOURCES += tree_dec.c -libwebpdecode_la_SOURCES += vp8_dec.c -libwebpdecode_la_SOURCES += vp8i_dec.h -libwebpdecode_la_SOURCES += vp8l_dec.c -libwebpdecode_la_SOURCES += vp8li_dec.h -libwebpdecode_la_SOURCES += webp_dec.c -libwebpdecode_la_SOURCES += webpi_dec.h - -libwebpdecodeinclude_HEADERS = -libwebpdecodeinclude_HEADERS += ../webp/decode.h -libwebpdecodeinclude_HEADERS += ../webp/types.h -noinst_HEADERS = -noinst_HEADERS += ../webp/format_constants.h - -libwebpdecode_la_CPPFLAGS = $(AM_CPPFLAGS) -libwebpdecodeincludedir = $(includedir)/webp diff --git a/libwebp/src/dec/alpha_dec.c b/libwebp/src/dec/alpha_dec.c index b6c874fb..d90bfd2b 100644 --- a/libwebp/src/dec/alpha_dec.c +++ b/libwebp/src/dec/alpha_dec.c @@ -11,14 +11,18 @@ // // Author: Skal (pascal.massimino@gmail.com) +#include #include + #include "src/dec/alphai_dec.h" #include "src/dec/vp8_dec.h" #include "src/dec/vp8i_dec.h" #include "src/dec/vp8li_dec.h" +#include "src/dec/webpi_dec.h" #include "src/dsp/dsp.h" #include "src/utils/quant_levels_dec_utils.h" #include "src/utils/utils.h" +#include "src/webp/decode.h" #include "src/webp/format_constants.h" #include "src/webp/types.h" @@ -34,8 +38,8 @@ WEBP_NODISCARD static ALPHDecoder* ALPHNew(void) { // Clears and deallocates an alpha decoder instance. static void ALPHDelete(ALPHDecoder* const dec) { if (dec != NULL) { - VP8LDelete(dec->vp8l_dec_); - dec->vp8l_dec_ = NULL; + VP8LDelete(dec->vp8l_dec); + dec->vp8l_dec = NULL; WebPSafeFree(dec); } } @@ -54,28 +58,28 @@ WEBP_NODISCARD static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data, const uint8_t* const alpha_data = data + ALPHA_HEADER_LEN; const size_t alpha_data_size = data_size - ALPHA_HEADER_LEN; int rsrv; - VP8Io* const io = &dec->io_; + VP8Io* const io = &dec->io; assert(data != NULL && output != NULL && src_io != NULL); VP8FiltersInit(); - dec->output_ = output; - dec->width_ = src_io->width; - dec->height_ = src_io->height; - assert(dec->width_ > 0 && dec->height_ > 0); + dec->output = output; + dec->width = src_io->width; + dec->height = src_io->height; + assert(dec->width > 0 && dec->height > 0); if (data_size <= ALPHA_HEADER_LEN) { return 0; } - dec->method_ = (data[0] >> 0) & 0x03; - dec->filter_ = (WEBP_FILTER_TYPE)((data[0] >> 2) & 0x03); - dec->pre_processing_ = (data[0] >> 4) & 0x03; + dec->method = (data[0] >> 0) & 0x03; + dec->filter = (WEBP_FILTER_TYPE)((data[0] >> 2) & 0x03); + dec->pre_processing = (data[0] >> 4) & 0x03; rsrv = (data[0] >> 6) & 0x03; - if (dec->method_ < ALPHA_NO_COMPRESSION || - dec->method_ > ALPHA_LOSSLESS_COMPRESSION || - dec->filter_ >= WEBP_FILTER_LAST || - dec->pre_processing_ > ALPHA_PREPROCESSED_LEVELS || + if (dec->method < ALPHA_NO_COMPRESSION || + dec->method > ALPHA_LOSSLESS_COMPRESSION || + dec->filter >= WEBP_FILTER_LAST || + dec->pre_processing > ALPHA_PREPROCESSED_LEVELS || rsrv != 0) { return 0; } @@ -96,11 +100,11 @@ WEBP_NODISCARD static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data, io->crop_bottom = src_io->crop_bottom; // No need to copy the scaling parameters. - if (dec->method_ == ALPHA_NO_COMPRESSION) { - const size_t alpha_decoded_size = dec->width_ * dec->height_; + if (dec->method == ALPHA_NO_COMPRESSION) { + const size_t alpha_decoded_size = dec->width * dec->height; ok = (alpha_data_size >= alpha_decoded_size); } else { - assert(dec->method_ == ALPHA_LOSSLESS_COMPRESSION); + assert(dec->method == ALPHA_LOSSLESS_COMPRESSION); ok = VP8LDecodeAlphaHeader(dec, alpha_data, alpha_data_size); } @@ -113,32 +117,32 @@ WEBP_NODISCARD static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data, // Returns false in case of bitstream error. WEBP_NODISCARD static int ALPHDecode(VP8Decoder* const dec, int row, int num_rows) { - ALPHDecoder* const alph_dec = dec->alph_dec_; - const int width = alph_dec->width_; - const int height = alph_dec->io_.crop_bottom; - if (alph_dec->method_ == ALPHA_NO_COMPRESSION) { + ALPHDecoder* const alph_dec = dec->alph_dec; + const int width = alph_dec->width; + const int height = alph_dec->io.crop_bottom; + if (alph_dec->method == ALPHA_NO_COMPRESSION) { int y; - const uint8_t* prev_line = dec->alpha_prev_line_; - const uint8_t* deltas = dec->alpha_data_ + ALPHA_HEADER_LEN + row * width; - uint8_t* dst = dec->alpha_plane_ + row * width; - assert(deltas <= &dec->alpha_data_[dec->alpha_data_size_]); - assert(WebPUnfilters[alph_dec->filter_] != NULL); + const uint8_t* prev_line = dec->alpha_prev_line; + const uint8_t* deltas = dec->alpha_data + ALPHA_HEADER_LEN + row * width; + uint8_t* dst = dec->alpha_plane + row * width; + assert(deltas <= &dec->alpha_data[dec->alpha_data_size]); + assert(WebPUnfilters[alph_dec->filter] != NULL); for (y = 0; y < num_rows; ++y) { - WebPUnfilters[alph_dec->filter_](prev_line, deltas, dst, width); + WebPUnfilters[alph_dec->filter](prev_line, deltas, dst, width); prev_line = dst; dst += width; deltas += width; } - dec->alpha_prev_line_ = prev_line; - } else { // alph_dec->method_ == ALPHA_LOSSLESS_COMPRESSION - assert(alph_dec->vp8l_dec_ != NULL); + dec->alpha_prev_line = prev_line; + } else { // alph_dec->method == ALPHA_LOSSLESS_COMPRESSION + assert(alph_dec->vp8l_dec != NULL); if (!VP8LDecodeAlphaImageStream(alph_dec, row + num_rows)) { return 0; } } if (row + num_rows >= height) { - dec->is_alpha_decoded_ = 1; + dec->is_alpha_decoded = 1; } return 1; } @@ -148,25 +152,25 @@ WEBP_NODISCARD static int AllocateAlphaPlane(VP8Decoder* const dec, const int stride = io->width; const int height = io->crop_bottom; const uint64_t alpha_size = (uint64_t)stride * height; - assert(dec->alpha_plane_mem_ == NULL); - dec->alpha_plane_mem_ = - (uint8_t*)WebPSafeMalloc(alpha_size, sizeof(*dec->alpha_plane_)); - if (dec->alpha_plane_mem_ == NULL) { + assert(dec->alpha_plane_mem == NULL); + dec->alpha_plane_mem = + (uint8_t*)WebPSafeMalloc(alpha_size, sizeof(*dec->alpha_plane)); + if (dec->alpha_plane_mem == NULL) { return VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY, "Alpha decoder initialization failed."); } - dec->alpha_plane_ = dec->alpha_plane_mem_; - dec->alpha_prev_line_ = NULL; + dec->alpha_plane = dec->alpha_plane_mem; + dec->alpha_prev_line = NULL; return 1; } void WebPDeallocateAlphaMemory(VP8Decoder* const dec) { assert(dec != NULL); - WebPSafeFree(dec->alpha_plane_mem_); - dec->alpha_plane_mem_ = NULL; - dec->alpha_plane_ = NULL; - ALPHDelete(dec->alph_dec_); - dec->alph_dec_ = NULL; + WebPSafeFree(dec->alpha_plane_mem); + dec->alpha_plane_mem = NULL; + dec->alpha_plane = NULL; + ALPHDelete(dec->alph_dec); + dec->alph_dec = NULL; } //------------------------------------------------------------------------------ @@ -184,46 +188,46 @@ WEBP_NODISCARD const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec, return NULL; } - if (!dec->is_alpha_decoded_) { - if (dec->alph_dec_ == NULL) { // Initialize decoder. - dec->alph_dec_ = ALPHNew(); - if (dec->alph_dec_ == NULL) { + if (!dec->is_alpha_decoded) { + if (dec->alph_dec == NULL) { // Initialize decoder. + dec->alph_dec = ALPHNew(); + if (dec->alph_dec == NULL) { VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY, "Alpha decoder initialization failed."); return NULL; } if (!AllocateAlphaPlane(dec, io)) goto Error; - if (!ALPHInit(dec->alph_dec_, dec->alpha_data_, dec->alpha_data_size_, - io, dec->alpha_plane_)) { - VP8LDecoder* const vp8l_dec = dec->alph_dec_->vp8l_dec_; + if (!ALPHInit(dec->alph_dec, dec->alpha_data, dec->alpha_data_size, + io, dec->alpha_plane)) { + VP8LDecoder* const vp8l_dec = dec->alph_dec->vp8l_dec; VP8SetError(dec, (vp8l_dec == NULL) ? VP8_STATUS_OUT_OF_MEMORY - : vp8l_dec->status_, + : vp8l_dec->status, "Alpha decoder initialization failed."); goto Error; } // if we allowed use of alpha dithering, check whether it's needed at all - if (dec->alph_dec_->pre_processing_ != ALPHA_PREPROCESSED_LEVELS) { - dec->alpha_dithering_ = 0; // disable dithering + if (dec->alph_dec->pre_processing != ALPHA_PREPROCESSED_LEVELS) { + dec->alpha_dithering = 0; // disable dithering } else { num_rows = height - row; // decode everything in one pass } } - assert(dec->alph_dec_ != NULL); + assert(dec->alph_dec != NULL); assert(row + num_rows <= height); if (!ALPHDecode(dec, row, num_rows)) goto Error; - if (dec->is_alpha_decoded_) { // finished? - ALPHDelete(dec->alph_dec_); - dec->alph_dec_ = NULL; - if (dec->alpha_dithering_ > 0) { - uint8_t* const alpha = dec->alpha_plane_ + io->crop_top * width + if (dec->is_alpha_decoded) { // finished? + ALPHDelete(dec->alph_dec); + dec->alph_dec = NULL; + if (dec->alpha_dithering > 0) { + uint8_t* const alpha = dec->alpha_plane + io->crop_top * width + io->crop_left; if (!WebPDequantizeLevels(alpha, io->crop_right - io->crop_left, io->crop_bottom - io->crop_top, - width, dec->alpha_dithering_)) { + width, dec->alpha_dithering)) { goto Error; } } @@ -231,7 +235,7 @@ WEBP_NODISCARD const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec, } // Return a pointer to the current decoded row. - return dec->alpha_plane_ + row * width; + return dec->alpha_plane + row * width; Error: WebPDeallocateAlphaMemory(dec); diff --git a/libwebp/src/dec/alphai_dec.h b/libwebp/src/dec/alphai_dec.h index a64104ab..49150318 100644 --- a/libwebp/src/dec/alphai_dec.h +++ b/libwebp/src/dec/alphai_dec.h @@ -14,7 +14,10 @@ #ifndef WEBP_DEC_ALPHAI_DEC_H_ #define WEBP_DEC_ALPHAI_DEC_H_ +#include "src/dec/vp8_dec.h" +#include "src/webp/types.h" #include "src/dec/webpi_dec.h" +#include "src/dsp/dsp.h" #include "src/utils/filters_utils.h" #ifdef __cplusplus @@ -25,24 +28,24 @@ struct VP8LDecoder; // Defined in dec/vp8li.h. typedef struct ALPHDecoder ALPHDecoder; struct ALPHDecoder { - int width_; - int height_; - int method_; - WEBP_FILTER_TYPE filter_; - int pre_processing_; - struct VP8LDecoder* vp8l_dec_; - VP8Io io_; - int use_8b_decode_; // Although alpha channel requires only 1 byte per + int width; + int height; + int method; + WEBP_FILTER_TYPE filter; + int pre_processing; + struct VP8LDecoder* vp8l_dec; + VP8Io io; + int use_8b_decode; // Although alpha channel requires only 1 byte per // pixel, sometimes VP8LDecoder may need to allocate // 4 bytes per pixel internally during decode. - uint8_t* output_; - const uint8_t* prev_line_; // last output row (or NULL) + uint8_t* output; + const uint8_t* prev_line; // last output row (or NULL) }; //------------------------------------------------------------------------------ // internal functions. Not public. -// Deallocate memory associated to dec->alpha_plane_ decoding +// Deallocate memory associated to dec->alpha_plane decoding void WebPDeallocateAlphaMemory(VP8Decoder* const dec); //------------------------------------------------------------------------------ diff --git a/libwebp/src/dec/buffer_dec.c b/libwebp/src/dec/buffer_dec.c index 11ce76f1..290f7ab3 100644 --- a/libwebp/src/dec/buffer_dec.c +++ b/libwebp/src/dec/buffer_dec.c @@ -11,11 +11,16 @@ // // Author: Skal (pascal.massimino@gmail.com) +#include #include +#include #include "src/dec/vp8i_dec.h" #include "src/dec/webpi_dec.h" +#include "src/utils/rescaler_utils.h" #include "src/utils/utils.h" +#include "src/webp/decode.h" +#include "src/webp/types.h" //------------------------------------------------------------------------------ // WebPDecBuffer @@ -26,10 +31,9 @@ static const uint8_t kModeBpp[MODE_LAST] = { 4, 4, 4, 2, // pre-multiplied modes 1, 1 }; -// Check that webp_csp_mode is within the bounds of WEBP_CSP_MODE. // Convert to an integer to handle both the unsigned/signed enum cases // without the need for casting to remove type limit warnings. -static int IsValidColorspace(int webp_csp_mode) { +int IsValidColorspace(int webp_csp_mode) { return (webp_csp_mode >= MODE_RGB && webp_csp_mode < MODE_LAST); } diff --git a/libwebp/src/dec/common_dec.h b/libwebp/src/dec/common_dec.h index b158550a..4a581cb3 100644 --- a/libwebp/src/dec/common_dec.h +++ b/libwebp/src/dec/common_dec.h @@ -51,4 +51,7 @@ enum { MB_FEATURE_TREE_PROBS = 3, NUM_PROBAS = 11 }; +// Check that webp_csp_mode is within the bounds of WEBP_CSP_MODE. +int IsValidColorspace(int webp_csp_mode); + #endif // WEBP_DEC_COMMON_DEC_H_ diff --git a/libwebp/src/dec/frame_dec.c b/libwebp/src/dec/frame_dec.c index 91ca1f86..87807722 100644 --- a/libwebp/src/dec/frame_dec.c +++ b/libwebp/src/dec/frame_dec.c @@ -11,9 +11,20 @@ // // Author: Skal (pascal.massimino@gmail.com) +#include #include +#include + +#include "src/dec/common_dec.h" +#include "src/dec/vp8_dec.h" #include "src/dec/vp8i_dec.h" +#include "src/dec/webpi_dec.h" +#include "src/dsp/dsp.h" +#include "src/utils/random_utils.h" +#include "src/utils/thread_utils.h" #include "src/utils/utils.h" +#include "src/webp/decode.h" +#include "src/webp/types.h" //------------------------------------------------------------------------------ // Main reconstruction function. @@ -72,11 +83,11 @@ static void ReconstructRow(const VP8Decoder* const dec, const VP8ThreadContext* ctx) { int j; int mb_x; - const int mb_y = ctx->mb_y_; - const int cache_id = ctx->id_; - uint8_t* const y_dst = dec->yuv_b_ + Y_OFF; - uint8_t* const u_dst = dec->yuv_b_ + U_OFF; - uint8_t* const v_dst = dec->yuv_b_ + V_OFF; + const int mb_y = ctx->mb_y; + const int cache_id = ctx->id; + uint8_t* const y_dst = dec->yuv_b + Y_OFF; + uint8_t* const u_dst = dec->yuv_b + U_OFF; + uint8_t* const v_dst = dec->yuv_b + V_OFF; // Initialize left-most block. for (j = 0; j < 16; ++j) { @@ -99,8 +110,8 @@ static void ReconstructRow(const VP8Decoder* const dec, } // Reconstruct one row. - for (mb_x = 0; mb_x < dec->mb_w_; ++mb_x) { - const VP8MBData* const block = ctx->mb_data_ + mb_x; + for (mb_x = 0; mb_x < dec->mb_w; ++mb_x) { + const VP8MBData* const block = ctx->mb_data + mb_x; // Rotate in the left samples from previously decoded block. We move four // pixels at a time for alignment reason, and because of in-loop filter. @@ -115,9 +126,9 @@ static void ReconstructRow(const VP8Decoder* const dec, } { // bring top samples into the cache - VP8TopSamples* const top_yuv = dec->yuv_t_ + mb_x; - const int16_t* const coeffs = block->coeffs_; - uint32_t bits = block->non_zero_y_; + VP8TopSamples* const top_yuv = dec->yuv_t + mb_x; + const int16_t* const coeffs = block->coeffs; + uint32_t bits = block->non_zero_y; int n; if (mb_y > 0) { @@ -127,11 +138,11 @@ static void ReconstructRow(const VP8Decoder* const dec, } // predict and add residuals - if (block->is_i4x4_) { // 4x4 + if (block->is_i4x4) { // 4x4 uint32_t* const top_right = (uint32_t*)(y_dst - BPS + 16); if (mb_y > 0) { - if (mb_x >= dec->mb_w_ - 1) { // on rightmost border + if (mb_x >= dec->mb_w - 1) { // on rightmost border memset(top_right, top_yuv[0].y[15], sizeof(*top_right)); } else { memcpy(top_right, top_yuv[1].y, sizeof(*top_right)); @@ -143,11 +154,11 @@ static void ReconstructRow(const VP8Decoder* const dec, // predict and add residuals for all 4x4 blocks in turn. for (n = 0; n < 16; ++n, bits <<= 2) { uint8_t* const dst = y_dst + kScan[n]; - VP8PredLuma4[block->imodes_[n]](dst); + VP8PredLuma4[block->imodes[n]](dst); DoTransform(bits, coeffs + n * 16, dst); } } else { // 16x16 - const int pred_func = CheckMode(mb_x, mb_y, block->imodes_[0]); + const int pred_func = CheckMode(mb_x, mb_y, block->imodes[0]); VP8PredLuma16[pred_func](y_dst); if (bits != 0) { for (n = 0; n < 16; ++n, bits <<= 2) { @@ -157,8 +168,8 @@ static void ReconstructRow(const VP8Decoder* const dec, } { // Chroma - const uint32_t bits_uv = block->non_zero_uv_; - const int pred_func = CheckMode(mb_x, mb_y, block->uvmode_); + const uint32_t bits_uv = block->non_zero_uv; + const int pred_func = CheckMode(mb_x, mb_y, block->uvmode); VP8PredChroma8[pred_func](u_dst); VP8PredChroma8[pred_func](v_dst); DoUVTransform(bits_uv >> 0, coeffs + 16 * 16, u_dst); @@ -166,25 +177,25 @@ static void ReconstructRow(const VP8Decoder* const dec, } // stash away top samples for next block - if (mb_y < dec->mb_h_ - 1) { + if (mb_y < dec->mb_h - 1) { memcpy(top_yuv[0].y, y_dst + 15 * BPS, 16); memcpy(top_yuv[0].u, u_dst + 7 * BPS, 8); memcpy(top_yuv[0].v, v_dst + 7 * BPS, 8); } } - // Transfer reconstructed samples from yuv_b_ cache to final destination. + // Transfer reconstructed samples from yuv_b cache to final destination. { - const int y_offset = cache_id * 16 * dec->cache_y_stride_; - const int uv_offset = cache_id * 8 * dec->cache_uv_stride_; - uint8_t* const y_out = dec->cache_y_ + mb_x * 16 + y_offset; - uint8_t* const u_out = dec->cache_u_ + mb_x * 8 + uv_offset; - uint8_t* const v_out = dec->cache_v_ + mb_x * 8 + uv_offset; + const int y_offset = cache_id * 16 * dec->cache_y_stride; + const int uv_offset = cache_id * 8 * dec->cache_uv_stride; + uint8_t* const y_out = dec->cache_y + mb_x * 16 + y_offset; + uint8_t* const u_out = dec->cache_u + mb_x * 8 + uv_offset; + uint8_t* const v_out = dec->cache_v + mb_x * 8 + uv_offset; for (j = 0; j < 16; ++j) { - memcpy(y_out + j * dec->cache_y_stride_, y_dst + j * BPS, 16); + memcpy(y_out + j * dec->cache_y_stride, y_dst + j * BPS, 16); } for (j = 0; j < 8; ++j) { - memcpy(u_out + j * dec->cache_uv_stride_, u_dst + j * BPS, 8); - memcpy(v_out + j * dec->cache_uv_stride_, v_dst + j * BPS, 8); + memcpy(u_out + j * dec->cache_uv_stride, u_dst + j * BPS, 8); + memcpy(v_out + j * dec->cache_uv_stride, v_dst + j * BPS, 8); } } } @@ -201,40 +212,40 @@ static void ReconstructRow(const VP8Decoder* const dec, static const uint8_t kFilterExtraRows[3] = { 0, 2, 8 }; static void DoFilter(const VP8Decoder* const dec, int mb_x, int mb_y) { - const VP8ThreadContext* const ctx = &dec->thread_ctx_; - const int cache_id = ctx->id_; - const int y_bps = dec->cache_y_stride_; - const VP8FInfo* const f_info = ctx->f_info_ + mb_x; - uint8_t* const y_dst = dec->cache_y_ + cache_id * 16 * y_bps + mb_x * 16; - const int ilevel = f_info->f_ilevel_; - const int limit = f_info->f_limit_; + const VP8ThreadContext* const ctx = &dec->thread_ctx; + const int cache_id = ctx->id; + const int y_bps = dec->cache_y_stride; + const VP8FInfo* const f_info = ctx->f_info + mb_x; + uint8_t* const y_dst = dec->cache_y + cache_id * 16 * y_bps + mb_x * 16; + const int ilevel = f_info->f_ilevel; + const int limit = f_info->f_limit; if (limit == 0) { return; } assert(limit >= 3); - if (dec->filter_type_ == 1) { // simple + if (dec->filter_type == 1) { // simple if (mb_x > 0) { VP8SimpleHFilter16(y_dst, y_bps, limit + 4); } - if (f_info->f_inner_) { + if (f_info->f_inner) { VP8SimpleHFilter16i(y_dst, y_bps, limit); } if (mb_y > 0) { VP8SimpleVFilter16(y_dst, y_bps, limit + 4); } - if (f_info->f_inner_) { + if (f_info->f_inner) { VP8SimpleVFilter16i(y_dst, y_bps, limit); } } else { // complex - const int uv_bps = dec->cache_uv_stride_; - uint8_t* const u_dst = dec->cache_u_ + cache_id * 8 * uv_bps + mb_x * 8; - uint8_t* const v_dst = dec->cache_v_ + cache_id * 8 * uv_bps + mb_x * 8; - const int hev_thresh = f_info->hev_thresh_; + const int uv_bps = dec->cache_uv_stride; + uint8_t* const u_dst = dec->cache_u + cache_id * 8 * uv_bps + mb_x * 8; + uint8_t* const v_dst = dec->cache_v + cache_id * 8 * uv_bps + mb_x * 8; + const int hev_thresh = f_info->hev_thresh; if (mb_x > 0) { VP8HFilter16(y_dst, y_bps, limit + 4, ilevel, hev_thresh); VP8HFilter8(u_dst, v_dst, uv_bps, limit + 4, ilevel, hev_thresh); } - if (f_info->f_inner_) { + if (f_info->f_inner) { VP8HFilter16i(y_dst, y_bps, limit, ilevel, hev_thresh); VP8HFilter8i(u_dst, v_dst, uv_bps, limit, ilevel, hev_thresh); } @@ -242,7 +253,7 @@ static void DoFilter(const VP8Decoder* const dec, int mb_x, int mb_y) { VP8VFilter16(y_dst, y_bps, limit + 4, ilevel, hev_thresh); VP8VFilter8(u_dst, v_dst, uv_bps, limit + 4, ilevel, hev_thresh); } - if (f_info->f_inner_) { + if (f_info->f_inner) { VP8VFilter16i(y_dst, y_bps, limit, ilevel, hev_thresh); VP8VFilter8i(u_dst, v_dst, uv_bps, limit, ilevel, hev_thresh); } @@ -252,9 +263,9 @@ static void DoFilter(const VP8Decoder* const dec, int mb_x, int mb_y) { // Filter the decoded macroblock row (if needed) static void FilterRow(const VP8Decoder* const dec) { int mb_x; - const int mb_y = dec->thread_ctx_.mb_y_; - assert(dec->thread_ctx_.filter_row_); - for (mb_x = dec->tl_mb_x_; mb_x < dec->br_mb_x_; ++mb_x) { + const int mb_y = dec->thread_ctx.mb_y; + assert(dec->thread_ctx.filter_row); + for (mb_x = dec->tl_mb_x; mb_x < dec->br_mb_x; ++mb_x) { DoFilter(dec, mb_x, mb_y); } } @@ -263,51 +274,51 @@ static void FilterRow(const VP8Decoder* const dec) { // Precompute the filtering strength for each segment and each i4x4/i16x16 mode. static void PrecomputeFilterStrengths(VP8Decoder* const dec) { - if (dec->filter_type_ > 0) { + if (dec->filter_type > 0) { int s; - const VP8FilterHeader* const hdr = &dec->filter_hdr_; + const VP8FilterHeader* const hdr = &dec->filter_hdr; for (s = 0; s < NUM_MB_SEGMENTS; ++s) { int i4x4; // First, compute the initial level int base_level; - if (dec->segment_hdr_.use_segment_) { - base_level = dec->segment_hdr_.filter_strength_[s]; - if (!dec->segment_hdr_.absolute_delta_) { - base_level += hdr->level_; + if (dec->segment_hdr.use_segment) { + base_level = dec->segment_hdr.filter_strength[s]; + if (!dec->segment_hdr.absolute_delta) { + base_level += hdr->level; } } else { - base_level = hdr->level_; + base_level = hdr->level; } for (i4x4 = 0; i4x4 <= 1; ++i4x4) { - VP8FInfo* const info = &dec->fstrengths_[s][i4x4]; + VP8FInfo* const info = &dec->fstrengths[s][i4x4]; int level = base_level; - if (hdr->use_lf_delta_) { - level += hdr->ref_lf_delta_[0]; + if (hdr->use_lf_delta) { + level += hdr->ref_lf_delta[0]; if (i4x4) { - level += hdr->mode_lf_delta_[0]; + level += hdr->mode_lf_delta[0]; } } level = (level < 0) ? 0 : (level > 63) ? 63 : level; if (level > 0) { int ilevel = level; - if (hdr->sharpness_ > 0) { - if (hdr->sharpness_ > 4) { + if (hdr->sharpness > 0) { + if (hdr->sharpness > 4) { ilevel >>= 2; } else { ilevel >>= 1; } - if (ilevel > 9 - hdr->sharpness_) { - ilevel = 9 - hdr->sharpness_; + if (ilevel > 9 - hdr->sharpness) { + ilevel = 9 - hdr->sharpness; } } if (ilevel < 1) ilevel = 1; - info->f_ilevel_ = ilevel; - info->f_limit_ = 2 * level + ilevel; - info->hev_thresh_ = (level >= 40) ? 2 : (level >= 15) ? 1 : 0; + info->f_ilevel = ilevel; + info->f_limit = 2 * level + ilevel; + info->hev_thresh = (level >= 40) ? 2 : (level >= 15) ? 1 : 0; } else { - info->f_limit_ = 0; // no filtering + info->f_limit = 0; // no filtering } - info->f_inner_ = i4x4; + info->f_inner = i4x4; } } } @@ -321,7 +332,7 @@ static void PrecomputeFilterStrengths(VP8Decoder* const dec) { #define DITHER_AMP_TAB_SIZE 12 static const uint8_t kQuantToDitherAmp[DITHER_AMP_TAB_SIZE] = { - // roughly, it's dqm->uv_mat_[1] + // roughly, it's dqm->uv_mat[1] 8, 7, 6, 4, 4, 2, 2, 2, 1, 1, 1, 1 }; @@ -336,24 +347,24 @@ void VP8InitDithering(const WebPDecoderOptions* const options, int s; int all_amp = 0; for (s = 0; s < NUM_MB_SEGMENTS; ++s) { - VP8QuantMatrix* const dqm = &dec->dqm_[s]; - if (dqm->uv_quant_ < DITHER_AMP_TAB_SIZE) { - const int idx = (dqm->uv_quant_ < 0) ? 0 : dqm->uv_quant_; - dqm->dither_ = (f * kQuantToDitherAmp[idx]) >> 3; + VP8QuantMatrix* const dqm = &dec->dqm[s]; + if (dqm->uv_quant < DITHER_AMP_TAB_SIZE) { + const int idx = (dqm->uv_quant < 0) ? 0 : dqm->uv_quant; + dqm->dither = (f * kQuantToDitherAmp[idx]) >> 3; } - all_amp |= dqm->dither_; + all_amp |= dqm->dither; } if (all_amp != 0) { - VP8InitRandom(&dec->dithering_rg_, 1.0f); - dec->dither_ = 1; + VP8InitRandom(&dec->dithering_rg, 1.0f); + dec->dither = 1; } } // potentially allow alpha dithering - dec->alpha_dithering_ = options->alpha_dithering_strength; - if (dec->alpha_dithering_ > 100) { - dec->alpha_dithering_ = 100; - } else if (dec->alpha_dithering_ < 0) { - dec->alpha_dithering_ = 0; + dec->alpha_dithering = options->alpha_dithering_strength; + if (dec->alpha_dithering > 100) { + dec->alpha_dithering = 100; + } else if (dec->alpha_dithering < 0) { + dec->alpha_dithering = 0; } } } @@ -370,17 +381,17 @@ static void Dither8x8(VP8Random* const rg, uint8_t* dst, int bps, int amp) { static void DitherRow(VP8Decoder* const dec) { int mb_x; - assert(dec->dither_); - for (mb_x = dec->tl_mb_x_; mb_x < dec->br_mb_x_; ++mb_x) { - const VP8ThreadContext* const ctx = &dec->thread_ctx_; - const VP8MBData* const data = ctx->mb_data_ + mb_x; - const int cache_id = ctx->id_; - const int uv_bps = dec->cache_uv_stride_; - if (data->dither_ >= MIN_DITHER_AMP) { - uint8_t* const u_dst = dec->cache_u_ + cache_id * 8 * uv_bps + mb_x * 8; - uint8_t* const v_dst = dec->cache_v_ + cache_id * 8 * uv_bps + mb_x * 8; - Dither8x8(&dec->dithering_rg_, u_dst, uv_bps, data->dither_); - Dither8x8(&dec->dithering_rg_, v_dst, uv_bps, data->dither_); + assert(dec->dither); + for (mb_x = dec->tl_mb_x; mb_x < dec->br_mb_x; ++mb_x) { + const VP8ThreadContext* const ctx = &dec->thread_ctx; + const VP8MBData* const data = ctx->mb_data + mb_x; + const int cache_id = ctx->id; + const int uv_bps = dec->cache_uv_stride; + if (data->dither >= MIN_DITHER_AMP) { + uint8_t* const u_dst = dec->cache_u + cache_id * 8 * uv_bps + mb_x * 8; + uint8_t* const v_dst = dec->cache_v + cache_id * 8 * uv_bps + mb_x * 8; + Dither8x8(&dec->dithering_rg, u_dst, uv_bps, data->dither); + Dither8x8(&dec->dithering_rg, v_dst, uv_bps, data->dither); } } } @@ -403,29 +414,29 @@ static int FinishRow(void* arg1, void* arg2) { VP8Decoder* const dec = (VP8Decoder*)arg1; VP8Io* const io = (VP8Io*)arg2; int ok = 1; - const VP8ThreadContext* const ctx = &dec->thread_ctx_; - const int cache_id = ctx->id_; - const int extra_y_rows = kFilterExtraRows[dec->filter_type_]; - const int ysize = extra_y_rows * dec->cache_y_stride_; - const int uvsize = (extra_y_rows / 2) * dec->cache_uv_stride_; - const int y_offset = cache_id * 16 * dec->cache_y_stride_; - const int uv_offset = cache_id * 8 * dec->cache_uv_stride_; - uint8_t* const ydst = dec->cache_y_ - ysize + y_offset; - uint8_t* const udst = dec->cache_u_ - uvsize + uv_offset; - uint8_t* const vdst = dec->cache_v_ - uvsize + uv_offset; - const int mb_y = ctx->mb_y_; + const VP8ThreadContext* const ctx = &dec->thread_ctx; + const int cache_id = ctx->id; + const int extra_y_rows = kFilterExtraRows[dec->filter_type]; + const int ysize = extra_y_rows * dec->cache_y_stride; + const int uvsize = (extra_y_rows / 2) * dec->cache_uv_stride; + const int y_offset = cache_id * 16 * dec->cache_y_stride; + const int uv_offset = cache_id * 8 * dec->cache_uv_stride; + uint8_t* const ydst = dec->cache_y - ysize + y_offset; + uint8_t* const udst = dec->cache_u - uvsize + uv_offset; + uint8_t* const vdst = dec->cache_v - uvsize + uv_offset; + const int mb_y = ctx->mb_y; const int is_first_row = (mb_y == 0); - const int is_last_row = (mb_y >= dec->br_mb_y_ - 1); + const int is_last_row = (mb_y >= dec->br_mb_y - 1); - if (dec->mt_method_ == 2) { + if (dec->mt_method == 2) { ReconstructRow(dec, ctx); } - if (ctx->filter_row_) { + if (ctx->filter_row) { FilterRow(dec); } - if (dec->dither_) { + if (dec->dither) { DitherRow(dec); } @@ -438,9 +449,9 @@ static int FinishRow(void* arg1, void* arg2) { io->u = udst; io->v = vdst; } else { - io->y = dec->cache_y_ + y_offset; - io->u = dec->cache_u_ + uv_offset; - io->v = dec->cache_v_ + uv_offset; + io->y = dec->cache_y + y_offset; + io->u = dec->cache_u + uv_offset; + io->v = dec->cache_v + uv_offset; } if (!is_last_row) { @@ -449,9 +460,9 @@ static int FinishRow(void* arg1, void* arg2) { if (y_end > io->crop_bottom) { y_end = io->crop_bottom; // make sure we don't overflow on last row. } - // If dec->alpha_data_ is not NULL, we have some alpha plane present. + // If dec->alpha_data is not NULL, we have some alpha plane present. io->a = NULL; - if (dec->alpha_data_ != NULL && y_start < y_end) { + if (dec->alpha_data != NULL && y_start < y_end) { io->a = VP8DecompressAlphaRows(dec, io, y_start, y_end - y_start); if (io->a == NULL) { return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, @@ -462,9 +473,9 @@ static int FinishRow(void* arg1, void* arg2) { const int delta_y = io->crop_top - y_start; y_start = io->crop_top; assert(!(delta_y & 1)); - io->y += dec->cache_y_stride_ * delta_y; - io->u += dec->cache_uv_stride_ * (delta_y >> 1); - io->v += dec->cache_uv_stride_ * (delta_y >> 1); + io->y += dec->cache_y_stride * delta_y; + io->u += dec->cache_uv_stride * (delta_y >> 1); + io->v += dec->cache_uv_stride * (delta_y >> 1); if (io->a != NULL) { io->a += io->width * delta_y; } @@ -483,11 +494,11 @@ static int FinishRow(void* arg1, void* arg2) { } } // rotate top samples if needed - if (cache_id + 1 == dec->num_caches_) { + if (cache_id + 1 == dec->num_caches) { if (!is_last_row) { - memcpy(dec->cache_y_ - ysize, ydst + 16 * dec->cache_y_stride_, ysize); - memcpy(dec->cache_u_ - uvsize, udst + 8 * dec->cache_uv_stride_, uvsize); - memcpy(dec->cache_v_ - uvsize, vdst + 8 * dec->cache_uv_stride_, uvsize); + memcpy(dec->cache_y - ysize, ydst + 16 * dec->cache_y_stride, ysize); + memcpy(dec->cache_u - uvsize, udst + 8 * dec->cache_uv_stride, uvsize); + memcpy(dec->cache_v - uvsize, vdst + 8 * dec->cache_uv_stride, uvsize); } } @@ -500,43 +511,43 @@ static int FinishRow(void* arg1, void* arg2) { int VP8ProcessRow(VP8Decoder* const dec, VP8Io* const io) { int ok = 1; - VP8ThreadContext* const ctx = &dec->thread_ctx_; + VP8ThreadContext* const ctx = &dec->thread_ctx; const int filter_row = - (dec->filter_type_ > 0) && - (dec->mb_y_ >= dec->tl_mb_y_) && (dec->mb_y_ <= dec->br_mb_y_); - if (dec->mt_method_ == 0) { - // ctx->id_ and ctx->f_info_ are already set - ctx->mb_y_ = dec->mb_y_; - ctx->filter_row_ = filter_row; + (dec->filter_type > 0) && + (dec->mb_y >= dec->tl_mb_y) && (dec->mb_y <= dec->br_mb_y); + if (dec->mt_method == 0) { + // ctx->id and ctx->f_info are already set + ctx->mb_y = dec->mb_y; + ctx->filter_row = filter_row; ReconstructRow(dec, ctx); ok = FinishRow(dec, io); } else { - WebPWorker* const worker = &dec->worker_; + WebPWorker* const worker = &dec->worker; // Finish previous job *before* updating context ok &= WebPGetWorkerInterface()->Sync(worker); - assert(worker->status_ == OK); + assert(worker->status == OK); if (ok) { // spawn a new deblocking/output job - ctx->io_ = *io; - ctx->id_ = dec->cache_id_; - ctx->mb_y_ = dec->mb_y_; - ctx->filter_row_ = filter_row; - if (dec->mt_method_ == 2) { // swap macroblock data - VP8MBData* const tmp = ctx->mb_data_; - ctx->mb_data_ = dec->mb_data_; - dec->mb_data_ = tmp; + ctx->io = *io; + ctx->id = dec->cache_id; + ctx->mb_y = dec->mb_y; + ctx->filter_row = filter_row; + if (dec->mt_method == 2) { // swap macroblock data + VP8MBData* const tmp = ctx->mb_data; + ctx->mb_data = dec->mb_data; + dec->mb_data = tmp; } else { // perform reconstruction directly in main thread ReconstructRow(dec, ctx); } if (filter_row) { // swap filter info - VP8FInfo* const tmp = ctx->f_info_; - ctx->f_info_ = dec->f_info_; - dec->f_info_ = tmp; + VP8FInfo* const tmp = ctx->f_info; + ctx->f_info = dec->f_info; + dec->f_info = tmp; } // (reconstruct)+filter in parallel WebPGetWorkerInterface()->Launch(worker); - if (++dec->cache_id_ == dec->num_caches_) { - dec->cache_id_ = 0; + if (++dec->cache_id == dec->num_caches) { + dec->cache_id = 0; } } } @@ -551,12 +562,12 @@ VP8StatusCode VP8EnterCritical(VP8Decoder* const dec, VP8Io* const io) { // Note: Afterward, we must call teardown() no matter what. if (io->setup != NULL && !io->setup(io)) { VP8SetError(dec, VP8_STATUS_USER_ABORT, "Frame setup failed"); - return dec->status_; + return dec->status; } // Disable filtering per user request if (io->bypass_filtering) { - dec->filter_type_ = 0; + dec->filter_type = 0; } // Define the area where we can skip in-loop filtering, in case of cropping. @@ -569,29 +580,29 @@ VP8StatusCode VP8EnterCritical(VP8Decoder* const dec, VP8Io* const io) { // top-left corner of the picture (MB #0). We must filter all the previous // macroblocks. { - const int extra_pixels = kFilterExtraRows[dec->filter_type_]; - if (dec->filter_type_ == 2) { + const int extra_pixels = kFilterExtraRows[dec->filter_type]; + if (dec->filter_type == 2) { // For complex filter, we need to preserve the dependency chain. - dec->tl_mb_x_ = 0; - dec->tl_mb_y_ = 0; + dec->tl_mb_x = 0; + dec->tl_mb_y = 0; } else { // For simple filter, we can filter only the cropped region. // We include 'extra_pixels' on the other side of the boundary, since // vertical or horizontal filtering of the previous macroblock can // modify some abutting pixels. - dec->tl_mb_x_ = (io->crop_left - extra_pixels) >> 4; - dec->tl_mb_y_ = (io->crop_top - extra_pixels) >> 4; - if (dec->tl_mb_x_ < 0) dec->tl_mb_x_ = 0; - if (dec->tl_mb_y_ < 0) dec->tl_mb_y_ = 0; + dec->tl_mb_x = (io->crop_left - extra_pixels) >> 4; + dec->tl_mb_y = (io->crop_top - extra_pixels) >> 4; + if (dec->tl_mb_x < 0) dec->tl_mb_x = 0; + if (dec->tl_mb_y < 0) dec->tl_mb_y = 0; } // We need some 'extra' pixels on the right/bottom. - dec->br_mb_y_ = (io->crop_bottom + 15 + extra_pixels) >> 4; - dec->br_mb_x_ = (io->crop_right + 15 + extra_pixels) >> 4; - if (dec->br_mb_x_ > dec->mb_w_) { - dec->br_mb_x_ = dec->mb_w_; + dec->br_mb_y = (io->crop_bottom + 15 + extra_pixels) >> 4; + dec->br_mb_x = (io->crop_right + 15 + extra_pixels) >> 4; + if (dec->br_mb_x > dec->mb_w) { + dec->br_mb_x = dec->mb_w; } - if (dec->br_mb_y_ > dec->mb_h_) { - dec->br_mb_y_ = dec->mb_h_; + if (dec->br_mb_y > dec->mb_h) { + dec->br_mb_y = dec->mb_h; } } PrecomputeFilterStrengths(dec); @@ -600,8 +611,8 @@ VP8StatusCode VP8EnterCritical(VP8Decoder* const dec, VP8Io* const io) { int VP8ExitCritical(VP8Decoder* const dec, VP8Io* const io) { int ok = 1; - if (dec->mt_method_ > 0) { - ok = WebPGetWorkerInterface()->Sync(&dec->worker_); + if (dec->mt_method > 0) { + ok = WebPGetWorkerInterface()->Sync(&dec->worker); } if (io->teardown != NULL) { @@ -639,20 +650,20 @@ int VP8ExitCritical(VP8Decoder* const dec, VP8Io* const io) { // Initialize multi/single-thread worker static int InitThreadContext(VP8Decoder* const dec) { - dec->cache_id_ = 0; - if (dec->mt_method_ > 0) { - WebPWorker* const worker = &dec->worker_; + dec->cache_id = 0; + if (dec->mt_method > 0) { + WebPWorker* const worker = &dec->worker; if (!WebPGetWorkerInterface()->Reset(worker)) { return VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY, "thread initialization failed."); } worker->data1 = dec; - worker->data2 = (void*)&dec->thread_ctx_.io_; + worker->data2 = (void*)&dec->thread_ctx.io; worker->hook = FinishRow; - dec->num_caches_ = - (dec->filter_type_ > 0) ? MT_CACHE_LINES : MT_CACHE_LINES - 1; + dec->num_caches = + (dec->filter_type > 0) ? MT_CACHE_LINES : MT_CACHE_LINES - 1; } else { - dec->num_caches_ = ST_CACHE_LINES; + dec->num_caches = ST_CACHE_LINES; } return 1; } @@ -680,25 +691,25 @@ int VP8GetThreadMethod(const WebPDecoderOptions* const options, // Memory setup static int AllocateMemory(VP8Decoder* const dec) { - const int num_caches = dec->num_caches_; - const int mb_w = dec->mb_w_; + const int num_caches = dec->num_caches; + const int mb_w = dec->mb_w; // Note: we use 'size_t' when there's no overflow risk, uint64_t otherwise. const size_t intra_pred_mode_size = 4 * mb_w * sizeof(uint8_t); const size_t top_size = sizeof(VP8TopSamples) * mb_w; const size_t mb_info_size = (mb_w + 1) * sizeof(VP8MB); const size_t f_info_size = - (dec->filter_type_ > 0) ? - mb_w * (dec->mt_method_ > 0 ? 2 : 1) * sizeof(VP8FInfo) + (dec->filter_type > 0) ? + mb_w * (dec->mt_method > 0 ? 2 : 1) * sizeof(VP8FInfo) : 0; - const size_t yuv_size = YUV_SIZE * sizeof(*dec->yuv_b_); + const size_t yuv_size = YUV_SIZE * sizeof(*dec->yuv_b); const size_t mb_data_size = - (dec->mt_method_ == 2 ? 2 : 1) * mb_w * sizeof(*dec->mb_data_); + (dec->mt_method == 2 ? 2 : 1) * mb_w * sizeof(*dec->mb_data); const size_t cache_height = (16 * num_caches - + kFilterExtraRows[dec->filter_type_]) * 3 / 2; + + kFilterExtraRows[dec->filter_type]) * 3 / 2; const size_t cache_size = top_size * cache_height; // alpha_size is the only one that scales as width x height. - const uint64_t alpha_size = (dec->alpha_data_ != NULL) ? - (uint64_t)dec->pic_hdr_.width_ * dec->pic_hdr_.height_ : 0ULL; + const uint64_t alpha_size = (dec->alpha_data != NULL) ? + (uint64_t)dec->pic_hdr.width * dec->pic_hdr.height : 0ULL; const uint64_t needed = (uint64_t)intra_pred_mode_size + top_size + mb_info_size + f_info_size + yuv_size + mb_data_size @@ -706,77 +717,77 @@ static int AllocateMemory(VP8Decoder* const dec) { uint8_t* mem; if (!CheckSizeOverflow(needed)) return 0; // check for overflow - if (needed > dec->mem_size_) { - WebPSafeFree(dec->mem_); - dec->mem_size_ = 0; - dec->mem_ = WebPSafeMalloc(needed, sizeof(uint8_t)); - if (dec->mem_ == NULL) { + if (needed > dec->mem_size) { + WebPSafeFree(dec->mem); + dec->mem_size = 0; + dec->mem = WebPSafeMalloc(needed, sizeof(uint8_t)); + if (dec->mem == NULL) { return VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY, "no memory during frame initialization."); } // down-cast is ok, thanks to WebPSafeMalloc() above. - dec->mem_size_ = (size_t)needed; + dec->mem_size = (size_t)needed; } - mem = (uint8_t*)dec->mem_; - dec->intra_t_ = mem; + mem = (uint8_t*)dec->mem; + dec->intra_t = mem; mem += intra_pred_mode_size; - dec->yuv_t_ = (VP8TopSamples*)mem; + dec->yuv_t = (VP8TopSamples*)mem; mem += top_size; - dec->mb_info_ = ((VP8MB*)mem) + 1; + dec->mb_info = ((VP8MB*)mem) + 1; mem += mb_info_size; - dec->f_info_ = f_info_size ? (VP8FInfo*)mem : NULL; + dec->f_info = f_info_size ? (VP8FInfo*)mem : NULL; mem += f_info_size; - dec->thread_ctx_.id_ = 0; - dec->thread_ctx_.f_info_ = dec->f_info_; - if (dec->filter_type_ > 0 && dec->mt_method_ > 0) { + dec->thread_ctx.id = 0; + dec->thread_ctx.f_info = dec->f_info; + if (dec->filter_type > 0 && dec->mt_method > 0) { // secondary cache line. The deblocking process need to make use of the // filtering strength from previous macroblock row, while the new ones // are being decoded in parallel. We'll just swap the pointers. - dec->thread_ctx_.f_info_ += mb_w; + dec->thread_ctx.f_info += mb_w; } mem = (uint8_t*)WEBP_ALIGN(mem); assert((yuv_size & WEBP_ALIGN_CST) == 0); - dec->yuv_b_ = mem; + dec->yuv_b = mem; mem += yuv_size; - dec->mb_data_ = (VP8MBData*)mem; - dec->thread_ctx_.mb_data_ = (VP8MBData*)mem; - if (dec->mt_method_ == 2) { - dec->thread_ctx_.mb_data_ += mb_w; + dec->mb_data = (VP8MBData*)mem; + dec->thread_ctx.mb_data = (VP8MBData*)mem; + if (dec->mt_method == 2) { + dec->thread_ctx.mb_data += mb_w; } mem += mb_data_size; - dec->cache_y_stride_ = 16 * mb_w; - dec->cache_uv_stride_ = 8 * mb_w; + dec->cache_y_stride = 16 * mb_w; + dec->cache_uv_stride = 8 * mb_w; { - const int extra_rows = kFilterExtraRows[dec->filter_type_]; - const int extra_y = extra_rows * dec->cache_y_stride_; - const int extra_uv = (extra_rows / 2) * dec->cache_uv_stride_; - dec->cache_y_ = mem + extra_y; - dec->cache_u_ = dec->cache_y_ - + 16 * num_caches * dec->cache_y_stride_ + extra_uv; - dec->cache_v_ = dec->cache_u_ - + 8 * num_caches * dec->cache_uv_stride_ + extra_uv; - dec->cache_id_ = 0; + const int extra_rows = kFilterExtraRows[dec->filter_type]; + const int extra_y = extra_rows * dec->cache_y_stride; + const int extra_uv = (extra_rows / 2) * dec->cache_uv_stride; + dec->cache_y = mem + extra_y; + dec->cache_u = dec->cache_y + + 16 * num_caches * dec->cache_y_stride + extra_uv; + dec->cache_v = dec->cache_u + + 8 * num_caches * dec->cache_uv_stride + extra_uv; + dec->cache_id = 0; } mem += cache_size; // alpha plane - dec->alpha_plane_ = alpha_size ? mem : NULL; + dec->alpha_plane = alpha_size ? mem : NULL; mem += alpha_size; - assert(mem <= (uint8_t*)dec->mem_ + dec->mem_size_); + assert(mem <= (uint8_t*)dec->mem + dec->mem_size); // note: left/top-info is initialized once for all. - memset(dec->mb_info_ - 1, 0, mb_info_size); + memset(dec->mb_info - 1, 0, mb_info_size); VP8InitScanline(dec); // initialize left too. // initialize top - memset(dec->intra_t_, B_DC_PRED, intra_pred_mode_size); + memset(dec->intra_t, B_DC_PRED, intra_pred_mode_size); return 1; } @@ -784,16 +795,16 @@ static int AllocateMemory(VP8Decoder* const dec) { static void InitIo(VP8Decoder* const dec, VP8Io* io) { // prepare 'io' io->mb_y = 0; - io->y = dec->cache_y_; - io->u = dec->cache_u_; - io->v = dec->cache_v_; - io->y_stride = dec->cache_y_stride_; - io->uv_stride = dec->cache_uv_stride_; + io->y = dec->cache_y; + io->u = dec->cache_u; + io->v = dec->cache_v; + io->y_stride = dec->cache_y_stride; + io->uv_stride = dec->cache_uv_stride; io->a = NULL; } int VP8InitFrame(VP8Decoder* const dec, VP8Io* const io) { - if (!InitThreadContext(dec)) return 0; // call first. Sets dec->num_caches_. + if (!InitThreadContext(dec)) return 0; // call first. Sets dec->num_caches. if (!AllocateMemory(dec)) return 0; InitIo(dec, io); VP8DspInit(); // Init critical function pointers and look-up tables. diff --git a/libwebp/src/dec/idec_dec.c b/libwebp/src/dec/idec_dec.c index ad042a1f..cf8a33a4 100644 --- a/libwebp/src/dec/idec_dec.c +++ b/libwebp/src/dec/idec_dec.c @@ -12,15 +12,20 @@ // Author: somnath@google.com (Somnath Banerjee) #include -#include #include +#include #include "src/dec/alphai_dec.h" -#include "src/dec/webpi_dec.h" #include "src/dec/vp8_dec.h" #include "src/dec/vp8i_dec.h" +#include "src/dec/vp8li_dec.h" +#include "src/dec/webpi_dec.h" +#include "src/utils/bit_reader_utils.h" +#include "src/utils/thread_utils.h" #include "src/utils/utils.h" #include "src/webp/decode.h" +#include "src/webp/format_constants.h" +#include "src/webp/types.h" // In append mode, buffer allocations increase as multiples of this value. // Needs to be a power of 2. @@ -54,134 +59,140 @@ typedef enum { // storage for partition #0 and partial data (in a rolling fashion) typedef struct { - MemBufferMode mode_; // Operation mode - size_t start_; // start location of the data to be decoded - size_t end_; // end location - size_t buf_size_; // size of the allocated buffer - uint8_t* buf_; // We don't own this buffer in case WebPIUpdate() - - size_t part0_size_; // size of partition #0 - const uint8_t* part0_buf_; // buffer to store partition #0 + MemBufferMode mode; // Operation mode + size_t start; // start location of the data to be decoded + size_t end; // end location + size_t buf_size; // size of the allocated buffer + uint8_t* buf; // We don't own this buffer in case WebPIUpdate() + + size_t part0_size; // size of partition #0 + const uint8_t* part0_buf; // buffer to store partition #0 } MemBuffer; struct WebPIDecoder { - DecState state_; // current decoding state - WebPDecParams params_; // Params to store output info - int is_lossless_; // for down-casting 'dec_'. - void* dec_; // either a VP8Decoder or a VP8LDecoder instance - VP8Io io_; - - MemBuffer mem_; // input memory buffer. - WebPDecBuffer output_; // output buffer (when no external one is supplied, - // or if the external one has slow-memory) - WebPDecBuffer* final_output_; // Slow-memory output to copy to eventually. - size_t chunk_size_; // Compressed VP8/VP8L size extracted from Header. - - int last_mb_y_; // last row reached for intra-mode decoding + DecState state; // current decoding state + WebPDecParams params; // Params to store output info + int is_lossless; // for down-casting 'dec'. + void* dec; // either a VP8Decoder or a VP8LDecoder instance + VP8Io io; + + MemBuffer mem; // input memory buffer. + WebPDecBuffer output; // output buffer (when no external one is supplied, + // or if the external one has slow-memory) + WebPDecBuffer* final_output; // Slow-memory output to copy to eventually. + size_t chunk_size; // Compressed VP8/VP8L size extracted from Header. + + int last_mb_y; // last row reached for intra-mode decoding }; // MB context to restore in case VP8DecodeMB() fails typedef struct { - VP8MB left_; - VP8MB info_; - VP8BitReader token_br_; + VP8MB left; + VP8MB info; + VP8BitReader token_br; } MBContext; //------------------------------------------------------------------------------ // MemBuffer: incoming data handling static WEBP_INLINE size_t MemDataSize(const MemBuffer* mem) { - return (mem->end_ - mem->start_); + return (mem->end - mem->start); } // Check if we need to preserve the compressed alpha data, as it may not have // been decoded yet. static int NeedCompressedAlpha(const WebPIDecoder* const idec) { - if (idec->state_ == STATE_WEBP_HEADER) { + if (idec->state == STATE_WEBP_HEADER) { // We haven't parsed the headers yet, so we don't know whether the image is // lossy or lossless. This also means that we haven't parsed the ALPH chunk. return 0; } - if (idec->is_lossless_) { + if (idec->is_lossless) { return 0; // ALPH chunk is not present for lossless images. } else { - const VP8Decoder* const dec = (VP8Decoder*)idec->dec_; - assert(dec != NULL); // Must be true as idec->state_ != STATE_WEBP_HEADER. - return (dec->alpha_data_ != NULL) && !dec->is_alpha_decoded_; + const VP8Decoder* const dec = (VP8Decoder*)idec->dec; + assert(dec != NULL); // Must be true as idec->state != STATE_WEBP_HEADER. + return (dec->alpha_data != NULL) && !dec->is_alpha_decoded; } } static void DoRemap(WebPIDecoder* const idec, ptrdiff_t offset) { - MemBuffer* const mem = &idec->mem_; - const uint8_t* const new_base = mem->buf_ + mem->start_; - // note: for VP8, setting up idec->io_ is only really needed at the beginning + MemBuffer* const mem = &idec->mem; + const uint8_t* const new_base = mem->buf + mem->start; + // note: for VP8, setting up idec->io is only really needed at the beginning // of the decoding, till partition #0 is complete. - idec->io_.data = new_base; - idec->io_.data_size = MemDataSize(mem); + idec->io.data = new_base; + idec->io.data_size = MemDataSize(mem); - if (idec->dec_ != NULL) { - if (!idec->is_lossless_) { - VP8Decoder* const dec = (VP8Decoder*)idec->dec_; - const uint32_t last_part = dec->num_parts_minus_one_; + if (idec->dec != NULL) { + if (!idec->is_lossless) { + VP8Decoder* const dec = (VP8Decoder*)idec->dec; + const uint32_t last_part = dec->num_parts_minus_one; if (offset != 0) { uint32_t p; for (p = 0; p <= last_part; ++p) { - VP8RemapBitReader(dec->parts_ + p, offset); + VP8RemapBitReader(dec->parts + p, offset); } // Remap partition #0 data pointer to new offset, but only in MAP // mode (in APPEND mode, partition #0 is copied into a fixed memory). - if (mem->mode_ == MEM_MODE_MAP) { - VP8RemapBitReader(&dec->br_, offset); + if (mem->mode == MEM_MODE_MAP) { + VP8RemapBitReader(&dec->br, offset); } } { - const uint8_t* const last_start = dec->parts_[last_part].buf_; - VP8BitReaderSetBuffer(&dec->parts_[last_part], last_start, - mem->buf_ + mem->end_ - last_start); + const uint8_t* const last_start = dec->parts[last_part].buf; + // 'last_start' will be NULL when 'idec->state' is < STATE_VP8_PARTS0 + // and through a portion of that state (when there isn't enough data to + // parse the partitions). The bitreader is only used meaningfully when + // there is enough data to begin parsing partition 0. + if (last_start != NULL) { + VP8BitReaderSetBuffer(&dec->parts[last_part], last_start, + mem->buf + mem->end - last_start); + } } if (NeedCompressedAlpha(idec)) { - ALPHDecoder* const alph_dec = dec->alph_dec_; - dec->alpha_data_ += offset; - if (alph_dec != NULL && alph_dec->vp8l_dec_ != NULL) { - if (alph_dec->method_ == ALPHA_LOSSLESS_COMPRESSION) { - VP8LDecoder* const alph_vp8l_dec = alph_dec->vp8l_dec_; - assert(dec->alpha_data_size_ >= ALPHA_HEADER_LEN); - VP8LBitReaderSetBuffer(&alph_vp8l_dec->br_, - dec->alpha_data_ + ALPHA_HEADER_LEN, - dec->alpha_data_size_ - ALPHA_HEADER_LEN); - } else { // alph_dec->method_ == ALPHA_NO_COMPRESSION + ALPHDecoder* const alph_dec = dec->alph_dec; + dec->alpha_data += offset; + if (alph_dec != NULL && alph_dec->vp8l_dec != NULL) { + if (alph_dec->method == ALPHA_LOSSLESS_COMPRESSION) { + VP8LDecoder* const alph_vp8l_dec = alph_dec->vp8l_dec; + assert(dec->alpha_data_size >= ALPHA_HEADER_LEN); + VP8LBitReaderSetBuffer(&alph_vp8l_dec->br, + dec->alpha_data + ALPHA_HEADER_LEN, + dec->alpha_data_size - ALPHA_HEADER_LEN); + } else { // alph_dec->method == ALPHA_NO_COMPRESSION // Nothing special to do in this case. } } } } else { // Resize lossless bitreader - VP8LDecoder* const dec = (VP8LDecoder*)idec->dec_; - VP8LBitReaderSetBuffer(&dec->br_, new_base, MemDataSize(mem)); + VP8LDecoder* const dec = (VP8LDecoder*)idec->dec; + VP8LBitReaderSetBuffer(&dec->br, new_base, MemDataSize(mem)); } } } -// Appends data to the end of MemBuffer->buf_. It expands the allocated memory +// Appends data to the end of MemBuffer->buf. It expands the allocated memory // size if required and also updates VP8BitReader's if new memory is allocated. WEBP_NODISCARD static int AppendToMemBuffer(WebPIDecoder* const idec, const uint8_t* const data, size_t data_size) { - VP8Decoder* const dec = (VP8Decoder*)idec->dec_; - MemBuffer* const mem = &idec->mem_; + VP8Decoder* const dec = (VP8Decoder*)idec->dec; + MemBuffer* const mem = &idec->mem; const int need_compressed_alpha = NeedCompressedAlpha(idec); const uint8_t* const old_start = - (mem->buf_ == NULL) ? NULL : mem->buf_ + mem->start_; + (mem->buf == NULL) ? NULL : mem->buf + mem->start; const uint8_t* const old_base = - need_compressed_alpha ? dec->alpha_data_ : old_start; - assert(mem->buf_ != NULL || mem->start_ == 0); - assert(mem->mode_ == MEM_MODE_APPEND); + need_compressed_alpha ? dec->alpha_data : old_start; + assert(mem->buf != NULL || mem->start == 0); + assert(mem->mode == MEM_MODE_APPEND); if (data_size > MAX_CHUNK_PAYLOAD) { // security safeguard: trying to allocate more than what the format // allows for a chunk should be considered a smoke smell. return 0; } - if (mem->end_ + data_size > mem->buf_size_) { // Need some free memory + if (mem->end + data_size > mem->buf_size) { // Need some free memory const size_t new_mem_start = old_start - old_base; const size_t current_size = MemDataSize(mem) + new_mem_start; const uint64_t new_size = (uint64_t)current_size + data_size; @@ -190,85 +201,85 @@ WEBP_NODISCARD static int AppendToMemBuffer(WebPIDecoder* const idec, (uint8_t*)WebPSafeMalloc(extra_size, sizeof(*new_buf)); if (new_buf == NULL) return 0; if (old_base != NULL) memcpy(new_buf, old_base, current_size); - WebPSafeFree(mem->buf_); - mem->buf_ = new_buf; - mem->buf_size_ = (size_t)extra_size; - mem->start_ = new_mem_start; - mem->end_ = current_size; + WebPSafeFree(mem->buf); + mem->buf = new_buf; + mem->buf_size = (size_t)extra_size; + mem->start = new_mem_start; + mem->end = current_size; } - assert(mem->buf_ != NULL); - memcpy(mem->buf_ + mem->end_, data, data_size); - mem->end_ += data_size; - assert(mem->end_ <= mem->buf_size_); + assert(mem->buf != NULL); + memcpy(mem->buf + mem->end, data, data_size); + mem->end += data_size; + assert(mem->end <= mem->buf_size); - DoRemap(idec, mem->buf_ + mem->start_ - old_start); + DoRemap(idec, mem->buf + mem->start - old_start); return 1; } WEBP_NODISCARD static int RemapMemBuffer(WebPIDecoder* const idec, const uint8_t* const data, size_t data_size) { - MemBuffer* const mem = &idec->mem_; - const uint8_t* const old_buf = mem->buf_; + MemBuffer* const mem = &idec->mem; + const uint8_t* const old_buf = mem->buf; const uint8_t* const old_start = - (old_buf == NULL) ? NULL : old_buf + mem->start_; - assert(old_buf != NULL || mem->start_ == 0); - assert(mem->mode_ == MEM_MODE_MAP); + (old_buf == NULL) ? NULL : old_buf + mem->start; + assert(old_buf != NULL || mem->start == 0); + assert(mem->mode == MEM_MODE_MAP); - if (data_size < mem->buf_size_) return 0; // can't remap to a shorter buffer! + if (data_size < mem->buf_size) return 0; // can't remap to a shorter buffer! - mem->buf_ = (uint8_t*)data; - mem->end_ = mem->buf_size_ = data_size; + mem->buf = (uint8_t*)data; + mem->end = mem->buf_size = data_size; - DoRemap(idec, mem->buf_ + mem->start_ - old_start); + DoRemap(idec, mem->buf + mem->start - old_start); return 1; } static void InitMemBuffer(MemBuffer* const mem) { - mem->mode_ = MEM_MODE_NONE; - mem->buf_ = NULL; - mem->buf_size_ = 0; - mem->part0_buf_ = NULL; - mem->part0_size_ = 0; + mem->mode = MEM_MODE_NONE; + mem->buf = NULL; + mem->buf_size = 0; + mem->part0_buf = NULL; + mem->part0_size = 0; } static void ClearMemBuffer(MemBuffer* const mem) { assert(mem); - if (mem->mode_ == MEM_MODE_APPEND) { - WebPSafeFree(mem->buf_); - WebPSafeFree((void*)mem->part0_buf_); + if (mem->mode == MEM_MODE_APPEND) { + WebPSafeFree(mem->buf); + WebPSafeFree((void*)mem->part0_buf); } } WEBP_NODISCARD static int CheckMemBufferMode(MemBuffer* const mem, MemBufferMode expected) { - if (mem->mode_ == MEM_MODE_NONE) { - mem->mode_ = expected; // switch to the expected mode - } else if (mem->mode_ != expected) { + if (mem->mode == MEM_MODE_NONE) { + mem->mode = expected; // switch to the expected mode + } else if (mem->mode != expected) { return 0; // we mixed the modes => error } - assert(mem->mode_ == expected); // mode is ok + assert(mem->mode == expected); // mode is ok return 1; } // To be called last. WEBP_NODISCARD static VP8StatusCode FinishDecoding(WebPIDecoder* const idec) { - const WebPDecoderOptions* const options = idec->params_.options; - WebPDecBuffer* const output = idec->params_.output; + const WebPDecoderOptions* const options = idec->params.options; + WebPDecBuffer* const output = idec->params.output; - idec->state_ = STATE_DONE; + idec->state = STATE_DONE; if (options != NULL && options->flip) { const VP8StatusCode status = WebPFlipBuffer(output); if (status != VP8_STATUS_OK) return status; } - if (idec->final_output_ != NULL) { + if (idec->final_output != NULL) { const VP8StatusCode status = WebPCopyDecBufferPixels( - output, idec->final_output_); // do the slow-copy - WebPFreeDecBuffer(&idec->output_); + output, idec->final_output); // do the slow-copy + WebPFreeDecBuffer(&idec->output); if (status != VP8_STATUS_OK) return status; - *output = *idec->final_output_; - idec->final_output_ = NULL; + *output = *idec->final_output; + idec->final_output = NULL; } return VP8_STATUS_OK; } @@ -278,43 +289,43 @@ WEBP_NODISCARD static VP8StatusCode FinishDecoding(WebPIDecoder* const idec) { static void SaveContext(const VP8Decoder* dec, const VP8BitReader* token_br, MBContext* const context) { - context->left_ = dec->mb_info_[-1]; - context->info_ = dec->mb_info_[dec->mb_x_]; - context->token_br_ = *token_br; + context->left = dec->mb_info[-1]; + context->info = dec->mb_info[dec->mb_x]; + context->token_br = *token_br; } static void RestoreContext(const MBContext* context, VP8Decoder* const dec, VP8BitReader* const token_br) { - dec->mb_info_[-1] = context->left_; - dec->mb_info_[dec->mb_x_] = context->info_; - *token_br = context->token_br_; + dec->mb_info[-1] = context->left; + dec->mb_info[dec->mb_x] = context->info; + *token_br = context->token_br; } //------------------------------------------------------------------------------ static VP8StatusCode IDecError(WebPIDecoder* const idec, VP8StatusCode error) { - if (idec->state_ == STATE_VP8_DATA) { + if (idec->state == STATE_VP8_DATA) { // Synchronize the thread, clean-up and check for errors. - (void)VP8ExitCritical((VP8Decoder*)idec->dec_, &idec->io_); + (void)VP8ExitCritical((VP8Decoder*)idec->dec, &idec->io); } - idec->state_ = STATE_ERROR; + idec->state = STATE_ERROR; return error; } static void ChangeState(WebPIDecoder* const idec, DecState new_state, size_t consumed_bytes) { - MemBuffer* const mem = &idec->mem_; - idec->state_ = new_state; - mem->start_ += consumed_bytes; - assert(mem->start_ <= mem->end_); - idec->io_.data = mem->buf_ + mem->start_; - idec->io_.data_size = MemDataSize(mem); + MemBuffer* const mem = &idec->mem; + idec->state = new_state; + mem->start += consumed_bytes; + assert(mem->start <= mem->end); + idec->io.data = mem->buf + mem->start; + idec->io.data_size = MemDataSize(mem); } // Headers static VP8StatusCode DecodeWebPHeaders(WebPIDecoder* const idec) { - MemBuffer* const mem = &idec->mem_; - const uint8_t* data = mem->buf_ + mem->start_; + MemBuffer* const mem = &idec->mem; + const uint8_t* data = mem->buf + mem->start; size_t curr_size = MemDataSize(mem); VP8StatusCode status; WebPHeaderStructure headers; @@ -329,32 +340,32 @@ static VP8StatusCode DecodeWebPHeaders(WebPIDecoder* const idec) { return IDecError(idec, status); } - idec->chunk_size_ = headers.compressed_size; - idec->is_lossless_ = headers.is_lossless; - if (!idec->is_lossless_) { + idec->chunk_size = headers.compressed_size; + idec->is_lossless = headers.is_lossless; + if (!idec->is_lossless) { VP8Decoder* const dec = VP8New(); if (dec == NULL) { return VP8_STATUS_OUT_OF_MEMORY; } - dec->incremental_ = 1; - idec->dec_ = dec; - dec->alpha_data_ = headers.alpha_data; - dec->alpha_data_size_ = headers.alpha_data_size; + dec->incremental = 1; + idec->dec = dec; + dec->alpha_data = headers.alpha_data; + dec->alpha_data_size = headers.alpha_data_size; ChangeState(idec, STATE_VP8_HEADER, headers.offset); } else { VP8LDecoder* const dec = VP8LNew(); if (dec == NULL) { return VP8_STATUS_OUT_OF_MEMORY; } - idec->dec_ = dec; + idec->dec = dec; ChangeState(idec, STATE_VP8L_HEADER, headers.offset); } return VP8_STATUS_OK; } static VP8StatusCode DecodeVP8FrameHeader(WebPIDecoder* const idec) { - const uint8_t* data = idec->mem_.buf_ + idec->mem_.start_; - const size_t curr_size = MemDataSize(&idec->mem_); + const uint8_t* data = idec->mem.buf + idec->mem.start; + const size_t curr_size = MemDataSize(&idec->mem); int width, height; uint32_t bits; @@ -362,61 +373,61 @@ static VP8StatusCode DecodeVP8FrameHeader(WebPIDecoder* const idec) { // Not enough data bytes to extract VP8 Frame Header. return VP8_STATUS_SUSPENDED; } - if (!VP8GetInfo(data, curr_size, idec->chunk_size_, &width, &height)) { + if (!VP8GetInfo(data, curr_size, idec->chunk_size, &width, &height)) { return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR); } bits = data[0] | (data[1] << 8) | (data[2] << 16); - idec->mem_.part0_size_ = (bits >> 5) + VP8_FRAME_HEADER_SIZE; + idec->mem.part0_size = (bits >> 5) + VP8_FRAME_HEADER_SIZE; - idec->io_.data = data; - idec->io_.data_size = curr_size; - idec->state_ = STATE_VP8_PARTS0; + idec->io.data = data; + idec->io.data_size = curr_size; + idec->state = STATE_VP8_PARTS0; return VP8_STATUS_OK; } // Partition #0 static VP8StatusCode CopyParts0Data(WebPIDecoder* const idec) { - VP8Decoder* const dec = (VP8Decoder*)idec->dec_; - VP8BitReader* const br = &dec->br_; - const size_t part_size = br->buf_end_ - br->buf_; - MemBuffer* const mem = &idec->mem_; - assert(!idec->is_lossless_); - assert(mem->part0_buf_ == NULL); + VP8Decoder* const dec = (VP8Decoder*)idec->dec; + VP8BitReader* const br = &dec->br; + const size_t part_size = br->buf_end - br->buf; + MemBuffer* const mem = &idec->mem; + assert(!idec->is_lossless); + assert(mem->part0_buf == NULL); // the following is a format limitation, no need for runtime check: - assert(part_size <= mem->part0_size_); + assert(part_size <= mem->part0_size); if (part_size == 0) { // can't have zero-size partition #0 return VP8_STATUS_BITSTREAM_ERROR; } - if (mem->mode_ == MEM_MODE_APPEND) { + if (mem->mode == MEM_MODE_APPEND) { // We copy and grab ownership of the partition #0 data. uint8_t* const part0_buf = (uint8_t*)WebPSafeMalloc(1ULL, part_size); if (part0_buf == NULL) { return VP8_STATUS_OUT_OF_MEMORY; } - memcpy(part0_buf, br->buf_, part_size); - mem->part0_buf_ = part0_buf; + memcpy(part0_buf, br->buf, part_size); + mem->part0_buf = part0_buf; VP8BitReaderSetBuffer(br, part0_buf, part_size); } else { - // Else: just keep pointers to the partition #0's data in dec_->br_. + // Else: just keep pointers to the partition #0's data in dec->br. } - mem->start_ += part_size; + mem->start += part_size; return VP8_STATUS_OK; } static VP8StatusCode DecodePartition0(WebPIDecoder* const idec) { - VP8Decoder* const dec = (VP8Decoder*)idec->dec_; - VP8Io* const io = &idec->io_; - const WebPDecParams* const params = &idec->params_; + VP8Decoder* const dec = (VP8Decoder*)idec->dec; + VP8Io* const io = &idec->io; + const WebPDecParams* const params = &idec->params; WebPDecBuffer* const output = params->output; // Wait till we have enough data for the whole partition #0 - if (MemDataSize(&idec->mem_) < idec->mem_.part0_size_) { + if (MemDataSize(&idec->mem) < idec->mem.part0_size) { return VP8_STATUS_SUSPENDED; } if (!VP8GetHeaders(dec, io)) { - const VP8StatusCode status = dec->status_; + const VP8StatusCode status = dec->status; if (status == VP8_STATUS_SUSPENDED || status == VP8_STATUS_NOT_ENOUGH_DATA) { // treating NOT_ENOUGH_DATA as SUSPENDED state @@ -426,69 +437,69 @@ static VP8StatusCode DecodePartition0(WebPIDecoder* const idec) { } // Allocate/Verify output buffer now - dec->status_ = WebPAllocateDecBuffer(io->width, io->height, params->options, - output); - if (dec->status_ != VP8_STATUS_OK) { - return IDecError(idec, dec->status_); + dec->status = WebPAllocateDecBuffer(io->width, io->height, params->options, + output); + if (dec->status != VP8_STATUS_OK) { + return IDecError(idec, dec->status); } // This change must be done before calling VP8InitFrame() - dec->mt_method_ = VP8GetThreadMethod(params->options, NULL, - io->width, io->height); + dec->mt_method = VP8GetThreadMethod(params->options, NULL, + io->width, io->height); VP8InitDithering(params->options, dec); - dec->status_ = CopyParts0Data(idec); - if (dec->status_ != VP8_STATUS_OK) { - return IDecError(idec, dec->status_); + dec->status = CopyParts0Data(idec); + if (dec->status != VP8_STATUS_OK) { + return IDecError(idec, dec->status); } // Finish setting up the decoding parameters. Will call io->setup(). if (VP8EnterCritical(dec, io) != VP8_STATUS_OK) { - return IDecError(idec, dec->status_); + return IDecError(idec, dec->status); } // Note: past this point, teardown() must always be called // in case of error. - idec->state_ = STATE_VP8_DATA; + idec->state = STATE_VP8_DATA; // Allocate memory and prepare everything. if (!VP8InitFrame(dec, io)) { - return IDecError(idec, dec->status_); + return IDecError(idec, dec->status); } return VP8_STATUS_OK; } // Remaining partitions static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) { - VP8Decoder* const dec = (VP8Decoder*)idec->dec_; - VP8Io* const io = &idec->io_; + VP8Decoder* const dec = (VP8Decoder*)idec->dec; + VP8Io* const io = &idec->io; - // Make sure partition #0 has been read before, to set dec to ready_. - if (!dec->ready_) { + // Make sure partition #0 has been read before, to set dec to ready. + if (!dec->ready) { return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR); } - for (; dec->mb_y_ < dec->mb_h_; ++dec->mb_y_) { - if (idec->last_mb_y_ != dec->mb_y_) { - if (!VP8ParseIntraModeRow(&dec->br_, dec)) { + for (; dec->mb_y < dec->mb_h; ++dec->mb_y) { + if (idec->last_mb_y != dec->mb_y) { + if (!VP8ParseIntraModeRow(&dec->br, dec)) { // note: normally, error shouldn't occur since we already have the whole // partition0 available here in DecodeRemaining(). Reaching EOF while // reading intra modes really means a BITSTREAM_ERROR. return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR); } - idec->last_mb_y_ = dec->mb_y_; + idec->last_mb_y = dec->mb_y; } - for (; dec->mb_x_ < dec->mb_w_; ++dec->mb_x_) { + for (; dec->mb_x < dec->mb_w; ++dec->mb_x) { VP8BitReader* const token_br = - &dec->parts_[dec->mb_y_ & dec->num_parts_minus_one_]; + &dec->parts[dec->mb_y & dec->num_parts_minus_one]; MBContext context; SaveContext(dec, token_br, &context); if (!VP8DecodeMB(dec, token_br)) { // We shouldn't fail when MAX_MB data was available - if (dec->num_parts_minus_one_ == 0 && - MemDataSize(&idec->mem_) > MAX_MB_SIZE) { + if (dec->num_parts_minus_one == 0 && + MemDataSize(&idec->mem) > MAX_MB_SIZE) { return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR); } // Synchronize the threads. - if (dec->mt_method_ > 0) { - if (!WebPGetWorkerInterface()->Sync(&dec->worker_)) { + if (dec->mt_method > 0) { + if (!WebPGetWorkerInterface()->Sync(&dec->worker)) { return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR); } } @@ -496,9 +507,9 @@ static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) { return VP8_STATUS_SUSPENDED; } // Release buffer only if there is only one partition - if (dec->num_parts_minus_one_ == 0) { - idec->mem_.start_ = token_br->buf_ - idec->mem_.buf_; - assert(idec->mem_.start_ <= idec->mem_.end_); + if (dec->num_parts_minus_one == 0) { + idec->mem.start = token_br->buf - idec->mem.buf; + assert(idec->mem.start <= idec->mem.end); } } VP8InitScanline(dec); // Prepare for next scanline @@ -510,10 +521,10 @@ static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) { } // Synchronize the thread and check for errors. if (!VP8ExitCritical(dec, io)) { - idec->state_ = STATE_ERROR; // prevent re-entry in IDecError + idec->state = STATE_ERROR; // prevent re-entry in IDecError return IDecError(idec, VP8_STATUS_USER_ABORT); } - dec->ready_ = 0; + dec->ready = 0; return FinishDecoding(idec); } @@ -526,81 +537,81 @@ static VP8StatusCode ErrorStatusLossless(WebPIDecoder* const idec, } static VP8StatusCode DecodeVP8LHeader(WebPIDecoder* const idec) { - VP8Io* const io = &idec->io_; - VP8LDecoder* const dec = (VP8LDecoder*)idec->dec_; - const WebPDecParams* const params = &idec->params_; + VP8Io* const io = &idec->io; + VP8LDecoder* const dec = (VP8LDecoder*)idec->dec; + const WebPDecParams* const params = &idec->params; WebPDecBuffer* const output = params->output; - size_t curr_size = MemDataSize(&idec->mem_); - assert(idec->is_lossless_); + size_t curr_size = MemDataSize(&idec->mem); + assert(idec->is_lossless); // Wait until there's enough data for decoding header. - if (curr_size < (idec->chunk_size_ >> 3)) { - dec->status_ = VP8_STATUS_SUSPENDED; - return ErrorStatusLossless(idec, dec->status_); + if (curr_size < (idec->chunk_size >> 3)) { + dec->status = VP8_STATUS_SUSPENDED; + return ErrorStatusLossless(idec, dec->status); } if (!VP8LDecodeHeader(dec, io)) { - if (dec->status_ == VP8_STATUS_BITSTREAM_ERROR && - curr_size < idec->chunk_size_) { - dec->status_ = VP8_STATUS_SUSPENDED; + if (dec->status == VP8_STATUS_BITSTREAM_ERROR && + curr_size < idec->chunk_size) { + dec->status = VP8_STATUS_SUSPENDED; } - return ErrorStatusLossless(idec, dec->status_); + return ErrorStatusLossless(idec, dec->status); } // Allocate/verify output buffer now. - dec->status_ = WebPAllocateDecBuffer(io->width, io->height, params->options, - output); - if (dec->status_ != VP8_STATUS_OK) { - return IDecError(idec, dec->status_); + dec->status = WebPAllocateDecBuffer(io->width, io->height, params->options, + output); + if (dec->status != VP8_STATUS_OK) { + return IDecError(idec, dec->status); } - idec->state_ = STATE_VP8L_DATA; + idec->state = STATE_VP8L_DATA; return VP8_STATUS_OK; } static VP8StatusCode DecodeVP8LData(WebPIDecoder* const idec) { - VP8LDecoder* const dec = (VP8LDecoder*)idec->dec_; - const size_t curr_size = MemDataSize(&idec->mem_); - assert(idec->is_lossless_); + VP8LDecoder* const dec = (VP8LDecoder*)idec->dec; + const size_t curr_size = MemDataSize(&idec->mem); + assert(idec->is_lossless); // Switch to incremental decoding if we don't have all the bytes available. - dec->incremental_ = (curr_size < idec->chunk_size_); + dec->incremental = (curr_size < idec->chunk_size); if (!VP8LDecodeImage(dec)) { - return ErrorStatusLossless(idec, dec->status_); + return ErrorStatusLossless(idec, dec->status); } - assert(dec->status_ == VP8_STATUS_OK || dec->status_ == VP8_STATUS_SUSPENDED); - return (dec->status_ == VP8_STATUS_SUSPENDED) ? dec->status_ - : FinishDecoding(idec); + assert(dec->status == VP8_STATUS_OK || dec->status == VP8_STATUS_SUSPENDED); + return (dec->status == VP8_STATUS_SUSPENDED) ? dec->status + : FinishDecoding(idec); } // Main decoding loop static VP8StatusCode IDecode(WebPIDecoder* idec) { VP8StatusCode status = VP8_STATUS_SUSPENDED; - if (idec->state_ == STATE_WEBP_HEADER) { + if (idec->state == STATE_WEBP_HEADER) { status = DecodeWebPHeaders(idec); } else { - if (idec->dec_ == NULL) { + if (idec->dec == NULL) { return VP8_STATUS_SUSPENDED; // can't continue if we have no decoder. } } - if (idec->state_ == STATE_VP8_HEADER) { + if (idec->state == STATE_VP8_HEADER) { status = DecodeVP8FrameHeader(idec); } - if (idec->state_ == STATE_VP8_PARTS0) { + if (idec->state == STATE_VP8_PARTS0) { status = DecodePartition0(idec); } - if (idec->state_ == STATE_VP8_DATA) { - const VP8Decoder* const dec = (VP8Decoder*)idec->dec_; + if (idec->state == STATE_VP8_DATA) { + const VP8Decoder* const dec = (VP8Decoder*)idec->dec; if (dec == NULL) { return VP8_STATUS_SUSPENDED; // can't continue if we have no decoder. } status = DecodeRemaining(idec); } - if (idec->state_ == STATE_VP8L_HEADER) { + if (idec->state == STATE_VP8L_HEADER) { status = DecodeVP8LHeader(idec); } - if (idec->state_ == STATE_VP8L_DATA) { + if (idec->state == STATE_VP8L_DATA) { status = DecodeVP8LData(idec); } return status; @@ -617,29 +628,29 @@ WEBP_NODISCARD static WebPIDecoder* NewDecoder( return NULL; } - idec->state_ = STATE_WEBP_HEADER; - idec->chunk_size_ = 0; + idec->state = STATE_WEBP_HEADER; + idec->chunk_size = 0; - idec->last_mb_y_ = -1; + idec->last_mb_y = -1; - InitMemBuffer(&idec->mem_); - if (!WebPInitDecBuffer(&idec->output_) || !VP8InitIo(&idec->io_)) { + InitMemBuffer(&idec->mem); + if (!WebPInitDecBuffer(&idec->output) || !VP8InitIo(&idec->io)) { WebPSafeFree(idec); return NULL; } - WebPResetDecParams(&idec->params_); + WebPResetDecParams(&idec->params); if (output_buffer == NULL || WebPAvoidSlowMemory(output_buffer, features)) { - idec->params_.output = &idec->output_; - idec->final_output_ = output_buffer; + idec->params.output = &idec->output; + idec->final_output = output_buffer; if (output_buffer != NULL) { - idec->params_.output->colorspace = output_buffer->colorspace; + idec->params.output->colorspace = output_buffer->colorspace; } } else { - idec->params_.output = output_buffer; - idec->final_output_ = NULL; + idec->params.output = output_buffer; + idec->final_output = NULL; } - WebPInitCustomIo(&idec->params_, &idec->io_); // Plug the I/O functions. + WebPInitCustomIo(&idec->params, &idec->io); // Plug the I/O functions. return idec; } @@ -674,27 +685,27 @@ WebPIDecoder* WebPIDecode(const uint8_t* data, size_t data_size, } // Finish initialization if (config != NULL) { - idec->params_.options = &config->options; + idec->params.options = &config->options; } return idec; } void WebPIDelete(WebPIDecoder* idec) { if (idec == NULL) return; - if (idec->dec_ != NULL) { - if (!idec->is_lossless_) { - if (idec->state_ == STATE_VP8_DATA) { + if (idec->dec != NULL) { + if (!idec->is_lossless) { + if (idec->state == STATE_VP8_DATA) { // Synchronize the thread, clean-up and check for errors. // TODO(vrabaud) do we care about the return result? - (void)VP8ExitCritical((VP8Decoder*)idec->dec_, &idec->io_); + (void)VP8ExitCritical((VP8Decoder*)idec->dec, &idec->io); } - VP8Delete((VP8Decoder*)idec->dec_); + VP8Delete((VP8Decoder*)idec->dec); } else { - VP8LDelete((VP8LDecoder*)idec->dec_); + VP8LDelete((VP8LDecoder*)idec->dec); } } - ClearMemBuffer(&idec->mem_); - WebPFreeDecBuffer(&idec->output_); + ClearMemBuffer(&idec->mem); + WebPFreeDecBuffer(&idec->output); WebPSafeFree(idec); } @@ -717,11 +728,11 @@ WebPIDecoder* WebPINewRGB(WEBP_CSP_MODE csp, uint8_t* output_buffer, } idec = WebPINewDecoder(NULL); if (idec == NULL) return NULL; - idec->output_.colorspace = csp; - idec->output_.is_external_memory = is_external_memory; - idec->output_.u.RGBA.rgba = output_buffer; - idec->output_.u.RGBA.stride = output_stride; - idec->output_.u.RGBA.size = output_buffer_size; + idec->output.colorspace = csp; + idec->output.is_external_memory = is_external_memory; + idec->output.u.RGBA.rgba = output_buffer; + idec->output.u.RGBA.stride = output_stride; + idec->output.u.RGBA.size = output_buffer_size; return idec; } @@ -751,20 +762,20 @@ WebPIDecoder* WebPINewYUVA(uint8_t* luma, size_t luma_size, int luma_stride, idec = WebPINewDecoder(NULL); if (idec == NULL) return NULL; - idec->output_.colorspace = colorspace; - idec->output_.is_external_memory = is_external_memory; - idec->output_.u.YUVA.y = luma; - idec->output_.u.YUVA.y_stride = luma_stride; - idec->output_.u.YUVA.y_size = luma_size; - idec->output_.u.YUVA.u = u; - idec->output_.u.YUVA.u_stride = u_stride; - idec->output_.u.YUVA.u_size = u_size; - idec->output_.u.YUVA.v = v; - idec->output_.u.YUVA.v_stride = v_stride; - idec->output_.u.YUVA.v_size = v_size; - idec->output_.u.YUVA.a = a; - idec->output_.u.YUVA.a_stride = a_stride; - idec->output_.u.YUVA.a_size = a_size; + idec->output.colorspace = colorspace; + idec->output.is_external_memory = is_external_memory; + idec->output.u.YUVA.y = luma; + idec->output.u.YUVA.y_stride = luma_stride; + idec->output.u.YUVA.y_size = luma_size; + idec->output.u.YUVA.u = u; + idec->output.u.YUVA.u_stride = u_stride; + idec->output.u.YUVA.u_size = u_size; + idec->output.u.YUVA.v = v; + idec->output.u.YUVA.v_stride = v_stride; + idec->output.u.YUVA.v_size = v_size; + idec->output.u.YUVA.a = a; + idec->output.u.YUVA.a_stride = a_stride; + idec->output.u.YUVA.a_size = a_size; return idec; } @@ -781,10 +792,10 @@ WebPIDecoder* WebPINewYUV(uint8_t* luma, size_t luma_size, int luma_stride, static VP8StatusCode IDecCheckStatus(const WebPIDecoder* const idec) { assert(idec); - if (idec->state_ == STATE_ERROR) { + if (idec->state == STATE_ERROR) { return VP8_STATUS_BITSTREAM_ERROR; } - if (idec->state_ == STATE_DONE) { + if (idec->state == STATE_DONE) { return VP8_STATUS_OK; } return VP8_STATUS_SUSPENDED; @@ -801,7 +812,7 @@ VP8StatusCode WebPIAppend(WebPIDecoder* idec, return status; } // Check mixed calls between RemapMemBuffer and AppendToMemBuffer. - if (!CheckMemBufferMode(&idec->mem_, MEM_MODE_APPEND)) { + if (!CheckMemBufferMode(&idec->mem, MEM_MODE_APPEND)) { return VP8_STATUS_INVALID_PARAM; } // Append data to memory buffer @@ -822,7 +833,7 @@ VP8StatusCode WebPIUpdate(WebPIDecoder* idec, return status; } // Check mixed calls between RemapMemBuffer and AppendToMemBuffer. - if (!CheckMemBufferMode(&idec->mem_, MEM_MODE_MAP)) { + if (!CheckMemBufferMode(&idec->mem, MEM_MODE_MAP)) { return VP8_STATUS_INVALID_PARAM; } // Make the memory buffer point to the new buffer @@ -835,16 +846,16 @@ VP8StatusCode WebPIUpdate(WebPIDecoder* idec, //------------------------------------------------------------------------------ static const WebPDecBuffer* GetOutputBuffer(const WebPIDecoder* const idec) { - if (idec == NULL || idec->dec_ == NULL) { + if (idec == NULL || idec->dec == NULL) { return NULL; } - if (idec->state_ <= STATE_VP8_PARTS0) { + if (idec->state <= STATE_VP8_PARTS0) { return NULL; } - if (idec->final_output_ != NULL) { + if (idec->final_output != NULL) { return NULL; // not yet slow-copied } - return idec->params_.output; + return idec->params.output; } const WebPDecBuffer* WebPIDecodedArea(const WebPIDecoder* idec, @@ -855,7 +866,7 @@ const WebPDecBuffer* WebPIDecodedArea(const WebPIDecoder* idec, if (top != NULL) *top = 0; if (src != NULL) { if (width != NULL) *width = src->width; - if (height != NULL) *height = idec->params_.last_y; + if (height != NULL) *height = idec->params.last_y; } else { if (width != NULL) *width = 0; if (height != NULL) *height = 0; @@ -871,7 +882,7 @@ WEBP_NODISCARD uint8_t* WebPIDecGetRGB(const WebPIDecoder* idec, int* last_y, return NULL; } - if (last_y != NULL) *last_y = idec->params_.last_y; + if (last_y != NULL) *last_y = idec->params.last_y; if (width != NULL) *width = src->width; if (height != NULL) *height = src->height; if (stride != NULL) *stride = src->u.RGBA.stride; @@ -889,7 +900,7 @@ WEBP_NODISCARD uint8_t* WebPIDecGetYUVA(const WebPIDecoder* idec, int* last_y, return NULL; } - if (last_y != NULL) *last_y = idec->params_.last_y; + if (last_y != NULL) *last_y = idec->params.last_y; if (u != NULL) *u = src->u.YUVA.u; if (v != NULL) *v = src->u.YUVA.v; if (a != NULL) *a = src->u.YUVA.a; @@ -907,14 +918,14 @@ int WebPISetIOHooks(WebPIDecoder* const idec, VP8IoSetupHook setup, VP8IoTeardownHook teardown, void* user_data) { - if (idec == NULL || idec->state_ > STATE_WEBP_HEADER) { + if (idec == NULL || idec->state > STATE_WEBP_HEADER) { return 0; } - idec->io_.put = put; - idec->io_.setup = setup; - idec->io_.teardown = teardown; - idec->io_.opaque = user_data; + idec->io.put = put; + idec->io.setup = setup; + idec->io.teardown = teardown; + idec->io.opaque = user_data; return 1; } diff --git a/libwebp/src/dec/io_dec.c b/libwebp/src/dec/io_dec.c index 5ef62988..b6e720ed 100644 --- a/libwebp/src/dec/io_dec.c +++ b/libwebp/src/dec/io_dec.c @@ -12,12 +12,20 @@ // Author: Skal (pascal.massimino@gmail.com) #include +#include #include +#include + +#include "src/dec/vp8_dec.h" +#include "src/webp/types.h" #include "src/dec/vp8i_dec.h" #include "src/dec/webpi_dec.h" +#include "src/dsp/cpu.h" #include "src/dsp/dsp.h" #include "src/dsp/yuv.h" +#include "src/utils/rescaler_utils.h" #include "src/utils/utils.h" +#include "src/webp/decode.h" //------------------------------------------------------------------------------ // Main YUV<->RGB conversion functions @@ -25,9 +33,9 @@ static int EmitYUV(const VP8Io* const io, WebPDecParams* const p) { WebPDecBuffer* output = p->output; const WebPYUVABuffer* const buf = &output->u.YUVA; - uint8_t* const y_dst = buf->y + (size_t)io->mb_y * buf->y_stride; - uint8_t* const u_dst = buf->u + (size_t)(io->mb_y >> 1) * buf->u_stride; - uint8_t* const v_dst = buf->v + (size_t)(io->mb_y >> 1) * buf->v_stride; + uint8_t* const y_dst = buf->y + (ptrdiff_t)io->mb_y * buf->y_stride; + uint8_t* const u_dst = buf->u + (ptrdiff_t)(io->mb_y >> 1) * buf->u_stride; + uint8_t* const v_dst = buf->v + (ptrdiff_t)(io->mb_y >> 1) * buf->v_stride; const int mb_w = io->mb_w; const int mb_h = io->mb_h; const int uv_w = (mb_w + 1) / 2; @@ -42,7 +50,7 @@ static int EmitYUV(const VP8Io* const io, WebPDecParams* const p) { static int EmitSampledRGB(const VP8Io* const io, WebPDecParams* const p) { WebPDecBuffer* const output = p->output; WebPRGBABuffer* const buf = &output->u.RGBA; - uint8_t* const dst = buf->rgba + (size_t)io->mb_y * buf->stride; + uint8_t* const dst = buf->rgba + (ptrdiff_t)io->mb_y * buf->stride; WebPSamplerProcessPlane(io->y, io->y_stride, io->u, io->v, io->uv_stride, dst, buf->stride, io->mb_w, io->mb_h, @@ -57,7 +65,7 @@ static int EmitSampledRGB(const VP8Io* const io, WebPDecParams* const p) { static int EmitFancyRGB(const VP8Io* const io, WebPDecParams* const p) { int num_lines_out = io->mb_h; // a priori guess const WebPRGBABuffer* const buf = &p->output->u.RGBA; - uint8_t* dst = buf->rgba + (size_t)io->mb_y * buf->stride; + uint8_t* dst = buf->rgba + (ptrdiff_t)io->mb_y * buf->stride; WebPUpsampleLinePairFunc upsample = WebPUpsamplers[p->output->colorspace]; const uint8_t* cur_y = io->y; const uint8_t* cur_u = io->u; @@ -128,7 +136,7 @@ static int EmitAlphaYUV(const VP8Io* const io, WebPDecParams* const p, const WebPYUVABuffer* const buf = &p->output->u.YUVA; const int mb_w = io->mb_w; const int mb_h = io->mb_h; - uint8_t* dst = buf->a + (size_t)io->mb_y * buf->a_stride; + uint8_t* dst = buf->a + (ptrdiff_t)io->mb_y * buf->a_stride; int j; (void)expected_num_lines_out; assert(expected_num_lines_out == mb_h); @@ -181,8 +189,8 @@ static int EmitAlphaRGB(const VP8Io* const io, WebPDecParams* const p, (colorspace == MODE_ARGB || colorspace == MODE_Argb); const WebPRGBABuffer* const buf = &p->output->u.RGBA; int num_rows; - const size_t start_y = GetAlphaSourceRow(io, &alpha, &num_rows); - uint8_t* const base_rgba = buf->rgba + start_y * buf->stride; + const int start_y = GetAlphaSourceRow(io, &alpha, &num_rows); + uint8_t* const base_rgba = buf->rgba + (ptrdiff_t)start_y * buf->stride; uint8_t* const dst = base_rgba + (alpha_first ? 0 : 3); const int has_alpha = WebPDispatchAlpha(alpha, io->width, mb_w, num_rows, dst, buf->stride); @@ -205,8 +213,8 @@ static int EmitAlphaRGBA4444(const VP8Io* const io, WebPDecParams* const p, const WEBP_CSP_MODE colorspace = p->output->colorspace; const WebPRGBABuffer* const buf = &p->output->u.RGBA; int num_rows; - const size_t start_y = GetAlphaSourceRow(io, &alpha, &num_rows); - uint8_t* const base_rgba = buf->rgba + start_y * buf->stride; + const int start_y = GetAlphaSourceRow(io, &alpha, &num_rows); + uint8_t* const base_rgba = buf->rgba + (ptrdiff_t)start_y * buf->stride; #if (WEBP_SWAP_16BIT_CSP == 1) uint8_t* alpha_dst = base_rgba; #else @@ -257,7 +265,7 @@ static int EmitRescaledYUV(const VP8Io* const io, WebPDecParams* const p) { if (WebPIsAlphaMode(p->output->colorspace) && io->a != NULL) { // Before rescaling, we premultiply the luma directly into the io->y // internal buffer. This is OK since these samples are not used for - // intra-prediction (the top samples are saved in cache_y_/u_/v_). + // intra-prediction (the top samples are saved in cache_y/u/v). // But we need to cast the const away, though. WebPMultRows((uint8_t*)io->y, io->y_stride, io->a, io->width, io->mb_w, mb_h, 0); @@ -271,9 +279,9 @@ static int EmitRescaledYUV(const VP8Io* const io, WebPDecParams* const p) { static int EmitRescaledAlphaYUV(const VP8Io* const io, WebPDecParams* const p, int expected_num_lines_out) { const WebPYUVABuffer* const buf = &p->output->u.YUVA; - uint8_t* const dst_a = buf->a + (size_t)p->last_y * buf->a_stride; + uint8_t* const dst_a = buf->a + (ptrdiff_t)p->last_y * buf->a_stride; if (io->a != NULL) { - uint8_t* const dst_y = buf->y + (size_t)p->last_y * buf->y_stride; + uint8_t* const dst_y = buf->y + (ptrdiff_t)p->last_y * buf->y_stride; const int num_lines_out = Rescale(io->a, io->width, io->mb_h, p->scaler_a); assert(expected_num_lines_out == num_lines_out); if (num_lines_out > 0) { // unmultiply the Y @@ -362,7 +370,7 @@ static int ExportRGB(WebPDecParams* const p, int y_pos) { const WebPYUV444Converter convert = WebPYUV444Converters[p->output->colorspace]; const WebPRGBABuffer* const buf = &p->output->u.RGBA; - uint8_t* dst = buf->rgba + (size_t)y_pos * buf->stride; + uint8_t* dst = buf->rgba + (ptrdiff_t)y_pos * buf->stride; int num_lines_out = 0; // For RGB rescaling, because of the YUV420, current scan position // U/V can be +1/-1 line from the Y one. Hence the double test. @@ -389,14 +397,14 @@ static int EmitRescaledRGB(const VP8Io* const io, WebPDecParams* const p) { while (j < mb_h) { const int y_lines_in = WebPRescalerImport(p->scaler_y, mb_h - j, - io->y + (size_t)j * io->y_stride, io->y_stride); + io->y + (ptrdiff_t)j * io->y_stride, io->y_stride); j += y_lines_in; if (WebPRescaleNeededLines(p->scaler_u, uv_mb_h - uv_j)) { const int u_lines_in = WebPRescalerImport( - p->scaler_u, uv_mb_h - uv_j, io->u + (size_t)uv_j * io->uv_stride, + p->scaler_u, uv_mb_h - uv_j, io->u + (ptrdiff_t)uv_j * io->uv_stride, io->uv_stride); const int v_lines_in = WebPRescalerImport( - p->scaler_v, uv_mb_h - uv_j, io->v + (size_t)uv_j * io->uv_stride, + p->scaler_v, uv_mb_h - uv_j, io->v + (ptrdiff_t)uv_j * io->uv_stride, io->uv_stride); (void)v_lines_in; // remove a gcc warning assert(u_lines_in == v_lines_in); @@ -409,7 +417,7 @@ static int EmitRescaledRGB(const VP8Io* const io, WebPDecParams* const p) { static int ExportAlpha(WebPDecParams* const p, int y_pos, int max_lines_out) { const WebPRGBABuffer* const buf = &p->output->u.RGBA; - uint8_t* const base_rgba = buf->rgba + (size_t)y_pos * buf->stride; + uint8_t* const base_rgba = buf->rgba + (ptrdiff_t)y_pos * buf->stride; const WEBP_CSP_MODE colorspace = p->output->colorspace; const int alpha_first = (colorspace == MODE_ARGB || colorspace == MODE_Argb); @@ -437,7 +445,7 @@ static int ExportAlpha(WebPDecParams* const p, int y_pos, int max_lines_out) { static int ExportAlphaRGBA4444(WebPDecParams* const p, int y_pos, int max_lines_out) { const WebPRGBABuffer* const buf = &p->output->u.RGBA; - uint8_t* const base_rgba = buf->rgba + (size_t)y_pos * buf->stride; + uint8_t* const base_rgba = buf->rgba + (ptrdiff_t)y_pos * buf->stride; #if (WEBP_SWAP_16BIT_CSP == 1) uint8_t* alpha_dst = base_rgba; #else @@ -476,7 +484,7 @@ static int EmitRescaledAlphaRGB(const VP8Io* const io, WebPDecParams* const p, int lines_left = expected_num_out_lines; const int y_end = p->last_y + lines_left; while (lines_left > 0) { - const int64_t row_offset = (int64_t)scaler->src_y - io->mb_y; + const int64_t row_offset = (ptrdiff_t)scaler->src_y - io->mb_y; WebPRescalerImport(scaler, io->mb_h + io->mb_y - scaler->src_y, io->a + row_offset * io->width, io->width); lines_left -= p->emit_alpha_row(p, y_end - lines_left, lines_left); diff --git a/libwebp/src/dec/quant_dec.c b/libwebp/src/dec/quant_dec.c index a0ac018b..977bec56 100644 --- a/libwebp/src/dec/quant_dec.c +++ b/libwebp/src/dec/quant_dec.c @@ -11,7 +11,11 @@ // // Author: Skal (pascal.massimino@gmail.com) +#include "src/dec/common_dec.h" +#include "src/dec/vp8_dec.h" #include "src/dec/vp8i_dec.h" +#include "src/utils/bit_reader_utils.h" +#include "src/webp/types.h" static WEBP_INLINE int clip(int v, int M) { return v < 0 ? 0 : v > M ? M : v; @@ -60,7 +64,7 @@ static const uint16_t kAcTable[128] = { // Paragraph 9.6 void VP8ParseQuant(VP8Decoder* const dec) { - VP8BitReader* const br = &dec->br_; + VP8BitReader* const br = &dec->br; const int base_q0 = VP8GetValue(br, 7, "global-header"); const int dqy1_dc = VP8Get(br, "global-header") ? VP8GetSignedValue(br, 4, "global-header") : 0; @@ -73,43 +77,42 @@ void VP8ParseQuant(VP8Decoder* const dec) { const int dquv_ac = VP8Get(br, "global-header") ? VP8GetSignedValue(br, 4, "global-header") : 0; - const VP8SegmentHeader* const hdr = &dec->segment_hdr_; + const VP8SegmentHeader* const hdr = &dec->segment_hdr; int i; for (i = 0; i < NUM_MB_SEGMENTS; ++i) { int q; - if (hdr->use_segment_) { - q = hdr->quantizer_[i]; - if (!hdr->absolute_delta_) { + if (hdr->use_segment) { + q = hdr->quantizer[i]; + if (!hdr->absolute_delta) { q += base_q0; } } else { if (i > 0) { - dec->dqm_[i] = dec->dqm_[0]; + dec->dqm[i] = dec->dqm[0]; continue; } else { q = base_q0; } } { - VP8QuantMatrix* const m = &dec->dqm_[i]; - m->y1_mat_[0] = kDcTable[clip(q + dqy1_dc, 127)]; - m->y1_mat_[1] = kAcTable[clip(q + 0, 127)]; + VP8QuantMatrix* const m = &dec->dqm[i]; + m->y1_mat[0] = kDcTable[clip(q + dqy1_dc, 127)]; + m->y1_mat[1] = kAcTable[clip(q + 0, 127)]; - m->y2_mat_[0] = kDcTable[clip(q + dqy2_dc, 127)] * 2; + m->y2_mat[0] = kDcTable[clip(q + dqy2_dc, 127)] * 2; // For all x in [0..284], x*155/100 is bitwise equal to (x*101581) >> 16. // The smallest precision for that is '(x*6349) >> 12' but 16 is a good // word size. - m->y2_mat_[1] = (kAcTable[clip(q + dqy2_ac, 127)] * 101581) >> 16; - if (m->y2_mat_[1] < 8) m->y2_mat_[1] = 8; + m->y2_mat[1] = (kAcTable[clip(q + dqy2_ac, 127)] * 101581) >> 16; + if (m->y2_mat[1] < 8) m->y2_mat[1] = 8; - m->uv_mat_[0] = kDcTable[clip(q + dquv_dc, 117)]; - m->uv_mat_[1] = kAcTable[clip(q + dquv_ac, 127)]; + m->uv_mat[0] = kDcTable[clip(q + dquv_dc, 117)]; + m->uv_mat[1] = kAcTable[clip(q + dquv_ac, 127)]; - m->uv_quant_ = q + dquv_ac; // for dithering strength evaluation + m->uv_quant = q + dquv_ac; // for dithering strength evaluation } } } //------------------------------------------------------------------------------ - diff --git a/libwebp/src/dec/tree_dec.c b/libwebp/src/dec/tree_dec.c index 24346059..a3b00ef7 100644 --- a/libwebp/src/dec/tree_dec.c +++ b/libwebp/src/dec/tree_dec.c @@ -11,12 +11,19 @@ // // Author: Skal (pascal.massimino@gmail.com) +#include + +#include "src/dec/common_dec.h" +#include "src/webp/types.h" +#include "src/dec/vp8_dec.h" #include "src/dec/vp8i_dec.h" #include "src/dsp/cpu.h" #include "src/utils/bit_reader_inl_utils.h" +#include "src/utils/bit_reader_utils.h" #if !defined(USE_GENERIC_TREE) -#if !defined(__arm__) && !defined(_M_ARM) && !WEBP_AARCH64 +#if !defined(__arm__) && !defined(_M_ARM) && !WEBP_AARCH64 && \ + !defined(__wasm__) // using a table is ~1-2% slower on ARM. Prefer the coded-tree approach then. #define USE_GENERIC_TREE 1 // ALTERNATE_CODE #else @@ -283,40 +290,40 @@ static const uint8_t kBModesProba[NUM_BMODES][NUM_BMODES][NUM_BMODES - 1] = { }; void VP8ResetProba(VP8Proba* const proba) { - memset(proba->segments_, 255u, sizeof(proba->segments_)); - // proba->bands_[][] is initialized later + memset(proba->segments, 255u, sizeof(proba->segments)); + // proba->bands[][] is initialized later } static void ParseIntraMode(VP8BitReader* const br, VP8Decoder* const dec, int mb_x) { - uint8_t* const top = dec->intra_t_ + 4 * mb_x; - uint8_t* const left = dec->intra_l_; - VP8MBData* const block = dec->mb_data_ + mb_x; + uint8_t* const top = dec->intra_t + 4 * mb_x; + uint8_t* const left = dec->intra_l; + VP8MBData* const block = dec->mb_data + mb_x; // Note: we don't save segment map (yet), as we don't expect // to decode more than 1 keyframe. - if (dec->segment_hdr_.update_map_) { + if (dec->segment_hdr.update_map) { // Hardcoded tree parsing - block->segment_ = !VP8GetBit(br, dec->proba_.segments_[0], "segments") - ? VP8GetBit(br, dec->proba_.segments_[1], "segments") - : VP8GetBit(br, dec->proba_.segments_[2], "segments") + 2; + block->segment = !VP8GetBit(br, dec->proba.segments[0], "segments") + ? VP8GetBit(br, dec->proba.segments[1], "segments") + : VP8GetBit(br, dec->proba.segments[2], "segments") + 2; } else { - block->segment_ = 0; // default for intra + block->segment = 0; // default for intra } - if (dec->use_skip_proba_) block->skip_ = VP8GetBit(br, dec->skip_p_, "skip"); + if (dec->use_skip_proba) block->skip = VP8GetBit(br, dec->skip_p, "skip"); - block->is_i4x4_ = !VP8GetBit(br, 145, "block-size"); - if (!block->is_i4x4_) { + block->is_i4x4 = !VP8GetBit(br, 145, "block-size"); + if (!block->is_i4x4) { // Hardcoded 16x16 intra-mode decision tree. const int ymode = VP8GetBit(br, 156, "pred-modes") ? (VP8GetBit(br, 128, "pred-modes") ? TM_PRED : H_PRED) : (VP8GetBit(br, 163, "pred-modes") ? V_PRED : DC_PRED); - block->imodes_[0] = ymode; + block->imodes[0] = ymode; memset(top, ymode, 4 * sizeof(*top)); memset(left, ymode, 4 * sizeof(*left)); } else { - uint8_t* modes = block->imodes_; + uint8_t* modes = block->imodes; int y; for (y = 0; y < 4; ++y) { int ymode = left[y]; @@ -353,17 +360,17 @@ static void ParseIntraMode(VP8BitReader* const br, } } // Hardcoded UVMode decision tree - block->uvmode_ = !VP8GetBit(br, 142, "pred-modes-uv") ? DC_PRED - : !VP8GetBit(br, 114, "pred-modes-uv") ? V_PRED - : VP8GetBit(br, 183, "pred-modes-uv") ? TM_PRED : H_PRED; + block->uvmode = !VP8GetBit(br, 142, "pred-modes-uv") ? DC_PRED + : !VP8GetBit(br, 114, "pred-modes-uv") ? V_PRED + : VP8GetBit(br, 183, "pred-modes-uv") ? TM_PRED : H_PRED; } int VP8ParseIntraModeRow(VP8BitReader* const br, VP8Decoder* const dec) { int mb_x; - for (mb_x = 0; mb_x < dec->mb_w_; ++mb_x) { + for (mb_x = 0; mb_x < dec->mb_w; ++mb_x) { ParseIntraMode(br, dec, mb_x); } - return !dec->br_.eof_; + return !dec->br.eof; } //------------------------------------------------------------------------------ @@ -513,7 +520,7 @@ static const uint8_t kBands[16 + 1] = { }; void VP8ParseProba(VP8BitReader* const br, VP8Decoder* const dec) { - VP8Proba* const proba = &dec->proba_; + VP8Proba* const proba = &dec->proba; int t, b, c, p; for (t = 0; t < NUM_TYPES; ++t) { for (b = 0; b < NUM_BANDS; ++b) { @@ -523,16 +530,16 @@ void VP8ParseProba(VP8BitReader* const br, VP8Decoder* const dec) { VP8GetBit(br, CoeffsUpdateProba[t][b][c][p], "global-header") ? VP8GetValue(br, 8, "global-header") : CoeffsProba0[t][b][c][p]; - proba->bands_[t][b].probas_[c][p] = v; + proba->bands[t][b].probas[c][p] = v; } } } for (b = 0; b < 16 + 1; ++b) { - proba->bands_ptr_[t][b] = &proba->bands_[t][kBands[b]]; + proba->bands_ptr[t][b] = &proba->bands[t][kBands[b]]; } } - dec->use_skip_proba_ = VP8Get(br, "global-header"); - if (dec->use_skip_proba_) { - dec->skip_p_ = VP8GetValue(br, 8, "global-header"); + dec->use_skip_proba = VP8Get(br, "global-header"); + if (dec->use_skip_proba) { + dec->skip_p = VP8GetValue(br, 8, "global-header"); } } diff --git a/libwebp/src/dec/vp8_dec.c b/libwebp/src/dec/vp8_dec.c index 2ee89006..b1df3a0a 100644 --- a/libwebp/src/dec/vp8_dec.c +++ b/libwebp/src/dec/vp8_dec.c @@ -11,14 +11,25 @@ // // Author: Skal (pascal.massimino@gmail.com) +#include #include +#include #include "src/dec/alphai_dec.h" +#include "src/dec/common_dec.h" +#include "src/dec/vp8_dec.h" #include "src/dec/vp8i_dec.h" #include "src/dec/vp8li_dec.h" #include "src/dec/webpi_dec.h" +#include "src/dsp/cpu.h" +#include "src/dsp/dsp.h" #include "src/utils/bit_reader_inl_utils.h" +#include "src/utils/bit_reader_utils.h" +#include "src/utils/thread_utils.h" #include "src/utils/utils.h" +#include "src/webp/decode.h" +#include "src/webp/format_constants.h" +#include "src/webp/types.h" //------------------------------------------------------------------------------ @@ -40,8 +51,8 @@ static void InitGetCoeffs(void); // VP8Decoder static void SetOk(VP8Decoder* const dec) { - dec->status_ = VP8_STATUS_OK; - dec->error_msg_ = "OK"; + dec->status = VP8_STATUS_OK; + dec->error_msg = "OK"; } int VP8InitIoInternal(VP8Io* const io, int version) { @@ -58,9 +69,9 @@ VP8Decoder* VP8New(void) { VP8Decoder* const dec = (VP8Decoder*)WebPSafeCalloc(1ULL, sizeof(*dec)); if (dec != NULL) { SetOk(dec); - WebPGetWorkerInterface()->Init(&dec->worker_); - dec->ready_ = 0; - dec->num_parts_minus_one_ = 0; + WebPGetWorkerInterface()->Init(&dec->worker); + dec->ready = 0; + dec->num_parts_minus_one = 0; InitGetCoeffs(); } return dec; @@ -68,13 +79,13 @@ VP8Decoder* VP8New(void) { VP8StatusCode VP8Status(VP8Decoder* const dec) { if (!dec) return VP8_STATUS_INVALID_PARAM; - return dec->status_; + return dec->status; } const char* VP8StatusMessage(VP8Decoder* const dec) { if (dec == NULL) return "no object"; - if (!dec->error_msg_) return "OK"; - return dec->error_msg_; + if (!dec->error_msg) return "OK"; + return dec->error_msg; } void VP8Delete(VP8Decoder* const dec) { @@ -87,12 +98,12 @@ void VP8Delete(VP8Decoder* const dec) { int VP8SetError(VP8Decoder* const dec, VP8StatusCode error, const char* const msg) { // VP8_STATUS_SUSPENDED is only meaningful in incremental decoding. - assert(dec->incremental_ || error != VP8_STATUS_SUSPENDED); + assert(dec->incremental || error != VP8_STATUS_SUSPENDED); // The oldest error reported takes precedence over the new one. - if (dec->status_ == VP8_STATUS_OK) { - dec->status_ = error; - dec->error_msg_ = msg; - dec->ready_ = 0; + if (dec->status == VP8_STATUS_OK) { + dec->status = error; + dec->error_msg = msg; + dec->ready = 0; } return 0; } @@ -151,11 +162,11 @@ int VP8GetInfo(const uint8_t* data, size_t data_size, size_t chunk_size, static void ResetSegmentHeader(VP8SegmentHeader* const hdr) { assert(hdr != NULL); - hdr->use_segment_ = 0; - hdr->update_map_ = 0; - hdr->absolute_delta_ = 1; - memset(hdr->quantizer_, 0, sizeof(hdr->quantizer_)); - memset(hdr->filter_strength_, 0, sizeof(hdr->filter_strength_)); + hdr->use_segment = 0; + hdr->update_map = 0; + hdr->absolute_delta = 1; + memset(hdr->quantizer, 0, sizeof(hdr->quantizer)); + memset(hdr->filter_strength, 0, sizeof(hdr->filter_strength)); } // Paragraph 9.3 @@ -163,32 +174,32 @@ static int ParseSegmentHeader(VP8BitReader* br, VP8SegmentHeader* hdr, VP8Proba* proba) { assert(br != NULL); assert(hdr != NULL); - hdr->use_segment_ = VP8Get(br, "global-header"); - if (hdr->use_segment_) { - hdr->update_map_ = VP8Get(br, "global-header"); + hdr->use_segment = VP8Get(br, "global-header"); + if (hdr->use_segment) { + hdr->update_map = VP8Get(br, "global-header"); if (VP8Get(br, "global-header")) { // update data int s; - hdr->absolute_delta_ = VP8Get(br, "global-header"); + hdr->absolute_delta = VP8Get(br, "global-header"); for (s = 0; s < NUM_MB_SEGMENTS; ++s) { - hdr->quantizer_[s] = VP8Get(br, "global-header") ? + hdr->quantizer[s] = VP8Get(br, "global-header") ? VP8GetSignedValue(br, 7, "global-header") : 0; } for (s = 0; s < NUM_MB_SEGMENTS; ++s) { - hdr->filter_strength_[s] = VP8Get(br, "global-header") ? + hdr->filter_strength[s] = VP8Get(br, "global-header") ? VP8GetSignedValue(br, 6, "global-header") : 0; } } - if (hdr->update_map_) { + if (hdr->update_map) { int s; for (s = 0; s < MB_FEATURE_TREE_PROBS; ++s) { - proba->segments_[s] = VP8Get(br, "global-header") ? + proba->segments[s] = VP8Get(br, "global-header") ? VP8GetValue(br, 8, "global-header") : 255u; } } } else { - hdr->update_map_ = 0; + hdr->update_map = 0; } - return !br->eof_; + return !br->eof; } // Paragraph 9.5 @@ -202,7 +213,7 @@ static int ParseSegmentHeader(VP8BitReader* br, // If the partitions were positioned ok, VP8_STATUS_OK is returned. static VP8StatusCode ParsePartitions(VP8Decoder* const dec, const uint8_t* buf, size_t size) { - VP8BitReader* const br = &dec->br_; + VP8BitReader* const br = &dec->br; const uint8_t* sz = buf; const uint8_t* buf_end = buf + size; const uint8_t* part_start; @@ -210,8 +221,8 @@ static VP8StatusCode ParsePartitions(VP8Decoder* const dec, size_t last_part; size_t p; - dec->num_parts_minus_one_ = (1 << VP8GetValue(br, 2, "global-header")) - 1; - last_part = dec->num_parts_minus_one_; + dec->num_parts_minus_one = (1 << VP8GetValue(br, 2, "global-header")) - 1; + last_part = dec->num_parts_minus_one; if (size < 3 * last_part) { // we can't even read the sizes with sz[]! That's a failure. return VP8_STATUS_NOT_ENOUGH_DATA; @@ -221,42 +232,42 @@ static VP8StatusCode ParsePartitions(VP8Decoder* const dec, for (p = 0; p < last_part; ++p) { size_t psize = sz[0] | (sz[1] << 8) | (sz[2] << 16); if (psize > size_left) psize = size_left; - VP8InitBitReader(dec->parts_ + p, part_start, psize); + VP8InitBitReader(dec->parts + p, part_start, psize); part_start += psize; size_left -= psize; sz += 3; } - VP8InitBitReader(dec->parts_ + last_part, part_start, size_left); + VP8InitBitReader(dec->parts + last_part, part_start, size_left); if (part_start < buf_end) return VP8_STATUS_OK; - return dec->incremental_ + return dec->incremental ? VP8_STATUS_SUSPENDED // Init is ok, but there's not enough data : VP8_STATUS_NOT_ENOUGH_DATA; } // Paragraph 9.4 static int ParseFilterHeader(VP8BitReader* br, VP8Decoder* const dec) { - VP8FilterHeader* const hdr = &dec->filter_hdr_; - hdr->simple_ = VP8Get(br, "global-header"); - hdr->level_ = VP8GetValue(br, 6, "global-header"); - hdr->sharpness_ = VP8GetValue(br, 3, "global-header"); - hdr->use_lf_delta_ = VP8Get(br, "global-header"); - if (hdr->use_lf_delta_) { + VP8FilterHeader* const hdr = &dec->filter_hdr; + hdr->simple = VP8Get(br, "global-header"); + hdr->level = VP8GetValue(br, 6, "global-header"); + hdr->sharpness = VP8GetValue(br, 3, "global-header"); + hdr->use_lf_delta = VP8Get(br, "global-header"); + if (hdr->use_lf_delta) { if (VP8Get(br, "global-header")) { // update lf-delta? int i; for (i = 0; i < NUM_REF_LF_DELTAS; ++i) { if (VP8Get(br, "global-header")) { - hdr->ref_lf_delta_[i] = VP8GetSignedValue(br, 6, "global-header"); + hdr->ref_lf_delta[i] = VP8GetSignedValue(br, 6, "global-header"); } } for (i = 0; i < NUM_MODE_LF_DELTAS; ++i) { if (VP8Get(br, "global-header")) { - hdr->mode_lf_delta_[i] = VP8GetSignedValue(br, 6, "global-header"); + hdr->mode_lf_delta[i] = VP8GetSignedValue(br, 6, "global-header"); } } } } - dec->filter_type_ = (hdr->level_ == 0) ? 0 : hdr->simple_ ? 1 : 2; - return !br->eof_; + dec->filter_type = (hdr->level == 0) ? 0 : hdr->simple ? 1 : 2; + return !br->eof; } // Topmost call @@ -286,16 +297,16 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) { // Paragraph 9.1 { const uint32_t bits = buf[0] | (buf[1] << 8) | (buf[2] << 16); - frm_hdr = &dec->frm_hdr_; - frm_hdr->key_frame_ = !(bits & 1); - frm_hdr->profile_ = (bits >> 1) & 7; - frm_hdr->show_ = (bits >> 4) & 1; - frm_hdr->partition_length_ = (bits >> 5); - if (frm_hdr->profile_ > 3) { + frm_hdr = &dec->frm_hdr; + frm_hdr->key_frame = !(bits & 1); + frm_hdr->profile = (bits >> 1) & 7; + frm_hdr->show = (bits >> 4) & 1; + frm_hdr->partition_length = (bits >> 5); + if (frm_hdr->profile > 3) { return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, "Incorrect keyframe parameters."); } - if (!frm_hdr->show_) { + if (!frm_hdr->show) { return VP8SetError(dec, VP8_STATUS_UNSUPPORTED_FEATURE, "Frame not displayable."); } @@ -303,8 +314,8 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) { buf_size -= 3; } - pic_hdr = &dec->pic_hdr_; - if (frm_hdr->key_frame_) { + pic_hdr = &dec->pic_hdr; + if (frm_hdr->key_frame) { // Paragraph 9.2 if (buf_size < 7) { return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA, @@ -314,20 +325,20 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) { return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, "Bad code word"); } - pic_hdr->width_ = ((buf[4] << 8) | buf[3]) & 0x3fff; - pic_hdr->xscale_ = buf[4] >> 6; // ratio: 1, 5/4 5/3 or 2 - pic_hdr->height_ = ((buf[6] << 8) | buf[5]) & 0x3fff; - pic_hdr->yscale_ = buf[6] >> 6; + pic_hdr->width = ((buf[4] << 8) | buf[3]) & 0x3fff; + pic_hdr->xscale = buf[4] >> 6; // ratio: 1, 5/4 5/3 or 2 + pic_hdr->height = ((buf[6] << 8) | buf[5]) & 0x3fff; + pic_hdr->yscale = buf[6] >> 6; buf += 7; buf_size -= 7; - dec->mb_w_ = (pic_hdr->width_ + 15) >> 4; - dec->mb_h_ = (pic_hdr->height_ + 15) >> 4; + dec->mb_w = (pic_hdr->width + 15) >> 4; + dec->mb_h = (pic_hdr->height + 15) >> 4; // Setup default output area (can be later modified during io->setup()) - io->width = pic_hdr->width_; - io->height = pic_hdr->height_; - // IMPORTANT! use some sane dimensions in crop_* and scaled_* fields. + io->width = pic_hdr->width; + io->height = pic_hdr->height; + // IMPORTANT! use some sane dimensions in crop* and scaled* fields. // So they can be used interchangeably without always testing for // 'use_cropping'. io->use_cropping = 0; @@ -342,27 +353,27 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) { io->mb_w = io->width; // for soundness io->mb_h = io->height; // ditto - VP8ResetProba(&dec->proba_); - ResetSegmentHeader(&dec->segment_hdr_); + VP8ResetProba(&dec->proba); + ResetSegmentHeader(&dec->segment_hdr); } - // Check if we have all the partition #0 available, and initialize dec->br_ + // Check if we have all the partition #0 available, and initialize dec->br // to read this partition (and this partition only). - if (frm_hdr->partition_length_ > buf_size) { + if (frm_hdr->partition_length > buf_size) { return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA, "bad partition length"); } - br = &dec->br_; - VP8InitBitReader(br, buf, frm_hdr->partition_length_); - buf += frm_hdr->partition_length_; - buf_size -= frm_hdr->partition_length_; + br = &dec->br; + VP8InitBitReader(br, buf, frm_hdr->partition_length); + buf += frm_hdr->partition_length; + buf_size -= frm_hdr->partition_length; - if (frm_hdr->key_frame_) { - pic_hdr->colorspace_ = VP8Get(br, "global-header"); - pic_hdr->clamp_type_ = VP8Get(br, "global-header"); + if (frm_hdr->key_frame) { + pic_hdr->colorspace = VP8Get(br, "global-header"); + pic_hdr->clamp_type = VP8Get(br, "global-header"); } - if (!ParseSegmentHeader(br, &dec->segment_hdr_, &dec->proba_)) { + if (!ParseSegmentHeader(br, &dec->segment_hdr, &dec->proba)) { return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, "cannot parse segment header"); } @@ -380,17 +391,17 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) { VP8ParseQuant(dec); // Frame buffer marking - if (!frm_hdr->key_frame_) { + if (!frm_hdr->key_frame) { return VP8SetError(dec, VP8_STATUS_UNSUPPORTED_FEATURE, "Not a key frame."); } - VP8Get(br, "global-header"); // ignore the value of update_proba_ + VP8Get(br, "global-header"); // ignore the value of 'update_proba' VP8ParseProba(br, dec); // sanitized state - dec->ready_ = 1; + dec->ready = 1; return 1; } @@ -443,17 +454,17 @@ static int GetLargeValue(VP8BitReader* const br, const uint8_t* const p) { static int GetCoeffsFast(VP8BitReader* const br, const VP8BandProbas* const prob[], int ctx, const quant_t dq, int n, int16_t* out) { - const uint8_t* p = prob[n]->probas_[ctx]; + const uint8_t* p = prob[n]->probas[ctx]; for (; n < 16; ++n) { if (!VP8GetBit(br, p[0], "coeffs")) { return n; // previous coeff was last non-zero coeff } while (!VP8GetBit(br, p[1], "coeffs")) { // sequence of zero coeffs - p = prob[++n]->probas_[0]; + p = prob[++n]->probas[0]; if (n == 16) return 16; } { // non zero coeff - const VP8ProbaArray* const p_ctx = &prob[n + 1]->probas_[0]; + const VP8ProbaArray* const p_ctx = &prob[n + 1]->probas[0]; int v; if (!VP8GetBit(br, p[2], "coeffs")) { v = 1; @@ -473,17 +484,17 @@ static int GetCoeffsFast(VP8BitReader* const br, static int GetCoeffsAlt(VP8BitReader* const br, const VP8BandProbas* const prob[], int ctx, const quant_t dq, int n, int16_t* out) { - const uint8_t* p = prob[n]->probas_[ctx]; + const uint8_t* p = prob[n]->probas[ctx]; for (; n < 16; ++n) { if (!VP8GetBitAlt(br, p[0], "coeffs")) { return n; // previous coeff was last non-zero coeff } while (!VP8GetBitAlt(br, p[1], "coeffs")) { // sequence of zero coeffs - p = prob[++n]->probas_[0]; + p = prob[++n]->probas[0]; if (n == 16) return 16; } { // non zero coeff - const VP8ProbaArray* const p_ctx = &prob[n + 1]->probas_[0]; + const VP8ProbaArray* const p_ctx = &prob[n + 1]->probas[0]; int v; if (!VP8GetBitAlt(br, p[2], "coeffs")) { v = 1; @@ -516,12 +527,12 @@ static WEBP_INLINE uint32_t NzCodeBits(uint32_t nz_coeffs, int nz, int dc_nz) { static int ParseResiduals(VP8Decoder* const dec, VP8MB* const mb, VP8BitReader* const token_br) { - const VP8BandProbas* (* const bands)[16 + 1] = dec->proba_.bands_ptr_; + const VP8BandProbas* (* const bands)[16 + 1] = dec->proba.bands_ptr; const VP8BandProbas* const * ac_proba; - VP8MBData* const block = dec->mb_data_ + dec->mb_x_; - const VP8QuantMatrix* const q = &dec->dqm_[block->segment_]; - int16_t* dst = block->coeffs_; - VP8MB* const left_mb = dec->mb_info_ - 1; + VP8MBData* const block = dec->mb_data + dec->mb_x; + const VP8QuantMatrix* const q = &dec->dqm[block->segment]; + int16_t* dst = block->coeffs; + VP8MB* const left_mb = dec->mb_info - 1; uint8_t tnz, lnz; uint32_t non_zero_y = 0; uint32_t non_zero_uv = 0; @@ -530,11 +541,11 @@ static int ParseResiduals(VP8Decoder* const dec, int first; memset(dst, 0, 384 * sizeof(*dst)); - if (!block->is_i4x4_) { // parse DC + if (!block->is_i4x4) { // parse DC int16_t dc[16] = { 0 }; - const int ctx = mb->nz_dc_ + left_mb->nz_dc_; - const int nz = GetCoeffs(token_br, bands[1], ctx, q->y2_mat_, 0, dc); - mb->nz_dc_ = left_mb->nz_dc_ = (nz > 0); + const int ctx = mb->nz_dc + left_mb->nz_dc; + const int nz = GetCoeffs(token_br, bands[1], ctx, q->y2_mat, 0, dc); + mb->nz_dc = left_mb->nz_dc = (nz > 0); if (nz > 1) { // more than just the DC -> perform the full transform VP8TransformWHT(dc, dst); } else { // only DC is non-zero -> inlined simplified transform @@ -549,14 +560,14 @@ static int ParseResiduals(VP8Decoder* const dec, ac_proba = bands[3]; } - tnz = mb->nz_ & 0x0f; - lnz = left_mb->nz_ & 0x0f; + tnz = mb->nz & 0x0f; + lnz = left_mb->nz & 0x0f; for (y = 0; y < 4; ++y) { int l = lnz & 1; uint32_t nz_coeffs = 0; for (x = 0; x < 4; ++x) { const int ctx = l + (tnz & 1); - const int nz = GetCoeffs(token_br, ac_proba, ctx, q->y1_mat_, first, dst); + const int nz = GetCoeffs(token_br, ac_proba, ctx, q->y1_mat, first, dst); l = (nz > first); tnz = (tnz >> 1) | (l << 7); nz_coeffs = NzCodeBits(nz_coeffs, nz, dst[0] != 0); @@ -571,13 +582,13 @@ static int ParseResiduals(VP8Decoder* const dec, for (ch = 0; ch < 4; ch += 2) { uint32_t nz_coeffs = 0; - tnz = mb->nz_ >> (4 + ch); - lnz = left_mb->nz_ >> (4 + ch); + tnz = mb->nz >> (4 + ch); + lnz = left_mb->nz >> (4 + ch); for (y = 0; y < 2; ++y) { int l = lnz & 1; for (x = 0; x < 2; ++x) { const int ctx = l + (tnz & 1); - const int nz = GetCoeffs(token_br, bands[2], ctx, q->uv_mat_, 0, dst); + const int nz = GetCoeffs(token_br, bands[2], ctx, q->uv_mat, 0, dst); l = (nz > 0); tnz = (tnz >> 1) | (l << 3); nz_coeffs = NzCodeBits(nz_coeffs, nz, dst[0] != 0); @@ -591,16 +602,16 @@ static int ParseResiduals(VP8Decoder* const dec, out_t_nz |= (tnz << 4) << ch; out_l_nz |= (lnz & 0xf0) << ch; } - mb->nz_ = out_t_nz; - left_mb->nz_ = out_l_nz; + mb->nz = out_t_nz; + left_mb->nz = out_l_nz; - block->non_zero_y_ = non_zero_y; - block->non_zero_uv_ = non_zero_uv; + block->non_zero_y = non_zero_y; + block->non_zero_uv = non_zero_uv; // We look at the mode-code of each block and check if some blocks have less // than three non-zero coeffs (code < 2). This is to avoid dithering flat and // empty blocks. - block->dither_ = (non_zero_uv & 0xaaaa) ? 0 : q->dither_; + block->dither = (non_zero_uv & 0xaaaa) ? 0 : q->dither; return !(non_zero_y | non_zero_uv); // will be used for further optimization } @@ -609,50 +620,50 @@ static int ParseResiduals(VP8Decoder* const dec, // Main loop int VP8DecodeMB(VP8Decoder* const dec, VP8BitReader* const token_br) { - VP8MB* const left = dec->mb_info_ - 1; - VP8MB* const mb = dec->mb_info_ + dec->mb_x_; - VP8MBData* const block = dec->mb_data_ + dec->mb_x_; - int skip = dec->use_skip_proba_ ? block->skip_ : 0; + VP8MB* const left = dec->mb_info - 1; + VP8MB* const mb = dec->mb_info + dec->mb_x; + VP8MBData* const block = dec->mb_data + dec->mb_x; + int skip = dec->use_skip_proba ? block->skip : 0; if (!skip) { skip = ParseResiduals(dec, mb, token_br); } else { - left->nz_ = mb->nz_ = 0; - if (!block->is_i4x4_) { - left->nz_dc_ = mb->nz_dc_ = 0; + left->nz = mb->nz = 0; + if (!block->is_i4x4) { + left->nz_dc = mb->nz_dc = 0; } - block->non_zero_y_ = 0; - block->non_zero_uv_ = 0; - block->dither_ = 0; + block->non_zero_y = 0; + block->non_zero_uv = 0; + block->dither = 0; } - if (dec->filter_type_ > 0) { // store filter info - VP8FInfo* const finfo = dec->f_info_ + dec->mb_x_; - *finfo = dec->fstrengths_[block->segment_][block->is_i4x4_]; - finfo->f_inner_ |= !skip; + if (dec->filter_type > 0) { // store filter info + VP8FInfo* const finfo = dec->f_info + dec->mb_x; + *finfo = dec->fstrengths[block->segment][block->is_i4x4]; + finfo->f_inner |= !skip; } - return !token_br->eof_; + return !token_br->eof; } void VP8InitScanline(VP8Decoder* const dec) { - VP8MB* const left = dec->mb_info_ - 1; - left->nz_ = 0; - left->nz_dc_ = 0; - memset(dec->intra_l_, B_DC_PRED, sizeof(dec->intra_l_)); - dec->mb_x_ = 0; + VP8MB* const left = dec->mb_info - 1; + left->nz = 0; + left->nz_dc = 0; + memset(dec->intra_l, B_DC_PRED, sizeof(dec->intra_l)); + dec->mb_x = 0; } static int ParseFrame(VP8Decoder* const dec, VP8Io* io) { - for (dec->mb_y_ = 0; dec->mb_y_ < dec->br_mb_y_; ++dec->mb_y_) { + for (dec->mb_y = 0; dec->mb_y < dec->br_mb_y; ++dec->mb_y) { // Parse bitstream for this row. VP8BitReader* const token_br = - &dec->parts_[dec->mb_y_ & dec->num_parts_minus_one_]; - if (!VP8ParseIntraModeRow(&dec->br_, dec)) { + &dec->parts[dec->mb_y & dec->num_parts_minus_one]; + if (!VP8ParseIntraModeRow(&dec->br, dec)) { return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA, "Premature end-of-partition0 encountered."); } - for (; dec->mb_x_ < dec->mb_w_; ++dec->mb_x_) { + for (; dec->mb_x < dec->mb_w; ++dec->mb_x) { if (!VP8DecodeMB(dec, token_br)) { return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA, "Premature end-of-file encountered."); @@ -665,8 +676,8 @@ static int ParseFrame(VP8Decoder* const dec, VP8Io* io) { return VP8SetError(dec, VP8_STATUS_USER_ABORT, "Output aborted."); } } - if (dec->mt_method_ > 0) { - if (!WebPGetWorkerInterface()->Sync(&dec->worker_)) return 0; + if (dec->mt_method > 0) { + if (!WebPGetWorkerInterface()->Sync(&dec->worker)) return 0; } return 1; @@ -683,12 +694,12 @@ int VP8Decode(VP8Decoder* const dec, VP8Io* const io) { "NULL VP8Io parameter in VP8Decode()."); } - if (!dec->ready_) { + if (!dec->ready) { if (!VP8GetHeaders(dec, io)) { return 0; } } - assert(dec->ready_); + assert(dec->ready); // Finish setting up the decoding parameter. Will call io->setup(). ok = (VP8EnterCritical(dec, io) == VP8_STATUS_OK); @@ -708,7 +719,7 @@ int VP8Decode(VP8Decoder* const dec, VP8Io* const io) { return 0; } - dec->ready_ = 0; + dec->ready = 0; return ok; } @@ -716,13 +727,13 @@ void VP8Clear(VP8Decoder* const dec) { if (dec == NULL) { return; } - WebPGetWorkerInterface()->End(&dec->worker_); + WebPGetWorkerInterface()->End(&dec->worker); WebPDeallocateAlphaMemory(dec); - WebPSafeFree(dec->mem_); - dec->mem_ = NULL; - dec->mem_size_ = 0; - memset(&dec->br_, 0, sizeof(dec->br_)); - dec->ready_ = 0; + WebPSafeFree(dec->mem); + dec->mem = NULL; + dec->mem_size = 0; + memset(&dec->br, 0, sizeof(dec->br)); + dec->ready = 0; } //------------------------------------------------------------------------------ diff --git a/libwebp/src/dec/vp8_dec.h b/libwebp/src/dec/vp8_dec.h index 91fe1040..eb292b14 100644 --- a/libwebp/src/dec/vp8_dec.h +++ b/libwebp/src/dec/vp8_dec.h @@ -14,6 +14,8 @@ #ifndef WEBP_DEC_VP8_DEC_H_ #define WEBP_DEC_VP8_DEC_H_ +#include + #include "src/webp/decode.h" #include "src/webp/types.h" diff --git a/libwebp/src/dec/vp8i_dec.h b/libwebp/src/dec/vp8i_dec.h index 49ea02ae..6d4c092b 100644 --- a/libwebp/src/dec/vp8i_dec.h +++ b/libwebp/src/dec/vp8i_dec.h @@ -15,12 +15,16 @@ #define WEBP_DEC_VP8I_DEC_H_ #include // for memcpy() + #include "src/dec/common_dec.h" +#include "src/dec/vp8_dec.h" #include "src/dec/vp8li_dec.h" +#include "src/dec/webpi_dec.h" +#include "src/dsp/dsp.h" #include "src/utils/bit_reader_utils.h" #include "src/utils/random_utils.h" #include "src/utils/thread_utils.h" -#include "src/dsp/dsp.h" +#include "src/webp/decode.h" #include "src/webp/types.h" #ifdef __cplusplus @@ -32,8 +36,8 @@ extern "C" { // version numbers #define DEC_MAJ_VERSION 1 -#define DEC_MIN_VERSION 3 -#define DEC_REV_VERSION 2 +#define DEC_MIN_VERSION 6 +#define DEC_REV_VERSION 0 // YUV-cache parameters. Cache is 32-bytes wide (= one cacheline). // Constraints are: We need to store one 16x16 block of luma samples (y), @@ -69,85 +73,85 @@ extern "C" { // Headers typedef struct { - uint8_t key_frame_; - uint8_t profile_; - uint8_t show_; - uint32_t partition_length_; + uint8_t key_frame; + uint8_t profile; + uint8_t show; + uint32_t partition_length; } VP8FrameHeader; typedef struct { - uint16_t width_; - uint16_t height_; - uint8_t xscale_; - uint8_t yscale_; - uint8_t colorspace_; // 0 = YCbCr - uint8_t clamp_type_; + uint16_t width; + uint16_t height; + uint8_t xscale; + uint8_t yscale; + uint8_t colorspace; // 0 = YCbCr + uint8_t clamp_type; } VP8PictureHeader; // segment features typedef struct { - int use_segment_; - int update_map_; // whether to update the segment map or not - int absolute_delta_; // absolute or delta values for quantizer and filter - int8_t quantizer_[NUM_MB_SEGMENTS]; // quantization changes - int8_t filter_strength_[NUM_MB_SEGMENTS]; // filter strength for segments + int use_segment; + int update_map; // whether to update the segment map or not + int absolute_delta; // absolute or delta values for quantizer and filter + int8_t quantizer[NUM_MB_SEGMENTS]; // quantization changes + int8_t filter_strength[NUM_MB_SEGMENTS]; // filter strength for segments } VP8SegmentHeader; // probas associated to one of the contexts typedef uint8_t VP8ProbaArray[NUM_PROBAS]; typedef struct { // all the probas associated to one band - VP8ProbaArray probas_[NUM_CTX]; + VP8ProbaArray probas[NUM_CTX]; } VP8BandProbas; // Struct collecting all frame-persistent probabilities. typedef struct { - uint8_t segments_[MB_FEATURE_TREE_PROBS]; + uint8_t segments[MB_FEATURE_TREE_PROBS]; // Type: 0:Intra16-AC 1:Intra16-DC 2:Chroma 3:Intra4 - VP8BandProbas bands_[NUM_TYPES][NUM_BANDS]; - const VP8BandProbas* bands_ptr_[NUM_TYPES][16 + 1]; + VP8BandProbas bands[NUM_TYPES][NUM_BANDS]; + const VP8BandProbas* bands_ptr[NUM_TYPES][16 + 1]; } VP8Proba; // Filter parameters typedef struct { - int simple_; // 0=complex, 1=simple - int level_; // [0..63] - int sharpness_; // [0..7] - int use_lf_delta_; - int ref_lf_delta_[NUM_REF_LF_DELTAS]; - int mode_lf_delta_[NUM_MODE_LF_DELTAS]; + int simple; // 0=complex, 1=simple + int level; // [0..63] + int sharpness; // [0..7] + int use_lf_delta; + int ref_lf_delta[NUM_REF_LF_DELTAS]; + int mode_lf_delta[NUM_MODE_LF_DELTAS]; } VP8FilterHeader; //------------------------------------------------------------------------------ // Informations about the macroblocks. typedef struct { // filter specs - uint8_t f_limit_; // filter limit in [3..189], or 0 if no filtering - uint8_t f_ilevel_; // inner limit in [1..63] - uint8_t f_inner_; // do inner filtering? - uint8_t hev_thresh_; // high edge variance threshold in [0..2] + uint8_t f_limit; // filter limit in [3..189], or 0 if no filtering + uint8_t f_ilevel; // inner limit in [1..63] + uint8_t f_inner; // do inner filtering? + uint8_t hev_thresh; // high edge variance threshold in [0..2] } VP8FInfo; typedef struct { // Top/Left Contexts used for syntax-parsing - uint8_t nz_; // non-zero AC/DC coeffs (4bit for luma + 4bit for chroma) - uint8_t nz_dc_; // non-zero DC coeff (1bit) + uint8_t nz; // non-zero AC/DC coeffs (4bit for luma + 4bit for chroma) + uint8_t nz_dc; // non-zero DC coeff (1bit) } VP8MB; // Dequantization matrices typedef int quant_t[2]; // [DC / AC]. Can be 'uint16_t[2]' too (~slower). typedef struct { - quant_t y1_mat_, y2_mat_, uv_mat_; + quant_t y1_mat, y2_mat, uv_mat; - int uv_quant_; // U/V quantizer value - int dither_; // dithering amplitude (0 = off, max=255) + int uv_quant; // U/V quantizer value + int dither; // dithering amplitude (0 = off, max=255) } VP8QuantMatrix; // Data needed to reconstruct a macroblock typedef struct { - int16_t coeffs_[384]; // 384 coeffs = (16+4+4) * 4*4 - uint8_t is_i4x4_; // true if intra4x4 - uint8_t imodes_[16]; // one 16x16 mode (#0) or sixteen 4x4 modes - uint8_t uvmode_; // chroma prediction mode + int16_t coeffs[384]; // 384 coeffs = (16+4+4) * 4*4 + uint8_t is_i4x4; // true if intra4x4 + uint8_t imodes[16]; // one 16x16 mode (#0) or sixteen 4x4 modes + uint8_t uvmode; // chroma prediction mode // bit-wise info about the content of each sub-4x4 blocks (in decoding order). // Each of the 4x4 blocks for y/u/v is associated with a 2b code according to: // code=0 -> no coefficient @@ -155,21 +159,21 @@ typedef struct { // code=2 -> first three coefficients are non-zero // code=3 -> more than three coefficients are non-zero // This allows to call specialized transform functions. - uint32_t non_zero_y_; - uint32_t non_zero_uv_; - uint8_t dither_; // local dithering strength (deduced from non_zero_*) - uint8_t skip_; - uint8_t segment_; + uint32_t non_zero_y; + uint32_t non_zero_uv; + uint8_t dither; // local dithering strength (deduced from non_zero*) + uint8_t skip; + uint8_t segment; } VP8MBData; // Persistent information needed by the parallel processing typedef struct { - int id_; // cache row to process (in [0..2]) - int mb_y_; // macroblock position of the row - int filter_row_; // true if row-filtering is needed - VP8FInfo* f_info_; // filter strengths (swapped with dec->f_info_) - VP8MBData* mb_data_; // reconstruction data (swapped with dec->mb_data_) - VP8Io io_; // copy of the VP8Io to pass to put() + int id; // cache row to process (in [0..2]) + int mb_y; // macroblock position of the row + int filter_row; // true if row-filtering is needed + VP8FInfo* f_info; // filter strengths (swapped with dec->f_info) + VP8MBData* mb_data; // reconstruction data (swapped with dec->mb_data) + VP8Io io; // copy of the VP8Io to pass to put() } VP8ThreadContext; // Saved top samples, per macroblock. Fits into a cache-line. @@ -181,89 +185,89 @@ typedef struct { // VP8Decoder: the main opaque structure handed over to user struct VP8Decoder { - VP8StatusCode status_; - int ready_; // true if ready to decode a picture with VP8Decode() - const char* error_msg_; // set when status_ is not OK. + VP8StatusCode status; + int ready; // true if ready to decode a picture with VP8Decode() + const char* error_msg; // set when status is not OK. // Main data source - VP8BitReader br_; - int incremental_; // if true, incremental decoding is expected + VP8BitReader br; + int incremental; // if true, incremental decoding is expected // headers - VP8FrameHeader frm_hdr_; - VP8PictureHeader pic_hdr_; - VP8FilterHeader filter_hdr_; - VP8SegmentHeader segment_hdr_; + VP8FrameHeader frm_hdr; + VP8PictureHeader pic_hdr; + VP8FilterHeader filter_hdr; + VP8SegmentHeader segment_hdr; // Worker - WebPWorker worker_; - int mt_method_; // multi-thread method: 0=off, 1=[parse+recon][filter] - // 2=[parse][recon+filter] - int cache_id_; // current cache row - int num_caches_; // number of cached rows of 16 pixels (1, 2 or 3) - VP8ThreadContext thread_ctx_; // Thread context + WebPWorker worker; + int mt_method; // multi-thread method: 0=off, 1=[parse+recon][filter] + // 2=[parse][recon+filter] + int cache_id; // current cache row + int num_caches; // number of cached rows of 16 pixels (1, 2 or 3) + VP8ThreadContext thread_ctx; // Thread context // dimension, in macroblock units. - int mb_w_, mb_h_; + int mb_w, mb_h; // Macroblock to process/filter, depending on cropping and filter_type. - int tl_mb_x_, tl_mb_y_; // top-left MB that must be in-loop filtered - int br_mb_x_, br_mb_y_; // last bottom-right MB that must be decoded + int tl_mb_x, tl_mb_y; // top-left MB that must be in-loop filtered + int br_mb_x, br_mb_y; // last bottom-right MB that must be decoded // number of partitions minus one. - uint32_t num_parts_minus_one_; + uint32_t num_parts_minus_one; // per-partition boolean decoders. - VP8BitReader parts_[MAX_NUM_PARTITIONS]; + VP8BitReader parts[MAX_NUM_PARTITIONS]; // Dithering strength, deduced from decoding options - int dither_; // whether to use dithering or not - VP8Random dithering_rg_; // random generator for dithering + int dither; // whether to use dithering or not + VP8Random dithering_rg; // random generator for dithering // dequantization (one set of DC/AC dequant factor per segment) - VP8QuantMatrix dqm_[NUM_MB_SEGMENTS]; + VP8QuantMatrix dqm[NUM_MB_SEGMENTS]; // probabilities - VP8Proba proba_; - int use_skip_proba_; - uint8_t skip_p_; + VP8Proba proba; + int use_skip_proba; + uint8_t skip_p; // Boundary data cache and persistent buffers. - uint8_t* intra_t_; // top intra modes values: 4 * mb_w_ - uint8_t intra_l_[4]; // left intra modes values + uint8_t* intra_t; // top intra modes values: 4 * mb_w + uint8_t intra_l[4]; // left intra modes values - VP8TopSamples* yuv_t_; // top y/u/v samples + VP8TopSamples* yuv_t; // top y/u/v samples - VP8MB* mb_info_; // contextual macroblock info (mb_w_ + 1) - VP8FInfo* f_info_; // filter strength info - uint8_t* yuv_b_; // main block for Y/U/V (size = YUV_SIZE) + VP8MB* mb_info; // contextual macroblock info (mb_w + 1) + VP8FInfo* f_info; // filter strength info + uint8_t* yuv_b; // main block for Y/U/V (size = YUV_SIZE) - uint8_t* cache_y_; // macroblock row for storing unfiltered samples - uint8_t* cache_u_; - uint8_t* cache_v_; - int cache_y_stride_; - int cache_uv_stride_; + uint8_t* cache_y; // macroblock row for storing unfiltered samples + uint8_t* cache_u; + uint8_t* cache_v; + int cache_y_stride; + int cache_uv_stride; // main memory chunk for the above data. Persistent. - void* mem_; - size_t mem_size_; + void* mem; + size_t mem_size; // Per macroblock non-persistent infos. - int mb_x_, mb_y_; // current position, in macroblock units - VP8MBData* mb_data_; // parsed reconstruction data + int mb_x, mb_y; // current position, in macroblock units + VP8MBData* mb_data; // parsed reconstruction data // Filtering side-info - int filter_type_; // 0=off, 1=simple, 2=complex - VP8FInfo fstrengths_[NUM_MB_SEGMENTS][2]; // precalculated per-segment/type + int filter_type; // 0=off, 1=simple, 2=complex + VP8FInfo fstrengths[NUM_MB_SEGMENTS][2]; // precalculated per-segment/type // Alpha - struct ALPHDecoder* alph_dec_; // alpha-plane decoder object - const uint8_t* alpha_data_; // compressed alpha data (if present) - size_t alpha_data_size_; - int is_alpha_decoded_; // true if alpha_data_ is decoded in alpha_plane_ - uint8_t* alpha_plane_mem_; // memory allocated for alpha_plane_ - uint8_t* alpha_plane_; // output. Persistent, contains the whole data. - const uint8_t* alpha_prev_line_; // last decoded alpha row (or NULL) - int alpha_dithering_; // derived from decoding options (0=off, 100=full) + struct ALPHDecoder* alph_dec; // alpha-plane decoder object + const uint8_t* alpha_data; // compressed alpha data (if present) + size_t alpha_data_size; + int is_alpha_decoded; // true if alpha_data is decoded in alpha_plane + uint8_t* alpha_plane_mem; // memory allocated for alpha_plane + uint8_t* alpha_plane; // output. Persistent, contains the whole data. + const uint8_t* alpha_prev_line; // last decoded alpha row (or NULL) + int alpha_dithering; // derived from decoding options (0=off, 100=full) }; //------------------------------------------------------------------------------ diff --git a/libwebp/src/dec/vp8l_dec.c b/libwebp/src/dec/vp8l_dec.c index 11c00ea9..cf8cd82c 100644 --- a/libwebp/src/dec/vp8l_dec.c +++ b/libwebp/src/dec/vp8l_dec.c @@ -13,17 +13,25 @@ // Jyrki Alakuijala (jyrki@google.com) #include +#include #include +#include #include "src/dec/alphai_dec.h" +#include "src/dec/vp8_dec.h" #include "src/dec/vp8li_dec.h" +#include "src/dec/webpi_dec.h" #include "src/dsp/dsp.h" #include "src/dsp/lossless.h" #include "src/dsp/lossless_common.h" -#include "src/dsp/yuv.h" -#include "src/utils/endian_inl_utils.h" +#include "src/utils/bit_reader_utils.h" +#include "src/utils/color_cache_utils.h" #include "src/utils/huffman_utils.h" +#include "src/utils/rescaler_utils.h" #include "src/utils/utils.h" +#include "src/webp/decode.h" +#include "src/webp/format_constants.h" +#include "src/webp/types.h" #define NUM_ARGB_CACHE_ROWS 16 @@ -104,8 +112,8 @@ static const uint16_t kTableSize[12] = { static int VP8LSetError(VP8LDecoder* const dec, VP8StatusCode error) { // The oldest error reported takes precedence over the new one. - if (dec->status_ == VP8_STATUS_OK || dec->status_ == VP8_STATUS_SUSPENDED) { - dec->status_ = error; + if (dec->status == VP8_STATUS_OK || dec->status == VP8_STATUS_SUSPENDED) { + dec->status = error; } return 0; } @@ -131,7 +139,7 @@ static int ReadImageInfo(VP8LBitReader* const br, *height = VP8LReadBits(br, VP8L_IMAGE_SIZE_BITS) + 1; *has_alpha = VP8LReadBits(br, 1); if (VP8LReadBits(br, VP8L_VERSION_BITS) != 0) return 0; - return !br->eos_; + return !br->eos; } int VP8LGetInfo(const uint8_t* data, size_t data_size, @@ -196,12 +204,12 @@ static WEBP_INLINE int ReadSymbol(const HuffmanCode* table, table += val & HUFFMAN_TABLE_MASK; nbits = table->bits - HUFFMAN_TABLE_BITS; if (nbits > 0) { - VP8LSetBitPos(br, br->bit_pos_ + HUFFMAN_TABLE_BITS); + VP8LSetBitPos(br, br->bit_pos + HUFFMAN_TABLE_BITS); val = VP8LPrefetchBits(br); table += table->value; table += val & ((1 << nbits) - 1); } - VP8LSetBitPos(br, br->bit_pos_ + table->bits); + VP8LSetBitPos(br, br->bit_pos + table->bits); return table->value; } @@ -215,11 +223,11 @@ static WEBP_INLINE int ReadPackedSymbols(const HTreeGroup* group, const HuffmanCode32 code = group->packed_table[val]; assert(group->use_packed_table); if (code.bits < BITS_SPECIAL_MARKER) { - VP8LSetBitPos(br, br->bit_pos_ + code.bits); + VP8LSetBitPos(br, br->bit_pos + code.bits); *dst = code.value; return PACKED_NON_LITERAL_CODE; } else { - VP8LSetBitPos(br, br->bit_pos_ + code.bits - BITS_SPECIAL_MARKER); + VP8LSetBitPos(br, br->bit_pos + code.bits - BITS_SPECIAL_MARKER); assert(code.value >= NUM_LITERAL_CODES); return code.value; } @@ -258,7 +266,7 @@ static int ReadHuffmanCodeLengths( VP8LDecoder* const dec, const int* const code_length_code_lengths, int num_symbols, int* const code_lengths) { int ok = 0; - VP8LBitReader* const br = &dec->br_; + VP8LBitReader* const br = &dec->br; int symbol; int max_symbol; int prev_code_len = DEFAULT_CODE_LENGTH; @@ -287,7 +295,7 @@ static int ReadHuffmanCodeLengths( if (max_symbol-- == 0) break; VP8LFillBitWindow(br); p = &tables.curr_segment->start[VP8LPrefetchBits(br) & LENGTHS_TABLE_MASK]; - VP8LSetBitPos(br, br->bit_pos_ + p->bits); + VP8LSetBitPos(br, br->bit_pos + p->bits); code_len = p->value; if (code_len < kCodeLengthLiterals) { code_lengths[symbol++] = code_len; @@ -321,7 +329,7 @@ static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec, HuffmanTables* const table) { int ok = 0; int size = 0; - VP8LBitReader* const br = &dec->br_; + VP8LBitReader* const br = &dec->br; const int simple_code = VP8LReadBits(br, 1); memset(code_lengths, 0, alphabet_size * sizeof(*code_lengths)); @@ -351,7 +359,7 @@ static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec, code_lengths); } - ok = ok && !br->eos_; + ok = ok && !br->eos; if (ok) { size = VP8LBuildHuffmanTable(table, HUFFMAN_TABLE_BITS, code_lengths, alphabet_size); @@ -365,11 +373,11 @@ static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec, static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize, int color_cache_bits, int allow_recursion) { int i; - VP8LBitReader* const br = &dec->br_; - VP8LMetadata* const hdr = &dec->hdr_; + VP8LBitReader* const br = &dec->br; + VP8LMetadata* const hdr = &dec->hdr; uint32_t* huffman_image = NULL; HTreeGroup* htree_groups = NULL; - HuffmanTables* huffman_tables = &hdr->huffman_tables_; + HuffmanTables* huffman_tables = &hdr->huffman_tables; int num_htree_groups = 1; int num_htree_groups_max = 1; int* mapping = NULL; @@ -381,7 +389,8 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize, if (allow_recursion && VP8LReadBits(br, 1)) { // use meta Huffman codes. - const int huffman_precision = VP8LReadBits(br, 3) + 2; + const int huffman_precision = + MIN_HUFFMAN_BITS + VP8LReadBits(br, NUM_HUFFMAN_BITS); const int huffman_xsize = VP8LSubSampleSize(xsize, huffman_precision); const int huffman_ysize = VP8LSubSampleSize(ysize, huffman_precision); const int huffman_pixs = huffman_xsize * huffman_ysize; @@ -389,7 +398,7 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize, &huffman_image)) { goto Error; } - hdr->huffman_subsample_bits_ = huffman_precision; + hdr->huffman_subsample_bits = huffman_precision; for (i = 0; i < huffman_pixs; ++i) { // The huffman data is stored in red and green bytes. const int group = (huffman_image[i] >> 8) & 0xffff; @@ -426,7 +435,7 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize, } } - if (br->eos_) goto Error; + if (br->eos) goto Error; if (!ReadHuffmanCodesHelper(color_cache_bits, num_htree_groups, num_htree_groups_max, mapping, dec, @@ -436,9 +445,9 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize, ok = 1; // All OK. Finalize pointers. - hdr->huffman_image_ = huffman_image; - hdr->num_htree_groups_ = num_htree_groups; - hdr->htree_groups_ = htree_groups; + hdr->huffman_image = huffman_image; + hdr->num_htree_groups = num_htree_groups; + hdr->htree_groups = htree_groups; Error: WebPSafeFree(mapping); @@ -620,12 +629,12 @@ static int Export(WebPRescaler* const rescaler, WEBP_CSP_MODE colorspace, static int EmitRescaledRowsRGBA(const VP8LDecoder* const dec, uint8_t* in, int in_stride, int mb_h, uint8_t* const out, int out_stride) { - const WEBP_CSP_MODE colorspace = dec->output_->colorspace; + const WEBP_CSP_MODE colorspace = dec->output->colorspace; int num_lines_in = 0; int num_lines_out = 0; while (num_lines_in < mb_h) { - uint8_t* const row_in = in + (uint64_t)num_lines_in * in_stride; - uint8_t* const row_out = out + (uint64_t)num_lines_out * out_stride; + uint8_t* const row_in = in + (ptrdiff_t)num_lines_in * in_stride; + uint8_t* const row_out = out + (ptrdiff_t)num_lines_out * out_stride; const int lines_left = mb_h - num_lines_in; const int needed_lines = WebPRescaleNeededLines(dec->rescaler, lines_left); int lines_imported; @@ -695,7 +704,7 @@ static int ExportYUVA(const VP8LDecoder* const dec, int y_pos) { while (WebPRescalerHasPendingOutput(rescaler)) { WebPRescalerExportRow(rescaler); WebPMultARGBRow(src, dst_width, 1); - ConvertToYUVA(src, dst_width, y_pos, dec->output_); + ConvertToYUVA(src, dst_width, y_pos, dec->output); ++y_pos; ++num_lines_out; } @@ -705,7 +714,7 @@ static int ExportYUVA(const VP8LDecoder* const dec, int y_pos) { static int EmitRescaledRowsYUVA(const VP8LDecoder* const dec, uint8_t* in, int in_stride, int mb_h) { int num_lines_in = 0; - int y_pos = dec->last_out_row_; + int y_pos = dec->last_out_row; while (num_lines_in < mb_h) { const int lines_left = mb_h - num_lines_in; const int needed_lines = WebPRescaleNeededLines(dec->rescaler, lines_left); @@ -724,9 +733,9 @@ static int EmitRescaledRowsYUVA(const VP8LDecoder* const dec, static int EmitRowsYUVA(const VP8LDecoder* const dec, const uint8_t* in, int in_stride, int mb_w, int num_rows) { - int y_pos = dec->last_out_row_; + int y_pos = dec->last_out_row; while (num_rows-- > 0) { - ConvertToYUVA((const uint32_t*)in, mb_w, y_pos, dec->output_); + ConvertToYUVA((const uint32_t*)in, mb_w, y_pos, dec->output); in += in_stride; ++y_pos; } @@ -773,10 +782,10 @@ static WEBP_INLINE int GetMetaIndex( static WEBP_INLINE HTreeGroup* GetHtreeGroupForPos(VP8LMetadata* const hdr, int x, int y) { - const int meta_index = GetMetaIndex(hdr->huffman_image_, hdr->huffman_xsize_, - hdr->huffman_subsample_bits_, x, y); - assert(meta_index < hdr->num_htree_groups_); - return hdr->htree_groups_ + meta_index; + const int meta_index = GetMetaIndex(hdr->huffman_image, hdr->huffman_xsize, + hdr->huffman_subsample_bits, x, y); + assert(meta_index < hdr->num_htree_groups); + return hdr->htree_groups + meta_index; } //------------------------------------------------------------------------------ @@ -787,15 +796,15 @@ typedef void (*ProcessRowsFunc)(VP8LDecoder* const dec, int row); static void ApplyInverseTransforms(VP8LDecoder* const dec, int start_row, int num_rows, const uint32_t* const rows) { - int n = dec->next_transform_; - const int cache_pixs = dec->width_ * num_rows; + int n = dec->next_transform; + const int cache_pixs = dec->width * num_rows; const int end_row = start_row + num_rows; const uint32_t* rows_in = rows; - uint32_t* const rows_out = dec->argb_cache_; + uint32_t* const rows_out = dec->argb_cache; // Inverse transforms. while (n-- > 0) { - VP8LTransform* const transform = &dec->transforms_[n]; + VP8LTransform* const transform = &dec->transforms[n]; VP8LInverseTransform(transform, start_row, end_row, rows_in, rows_out); rows_in = rows_out; } @@ -808,26 +817,26 @@ static void ApplyInverseTransforms(VP8LDecoder* const dec, // Processes (transforms, scales & color-converts) the rows decoded after the // last call. static void ProcessRows(VP8LDecoder* const dec, int row) { - const uint32_t* const rows = dec->pixels_ + dec->width_ * dec->last_row_; - const int num_rows = row - dec->last_row_; + const uint32_t* const rows = dec->pixels + dec->width * dec->last_row; + const int num_rows = row - dec->last_row; - assert(row <= dec->io_->crop_bottom); + assert(row <= dec->io->crop_bottom); // We can't process more than NUM_ARGB_CACHE_ROWS at a time (that's the size - // of argb_cache_), but we currently don't need more than that. + // of argb_cache), but we currently don't need more than that. assert(num_rows <= NUM_ARGB_CACHE_ROWS); if (num_rows > 0) { // Emit output. - VP8Io* const io = dec->io_; - uint8_t* rows_data = (uint8_t*)dec->argb_cache_; + VP8Io* const io = dec->io; + uint8_t* rows_data = (uint8_t*)dec->argb_cache; const int in_stride = io->width * sizeof(uint32_t); // in unit of RGBA - ApplyInverseTransforms(dec, dec->last_row_, num_rows, rows); - if (!SetCropWindow(io, dec->last_row_, row, &rows_data, in_stride)) { + ApplyInverseTransforms(dec, dec->last_row, num_rows, rows); + if (!SetCropWindow(io, dec->last_row, row, &rows_data, in_stride)) { // Nothing to output (this time). } else { - const WebPDecBuffer* const output = dec->output_; + const WebPDecBuffer* const output = dec->output; if (WebPIsRGBMode(output->colorspace)) { // convert to RGBA const WebPRGBABuffer* const buf = &output->u.RGBA; uint8_t* const rgba = - buf->rgba + (int64_t)dec->last_out_row_ * buf->stride; + buf->rgba + (ptrdiff_t)dec->last_out_row * buf->stride; const int num_rows_out = #if !defined(WEBP_REDUCE_SIZE) io->use_scaling ? @@ -836,31 +845,31 @@ static void ProcessRows(VP8LDecoder* const dec, int row) { #endif // WEBP_REDUCE_SIZE EmitRows(output->colorspace, rows_data, in_stride, io->mb_w, io->mb_h, rgba, buf->stride); - // Update 'last_out_row_'. - dec->last_out_row_ += num_rows_out; + // Update 'last_out_row'. + dec->last_out_row += num_rows_out; } else { // convert to YUVA - dec->last_out_row_ = io->use_scaling ? + dec->last_out_row = io->use_scaling ? EmitRescaledRowsYUVA(dec, rows_data, in_stride, io->mb_h) : EmitRowsYUVA(dec, rows_data, in_stride, io->mb_w, io->mb_h); } - assert(dec->last_out_row_ <= output->height); + assert(dec->last_out_row <= output->height); } } - // Update 'last_row_'. - dec->last_row_ = row; - assert(dec->last_row_ <= dec->height_); + // Update 'last_row'. + dec->last_row = row; + assert(dec->last_row <= dec->height); } // Row-processing for the special case when alpha data contains only one // transform (color indexing), and trivial non-green literals. static int Is8bOptimizable(const VP8LMetadata* const hdr) { int i; - if (hdr->color_cache_size_ > 0) return 0; + if (hdr->color_cache_size > 0) return 0; // When the Huffman tree contains only one symbol, we can skip the // call to ReadSymbol() for red/blue/alpha channels. - for (i = 0; i < hdr->num_htree_groups_; ++i) { - HuffmanCode** const htrees = hdr->htree_groups_[i].htrees; + for (i = 0; i < hdr->num_htree_groups; ++i) { + HuffmanCode** const htrees = hdr->htree_groups[i].htrees; if (htrees[RED][0].bits > 0) return 0; if (htrees[BLUE][0].bits > 0) return 0; if (htrees[ALPHA][0].bits > 0) return 0; @@ -871,43 +880,43 @@ static int Is8bOptimizable(const VP8LMetadata* const hdr) { static void AlphaApplyFilter(ALPHDecoder* const alph_dec, int first_row, int last_row, uint8_t* out, int stride) { - if (alph_dec->filter_ != WEBP_FILTER_NONE) { + if (alph_dec->filter != WEBP_FILTER_NONE) { int y; - const uint8_t* prev_line = alph_dec->prev_line_; - assert(WebPUnfilters[alph_dec->filter_] != NULL); + const uint8_t* prev_line = alph_dec->prev_line; + assert(WebPUnfilters[alph_dec->filter] != NULL); for (y = first_row; y < last_row; ++y) { - WebPUnfilters[alph_dec->filter_](prev_line, out, out, stride); + WebPUnfilters[alph_dec->filter](prev_line, out, out, stride); prev_line = out; out += stride; } - alph_dec->prev_line_ = prev_line; + alph_dec->prev_line = prev_line; } } static void ExtractPalettedAlphaRows(VP8LDecoder* const dec, int last_row) { // For vertical and gradient filtering, we need to decode the part above the // crop_top row, in order to have the correct spatial predictors. - ALPHDecoder* const alph_dec = (ALPHDecoder*)dec->io_->opaque; + ALPHDecoder* const alph_dec = (ALPHDecoder*)dec->io->opaque; const int top_row = - (alph_dec->filter_ == WEBP_FILTER_NONE || - alph_dec->filter_ == WEBP_FILTER_HORIZONTAL) ? dec->io_->crop_top - : dec->last_row_; - const int first_row = (dec->last_row_ < top_row) ? top_row : dec->last_row_; - assert(last_row <= dec->io_->crop_bottom); + (alph_dec->filter == WEBP_FILTER_NONE || + alph_dec->filter == WEBP_FILTER_HORIZONTAL) ? dec->io->crop_top + : dec->last_row; + const int first_row = (dec->last_row < top_row) ? top_row : dec->last_row; + assert(last_row <= dec->io->crop_bottom); if (last_row > first_row) { // Special method for paletted alpha data. We only process the cropped area. - const int width = dec->io_->width; - uint8_t* out = alph_dec->output_ + width * first_row; + const int width = dec->io->width; + uint8_t* out = alph_dec->output + width * first_row; const uint8_t* const in = - (uint8_t*)dec->pixels_ + dec->width_ * first_row; - VP8LTransform* const transform = &dec->transforms_[0]; - assert(dec->next_transform_ == 1); - assert(transform->type_ == COLOR_INDEXING_TRANSFORM); + (uint8_t*)dec->pixels + dec->width * first_row; + VP8LTransform* const transform = &dec->transforms[0]; + assert(dec->next_transform == 1); + assert(transform->type == COLOR_INDEXING_TRANSFORM); VP8LColorIndexInverseTransformAlpha(transform, first_row, last_row, in, out); AlphaApplyFilter(alph_dec, first_row, last_row, out, width); } - dec->last_row_ = dec->last_out_row_ = last_row; + dec->last_row = dec->last_out_row = last_row; } //------------------------------------------------------------------------------ @@ -1035,22 +1044,22 @@ static WEBP_INLINE void CopyBlock32b(uint32_t* const dst, static int DecodeAlphaData(VP8LDecoder* const dec, uint8_t* const data, int width, int height, int last_row) { int ok = 1; - int row = dec->last_pixel_ / width; - int col = dec->last_pixel_ % width; - VP8LBitReader* const br = &dec->br_; - VP8LMetadata* const hdr = &dec->hdr_; - int pos = dec->last_pixel_; // current position + int row = dec->last_pixel / width; + int col = dec->last_pixel % width; + VP8LBitReader* const br = &dec->br; + VP8LMetadata* const hdr = &dec->hdr; + int pos = dec->last_pixel; // current position const int end = width * height; // End of data const int last = width * last_row; // Last pixel to decode const int len_code_limit = NUM_LITERAL_CODES + NUM_LENGTH_CODES; - const int mask = hdr->huffman_mask_; + const int mask = hdr->huffman_mask; const HTreeGroup* htree_group = (pos < last) ? GetHtreeGroupForPos(hdr, col, row) : NULL; assert(pos <= end); assert(last_row <= height); assert(Is8bOptimizable(hdr)); - while (!br->eos_ && pos < last) { + while (!br->eos && pos < last) { int code; // Only update when changing tile. if ((col & mask) == 0) { @@ -1100,37 +1109,37 @@ static int DecodeAlphaData(VP8LDecoder* const dec, uint8_t* const data, ok = 0; goto End; } - br->eos_ = VP8LIsEndOfStream(br); + br->eos = VP8LIsEndOfStream(br); } // Process the remaining rows corresponding to last row-block. ExtractPalettedAlphaRows(dec, row > last_row ? last_row : row); End: - br->eos_ = VP8LIsEndOfStream(br); - if (!ok || (br->eos_ && pos < end)) { + br->eos = VP8LIsEndOfStream(br); + if (!ok || (br->eos && pos < end)) { return VP8LSetError( - dec, br->eos_ ? VP8_STATUS_SUSPENDED : VP8_STATUS_BITSTREAM_ERROR); + dec, br->eos ? VP8_STATUS_SUSPENDED : VP8_STATUS_BITSTREAM_ERROR); } - dec->last_pixel_ = pos; + dec->last_pixel = pos; return ok; } static void SaveState(VP8LDecoder* const dec, int last_pixel) { - assert(dec->incremental_); - dec->saved_br_ = dec->br_; - dec->saved_last_pixel_ = last_pixel; - if (dec->hdr_.color_cache_size_ > 0) { - VP8LColorCacheCopy(&dec->hdr_.color_cache_, &dec->hdr_.saved_color_cache_); + assert(dec->incremental); + dec->saved_br = dec->br; + dec->saved_last_pixel = last_pixel; + if (dec->hdr.color_cache_size > 0) { + VP8LColorCacheCopy(&dec->hdr.color_cache, &dec->hdr.saved_color_cache); } } static void RestoreState(VP8LDecoder* const dec) { - assert(dec->br_.eos_); - dec->status_ = VP8_STATUS_SUSPENDED; - dec->br_ = dec->saved_br_; - dec->last_pixel_ = dec->saved_last_pixel_; - if (dec->hdr_.color_cache_size_ > 0) { - VP8LColorCacheCopy(&dec->hdr_.saved_color_cache_, &dec->hdr_.color_cache_); + assert(dec->br.eos); + dec->status = VP8_STATUS_SUSPENDED; + dec->br = dec->saved_br; + dec->last_pixel = dec->saved_last_pixel; + if (dec->hdr.color_cache_size > 0) { + VP8LColorCacheCopy(&dec->hdr.saved_color_cache, &dec->hdr.color_cache); } } @@ -1138,23 +1147,23 @@ static void RestoreState(VP8LDecoder* const dec) { static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data, int width, int height, int last_row, ProcessRowsFunc process_func) { - int row = dec->last_pixel_ / width; - int col = dec->last_pixel_ % width; - VP8LBitReader* const br = &dec->br_; - VP8LMetadata* const hdr = &dec->hdr_; - uint32_t* src = data + dec->last_pixel_; + int row = dec->last_pixel / width; + int col = dec->last_pixel % width; + VP8LBitReader* const br = &dec->br; + VP8LMetadata* const hdr = &dec->hdr; + uint32_t* src = data + dec->last_pixel; uint32_t* last_cached = src; uint32_t* const src_end = data + width * height; // End of data uint32_t* const src_last = data + width * last_row; // Last pixel to decode const int len_code_limit = NUM_LITERAL_CODES + NUM_LENGTH_CODES; - const int color_cache_limit = len_code_limit + hdr->color_cache_size_; - int next_sync_row = dec->incremental_ ? row : 1 << 24; + const int color_cache_limit = len_code_limit + hdr->color_cache_size; + int next_sync_row = dec->incremental ? row : 1 << 24; VP8LColorCache* const color_cache = - (hdr->color_cache_size_ > 0) ? &hdr->color_cache_ : NULL; - const int mask = hdr->huffman_mask_; + (hdr->color_cache_size > 0) ? &hdr->color_cache : NULL; + const int mask = hdr->huffman_mask; const HTreeGroup* htree_group = (src < src_last) ? GetHtreeGroupForPos(hdr, col, row) : NULL; - assert(dec->last_row_ < last_row); + assert(dec->last_row < last_row); assert(src_last <= src_end); while (src < src_last) { @@ -1260,29 +1269,29 @@ static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data, } } - br->eos_ = VP8LIsEndOfStream(br); + br->eos = VP8LIsEndOfStream(br); // In incremental decoding: - // br->eos_ && src < src_last: if 'br' reached the end of the buffer and + // br->eos && src < src_last: if 'br' reached the end of the buffer and // 'src_last' has not been reached yet, there is not enough data. 'dec' has to // be reset until there is more data. - // !br->eos_ && src < src_last: this cannot happen as either the buffer is + // !br->eos && src < src_last: this cannot happen as either the buffer is // fully read, either enough has been read to reach 'src_last'. // src >= src_last: 'src_last' is reached, all is fine. 'src' can actually go // beyond 'src_last' in case the image is cropped and an LZ77 goes further. - // The buffer might have been enough or there is some left. 'br->eos_' does + // The buffer might have been enough or there is some left. 'br->eos' does // not matter. - assert(!dec->incremental_ || (br->eos_ && src < src_last) || src >= src_last); - if (dec->incremental_ && br->eos_ && src < src_last) { + assert(!dec->incremental || (br->eos && src < src_last) || src >= src_last); + if (dec->incremental && br->eos && src < src_last) { RestoreState(dec); - } else if ((dec->incremental_ && src >= src_last) || !br->eos_) { + } else if ((dec->incremental && src >= src_last) || !br->eos) { // Process the remaining rows corresponding to last row-block. if (process_func != NULL) { process_func(dec, row > last_row ? last_row : row); } - dec->status_ = VP8_STATUS_OK; - dec->last_pixel_ = (int)(src - data); // end-of-scan marker + dec->status = VP8_STATUS_OK; + dec->last_pixel = (int)(src - data); // end-of-scan marker } else { - // if not incremental, and we are past the end of buffer (eos_=1), then this + // if not incremental, and we are past the end of buffer (eos=1), then this // is a real bitstream error. goto Error; } @@ -1296,24 +1305,24 @@ static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data, // VP8LTransform static void ClearTransform(VP8LTransform* const transform) { - WebPSafeFree(transform->data_); - transform->data_ = NULL; + WebPSafeFree(transform->data); + transform->data = NULL; } // For security reason, we need to remap the color map to span // the total possible bundled values, and not just the num_colors. static int ExpandColorMap(int num_colors, VP8LTransform* const transform) { int i; - const int final_num_colors = 1 << (8 >> transform->bits_); + const int final_num_colors = 1 << (8 >> transform->bits); uint32_t* const new_color_map = (uint32_t*)WebPSafeMalloc((uint64_t)final_num_colors, sizeof(*new_color_map)); if (new_color_map == NULL) { return 0; } else { - uint8_t* const data = (uint8_t*)transform->data_; + uint8_t* const data = (uint8_t*)transform->data; uint8_t* const new_data = (uint8_t*)new_color_map; - new_color_map[0] = transform->data_[0]; + new_color_map[0] = transform->data[0]; for (i = 4; i < 4 * num_colors; ++i) { // Equivalent to VP8LAddPixels(), on a byte-basis. new_data[i] = (data[i] + new_data[i - 4]) & 0xff; @@ -1321,8 +1330,8 @@ static int ExpandColorMap(int num_colors, VP8LTransform* const transform) { for (; i < 4 * final_num_colors; ++i) { new_data[i] = 0; // black tail. } - WebPSafeFree(transform->data_); - transform->data_ = new_color_map; + WebPSafeFree(transform->data); + transform->data = new_color_map; } return 1; } @@ -1330,33 +1339,34 @@ static int ExpandColorMap(int num_colors, VP8LTransform* const transform) { static int ReadTransform(int* const xsize, int const* ysize, VP8LDecoder* const dec) { int ok = 1; - VP8LBitReader* const br = &dec->br_; - VP8LTransform* transform = &dec->transforms_[dec->next_transform_]; + VP8LBitReader* const br = &dec->br; + VP8LTransform* transform = &dec->transforms[dec->next_transform]; const VP8LImageTransformType type = (VP8LImageTransformType)VP8LReadBits(br, 2); // Each transform type can only be present once in the stream. - if (dec->transforms_seen_ & (1U << type)) { + if (dec->transforms_seen & (1U << type)) { return 0; // Already there, let's not accept the second same transform. } - dec->transforms_seen_ |= (1U << type); + dec->transforms_seen |= (1U << type); - transform->type_ = type; - transform->xsize_ = *xsize; - transform->ysize_ = *ysize; - transform->data_ = NULL; - ++dec->next_transform_; - assert(dec->next_transform_ <= NUM_TRANSFORMS); + transform->type = type; + transform->xsize = *xsize; + transform->ysize = *ysize; + transform->data = NULL; + ++dec->next_transform; + assert(dec->next_transform <= NUM_TRANSFORMS); switch (type) { case PREDICTOR_TRANSFORM: case CROSS_COLOR_TRANSFORM: - transform->bits_ = VP8LReadBits(br, 3) + 2; - ok = DecodeImageStream(VP8LSubSampleSize(transform->xsize_, - transform->bits_), - VP8LSubSampleSize(transform->ysize_, - transform->bits_), - /*is_level0=*/0, dec, &transform->data_); + transform->bits = + MIN_TRANSFORM_BITS + VP8LReadBits(br, NUM_TRANSFORM_BITS); + ok = DecodeImageStream(VP8LSubSampleSize(transform->xsize, + transform->bits), + VP8LSubSampleSize(transform->ysize, + transform->bits), + /*is_level0=*/0, dec, &transform->data); break; case COLOR_INDEXING_TRANSFORM: { const int num_colors = VP8LReadBits(br, 8) + 1; @@ -1364,10 +1374,10 @@ static int ReadTransform(int* const xsize, int const* ysize, : (num_colors > 4) ? 1 : (num_colors > 2) ? 2 : 3; - *xsize = VP8LSubSampleSize(transform->xsize_, bits); - transform->bits_ = bits; + *xsize = VP8LSubSampleSize(transform->xsize, bits); + transform->bits = bits; ok = DecodeImageStream(num_colors, /*ysize=*/1, /*is_level0=*/0, dec, - &transform->data_); + &transform->data); if (ok && !ExpandColorMap(num_colors, transform)) { return VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY); } @@ -1394,11 +1404,11 @@ static void InitMetadata(VP8LMetadata* const hdr) { static void ClearMetadata(VP8LMetadata* const hdr) { assert(hdr != NULL); - WebPSafeFree(hdr->huffman_image_); - VP8LHuffmanTablesDeallocate(&hdr->huffman_tables_); - VP8LHtreeGroupsFree(hdr->htree_groups_); - VP8LColorCacheClear(&hdr->color_cache_); - VP8LColorCacheClear(&hdr->saved_color_cache_); + WebPSafeFree(hdr->huffman_image); + VP8LHuffmanTablesDeallocate(&hdr->huffman_tables); + VP8LHtreeGroupsFree(hdr->htree_groups); + VP8LColorCacheClear(&hdr->color_cache); + VP8LColorCacheClear(&hdr->saved_color_cache); InitMetadata(hdr); } @@ -1408,31 +1418,33 @@ static void ClearMetadata(VP8LMetadata* const hdr) { VP8LDecoder* VP8LNew(void) { VP8LDecoder* const dec = (VP8LDecoder*)WebPSafeCalloc(1ULL, sizeof(*dec)); if (dec == NULL) return NULL; - dec->status_ = VP8_STATUS_OK; - dec->state_ = READ_DIM; + dec->status = VP8_STATUS_OK; + dec->state = READ_DIM; VP8LDspInit(); // Init critical function pointers. return dec; } -void VP8LClear(VP8LDecoder* const dec) { +// Resets the decoder in its initial state, reclaiming memory. +// Preserves the dec->status value. +static void VP8LClear(VP8LDecoder* const dec) { int i; if (dec == NULL) return; - ClearMetadata(&dec->hdr_); + ClearMetadata(&dec->hdr); - WebPSafeFree(dec->pixels_); - dec->pixels_ = NULL; - for (i = 0; i < dec->next_transform_; ++i) { - ClearTransform(&dec->transforms_[i]); + WebPSafeFree(dec->pixels); + dec->pixels = NULL; + for (i = 0; i < dec->next_transform; ++i) { + ClearTransform(&dec->transforms[i]); } - dec->next_transform_ = 0; - dec->transforms_seen_ = 0; + dec->next_transform = 0; + dec->transforms_seen = 0; WebPSafeFree(dec->rescaler_memory); dec->rescaler_memory = NULL; - dec->output_ = NULL; // leave no trace behind + dec->output = NULL; // leave no trace behind } void VP8LDelete(VP8LDecoder* const dec) { @@ -1443,13 +1455,13 @@ void VP8LDelete(VP8LDecoder* const dec) { } static void UpdateDecoder(VP8LDecoder* const dec, int width, int height) { - VP8LMetadata* const hdr = &dec->hdr_; - const int num_bits = hdr->huffman_subsample_bits_; - dec->width_ = width; - dec->height_ = height; + VP8LMetadata* const hdr = &dec->hdr; + const int num_bits = hdr->huffman_subsample_bits; + dec->width = width; + dec->height = height; - hdr->huffman_xsize_ = VP8LSubSampleSize(width, num_bits); - hdr->huffman_mask_ = (num_bits == 0) ? ~0 : (1 << num_bits) - 1; + hdr->huffman_xsize = VP8LSubSampleSize(width, num_bits); + hdr->huffman_mask = (num_bits == 0) ? ~0 : (1 << num_bits) - 1; } static int DecodeImageStream(int xsize, int ysize, @@ -1459,8 +1471,8 @@ static int DecodeImageStream(int xsize, int ysize, int ok = 1; int transform_xsize = xsize; int transform_ysize = ysize; - VP8LBitReader* const br = &dec->br_; - VP8LMetadata* const hdr = &dec->hdr_; + VP8LBitReader* const br = &dec->br; + VP8LMetadata* const hdr = &dec->hdr; uint32_t* data = NULL; int color_cache_bits = 0; @@ -1491,18 +1503,18 @@ static int DecodeImageStream(int xsize, int ysize, // Finish setting up the color-cache if (color_cache_bits > 0) { - hdr->color_cache_size_ = 1 << color_cache_bits; - if (!VP8LColorCacheInit(&hdr->color_cache_, color_cache_bits)) { + hdr->color_cache_size = 1 << color_cache_bits; + if (!VP8LColorCacheInit(&hdr->color_cache, color_cache_bits)) { ok = VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY); goto End; } } else { - hdr->color_cache_size_ = 0; + hdr->color_cache_size = 0; } UpdateDecoder(dec, transform_xsize, transform_ysize); if (is_level0) { // level 0 complete - dec->state_ = READ_HDR; + dec->state = READ_HDR; goto End; } @@ -1518,7 +1530,7 @@ static int DecodeImageStream(int xsize, int ysize, // Use the Huffman trees to decode the LZ77 encoded data. ok = DecodeImageData(dec, data, transform_xsize, transform_ysize, transform_ysize, NULL); - ok = ok && !br->eos_; + ok = ok && !br->eos; End: if (!ok) { @@ -1533,16 +1545,16 @@ static int DecodeImageStream(int xsize, int ysize, assert(data == NULL); assert(is_level0); } - dec->last_pixel_ = 0; // Reset for future DECODE_DATA_FUNC() calls. + dec->last_pixel = 0; // Reset for future DECODE_DATA_FUNC() calls. if (!is_level0) ClearMetadata(hdr); // Clean up temporary data behind. } return ok; } //------------------------------------------------------------------------------ -// Allocate internal buffers dec->pixels_ and dec->argb_cache_. +// Allocate internal buffers dec->pixels and dec->argb_cache. static int AllocateInternalBuffers32b(VP8LDecoder* const dec, int final_width) { - const uint64_t num_pixels = (uint64_t)dec->width_ * dec->height_; + const uint64_t num_pixels = (uint64_t)dec->width * dec->height; // Scratch buffer corresponding to top-prediction row for transforming the // first row in the row-blocks. Not needed for paletted alpha. const uint64_t cache_top_pixels = (uint16_t)final_width; @@ -1551,21 +1563,21 @@ static int AllocateInternalBuffers32b(VP8LDecoder* const dec, int final_width) { const uint64_t total_num_pixels = num_pixels + cache_top_pixels + cache_pixels; - assert(dec->width_ <= final_width); - dec->pixels_ = (uint32_t*)WebPSafeMalloc(total_num_pixels, sizeof(uint32_t)); - if (dec->pixels_ == NULL) { - dec->argb_cache_ = NULL; // for soundness + assert(dec->width <= final_width); + dec->pixels = (uint32_t*)WebPSafeMalloc(total_num_pixels, sizeof(uint32_t)); + if (dec->pixels == NULL) { + dec->argb_cache = NULL; // for soundness return VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY); } - dec->argb_cache_ = dec->pixels_ + num_pixels + cache_top_pixels; + dec->argb_cache = dec->pixels + num_pixels + cache_top_pixels; return 1; } static int AllocateInternalBuffers8b(VP8LDecoder* const dec) { - const uint64_t total_num_pixels = (uint64_t)dec->width_ * dec->height_; - dec->argb_cache_ = NULL; // for soundness - dec->pixels_ = (uint32_t*)WebPSafeMalloc(total_num_pixels, sizeof(uint8_t)); - if (dec->pixels_ == NULL) { + const uint64_t total_num_pixels = (uint64_t)dec->width * dec->height; + dec->argb_cache = NULL; // for soundness + dec->pixels = (uint32_t*)WebPSafeMalloc(total_num_pixels, sizeof(uint8_t)); + if (dec->pixels == NULL) { return VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY); } return 1; @@ -1575,31 +1587,31 @@ static int AllocateInternalBuffers8b(VP8LDecoder* const dec) { // Special row-processing that only stores the alpha data. static void ExtractAlphaRows(VP8LDecoder* const dec, int last_row) { - int cur_row = dec->last_row_; + int cur_row = dec->last_row; int num_rows = last_row - cur_row; - const uint32_t* in = dec->pixels_ + dec->width_ * cur_row; + const uint32_t* in = dec->pixels + dec->width * cur_row; - assert(last_row <= dec->io_->crop_bottom); + assert(last_row <= dec->io->crop_bottom); while (num_rows > 0) { const int num_rows_to_process = (num_rows > NUM_ARGB_CACHE_ROWS) ? NUM_ARGB_CACHE_ROWS : num_rows; // Extract alpha (which is stored in the green plane). - ALPHDecoder* const alph_dec = (ALPHDecoder*)dec->io_->opaque; - uint8_t* const output = alph_dec->output_; - const int width = dec->io_->width; // the final width (!= dec->width_) + ALPHDecoder* const alph_dec = (ALPHDecoder*)dec->io->opaque; + uint8_t* const output = alph_dec->output; + const int width = dec->io->width; // the final width (!= dec->width) const int cache_pixs = width * num_rows_to_process; uint8_t* const dst = output + width * cur_row; - const uint32_t* const src = dec->argb_cache_; + const uint32_t* const src = dec->argb_cache; ApplyInverseTransforms(dec, cur_row, num_rows_to_process, in); WebPExtractGreen(src, dst, cache_pixs); AlphaApplyFilter(alph_dec, cur_row, cur_row + num_rows_to_process, dst, width); num_rows -= num_rows_to_process; - in += num_rows_to_process * dec->width_; + in += num_rows_to_process * dec->width; cur_row += num_rows_to_process; } assert(cur_row == last_row); - dec->last_row_ = dec->last_out_row_ = last_row; + dec->last_row = dec->last_out_row = last_row; } int VP8LDecodeAlphaHeader(ALPHDecoder* const alph_dec, @@ -1611,17 +1623,17 @@ int VP8LDecodeAlphaHeader(ALPHDecoder* const alph_dec, assert(alph_dec != NULL); - dec->width_ = alph_dec->width_; - dec->height_ = alph_dec->height_; - dec->io_ = &alph_dec->io_; - dec->io_->opaque = alph_dec; - dec->io_->width = alph_dec->width_; - dec->io_->height = alph_dec->height_; + dec->width = alph_dec->width; + dec->height = alph_dec->height; + dec->io = &alph_dec->io; + dec->io->opaque = alph_dec; + dec->io->width = alph_dec->width; + dec->io->height = alph_dec->height; - dec->status_ = VP8_STATUS_OK; - VP8LInitBitReader(&dec->br_, data, data_size); + dec->status = VP8_STATUS_OK; + VP8LInitBitReader(&dec->br, data, data_size); - if (!DecodeImageStream(alph_dec->width_, alph_dec->height_, /*is_level0=*/1, + if (!DecodeImageStream(alph_dec->width, alph_dec->height, /*is_level0=*/1, dec, /*decoded_data=*/NULL)) { goto Err; } @@ -1629,21 +1641,21 @@ int VP8LDecodeAlphaHeader(ALPHDecoder* const alph_dec, // Special case: if alpha data uses only the color indexing transform and // doesn't use color cache (a frequent case), we will use DecodeAlphaData() // method that only needs allocation of 1 byte per pixel (alpha channel). - if (dec->next_transform_ == 1 && - dec->transforms_[0].type_ == COLOR_INDEXING_TRANSFORM && - Is8bOptimizable(&dec->hdr_)) { - alph_dec->use_8b_decode_ = 1; + if (dec->next_transform == 1 && + dec->transforms[0].type == COLOR_INDEXING_TRANSFORM && + Is8bOptimizable(&dec->hdr)) { + alph_dec->use_8b_decode = 1; ok = AllocateInternalBuffers8b(dec); } else { - // Allocate internal buffers (note that dec->width_ may have changed here). - alph_dec->use_8b_decode_ = 0; - ok = AllocateInternalBuffers32b(dec, alph_dec->width_); + // Allocate internal buffers (note that dec->width may have changed here). + alph_dec->use_8b_decode = 0; + ok = AllocateInternalBuffers32b(dec, alph_dec->width); } if (!ok) goto Err; // Only set here, once we are sure it is valid (to avoid thread races). - alph_dec->vp8l_dec_ = dec; + alph_dec->vp8l_dec = dec; return 1; Err: @@ -1652,21 +1664,21 @@ int VP8LDecodeAlphaHeader(ALPHDecoder* const alph_dec, } int VP8LDecodeAlphaImageStream(ALPHDecoder* const alph_dec, int last_row) { - VP8LDecoder* const dec = alph_dec->vp8l_dec_; + VP8LDecoder* const dec = alph_dec->vp8l_dec; assert(dec != NULL); - assert(last_row <= dec->height_); + assert(last_row <= dec->height); - if (dec->last_row_ >= last_row) { + if (dec->last_row >= last_row) { return 1; // done } - if (!alph_dec->use_8b_decode_) WebPInitAlphaProcessing(); + if (!alph_dec->use_8b_decode) WebPInitAlphaProcessing(); // Decode (with special row processing). - return alph_dec->use_8b_decode_ ? - DecodeAlphaData(dec, (uint8_t*)dec->pixels_, dec->width_, dec->height_, + return alph_dec->use_8b_decode ? + DecodeAlphaData(dec, (uint8_t*)dec->pixels, dec->width, dec->height, last_row) : - DecodeImageData(dec, dec->pixels_, dec->width_, dec->height_, + DecodeImageData(dec, dec->pixels, dec->width, dec->height, last_row, ExtractAlphaRows); } @@ -1680,14 +1692,14 @@ int VP8LDecodeHeader(VP8LDecoder* const dec, VP8Io* const io) { return VP8LSetError(dec, VP8_STATUS_INVALID_PARAM); } - dec->io_ = io; - dec->status_ = VP8_STATUS_OK; - VP8LInitBitReader(&dec->br_, io->data, io->data_size); - if (!ReadImageInfo(&dec->br_, &width, &height, &has_alpha)) { + dec->io = io; + dec->status = VP8_STATUS_OK; + VP8LInitBitReader(&dec->br, io->data, io->data_size); + if (!ReadImageInfo(&dec->br, &width, &height, &has_alpha)) { VP8LSetError(dec, VP8_STATUS_BITSTREAM_ERROR); goto Error; } - dec->state_ = READ_DIM; + dec->state = READ_DIM; io->width = width; io->height = height; @@ -1699,7 +1711,7 @@ int VP8LDecodeHeader(VP8LDecoder* const dec, VP8Io* const io) { Error: VP8LClear(dec); - assert(dec->status_ != VP8_STATUS_OK); + assert(dec->status != VP8_STATUS_OK); return 0; } @@ -1709,19 +1721,19 @@ int VP8LDecodeImage(VP8LDecoder* const dec) { if (dec == NULL) return 0; - assert(dec->hdr_.huffman_tables_.root.start != NULL); - assert(dec->hdr_.htree_groups_ != NULL); - assert(dec->hdr_.num_htree_groups_ > 0); + assert(dec->hdr.huffman_tables.root.start != NULL); + assert(dec->hdr.htree_groups != NULL); + assert(dec->hdr.num_htree_groups > 0); - io = dec->io_; + io = dec->io; assert(io != NULL); params = (WebPDecParams*)io->opaque; assert(params != NULL); // Initialization. - if (dec->state_ != READ_DATA) { - dec->output_ = params->output; - assert(dec->output_ != NULL); + if (dec->state != READ_DATA) { + dec->output = params->output; + assert(dec->output != NULL); if (!WebPIoInitFromOptions(params->options, io, MODE_BGRA)) { VP8LSetError(dec, VP8_STATUS_INVALID_PARAM); @@ -1738,40 +1750,40 @@ int VP8LDecodeImage(VP8LDecoder* const dec) { goto Err; } #endif - if (io->use_scaling || WebPIsPremultipliedMode(dec->output_->colorspace)) { + if (io->use_scaling || WebPIsPremultipliedMode(dec->output->colorspace)) { // need the alpha-multiply functions for premultiplied output or rescaling WebPInitAlphaProcessing(); } - if (!WebPIsRGBMode(dec->output_->colorspace)) { + if (!WebPIsRGBMode(dec->output->colorspace)) { WebPInitConvertARGBToYUV(); - if (dec->output_->u.YUVA.a != NULL) WebPInitAlphaProcessing(); + if (dec->output->u.YUVA.a != NULL) WebPInitAlphaProcessing(); } - if (dec->incremental_) { - if (dec->hdr_.color_cache_size_ > 0 && - dec->hdr_.saved_color_cache_.colors_ == NULL) { - if (!VP8LColorCacheInit(&dec->hdr_.saved_color_cache_, - dec->hdr_.color_cache_.hash_bits_)) { + if (dec->incremental) { + if (dec->hdr.color_cache_size > 0 && + dec->hdr.saved_color_cache.colors == NULL) { + if (!VP8LColorCacheInit(&dec->hdr.saved_color_cache, + dec->hdr.color_cache.hash_bits)) { VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY); goto Err; } } } - dec->state_ = READ_DATA; + dec->state = READ_DATA; } // Decode. - if (!DecodeImageData(dec, dec->pixels_, dec->width_, dec->height_, + if (!DecodeImageData(dec, dec->pixels, dec->width, dec->height, io->crop_bottom, ProcessRows)) { goto Err; } - params->last_y = dec->last_out_row_; + params->last_y = dec->last_out_row; return 1; Err: VP8LClear(dec); - assert(dec->status_ != VP8_STATUS_OK); + assert(dec->status != VP8_STATUS_OK); return 0; } diff --git a/libwebp/src/dec/vp8li_dec.h b/libwebp/src/dec/vp8li_dec.h index 9a13bcc9..4e2eadb3 100644 --- a/libwebp/src/dec/vp8li_dec.h +++ b/libwebp/src/dec/vp8li_dec.h @@ -16,10 +16,15 @@ #define WEBP_DEC_VP8LI_DEC_H_ #include // for memcpy() + +#include "src/dec/vp8_dec.h" #include "src/dec/webpi_dec.h" #include "src/utils/bit_reader_utils.h" #include "src/utils/color_cache_utils.h" #include "src/utils/huffman_utils.h" +#include "src/utils/rescaler_utils.h" +#include "src/webp/decode.h" +#include "src/webp/format_constants.h" #include "src/webp/types.h" #ifdef __cplusplus @@ -34,58 +39,58 @@ typedef enum { typedef struct VP8LTransform VP8LTransform; struct VP8LTransform { - VP8LImageTransformType type_; // transform type. - int bits_; // subsampling bits defining transform window. - int xsize_; // transform window X index. - int ysize_; // transform window Y index. - uint32_t* data_; // transform data. + VP8LImageTransformType type; // transform type. + int bits; // subsampling bits defining transform window. + int xsize; // transform window X index. + int ysize; // transform window Y index. + uint32_t* data; // transform data. }; typedef struct { - int color_cache_size_; - VP8LColorCache color_cache_; - VP8LColorCache saved_color_cache_; // for incremental - - int huffman_mask_; - int huffman_subsample_bits_; - int huffman_xsize_; - uint32_t* huffman_image_; - int num_htree_groups_; - HTreeGroup* htree_groups_; - HuffmanTables huffman_tables_; + int color_cache_size; + VP8LColorCache color_cache; + VP8LColorCache saved_color_cache; // for incremental + + int huffman_mask; + int huffman_subsample_bits; + int huffman_xsize; + uint32_t* huffman_image; + int num_htree_groups; + HTreeGroup* htree_groups; + HuffmanTables huffman_tables; } VP8LMetadata; typedef struct VP8LDecoder VP8LDecoder; struct VP8LDecoder { - VP8StatusCode status_; - VP8LDecodeState state_; - VP8Io* io_; + VP8StatusCode status; + VP8LDecodeState state; + VP8Io* io; - const WebPDecBuffer* output_; // shortcut to io->opaque->output + const WebPDecBuffer* output; // shortcut to io->opaque->output - uint32_t* pixels_; // Internal data: either uint8_t* for alpha - // or uint32_t* for BGRA. - uint32_t* argb_cache_; // Scratch buffer for temporary BGRA storage. + uint32_t* pixels; // Internal data: either uint8_t* for alpha + // or uint32_t* for BGRA. + uint32_t* argb_cache; // Scratch buffer for temporary BGRA storage. - VP8LBitReader br_; - int incremental_; // if true, incremental decoding is expected - VP8LBitReader saved_br_; // note: could be local variables too - int saved_last_pixel_; + VP8LBitReader br; + int incremental; // if true, incremental decoding is expected + VP8LBitReader saved_br; // note: could be local variables too + int saved_last_pixel; - int width_; - int height_; - int last_row_; // last input row decoded so far. - int last_pixel_; // last pixel decoded so far. However, it may - // not be transformed, scaled and - // color-converted yet. - int last_out_row_; // last row output so far. + int width; + int height; + int last_row; // last input row decoded so far. + int last_pixel; // last pixel decoded so far. However, it may + // not be transformed, scaled and + // color-converted yet. + int last_out_row; // last row output so far. - VP8LMetadata hdr_; + VP8LMetadata hdr; - int next_transform_; - VP8LTransform transforms_[NUM_TRANSFORMS]; + int next_transform; + VP8LTransform transforms[NUM_TRANSFORMS]; // or'd bitset storing the transforms types. - uint32_t transforms_seen_; + uint32_t transforms_seen; uint8_t* rescaler_memory; // Working memory for rescaling work. WebPRescaler* rescaler; // Common rescaler for all channels. @@ -118,13 +123,9 @@ WEBP_NODISCARD VP8LDecoder* VP8LNew(void); WEBP_NODISCARD int VP8LDecodeHeader(VP8LDecoder* const dec, VP8Io* const io); // Decodes an image. It's required to decode the lossless header before calling -// this function. Returns false in case of error, with updated dec->status_. +// this function. Returns false in case of error, with updated dec->status. WEBP_NODISCARD int VP8LDecodeImage(VP8LDecoder* const dec); -// Resets the decoder in its initial state, reclaiming memory. -// Preserves the dec->status_ value. -void VP8LClear(VP8LDecoder* const dec); - // Clears and deallocate a lossless decoder instance. void VP8LDelete(VP8LDecoder* const dec); diff --git a/libwebp/src/dec/webp_dec.c b/libwebp/src/dec/webp_dec.c index 49ef205c..5e7c23fe 100644 --- a/libwebp/src/dec/webp_dec.c +++ b/libwebp/src/dec/webp_dec.c @@ -11,15 +11,20 @@ // // Author: Skal (pascal.massimino@gmail.com) +#include #include +#include +#include "src/dec/common_dec.h" #include "src/dec/vp8_dec.h" #include "src/dec/vp8i_dec.h" #include "src/dec/vp8li_dec.h" #include "src/dec/webpi_dec.h" +#include "src/utils/rescaler_utils.h" #include "src/utils/utils.h" -#include "src/webp/mux_types.h" // ALPHA_FLAG #include "src/webp/decode.h" +#include "src/webp/format_constants.h" +#include "src/webp/mux_types.h" // ALPHA_FLAG #include "src/webp/types.h" //------------------------------------------------------------------------------ @@ -475,23 +480,23 @@ WEBP_NODISCARD static VP8StatusCode DecodeInto(const uint8_t* const data, if (dec == NULL) { return VP8_STATUS_OUT_OF_MEMORY; } - dec->alpha_data_ = headers.alpha_data; - dec->alpha_data_size_ = headers.alpha_data_size; + dec->alpha_data = headers.alpha_data; + dec->alpha_data_size = headers.alpha_data_size; // Decode bitstream header, update io->width/io->height. if (!VP8GetHeaders(dec, &io)) { - status = dec->status_; // An error occurred. Grab error status. + status = dec->status; // An error occurred. Grab error status. } else { // Allocate/check output buffers. status = WebPAllocateDecBuffer(io.width, io.height, params->options, params->output); if (status == VP8_STATUS_OK) { // Decode // This change must be done before calling VP8Decode() - dec->mt_method_ = VP8GetThreadMethod(params->options, &headers, - io.width, io.height); + dec->mt_method = VP8GetThreadMethod(params->options, &headers, + io.width, io.height); VP8InitDithering(params->options, dec); if (!VP8Decode(dec, &io)) { - status = dec->status_; + status = dec->status; } } } @@ -502,14 +507,14 @@ WEBP_NODISCARD static VP8StatusCode DecodeInto(const uint8_t* const data, return VP8_STATUS_OUT_OF_MEMORY; } if (!VP8LDecodeHeader(dec, &io)) { - status = dec->status_; // An error occurred. Grab error status. + status = dec->status; // An error occurred. Grab error status. } else { // Allocate/check output buffers. status = WebPAllocateDecBuffer(io.width, io.height, params->options, params->output); if (status == VP8_STATUS_OK) { // Decode if (!VP8LDecodeImage(dec)) { - status = dec->status_; + status = dec->status; } } } @@ -747,6 +752,61 @@ int WebPInitDecoderConfigInternal(WebPDecoderConfig* config, return 1; } +static int WebPCheckCropDimensionsBasic(int x, int y, int w, int h) { + return !(x < 0 || y < 0 || w <= 0 || h <= 0); +} + +int WebPValidateDecoderConfig(const WebPDecoderConfig* config) { + const WebPDecoderOptions* options; + if (config == NULL) return 0; + if (!IsValidColorspace(config->output.colorspace)) { + return 0; + } + + options = &config->options; + // bypass_filtering, no_fancy_upsampling, use_cropping, use_scaling, + // use_threads, flip can be any integer and are interpreted as boolean. + + // Check for cropping. + if (options->use_cropping && !WebPCheckCropDimensionsBasic( + options->crop_left, options->crop_top, + options->crop_width, options->crop_height)) { + return 0; + } + // Check for scaling. + if (options->use_scaling && + (options->scaled_width < 0 || options->scaled_height < 0 || + (options->scaled_width == 0 && options->scaled_height == 0))) { + return 0; + } + + // In case the WebPBitstreamFeatures has been filled in, check further. + if (config->input.width > 0 || config->input.height > 0) { + int scaled_width = options->scaled_width; + int scaled_height = options->scaled_height; + if (options->use_cropping && + !WebPCheckCropDimensions(config->input.width, config->input.height, + options->crop_left, options->crop_top, + options->crop_width, options->crop_height)) { + return 0; + } + if (options->use_scaling && !WebPRescalerGetScaledDimensions( + config->input.width, config->input.height, + &scaled_width, &scaled_height)) { + return 0; + } + } + + // Check for dithering. + if (options->dithering_strength < 0 || options->dithering_strength > 100 || + options->alpha_dithering_strength < 0 || + options->alpha_dithering_strength > 100) { + return 0; + } + + return 1; +} + VP8StatusCode WebPGetFeaturesInternal(const uint8_t* data, size_t data_size, WebPBitstreamFeatures* features, int version) { @@ -806,8 +866,8 @@ VP8StatusCode WebPDecode(const uint8_t* data, size_t data_size, int WebPCheckCropDimensions(int image_width, int image_height, int x, int y, int w, int h) { - return !(x < 0 || y < 0 || w <= 0 || h <= 0 || - x >= image_width || w > image_width || w > image_width - x || + return WebPCheckCropDimensionsBasic(x, y, w, h) && + !(x >= image_width || w > image_width || w > image_width - x || y >= image_height || h > image_height || h > image_height - y); } diff --git a/libwebp/src/dec/webpi_dec.h b/libwebp/src/dec/webpi_dec.h index 77bf5264..19297964 100644 --- a/libwebp/src/dec/webpi_dec.h +++ b/libwebp/src/dec/webpi_dec.h @@ -18,9 +18,12 @@ extern "C" { #endif -#include "src/utils/rescaler_utils.h" +#include + #include "src/dec/vp8_dec.h" +#include "src/utils/rescaler_utils.h" #include "src/webp/decode.h" +#include "src/webp/types.h" //------------------------------------------------------------------------------ // WebPDecParams: Decoding output parameters. Transient internal object. diff --git a/libwebp/src/demux/Makefile.am b/libwebp/src/demux/Makefile.am deleted file mode 100644 index 2df2db5b..00000000 --- a/libwebp/src/demux/Makefile.am +++ /dev/null @@ -1,18 +0,0 @@ -AM_CPPFLAGS += -I$(top_builddir) -I$(top_srcdir) -lib_LTLIBRARIES = libwebpdemux.la - -libwebpdemux_la_SOURCES = -libwebpdemux_la_SOURCES += anim_decode.c demux.c - -libwebpdemuxinclude_HEADERS = -libwebpdemuxinclude_HEADERS += ../webp/decode.h -libwebpdemuxinclude_HEADERS += ../webp/demux.h -libwebpdemuxinclude_HEADERS += ../webp/mux_types.h -libwebpdemuxinclude_HEADERS += ../webp/types.h -noinst_HEADERS = -noinst_HEADERS += ../webp/format_constants.h - -libwebpdemux_la_LIBADD = ../libwebp.la -libwebpdemux_la_LDFLAGS = -no-undefined -version-info 2:14:0 -libwebpdemuxincludedir = $(includedir)/webp -pkgconfig_DATA = libwebpdemux.pc diff --git a/libwebp/src/demux/anim_decode.c b/libwebp/src/demux/anim_decode.c index 27f0e2b0..f046f506 100644 --- a/libwebp/src/demux/anim_decode.c +++ b/libwebp/src/demux/anim_decode.c @@ -20,6 +20,8 @@ #include "src/utils/utils.h" #include "src/webp/decode.h" #include "src/webp/demux.h" +#include "src/webp/mux.h" +#include "src/webp/mux_types.h" #include "src/webp/types.h" #define NUM_CHANNELS 4 @@ -39,18 +41,18 @@ static void BlendPixelRowPremult(uint32_t* const src, const uint32_t* const dst, int num_pixels); struct WebPAnimDecoder { - WebPDemuxer* demux_; // Demuxer created from given WebP bitstream. - WebPDecoderConfig config_; // Decoder config. + WebPDemuxer* demux; // Demuxer created from given WebP bitstream. + WebPDecoderConfig config; // Decoder config. // Note: we use a pointer to a function blending multiple pixels at a time to // allow possible inlining of per-pixel blending function. - BlendRowFunc blend_func_; // Pointer to the chose blend row function. - WebPAnimInfo info_; // Global info about the animation. - uint8_t* curr_frame_; // Current canvas (not disposed). - uint8_t* prev_frame_disposed_; // Previous canvas (properly disposed). - int prev_frame_timestamp_; // Previous frame timestamp (milliseconds). - WebPIterator prev_iter_; // Iterator object for previous frame. - int prev_frame_was_keyframe_; // True if previous frame was a keyframe. - int next_frame_; // Index of the next frame to be decoded + BlendRowFunc blend_func; // Pointer to the chose blend row function. + WebPAnimInfo info; // Global info about the animation. + uint8_t* curr_frame; // Current canvas (not disposed). + uint8_t* prev_frame_disposed; // Previous canvas (properly disposed). + int prev_frame_timestamp; // Previous frame timestamp (milliseconds). + WebPIterator prev_iter; // Iterator object for previous frame. + int prev_frame_was_keyframe; // True if previous frame was a keyframe. + int next_frame; // Index of the next frame to be decoded // (starting from 1). }; @@ -73,7 +75,7 @@ WEBP_NODISCARD static int ApplyDecoderOptions( const WebPAnimDecoderOptions* const dec_options, WebPAnimDecoder* const dec) { WEBP_CSP_MODE mode; - WebPDecoderConfig* config = &dec->config_; + WebPDecoderConfig* config = &dec->config; assert(dec_options != NULL); mode = dec_options->color_mode; @@ -81,9 +83,9 @@ WEBP_NODISCARD static int ApplyDecoderOptions( mode != MODE_rgbA && mode != MODE_bgrA) { return 0; } - dec->blend_func_ = (mode == MODE_RGBA || mode == MODE_BGRA) - ? &BlendPixelRowNonPremult - : &BlendPixelRowPremult; + dec->blend_func = (mode == MODE_RGBA || mode == MODE_BGRA) + ? &BlendPixelRowNonPremult + : &BlendPixelRowPremult; if (!WebPInitDecoderConfig(config)) { return 0; } @@ -123,22 +125,22 @@ WebPAnimDecoder* WebPAnimDecoderNewInternal( } if (!ApplyDecoderOptions(&options, dec)) goto Error; - dec->demux_ = WebPDemux(webp_data); - if (dec->demux_ == NULL) goto Error; + dec->demux = WebPDemux(webp_data); + if (dec->demux == NULL) goto Error; - dec->info_.canvas_width = WebPDemuxGetI(dec->demux_, WEBP_FF_CANVAS_WIDTH); - dec->info_.canvas_height = WebPDemuxGetI(dec->demux_, WEBP_FF_CANVAS_HEIGHT); - dec->info_.loop_count = WebPDemuxGetI(dec->demux_, WEBP_FF_LOOP_COUNT); - dec->info_.bgcolor = WebPDemuxGetI(dec->demux_, WEBP_FF_BACKGROUND_COLOR); - dec->info_.frame_count = WebPDemuxGetI(dec->demux_, WEBP_FF_FRAME_COUNT); + dec->info.canvas_width = WebPDemuxGetI(dec->demux, WEBP_FF_CANVAS_WIDTH); + dec->info.canvas_height = WebPDemuxGetI(dec->demux, WEBP_FF_CANVAS_HEIGHT); + dec->info.loop_count = WebPDemuxGetI(dec->demux, WEBP_FF_LOOP_COUNT); + dec->info.bgcolor = WebPDemuxGetI(dec->demux, WEBP_FF_BACKGROUND_COLOR); + dec->info.frame_count = WebPDemuxGetI(dec->demux, WEBP_FF_FRAME_COUNT); // Note: calloc() because we fill frame with zeroes as well. - dec->curr_frame_ = (uint8_t*)WebPSafeCalloc( - dec->info_.canvas_width * NUM_CHANNELS, dec->info_.canvas_height); - if (dec->curr_frame_ == NULL) goto Error; - dec->prev_frame_disposed_ = (uint8_t*)WebPSafeCalloc( - dec->info_.canvas_width * NUM_CHANNELS, dec->info_.canvas_height); - if (dec->prev_frame_disposed_ == NULL) goto Error; + dec->curr_frame = (uint8_t*)WebPSafeCalloc( + dec->info.canvas_width * NUM_CHANNELS, dec->info.canvas_height); + if (dec->curr_frame == NULL) goto Error; + dec->prev_frame_disposed = (uint8_t*)WebPSafeCalloc( + dec->info.canvas_width * NUM_CHANNELS, dec->info.canvas_height); + if (dec->prev_frame_disposed == NULL) goto Error; WebPAnimDecoderReset(dec); return dec; @@ -150,7 +152,7 @@ WebPAnimDecoder* WebPAnimDecoderNewInternal( int WebPAnimDecoderGetInfo(const WebPAnimDecoder* dec, WebPAnimInfo* info) { if (dec == NULL || info == NULL) return 0; - *info = dec->info_; + *info = dec->info; return 1; } @@ -338,25 +340,25 @@ int WebPAnimDecoderGetNext(WebPAnimDecoder* dec, if (dec == NULL || buf_ptr == NULL || timestamp_ptr == NULL) return 0; if (!WebPAnimDecoderHasMoreFrames(dec)) return 0; - width = dec->info_.canvas_width; - height = dec->info_.canvas_height; - blend_row = dec->blend_func_; + width = dec->info.canvas_width; + height = dec->info.canvas_height; + blend_row = dec->blend_func; // Get compressed frame. - if (!WebPDemuxGetFrame(dec->demux_, dec->next_frame_, &iter)) { + if (!WebPDemuxGetFrame(dec->demux, dec->next_frame, &iter)) { return 0; } - timestamp = dec->prev_frame_timestamp_ + iter.duration; + timestamp = dec->prev_frame_timestamp + iter.duration; // Initialize. - is_key_frame = IsKeyFrame(&iter, &dec->prev_iter_, - dec->prev_frame_was_keyframe_, width, height); + is_key_frame = IsKeyFrame(&iter, &dec->prev_iter, + dec->prev_frame_was_keyframe, width, height); if (is_key_frame) { - if (!ZeroFillCanvas(dec->curr_frame_, width, height)) { + if (!ZeroFillCanvas(dec->curr_frame, width, height)) { goto Error; } } else { - if (!CopyCanvas(dec->prev_frame_disposed_, dec->curr_frame_, + if (!CopyCanvas(dec->prev_frame_disposed, dec->curr_frame, width, height)) { goto Error; } @@ -370,12 +372,12 @@ int WebPAnimDecoderGetNext(WebPAnimDecoder* dec, const uint64_t out_offset = (uint64_t)iter.y_offset * stride + (uint64_t)iter.x_offset * NUM_CHANNELS; // 53b const uint64_t size = (uint64_t)iter.height * stride; // at most 25 + 27b - WebPDecoderConfig* const config = &dec->config_; + WebPDecoderConfig* const config = &dec->config; WebPRGBABuffer* const buf = &config->output.u.RGBA; if ((size_t)size != size) goto Error; buf->stride = (int)stride; buf->size = (size_t)size; - buf->rgba = dec->curr_frame_ + out_offset; + buf->rgba = dec->curr_frame + out_offset; if (WebPDecode(in, in_size, config) != VP8_STATUS_OK) { goto Error; @@ -388,18 +390,18 @@ int WebPAnimDecoderGetNext(WebPAnimDecoder* dec, // that pixel in the previous frame if blending method of is WEBP_MUX_BLEND. if (iter.frame_num > 1 && iter.blend_method == WEBP_MUX_BLEND && !is_key_frame) { - if (dec->prev_iter_.dispose_method == WEBP_MUX_DISPOSE_NONE) { + if (dec->prev_iter.dispose_method == WEBP_MUX_DISPOSE_NONE) { int y; // Blend transparent pixels with pixels in previous canvas. for (y = 0; y < iter.height; ++y) { const size_t offset = (iter.y_offset + y) * width + iter.x_offset; - blend_row((uint32_t*)dec->curr_frame_ + offset, - (uint32_t*)dec->prev_frame_disposed_ + offset, iter.width); + blend_row((uint32_t*)dec->curr_frame + offset, + (uint32_t*)dec->prev_frame_disposed + offset, iter.width); } } else { int y; - assert(dec->prev_iter_.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND); + assert(dec->prev_iter.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND); // We need to blend a transparent pixel with its value just after // initialization. That is, blend it with: // * Fully transparent pixel if it belongs to prevRect <-- No-op. @@ -407,39 +409,39 @@ int WebPAnimDecoderGetNext(WebPAnimDecoder* dec, for (y = 0; y < iter.height; ++y) { const int canvas_y = iter.y_offset + y; int left1, width1, left2, width2; - FindBlendRangeAtRow(&iter, &dec->prev_iter_, canvas_y, &left1, &width1, + FindBlendRangeAtRow(&iter, &dec->prev_iter, canvas_y, &left1, &width1, &left2, &width2); if (width1 > 0) { const size_t offset1 = canvas_y * width + left1; - blend_row((uint32_t*)dec->curr_frame_ + offset1, - (uint32_t*)dec->prev_frame_disposed_ + offset1, width1); + blend_row((uint32_t*)dec->curr_frame + offset1, + (uint32_t*)dec->prev_frame_disposed + offset1, width1); } if (width2 > 0) { const size_t offset2 = canvas_y * width + left2; - blend_row((uint32_t*)dec->curr_frame_ + offset2, - (uint32_t*)dec->prev_frame_disposed_ + offset2, width2); + blend_row((uint32_t*)dec->curr_frame + offset2, + (uint32_t*)dec->prev_frame_disposed + offset2, width2); } } } } // Update info of the previous frame and dispose it for the next iteration. - dec->prev_frame_timestamp_ = timestamp; - WebPDemuxReleaseIterator(&dec->prev_iter_); - dec->prev_iter_ = iter; - dec->prev_frame_was_keyframe_ = is_key_frame; - if (!CopyCanvas(dec->curr_frame_, dec->prev_frame_disposed_, width, height)) { + dec->prev_frame_timestamp = timestamp; + WebPDemuxReleaseIterator(&dec->prev_iter); + dec->prev_iter = iter; + dec->prev_frame_was_keyframe = is_key_frame; + if (!CopyCanvas(dec->curr_frame, dec->prev_frame_disposed, width, height)) { goto Error; } - if (dec->prev_iter_.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) { - ZeroFillFrameRect(dec->prev_frame_disposed_, width * NUM_CHANNELS, - dec->prev_iter_.x_offset, dec->prev_iter_.y_offset, - dec->prev_iter_.width, dec->prev_iter_.height); + if (dec->prev_iter.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) { + ZeroFillFrameRect(dec->prev_frame_disposed, width * NUM_CHANNELS, + dec->prev_iter.x_offset, dec->prev_iter.y_offset, + dec->prev_iter.width, dec->prev_iter.height); } - ++dec->next_frame_; + ++dec->next_frame; // All OK, fill in the values. - *buf_ptr = dec->curr_frame_; + *buf_ptr = dec->curr_frame; *timestamp_ptr = timestamp; return 1; @@ -450,30 +452,30 @@ int WebPAnimDecoderGetNext(WebPAnimDecoder* dec, int WebPAnimDecoderHasMoreFrames(const WebPAnimDecoder* dec) { if (dec == NULL) return 0; - return (dec->next_frame_ <= (int)dec->info_.frame_count); + return (dec->next_frame <= (int)dec->info.frame_count); } void WebPAnimDecoderReset(WebPAnimDecoder* dec) { if (dec != NULL) { - dec->prev_frame_timestamp_ = 0; - WebPDemuxReleaseIterator(&dec->prev_iter_); - memset(&dec->prev_iter_, 0, sizeof(dec->prev_iter_)); - dec->prev_frame_was_keyframe_ = 0; - dec->next_frame_ = 1; + dec->prev_frame_timestamp = 0; + WebPDemuxReleaseIterator(&dec->prev_iter); + memset(&dec->prev_iter, 0, sizeof(dec->prev_iter)); + dec->prev_frame_was_keyframe = 0; + dec->next_frame = 1; } } const WebPDemuxer* WebPAnimDecoderGetDemuxer(const WebPAnimDecoder* dec) { if (dec == NULL) return NULL; - return dec->demux_; + return dec->demux; } void WebPAnimDecoderDelete(WebPAnimDecoder* dec) { if (dec != NULL) { - WebPDemuxReleaseIterator(&dec->prev_iter_); - WebPDemuxDelete(dec->demux_); - WebPSafeFree(dec->curr_frame_); - WebPSafeFree(dec->prev_frame_disposed_); + WebPDemuxReleaseIterator(&dec->prev_iter); + WebPDemuxDelete(dec->demux); + WebPSafeFree(dec->curr_frame); + WebPSafeFree(dec->prev_frame_disposed); WebPSafeFree(dec); } } diff --git a/libwebp/src/demux/demux.c b/libwebp/src/demux/demux.c index 4b0d3f59..7d4e23e2 100644 --- a/libwebp/src/demux/demux.c +++ b/libwebp/src/demux/demux.c @@ -22,55 +22,58 @@ #include "src/webp/decode.h" // WebPGetFeatures #include "src/webp/demux.h" #include "src/webp/format_constants.h" +#include "src/webp/mux.h" +#include "src/webp/mux_types.h" +#include "src/webp/types.h" #define DMUX_MAJ_VERSION 1 -#define DMUX_MIN_VERSION 3 -#define DMUX_REV_VERSION 2 +#define DMUX_MIN_VERSION 6 +#define DMUX_REV_VERSION 0 typedef struct { - size_t start_; // start location of the data - size_t end_; // end location - size_t riff_end_; // riff chunk end location, can be > end_. - size_t buf_size_; // size of the buffer - const uint8_t* buf_; + size_t start; // start location of the data + size_t end; // end location + size_t riff_end; // riff chunk end location, can be > end. + size_t buf_size; // size of the buffer + const uint8_t* buf; } MemBuffer; typedef struct { - size_t offset_; - size_t size_; + size_t offset; + size_t size; } ChunkData; typedef struct Frame { - int x_offset_, y_offset_; - int width_, height_; - int has_alpha_; - int duration_; - WebPMuxAnimDispose dispose_method_; - WebPMuxAnimBlend blend_method_; - int frame_num_; - int complete_; // img_components_ contains a full image. - ChunkData img_components_[2]; // 0=VP8{,L} 1=ALPH - struct Frame* next_; + int x_offset, y_offset; + int width, height; + int has_alpha; + int duration; + WebPMuxAnimDispose dispose_method; + WebPMuxAnimBlend blend_method; + int frame_num; + int complete; // img_components contains a full image. + ChunkData img_components[2]; // 0=VP8{,L} 1=ALPH + struct Frame* next; } Frame; typedef struct Chunk { - ChunkData data_; - struct Chunk* next_; + ChunkData data; + struct Chunk* next; } Chunk; struct WebPDemuxer { - MemBuffer mem_; - WebPDemuxState state_; - int is_ext_format_; - uint32_t feature_flags_; - int canvas_width_, canvas_height_; - int loop_count_; - uint32_t bgcolor_; - int num_frames_; - Frame* frames_; - Frame** frames_tail_; - Chunk* chunks_; // non-image chunks - Chunk** chunks_tail_; + MemBuffer mem; + WebPDemuxState state; + int is_ext_format; + uint32_t feature_flags; + int canvas_width, canvas_height; + int loop_count; + uint32_t bgcolor; + int num_frames; + Frame* frames; + Frame** frames_tail; + Chunk* chunks; // non-image chunks + Chunk** chunks_tail; }; typedef enum { @@ -108,10 +111,10 @@ int WebPGetDemuxVersion(void) { static int RemapMemBuffer(MemBuffer* const mem, const uint8_t* data, size_t size) { - if (size < mem->buf_size_) return 0; // can't remap to a shorter buffer! + if (size < mem->buf_size) return 0; // can't remap to a shorter buffer! - mem->buf_ = data; - mem->end_ = mem->buf_size_ = size; + mem->buf = data; + mem->end = mem->buf_size = size; return 1; } @@ -123,49 +126,49 @@ static int InitMemBuffer(MemBuffer* const mem, // Return the remaining data size available in 'mem'. static WEBP_INLINE size_t MemDataSize(const MemBuffer* const mem) { - return (mem->end_ - mem->start_); + return (mem->end - mem->start); } // Return true if 'size' exceeds the end of the RIFF chunk. static WEBP_INLINE int SizeIsInvalid(const MemBuffer* const mem, size_t size) { - return (size > mem->riff_end_ - mem->start_); + return (size > mem->riff_end - mem->start); } static WEBP_INLINE void Skip(MemBuffer* const mem, size_t size) { - mem->start_ += size; + mem->start += size; } static WEBP_INLINE void Rewind(MemBuffer* const mem, size_t size) { - mem->start_ -= size; + mem->start -= size; } static WEBP_INLINE const uint8_t* GetBuffer(MemBuffer* const mem) { - return mem->buf_ + mem->start_; + return mem->buf + mem->start; } // Read from 'mem' and skip the read bytes. static WEBP_INLINE uint8_t ReadByte(MemBuffer* const mem) { - const uint8_t byte = mem->buf_[mem->start_]; + const uint8_t byte = mem->buf[mem->start]; Skip(mem, 1); return byte; } static WEBP_INLINE int ReadLE16s(MemBuffer* const mem) { - const uint8_t* const data = mem->buf_ + mem->start_; + const uint8_t* const data = mem->buf + mem->start; const int val = GetLE16(data); Skip(mem, 2); return val; } static WEBP_INLINE int ReadLE24s(MemBuffer* const mem) { - const uint8_t* const data = mem->buf_ + mem->start_; + const uint8_t* const data = mem->buf + mem->start; const int val = GetLE24(data); Skip(mem, 3); return val; } static WEBP_INLINE uint32_t ReadLE32(MemBuffer* const mem) { - const uint8_t* const data = mem->buf_ + mem->start_; + const uint8_t* const data = mem->buf + mem->start; const uint32_t val = GetLE32(data); Skip(mem, 4); return val; @@ -175,20 +178,20 @@ static WEBP_INLINE uint32_t ReadLE32(MemBuffer* const mem) { // Secondary chunk parsing static void AddChunk(WebPDemuxer* const dmux, Chunk* const chunk) { - *dmux->chunks_tail_ = chunk; - chunk->next_ = NULL; - dmux->chunks_tail_ = &chunk->next_; + *dmux->chunks_tail = chunk; + chunk->next = NULL; + dmux->chunks_tail = &chunk->next; } // Add a frame to the end of the list, ensuring the last frame is complete. // Returns true on success, false otherwise. static int AddFrame(WebPDemuxer* const dmux, Frame* const frame) { - const Frame* const last_frame = *dmux->frames_tail_; - if (last_frame != NULL && !last_frame->complete_) return 0; + const Frame* const last_frame = *dmux->frames_tail; + if (last_frame != NULL && !last_frame->complete) return 0; - *dmux->frames_tail_ = frame; - frame->next_ = NULL; - dmux->frames_tail_ = &frame->next_; + *dmux->frames_tail = frame; + frame->next = NULL; + dmux->frames_tail = &frame->next; return 1; } @@ -196,13 +199,13 @@ static void SetFrameInfo(size_t start_offset, size_t size, int frame_num, int complete, const WebPBitstreamFeatures* const features, Frame* const frame) { - frame->img_components_[0].offset_ = start_offset; - frame->img_components_[0].size_ = size; - frame->width_ = features->width; - frame->height_ = features->height; - frame->has_alpha_ |= features->has_alpha; - frame->frame_num_ = frame_num; - frame->complete_ = complete; + frame->img_components[0].offset = start_offset; + frame->img_components[0].size = size; + frame->width = features->width; + frame->height = features->height; + frame->has_alpha |= features->has_alpha; + frame->frame_num = frame_num; + frame->complete = complete; } // Store image bearing chunks to 'frame'. 'min_size' is an optional size @@ -218,7 +221,7 @@ static ParseStatus StoreFrame(int frame_num, uint32_t min_size, if (done) return PARSE_NEED_MORE_DATA; do { - const size_t chunk_start_offset = mem->start_; + const size_t chunk_start_offset = mem->start; const uint32_t fourcc = ReadLE32(mem); const uint32_t payload_size = ReadLE32(mem); uint32_t payload_size_padded; @@ -238,10 +241,10 @@ static ParseStatus StoreFrame(int frame_num, uint32_t min_size, case MKFOURCC('A', 'L', 'P', 'H'): if (alpha_chunks == 0) { ++alpha_chunks; - frame->img_components_[1].offset_ = chunk_start_offset; - frame->img_components_[1].size_ = chunk_size; - frame->has_alpha_ = 1; - frame->frame_num_ = frame_num; + frame->img_components[1].offset = chunk_start_offset; + frame->img_components[1].size = chunk_size; + frame->has_alpha = 1; + frame->frame_num = frame_num; Skip(mem, payload_available); } else { goto Done; @@ -256,7 +259,7 @@ static ParseStatus StoreFrame(int frame_num, uint32_t min_size, // is incomplete. WebPBitstreamFeatures features; const VP8StatusCode vp8_status = - WebPGetFeatures(mem->buf_ + chunk_start_offset, chunk_size, + WebPGetFeatures(mem->buf + chunk_start_offset, chunk_size, &features); if (status == PARSE_NEED_MORE_DATA && vp8_status == VP8_STATUS_NOT_ENOUGH_DATA) { @@ -281,7 +284,7 @@ static ParseStatus StoreFrame(int frame_num, uint32_t min_size, break; } - if (mem->start_ == mem->riff_end_) { + if (mem->start == mem->riff_end) { done = 1; } else if (MemDataSize(mem) < CHUNK_HEADER_SIZE) { status = PARSE_NEED_MORE_DATA; @@ -310,42 +313,42 @@ static ParseStatus NewFrame(const MemBuffer* const mem, // 'frame_chunk_size' is the previously validated, padded chunk size. static ParseStatus ParseAnimationFrame( WebPDemuxer* const dmux, uint32_t frame_chunk_size) { - const int is_animation = !!(dmux->feature_flags_ & ANIMATION_FLAG); + const int is_animation = !!(dmux->feature_flags & ANIMATION_FLAG); const uint32_t anmf_payload_size = frame_chunk_size - ANMF_CHUNK_SIZE; int added_frame = 0; int bits; - MemBuffer* const mem = &dmux->mem_; + MemBuffer* const mem = &dmux->mem; Frame* frame; size_t start_offset; ParseStatus status = NewFrame(mem, ANMF_CHUNK_SIZE, frame_chunk_size, &frame); if (status != PARSE_OK) return status; - frame->x_offset_ = 2 * ReadLE24s(mem); - frame->y_offset_ = 2 * ReadLE24s(mem); - frame->width_ = 1 + ReadLE24s(mem); - frame->height_ = 1 + ReadLE24s(mem); - frame->duration_ = ReadLE24s(mem); + frame->x_offset = 2 * ReadLE24s(mem); + frame->y_offset = 2 * ReadLE24s(mem); + frame->width = 1 + ReadLE24s(mem); + frame->height = 1 + ReadLE24s(mem); + frame->duration = ReadLE24s(mem); bits = ReadByte(mem); - frame->dispose_method_ = + frame->dispose_method = (bits & 1) ? WEBP_MUX_DISPOSE_BACKGROUND : WEBP_MUX_DISPOSE_NONE; - frame->blend_method_ = (bits & 2) ? WEBP_MUX_NO_BLEND : WEBP_MUX_BLEND; - if (frame->width_ * (uint64_t)frame->height_ >= MAX_IMAGE_AREA) { + frame->blend_method = (bits & 2) ? WEBP_MUX_NO_BLEND : WEBP_MUX_BLEND; + if (frame->width * (uint64_t)frame->height >= MAX_IMAGE_AREA) { WebPSafeFree(frame); return PARSE_ERROR; } // Store a frame only if the animation flag is set there is some data for // this frame is available. - start_offset = mem->start_; - status = StoreFrame(dmux->num_frames_ + 1, anmf_payload_size, mem, frame); - if (status != PARSE_ERROR && mem->start_ - start_offset > anmf_payload_size) { + start_offset = mem->start; + status = StoreFrame(dmux->num_frames + 1, anmf_payload_size, mem, frame); + if (status != PARSE_ERROR && mem->start - start_offset > anmf_payload_size) { status = PARSE_ERROR; } - if (status != PARSE_ERROR && is_animation && frame->frame_num_ > 0) { + if (status != PARSE_ERROR && is_animation && frame->frame_num > 0) { added_frame = AddFrame(dmux, frame); if (added_frame) { - ++dmux->num_frames_; + ++dmux->num_frames; } else { status = PARSE_ERROR; } @@ -364,8 +367,8 @@ static int StoreChunk(WebPDemuxer* const dmux, Chunk* const chunk = (Chunk*)WebPSafeCalloc(1ULL, sizeof(*chunk)); if (chunk == NULL) return 0; - chunk->data_.offset_ = start_offset; - chunk->data_.size_ = size; + chunk->data.offset = start_offset; + chunk->data.size = size; AddChunk(dmux, chunk); return 1; } @@ -389,9 +392,9 @@ static ParseStatus ReadHeader(MemBuffer* const mem) { if (riff_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR; // There's no point in reading past the end of the RIFF chunk - mem->riff_end_ = riff_size + CHUNK_HEADER_SIZE; - if (mem->buf_size_ > mem->riff_end_) { - mem->buf_size_ = mem->end_ = mem->riff_end_; + mem->riff_end = riff_size + CHUNK_HEADER_SIZE; + if (mem->buf_size > mem->riff_end) { + mem->buf_size = mem->end = mem->riff_end; } Skip(mem, RIFF_HEADER_SIZE); @@ -400,12 +403,12 @@ static ParseStatus ReadHeader(MemBuffer* const mem) { static ParseStatus ParseSingleImage(WebPDemuxer* const dmux) { const size_t min_size = CHUNK_HEADER_SIZE; - MemBuffer* const mem = &dmux->mem_; + MemBuffer* const mem = &dmux->mem; Frame* frame; ParseStatus status; int image_added = 0; - if (dmux->frames_ != NULL) return PARSE_ERROR; + if (dmux->frames != NULL) return PARSE_ERROR; if (SizeIsInvalid(mem, min_size)) return PARSE_ERROR; if (MemDataSize(mem) < min_size) return PARSE_NEED_MORE_DATA; @@ -414,29 +417,29 @@ static ParseStatus ParseSingleImage(WebPDemuxer* const dmux) { // For the single image case we allow parsing of a partial frame, so no // minimum size is imposed here. - status = StoreFrame(1, 0, &dmux->mem_, frame); + status = StoreFrame(1, 0, &dmux->mem, frame); if (status != PARSE_ERROR) { - const int has_alpha = !!(dmux->feature_flags_ & ALPHA_FLAG); + const int has_alpha = !!(dmux->feature_flags & ALPHA_FLAG); // Clear any alpha when the alpha flag is missing. - if (!has_alpha && frame->img_components_[1].size_ > 0) { - frame->img_components_[1].offset_ = 0; - frame->img_components_[1].size_ = 0; - frame->has_alpha_ = 0; + if (!has_alpha && frame->img_components[1].size > 0) { + frame->img_components[1].offset = 0; + frame->img_components[1].size = 0; + frame->has_alpha = 0; } // Use the frame width/height as the canvas values for non-vp8x files. // Also, set ALPHA_FLAG if this is a lossless image with alpha. - if (!dmux->is_ext_format_ && frame->width_ > 0 && frame->height_ > 0) { - dmux->state_ = WEBP_DEMUX_PARSED_HEADER; - dmux->canvas_width_ = frame->width_; - dmux->canvas_height_ = frame->height_; - dmux->feature_flags_ |= frame->has_alpha_ ? ALPHA_FLAG : 0; + if (!dmux->is_ext_format && frame->width > 0 && frame->height > 0) { + dmux->state = WEBP_DEMUX_PARSED_HEADER; + dmux->canvas_width = frame->width; + dmux->canvas_height = frame->height; + dmux->feature_flags |= frame->has_alpha ? ALPHA_FLAG : 0; } if (!AddFrame(dmux, frame)) { status = PARSE_ERROR; // last frame was left incomplete } else { image_added = 1; - dmux->num_frames_ = 1; + dmux->num_frames = 1; } } @@ -445,14 +448,14 @@ static ParseStatus ParseSingleImage(WebPDemuxer* const dmux) { } static ParseStatus ParseVP8XChunks(WebPDemuxer* const dmux) { - const int is_animation = !!(dmux->feature_flags_ & ANIMATION_FLAG); - MemBuffer* const mem = &dmux->mem_; + const int is_animation = !!(dmux->feature_flags & ANIMATION_FLAG); + MemBuffer* const mem = &dmux->mem; int anim_chunks = 0; ParseStatus status = PARSE_OK; do { int store_chunk = 1; - const size_t chunk_start_offset = mem->start_; + const size_t chunk_start_offset = mem->start; const uint32_t fourcc = ReadLE32(mem); const uint32_t chunk_size = ReadLE32(mem); uint32_t chunk_size_padded; @@ -483,8 +486,8 @@ static ParseStatus ParseVP8XChunks(WebPDemuxer* const dmux) { status = PARSE_NEED_MORE_DATA; } else if (anim_chunks == 0) { ++anim_chunks; - dmux->bgcolor_ = ReadLE32(mem); - dmux->loop_count_ = ReadLE16s(mem); + dmux->bgcolor = ReadLE32(mem); + dmux->loop_count = ReadLE16s(mem); Skip(mem, chunk_size_padded - ANIM_CHUNK_SIZE); } else { store_chunk = 0; @@ -498,15 +501,15 @@ static ParseStatus ParseVP8XChunks(WebPDemuxer* const dmux) { break; } case MKFOURCC('I', 'C', 'C', 'P'): { - store_chunk = !!(dmux->feature_flags_ & ICCP_FLAG); + store_chunk = !!(dmux->feature_flags & ICCP_FLAG); goto Skip; } case MKFOURCC('E', 'X', 'I', 'F'): { - store_chunk = !!(dmux->feature_flags_ & EXIF_FLAG); + store_chunk = !!(dmux->feature_flags & EXIF_FLAG); goto Skip; } case MKFOURCC('X', 'M', 'P', ' '): { - store_chunk = !!(dmux->feature_flags_ & XMP_FLAG); + store_chunk = !!(dmux->feature_flags & XMP_FLAG); goto Skip; } Skip: @@ -527,7 +530,7 @@ static ParseStatus ParseVP8XChunks(WebPDemuxer* const dmux) { } } - if (mem->start_ == mem->riff_end_) { + if (mem->start == mem->riff_end) { break; } else if (MemDataSize(mem) < CHUNK_HEADER_SIZE) { status = PARSE_NEED_MORE_DATA; @@ -538,12 +541,12 @@ static ParseStatus ParseVP8XChunks(WebPDemuxer* const dmux) { } static ParseStatus ParseVP8X(WebPDemuxer* const dmux) { - MemBuffer* const mem = &dmux->mem_; + MemBuffer* const mem = &dmux->mem; uint32_t vp8x_size; if (MemDataSize(mem) < CHUNK_HEADER_SIZE) return PARSE_NEED_MORE_DATA; - dmux->is_ext_format_ = 1; + dmux->is_ext_format = 1; Skip(mem, TAG_SIZE); // VP8X vp8x_size = ReadLE32(mem); if (vp8x_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR; @@ -552,15 +555,15 @@ static ParseStatus ParseVP8X(WebPDemuxer* const dmux) { if (SizeIsInvalid(mem, vp8x_size)) return PARSE_ERROR; if (MemDataSize(mem) < vp8x_size) return PARSE_NEED_MORE_DATA; - dmux->feature_flags_ = ReadByte(mem); + dmux->feature_flags = ReadByte(mem); Skip(mem, 3); // Reserved. - dmux->canvas_width_ = 1 + ReadLE24s(mem); - dmux->canvas_height_ = 1 + ReadLE24s(mem); - if (dmux->canvas_width_ * (uint64_t)dmux->canvas_height_ >= MAX_IMAGE_AREA) { + dmux->canvas_width = 1 + ReadLE24s(mem); + dmux->canvas_height = 1 + ReadLE24s(mem); + if (dmux->canvas_width * (uint64_t)dmux->canvas_height >= MAX_IMAGE_AREA) { return PARSE_ERROR; // image final dimension is too large } Skip(mem, vp8x_size - VP8X_CHUNK_SIZE); // skip any trailing data. - dmux->state_ = WEBP_DEMUX_PARSED_HEADER; + dmux->state = WEBP_DEMUX_PARSED_HEADER; if (SizeIsInvalid(mem, CHUNK_HEADER_SIZE)) return PARSE_ERROR; if (MemDataSize(mem) < CHUNK_HEADER_SIZE) return PARSE_NEED_MORE_DATA; @@ -572,13 +575,13 @@ static ParseStatus ParseVP8X(WebPDemuxer* const dmux) { // Format validation static int IsValidSimpleFormat(const WebPDemuxer* const dmux) { - const Frame* const frame = dmux->frames_; - if (dmux->state_ == WEBP_DEMUX_PARSING_HEADER) return 1; + const Frame* const frame = dmux->frames; + if (dmux->state == WEBP_DEMUX_PARSING_HEADER) return 1; - if (dmux->canvas_width_ <= 0 || dmux->canvas_height_ <= 0) return 0; - if (dmux->state_ == WEBP_DEMUX_DONE && frame == NULL) return 0; + if (dmux->canvas_width <= 0 || dmux->canvas_height <= 0) return 0; + if (dmux->state == WEBP_DEMUX_DONE && frame == NULL) return 0; - if (frame->width_ <= 0 || frame->height_ <= 0) return 0; + if (frame->width <= 0 || frame->height <= 0) return 0; return 1; } @@ -587,65 +590,65 @@ static int IsValidSimpleFormat(const WebPDemuxer* const dmux) { static int CheckFrameBounds(const Frame* const frame, int exact, int canvas_width, int canvas_height) { if (exact) { - if (frame->x_offset_ != 0 || frame->y_offset_ != 0) { + if (frame->x_offset != 0 || frame->y_offset != 0) { return 0; } - if (frame->width_ != canvas_width || frame->height_ != canvas_height) { + if (frame->width != canvas_width || frame->height != canvas_height) { return 0; } } else { - if (frame->x_offset_ < 0 || frame->y_offset_ < 0) return 0; - if (frame->width_ + frame->x_offset_ > canvas_width) return 0; - if (frame->height_ + frame->y_offset_ > canvas_height) return 0; + if (frame->x_offset < 0 || frame->y_offset < 0) return 0; + if (frame->width + frame->x_offset > canvas_width) return 0; + if (frame->height + frame->y_offset > canvas_height) return 0; } return 1; } static int IsValidExtendedFormat(const WebPDemuxer* const dmux) { - const int is_animation = !!(dmux->feature_flags_ & ANIMATION_FLAG); - const Frame* f = dmux->frames_; + const int is_animation = !!(dmux->feature_flags & ANIMATION_FLAG); + const Frame* f = dmux->frames; - if (dmux->state_ == WEBP_DEMUX_PARSING_HEADER) return 1; + if (dmux->state == WEBP_DEMUX_PARSING_HEADER) return 1; - if (dmux->canvas_width_ <= 0 || dmux->canvas_height_ <= 0) return 0; - if (dmux->loop_count_ < 0) return 0; - if (dmux->state_ == WEBP_DEMUX_DONE && dmux->frames_ == NULL) return 0; - if (dmux->feature_flags_ & ~ALL_VALID_FLAGS) return 0; // invalid bitstream + if (dmux->canvas_width <= 0 || dmux->canvas_height <= 0) return 0; + if (dmux->loop_count < 0) return 0; + if (dmux->state == WEBP_DEMUX_DONE && dmux->frames == NULL) return 0; + if (dmux->feature_flags & ~ALL_VALID_FLAGS) return 0; // invalid bitstream while (f != NULL) { - const int cur_frame_set = f->frame_num_; + const int cur_frame_set = f->frame_num; // Check frame properties. - for (; f != NULL && f->frame_num_ == cur_frame_set; f = f->next_) { - const ChunkData* const image = f->img_components_; - const ChunkData* const alpha = f->img_components_ + 1; + for (; f != NULL && f->frame_num == cur_frame_set; f = f->next) { + const ChunkData* const image = f->img_components; + const ChunkData* const alpha = f->img_components + 1; - if (!is_animation && f->frame_num_ > 1) return 0; + if (!is_animation && f->frame_num > 1) return 0; - if (f->complete_) { - if (alpha->size_ == 0 && image->size_ == 0) return 0; + if (f->complete) { + if (alpha->size == 0 && image->size == 0) return 0; // Ensure alpha precedes image bitstream. - if (alpha->size_ > 0 && alpha->offset_ > image->offset_) { + if (alpha->size > 0 && alpha->offset > image->offset) { return 0; } - if (f->width_ <= 0 || f->height_ <= 0) return 0; + if (f->width <= 0 || f->height <= 0) return 0; } else { // There shouldn't be a partial frame in a complete file. - if (dmux->state_ == WEBP_DEMUX_DONE) return 0; + if (dmux->state == WEBP_DEMUX_DONE) return 0; // Ensure alpha precedes image bitstream. - if (alpha->size_ > 0 && image->size_ > 0 && - alpha->offset_ > image->offset_) { + if (alpha->size > 0 && image->size > 0 && + alpha->offset > image->offset) { return 0; } // There shouldn't be any frames after an incomplete one. - if (f->next_ != NULL) return 0; + if (f->next != NULL) return 0; } - if (f->width_ > 0 && f->height_ > 0 && + if (f->width > 0 && f->height > 0 && !CheckFrameBounds(f, !is_animation, - dmux->canvas_width_, dmux->canvas_height_)) { + dmux->canvas_width, dmux->canvas_height)) { return 0; } } @@ -657,21 +660,21 @@ static int IsValidExtendedFormat(const WebPDemuxer* const dmux) { // WebPDemuxer object static void InitDemux(WebPDemuxer* const dmux, const MemBuffer* const mem) { - dmux->state_ = WEBP_DEMUX_PARSING_HEADER; - dmux->loop_count_ = 1; - dmux->bgcolor_ = 0xFFFFFFFF; // White background by default. - dmux->canvas_width_ = -1; - dmux->canvas_height_ = -1; - dmux->frames_tail_ = &dmux->frames_; - dmux->chunks_tail_ = &dmux->chunks_; - dmux->mem_ = *mem; + dmux->state = WEBP_DEMUX_PARSING_HEADER; + dmux->loop_count = 1; + dmux->bgcolor = 0xFFFFFFFF; // White background by default. + dmux->canvas_width = -1; + dmux->canvas_height = -1; + dmux->frames_tail = &dmux->frames; + dmux->chunks_tail = &dmux->chunks; + dmux->mem = *mem; } static ParseStatus CreateRawImageDemuxer(MemBuffer* const mem, WebPDemuxer** demuxer) { WebPBitstreamFeatures features; const VP8StatusCode status = - WebPGetFeatures(mem->buf_, mem->buf_size_, &features); + WebPGetFeatures(mem->buf, mem->buf_size, &features); *demuxer = NULL; if (status != VP8_STATUS_OK) { return (status == VP8_STATUS_NOT_ENOUGH_DATA) ? PARSE_NEED_MORE_DATA @@ -683,14 +686,14 @@ static ParseStatus CreateRawImageDemuxer(MemBuffer* const mem, Frame* const frame = (Frame*)WebPSafeCalloc(1ULL, sizeof(*frame)); if (dmux == NULL || frame == NULL) goto Error; InitDemux(dmux, mem); - SetFrameInfo(0, mem->buf_size_, 1 /*frame_num*/, 1 /*complete*/, &features, + SetFrameInfo(0, mem->buf_size, 1 /*frame_num*/, 1 /*complete*/, &features, frame); if (!AddFrame(dmux, frame)) goto Error; - dmux->state_ = WEBP_DEMUX_DONE; - dmux->canvas_width_ = frame->width_; - dmux->canvas_height_ = frame->height_; - dmux->feature_flags_ |= frame->has_alpha_ ? ALPHA_FLAG : 0; - dmux->num_frames_ = 1; + dmux->state = WEBP_DEMUX_DONE; + dmux->canvas_width = frame->width; + dmux->canvas_height = frame->height; + dmux->feature_flags |= frame->has_alpha ? ALPHA_FLAG : 0; + dmux->num_frames = 1; assert(IsValidSimpleFormat(dmux)); *demuxer = dmux; return PARSE_OK; @@ -734,7 +737,7 @@ WebPDemuxer* WebPDemuxInternal(const WebPData* data, int allow_partial, return NULL; } - partial = (mem.buf_size_ < mem.riff_end_); + partial = (mem.buf_size < mem.riff_end); if (!allow_partial && partial) return NULL; dmux = (WebPDemuxer*)WebPSafeCalloc(1ULL, sizeof(*dmux)); @@ -743,16 +746,16 @@ WebPDemuxer* WebPDemuxInternal(const WebPData* data, int allow_partial, status = PARSE_ERROR; for (parser = kMasterChunks; parser->parse != NULL; ++parser) { - if (!memcmp(parser->id, GetBuffer(&dmux->mem_), TAG_SIZE)) { + if (!memcmp(parser->id, GetBuffer(&dmux->mem), TAG_SIZE)) { status = parser->parse(dmux); - if (status == PARSE_OK) dmux->state_ = WEBP_DEMUX_DONE; + if (status == PARSE_OK) dmux->state = WEBP_DEMUX_DONE; if (status == PARSE_NEED_MORE_DATA && !partial) status = PARSE_ERROR; if (status != PARSE_ERROR && !parser->valid(dmux)) status = PARSE_ERROR; - if (status == PARSE_ERROR) dmux->state_ = WEBP_DEMUX_PARSE_ERROR; + if (status == PARSE_ERROR) dmux->state = WEBP_DEMUX_PARSE_ERROR; break; } } - if (state != NULL) *state = dmux->state_; + if (state != NULL) *state = dmux->state; if (status == PARSE_ERROR) { WebPDemuxDelete(dmux); @@ -766,14 +769,14 @@ void WebPDemuxDelete(WebPDemuxer* dmux) { Frame* f; if (dmux == NULL) return; - for (f = dmux->frames_; f != NULL;) { + for (f = dmux->frames; f != NULL;) { Frame* const cur_frame = f; - f = f->next_; + f = f->next; WebPSafeFree(cur_frame); } - for (c = dmux->chunks_; c != NULL;) { + for (c = dmux->chunks; c != NULL;) { Chunk* const cur_chunk = c; - c = c->next_; + c = c->next; WebPSafeFree(cur_chunk); } WebPSafeFree(dmux); @@ -785,12 +788,12 @@ uint32_t WebPDemuxGetI(const WebPDemuxer* dmux, WebPFormatFeature feature) { if (dmux == NULL) return 0; switch (feature) { - case WEBP_FF_FORMAT_FLAGS: return dmux->feature_flags_; - case WEBP_FF_CANVAS_WIDTH: return (uint32_t)dmux->canvas_width_; - case WEBP_FF_CANVAS_HEIGHT: return (uint32_t)dmux->canvas_height_; - case WEBP_FF_LOOP_COUNT: return (uint32_t)dmux->loop_count_; - case WEBP_FF_BACKGROUND_COLOR: return dmux->bgcolor_; - case WEBP_FF_FRAME_COUNT: return (uint32_t)dmux->num_frames_; + case WEBP_FF_FORMAT_FLAGS: return dmux->feature_flags; + case WEBP_FF_CANVAS_WIDTH: return (uint32_t)dmux->canvas_width; + case WEBP_FF_CANVAS_HEIGHT: return (uint32_t)dmux->canvas_height; + case WEBP_FF_LOOP_COUNT: return (uint32_t)dmux->loop_count; + case WEBP_FF_BACKGROUND_COLOR: return dmux->bgcolor; + case WEBP_FF_FRAME_COUNT: return (uint32_t)dmux->num_frames; } return 0; } @@ -800,8 +803,8 @@ uint32_t WebPDemuxGetI(const WebPDemuxer* dmux, WebPFormatFeature feature) { static const Frame* GetFrame(const WebPDemuxer* const dmux, int frame_num) { const Frame* f; - for (f = dmux->frames_; f != NULL; f = f->next_) { - if (frame_num == f->frame_num_) break; + for (f = dmux->frames; f != NULL; f = f->next) { + if (frame_num == f->frame_num) break; } return f; } @@ -811,19 +814,19 @@ static const uint8_t* GetFramePayload(const uint8_t* const mem_buf, size_t* const data_size) { *data_size = 0; if (frame != NULL) { - const ChunkData* const image = frame->img_components_; - const ChunkData* const alpha = frame->img_components_ + 1; - size_t start_offset = image->offset_; - *data_size = image->size_; + const ChunkData* const image = frame->img_components; + const ChunkData* const alpha = frame->img_components + 1; + size_t start_offset = image->offset; + *data_size = image->size; // if alpha exists it precedes image, update the size allowing for // intervening chunks. - if (alpha->size_ > 0) { - const size_t inter_size = (image->offset_ > 0) - ? image->offset_ - (alpha->offset_ + alpha->size_) + if (alpha->size > 0) { + const size_t inter_size = (image->offset > 0) + ? image->offset - (alpha->offset + alpha->size) : 0; - start_offset = alpha->offset_; - *data_size += alpha->size_ + inter_size; + start_offset = alpha->offset; + *data_size += alpha->size + inter_size; } return mem_buf + start_offset; } @@ -834,23 +837,23 @@ static const uint8_t* GetFramePayload(const uint8_t* const mem_buf, static int SynthesizeFrame(const WebPDemuxer* const dmux, const Frame* const frame, WebPIterator* const iter) { - const uint8_t* const mem_buf = dmux->mem_.buf_; + const uint8_t* const mem_buf = dmux->mem.buf; size_t payload_size = 0; const uint8_t* const payload = GetFramePayload(mem_buf, frame, &payload_size); if (payload == NULL) return 0; assert(frame != NULL); - iter->frame_num = frame->frame_num_; - iter->num_frames = dmux->num_frames_; - iter->x_offset = frame->x_offset_; - iter->y_offset = frame->y_offset_; - iter->width = frame->width_; - iter->height = frame->height_; - iter->has_alpha = frame->has_alpha_; - iter->duration = frame->duration_; - iter->dispose_method = frame->dispose_method_; - iter->blend_method = frame->blend_method_; - iter->complete = frame->complete_; + iter->frame_num = frame->frame_num; + iter->num_frames = dmux->num_frames; + iter->x_offset = frame->x_offset; + iter->y_offset = frame->y_offset; + iter->width = frame->width; + iter->height = frame->height; + iter->has_alpha = frame->has_alpha; + iter->duration = frame->duration; + iter->dispose_method = frame->dispose_method; + iter->blend_method = frame->blend_method; + iter->complete = frame->complete; iter->fragment.bytes = payload; iter->fragment.size = payload_size; return 1; @@ -860,8 +863,8 @@ static int SetFrame(int frame_num, WebPIterator* const iter) { const Frame* frame; const WebPDemuxer* const dmux = (WebPDemuxer*)iter->private_; if (dmux == NULL || frame_num < 0) return 0; - if (frame_num > dmux->num_frames_) return 0; - if (frame_num == 0) frame_num = dmux->num_frames_; + if (frame_num > dmux->num_frames) return 0; + if (frame_num == 0) frame_num = dmux->num_frames; frame = GetFrame(dmux, frame_num); if (frame == NULL) return 0; @@ -896,11 +899,11 @@ void WebPDemuxReleaseIterator(WebPIterator* iter) { // Chunk iteration static int ChunkCount(const WebPDemuxer* const dmux, const char fourcc[4]) { - const uint8_t* const mem_buf = dmux->mem_.buf_; + const uint8_t* const mem_buf = dmux->mem.buf; const Chunk* c; int count = 0; - for (c = dmux->chunks_; c != NULL; c = c->next_) { - const uint8_t* const header = mem_buf + c->data_.offset_; + for (c = dmux->chunks; c != NULL; c = c->next) { + const uint8_t* const header = mem_buf + c->data.offset; if (!memcmp(header, fourcc, TAG_SIZE)) ++count; } return count; @@ -908,11 +911,11 @@ static int ChunkCount(const WebPDemuxer* const dmux, const char fourcc[4]) { static const Chunk* GetChunk(const WebPDemuxer* const dmux, const char fourcc[4], int chunk_num) { - const uint8_t* const mem_buf = dmux->mem_.buf_; + const uint8_t* const mem_buf = dmux->mem.buf; const Chunk* c; int count = 0; - for (c = dmux->chunks_; c != NULL; c = c->next_) { - const uint8_t* const header = mem_buf + c->data_.offset_; + for (c = dmux->chunks; c != NULL; c = c->next) { + const uint8_t* const header = mem_buf + c->data.offset; if (!memcmp(header, fourcc, TAG_SIZE)) ++count; if (count == chunk_num) break; } @@ -930,10 +933,10 @@ static int SetChunk(const char fourcc[4], int chunk_num, if (chunk_num == 0) chunk_num = count; if (chunk_num <= count) { - const uint8_t* const mem_buf = dmux->mem_.buf_; + const uint8_t* const mem_buf = dmux->mem.buf; const Chunk* const chunk = GetChunk(dmux, fourcc, chunk_num); - iter->chunk.bytes = mem_buf + chunk->data_.offset_ + CHUNK_HEADER_SIZE; - iter->chunk.size = chunk->data_.size_ - CHUNK_HEADER_SIZE; + iter->chunk.bytes = mem_buf + chunk->data.offset + CHUNK_HEADER_SIZE; + iter->chunk.size = chunk->data.size - CHUNK_HEADER_SIZE; iter->num_chunks = count; iter->chunk_num = chunk_num; return 1; @@ -972,4 +975,3 @@ int WebPDemuxPrevChunk(WebPChunkIterator* iter) { void WebPDemuxReleaseChunkIterator(WebPChunkIterator* iter) { (void)iter; } - diff --git a/libwebp/src/demux/libwebpdemux.pc.in b/libwebp/src/demux/libwebpdemux.pc.in deleted file mode 100644 index 4da2e40a..00000000 --- a/libwebp/src/demux/libwebpdemux.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: libwebpdemux -Description: Library for parsing the WebP graphics format container -Version: @PACKAGE_VERSION@ -Requires.private: libwebp >= 0.2.0 -Cflags: -I${includedir} -Libs: -L${libdir} -l@webp_libname_prefix@webpdemux diff --git a/libwebp/src/demux/libwebpdemux.rc b/libwebp/src/demux/libwebpdemux.rc deleted file mode 100644 index b0c9413e..00000000 --- a/libwebp/src/demux/libwebpdemux.rc +++ /dev/null @@ -1,41 +0,0 @@ -#define APSTUDIO_READONLY_SYMBOLS -#include "winres.h" -#undef APSTUDIO_READONLY_SYMBOLS - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US - -VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,0,3,2 - PRODUCTVERSION 1,0,3,2 - FILEFLAGSMASK 0x3fL -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x40004L - FILETYPE 0x2L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "CompanyName", "Google, Inc." - VALUE "FileDescription", "libwebpdemux DLL" - VALUE "FileVersion", "1.3.2" - VALUE "InternalName", "libwebpdemux.dll" - VALUE "LegalCopyright", "Copyright (C) 2023" - VALUE "OriginalFilename", "libwebpdemux.dll" - VALUE "ProductName", "WebP Image Demuxer" - VALUE "ProductVersion", "1.3.2" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - -#endif // English (United States) resources diff --git a/libwebp/src/dsp/Makefile.am b/libwebp/src/dsp/Makefile.am deleted file mode 100644 index 7db4ef0f..00000000 --- a/libwebp/src/dsp/Makefile.am +++ /dev/null @@ -1,187 +0,0 @@ -AM_CPPFLAGS += -I$(top_builddir) -I$(top_srcdir) -noinst_LTLIBRARIES = -noinst_LTLIBRARIES += libwebpdsp.la -noinst_LTLIBRARIES += libwebpdsp_sse2.la -noinst_LTLIBRARIES += libwebpdspdecode_sse2.la -noinst_LTLIBRARIES += libwebpdsp_sse41.la -noinst_LTLIBRARIES += libwebpdspdecode_sse41.la -noinst_LTLIBRARIES += libwebpdsp_neon.la -noinst_LTLIBRARIES += libwebpdspdecode_neon.la -noinst_LTLIBRARIES += libwebpdsp_msa.la -noinst_LTLIBRARIES += libwebpdspdecode_msa.la -noinst_LTLIBRARIES += libwebpdsp_mips32.la -noinst_LTLIBRARIES += libwebpdspdecode_mips32.la -noinst_LTLIBRARIES += libwebpdsp_mips_dsp_r2.la -noinst_LTLIBRARIES += libwebpdspdecode_mips_dsp_r2.la - -if BUILD_LIBWEBPDECODER - noinst_LTLIBRARIES += libwebpdspdecode.la -endif - -common_HEADERS = ../webp/types.h -commondir = $(includedir)/webp - -COMMON_SOURCES = -COMMON_SOURCES += alpha_processing.c -COMMON_SOURCES += cpu.c -COMMON_SOURCES += cpu.h -COMMON_SOURCES += dec.c -COMMON_SOURCES += dec_clip_tables.c -COMMON_SOURCES += dsp.h -COMMON_SOURCES += filters.c -COMMON_SOURCES += lossless.c -COMMON_SOURCES += lossless.h -COMMON_SOURCES += lossless_common.h -COMMON_SOURCES += rescaler.c -COMMON_SOURCES += upsampling.c -COMMON_SOURCES += yuv.c -COMMON_SOURCES += yuv.h - -ENC_SOURCES = -ENC_SOURCES += cost.c -ENC_SOURCES += enc.c -ENC_SOURCES += lossless_enc.c -ENC_SOURCES += quant.h -ENC_SOURCES += ssim.c - -libwebpdspdecode_sse41_la_SOURCES = -libwebpdspdecode_sse41_la_SOURCES += alpha_processing_sse41.c -libwebpdspdecode_sse41_la_SOURCES += dec_sse41.c -libwebpdspdecode_sse41_la_SOURCES += lossless_sse41.c -libwebpdspdecode_sse41_la_SOURCES += upsampling_sse41.c -libwebpdspdecode_sse41_la_SOURCES += yuv_sse41.c -libwebpdspdecode_sse41_la_CPPFLAGS = $(libwebpdsp_la_CPPFLAGS) -libwebpdspdecode_sse41_la_CFLAGS = $(AM_CFLAGS) $(SSE41_FLAGS) - -libwebpdspdecode_sse2_la_SOURCES = -libwebpdspdecode_sse2_la_SOURCES += alpha_processing_sse2.c -libwebpdspdecode_sse2_la_SOURCES += common_sse2.h -libwebpdspdecode_sse2_la_SOURCES += dec_sse2.c -libwebpdspdecode_sse2_la_SOURCES += filters_sse2.c -libwebpdspdecode_sse2_la_SOURCES += lossless_sse2.c -libwebpdspdecode_sse2_la_SOURCES += rescaler_sse2.c -libwebpdspdecode_sse2_la_SOURCES += upsampling_sse2.c -libwebpdspdecode_sse2_la_SOURCES += yuv_sse2.c -libwebpdspdecode_sse2_la_CPPFLAGS = $(libwebpdsp_sse2_la_CPPFLAGS) -libwebpdspdecode_sse2_la_CFLAGS = $(libwebpdsp_sse2_la_CFLAGS) - -libwebpdspdecode_neon_la_SOURCES = -libwebpdspdecode_neon_la_SOURCES += alpha_processing_neon.c -libwebpdspdecode_neon_la_SOURCES += dec_neon.c -libwebpdspdecode_neon_la_SOURCES += filters_neon.c -libwebpdspdecode_neon_la_SOURCES += lossless_neon.c -libwebpdspdecode_neon_la_SOURCES += neon.h -libwebpdspdecode_neon_la_SOURCES += rescaler_neon.c -libwebpdspdecode_neon_la_SOURCES += upsampling_neon.c -libwebpdspdecode_neon_la_SOURCES += yuv_neon.c -libwebpdspdecode_neon_la_CPPFLAGS = $(libwebpdsp_neon_la_CPPFLAGS) -libwebpdspdecode_neon_la_CFLAGS = $(libwebpdsp_neon_la_CFLAGS) - -libwebpdspdecode_msa_la_SOURCES = -libwebpdspdecode_msa_la_SOURCES += dec_msa.c -libwebpdspdecode_msa_la_SOURCES += filters_msa.c -libwebpdspdecode_msa_la_SOURCES += lossless_msa.c -libwebpdspdecode_msa_la_SOURCES += msa_macro.h -libwebpdspdecode_msa_la_SOURCES += rescaler_msa.c -libwebpdspdecode_msa_la_SOURCES += upsampling_msa.c -libwebpdspdecode_msa_la_CPPFLAGS = $(libwebpdsp_msa_la_CPPFLAGS) -libwebpdspdecode_msa_la_CFLAGS = $(libwebpdsp_msa_la_CFLAGS) - -libwebpdspdecode_mips32_la_SOURCES = -libwebpdspdecode_mips32_la_SOURCES += dec_mips32.c -libwebpdspdecode_mips32_la_SOURCES += mips_macro.h -libwebpdspdecode_mips32_la_SOURCES += rescaler_mips32.c -libwebpdspdecode_mips32_la_SOURCES += yuv_mips32.c -libwebpdspdecode_mips32_la_CPPFLAGS = $(libwebpdsp_mips32_la_CPPFLAGS) -libwebpdspdecode_mips32_la_CFLAGS = $(libwebpdsp_mips32_la_CFLAGS) - -libwebpdspdecode_mips_dsp_r2_la_SOURCES = -libwebpdspdecode_mips_dsp_r2_la_SOURCES += alpha_processing_mips_dsp_r2.c -libwebpdspdecode_mips_dsp_r2_la_SOURCES += dec_mips_dsp_r2.c -libwebpdspdecode_mips_dsp_r2_la_SOURCES += filters_mips_dsp_r2.c -libwebpdspdecode_mips_dsp_r2_la_SOURCES += lossless_mips_dsp_r2.c -libwebpdspdecode_mips_dsp_r2_la_SOURCES += mips_macro.h -libwebpdspdecode_mips_dsp_r2_la_SOURCES += rescaler_mips_dsp_r2.c -libwebpdspdecode_mips_dsp_r2_la_SOURCES += upsampling_mips_dsp_r2.c -libwebpdspdecode_mips_dsp_r2_la_SOURCES += yuv_mips_dsp_r2.c -libwebpdspdecode_mips_dsp_r2_la_CPPFLAGS = $(libwebpdsp_mips_dsp_r2_la_CPPFLAGS) -libwebpdspdecode_mips_dsp_r2_la_CFLAGS = $(libwebpdsp_mips_dsp_r2_la_CFLAGS) - -libwebpdsp_sse2_la_SOURCES = -libwebpdsp_sse2_la_SOURCES += cost_sse2.c -libwebpdsp_sse2_la_SOURCES += enc_sse2.c -libwebpdsp_sse2_la_SOURCES += lossless_enc_sse2.c -libwebpdsp_sse2_la_SOURCES += ssim_sse2.c -libwebpdsp_sse2_la_CPPFLAGS = $(libwebpdsp_la_CPPFLAGS) -libwebpdsp_sse2_la_CFLAGS = $(AM_CFLAGS) $(SSE2_FLAGS) -libwebpdsp_sse2_la_LIBADD = libwebpdspdecode_sse2.la - -libwebpdsp_sse41_la_SOURCES = -libwebpdsp_sse41_la_SOURCES += enc_sse41.c -libwebpdsp_sse41_la_SOURCES += lossless_enc_sse41.c -libwebpdsp_sse41_la_CPPFLAGS = $(libwebpdsp_la_CPPFLAGS) -libwebpdsp_sse41_la_CFLAGS = $(AM_CFLAGS) $(SSE41_FLAGS) -libwebpdsp_sse41_la_LIBADD = libwebpdspdecode_sse41.la - -libwebpdsp_neon_la_SOURCES = -libwebpdsp_neon_la_SOURCES += cost_neon.c -libwebpdsp_neon_la_SOURCES += enc_neon.c -libwebpdsp_neon_la_SOURCES += lossless_enc_neon.c -libwebpdsp_neon_la_CPPFLAGS = $(libwebpdsp_la_CPPFLAGS) -libwebpdsp_neon_la_CFLAGS = $(AM_CFLAGS) $(NEON_FLAGS) -libwebpdsp_neon_la_LIBADD = libwebpdspdecode_neon.la - -libwebpdsp_msa_la_SOURCES = -libwebpdsp_msa_la_SOURCES += enc_msa.c -libwebpdsp_msa_la_SOURCES += lossless_enc_msa.c -libwebpdsp_msa_la_CPPFLAGS = $(libwebpdsp_la_CPPFLAGS) -libwebpdsp_msa_la_CFLAGS = $(AM_CFLAGS) -libwebpdsp_msa_la_LIBADD = libwebpdspdecode_msa.la - -libwebpdsp_mips32_la_SOURCES = -libwebpdsp_mips32_la_SOURCES += cost_mips32.c -libwebpdsp_mips32_la_SOURCES += enc_mips32.c -libwebpdsp_mips32_la_SOURCES += lossless_enc_mips32.c -libwebpdsp_mips32_la_CPPFLAGS = $(libwebpdsp_la_CPPFLAGS) -libwebpdsp_mips32_la_CFLAGS = $(AM_CFLAGS) -libwebpdsp_mips32_la_LIBADD = libwebpdspdecode_mips32.la - -libwebpdsp_mips_dsp_r2_la_SOURCES = -libwebpdsp_mips_dsp_r2_la_SOURCES += cost_mips_dsp_r2.c -libwebpdsp_mips_dsp_r2_la_SOURCES += enc_mips_dsp_r2.c -libwebpdsp_mips_dsp_r2_la_SOURCES += lossless_enc_mips_dsp_r2.c -libwebpdsp_mips_dsp_r2_la_CPPFLAGS = $(libwebpdsp_la_CPPFLAGS) -libwebpdsp_mips_dsp_r2_la_CFLAGS = $(AM_CFLAGS) -libwebpdsp_mips_dsp_r2_la_LIBADD = libwebpdspdecode_mips_dsp_r2.la - -libwebpdsp_la_SOURCES = $(COMMON_SOURCES) $(ENC_SOURCES) - -noinst_HEADERS = -noinst_HEADERS += ../dec/vp8_dec.h -noinst_HEADERS += ../webp/decode.h - -libwebpdsp_la_CPPFLAGS = -libwebpdsp_la_CPPFLAGS += $(AM_CPPFLAGS) -libwebpdsp_la_CPPFLAGS += $(USE_SWAP_16BIT_CSP) -libwebpdsp_la_LDFLAGS = -lm -libwebpdsp_la_LIBADD = -libwebpdsp_la_LIBADD += libwebpdsp_sse2.la -libwebpdsp_la_LIBADD += libwebpdsp_sse41.la -libwebpdsp_la_LIBADD += libwebpdsp_neon.la -libwebpdsp_la_LIBADD += libwebpdsp_msa.la -libwebpdsp_la_LIBADD += libwebpdsp_mips32.la -libwebpdsp_la_LIBADD += libwebpdsp_mips_dsp_r2.la - -if BUILD_LIBWEBPDECODER - libwebpdspdecode_la_SOURCES = $(COMMON_SOURCES) - - libwebpdspdecode_la_CPPFLAGS = $(libwebpdsp_la_CPPFLAGS) - libwebpdspdecode_la_LDFLAGS = $(libwebpdsp_la_LDFLAGS) - libwebpdspdecode_la_LIBADD = - libwebpdspdecode_la_LIBADD += libwebpdspdecode_sse2.la - libwebpdspdecode_la_LIBADD += libwebpdspdecode_sse41.la - libwebpdspdecode_la_LIBADD += libwebpdspdecode_neon.la - libwebpdspdecode_la_LIBADD += libwebpdspdecode_msa.la - libwebpdspdecode_la_LIBADD += libwebpdspdecode_mips32.la - libwebpdspdecode_la_LIBADD += libwebpdspdecode_mips_dsp_r2.la -endif diff --git a/libwebp/src/dsp/alpha_processing.c b/libwebp/src/dsp/alpha_processing.c index 1d152f24..4927e73e 100644 --- a/libwebp/src/dsp/alpha_processing.c +++ b/libwebp/src/dsp/alpha_processing.c @@ -12,7 +12,11 @@ // Author: Skal (pascal.massimino@gmail.com) #include +#include + +#include "src/dsp/cpu.h" #include "src/dsp/dsp.h" +#include "src/webp/types.h" // Tables can be faster on some platform but incur some extra binary size (~2k). #if !defined(USE_TABLES_FOR_ALPHA_MULT) diff --git a/libwebp/src/dsp/alpha_processing_sse2.c b/libwebp/src/dsp/alpha_processing_sse2.c index aa0cc284..1a6bfcb9 100644 --- a/libwebp/src/dsp/alpha_processing_sse2.c +++ b/libwebp/src/dsp/alpha_processing_sse2.c @@ -16,6 +16,9 @@ #if defined(WEBP_USE_SSE2) #include +#include "src/webp/types.h" +#include "src/dsp/cpu.h" + //------------------------------------------------------------------------------ static int DispatchAlpha_SSE2(const uint8_t* WEBP_RESTRICT alpha, @@ -26,38 +29,44 @@ static int DispatchAlpha_SSE2(const uint8_t* WEBP_RESTRICT alpha, uint32_t alpha_and = 0xff; int i, j; const __m128i zero = _mm_setzero_si128(); - const __m128i rgb_mask = _mm_set1_epi32((int)0xffffff00); // to preserve RGB - const __m128i all_0xff = _mm_set_epi32(0, 0, ~0, ~0); - __m128i all_alphas = all_0xff; + const __m128i alpha_mask = _mm_set1_epi32((int)0xff); // to preserve A + const __m128i all_0xff = _mm_set1_epi8((char)0xff); + __m128i all_alphas16 = all_0xff; + __m128i all_alphas8 = all_0xff; // We must be able to access 3 extra bytes after the last written byte // 'dst[4 * width - 4]', because we don't know if alpha is the first or the // last byte of the quadruplet. - const int limit = (width - 1) & ~7; - for (j = 0; j < height; ++j) { - __m128i* out = (__m128i*)dst; - for (i = 0; i < limit; i += 8) { + char* ptr = (char*)dst; + for (i = 0; i + 16 <= width - 1; i += 16) { + // load 16 alpha bytes + const __m128i a0 = _mm_loadu_si128((const __m128i*)&alpha[i]); + const __m128i a1_lo = _mm_unpacklo_epi8(a0, zero); + const __m128i a1_hi = _mm_unpackhi_epi8(a0, zero); + const __m128i a2_lo_lo = _mm_unpacklo_epi16(a1_lo, zero); + const __m128i a2_lo_hi = _mm_unpackhi_epi16(a1_lo, zero); + const __m128i a2_hi_lo = _mm_unpacklo_epi16(a1_hi, zero); + const __m128i a2_hi_hi = _mm_unpackhi_epi16(a1_hi, zero); + _mm_maskmoveu_si128(a2_lo_lo, alpha_mask, ptr + 0); + _mm_maskmoveu_si128(a2_lo_hi, alpha_mask, ptr + 16); + _mm_maskmoveu_si128(a2_hi_lo, alpha_mask, ptr + 32); + _mm_maskmoveu_si128(a2_hi_hi, alpha_mask, ptr + 48); + // accumulate 16 alpha 'and' in parallel + all_alphas16 = _mm_and_si128(all_alphas16, a0); + ptr += 64; + } + if (i + 8 <= width - 1) { // load 8 alpha bytes const __m128i a0 = _mm_loadl_epi64((const __m128i*)&alpha[i]); const __m128i a1 = _mm_unpacklo_epi8(a0, zero); const __m128i a2_lo = _mm_unpacklo_epi16(a1, zero); const __m128i a2_hi = _mm_unpackhi_epi16(a1, zero); - // load 8 dst pixels (32 bytes) - const __m128i b0_lo = _mm_loadu_si128(out + 0); - const __m128i b0_hi = _mm_loadu_si128(out + 1); - // mask dst alpha values - const __m128i b1_lo = _mm_and_si128(b0_lo, rgb_mask); - const __m128i b1_hi = _mm_and_si128(b0_hi, rgb_mask); - // combine - const __m128i b2_lo = _mm_or_si128(b1_lo, a2_lo); - const __m128i b2_hi = _mm_or_si128(b1_hi, a2_hi); - // store - _mm_storeu_si128(out + 0, b2_lo); - _mm_storeu_si128(out + 1, b2_hi); - // accumulate eight alpha 'and' in parallel - all_alphas = _mm_and_si128(all_alphas, a0); - out += 2; + _mm_maskmoveu_si128(a2_lo, alpha_mask, ptr); + _mm_maskmoveu_si128(a2_hi, alpha_mask, ptr + 16); + // accumulate 8 alpha 'and' in parallel + all_alphas8 = _mm_and_si128(all_alphas8, a0); + i += 8; } for (; i < width; ++i) { const uint32_t alpha_value = alpha[i]; @@ -68,8 +77,9 @@ static int DispatchAlpha_SSE2(const uint8_t* WEBP_RESTRICT alpha, dst += dst_stride; } // Combine the eight alpha 'and' into a 8-bit mask. - alpha_and &= _mm_movemask_epi8(_mm_cmpeq_epi8(all_alphas, all_0xff)); - return (alpha_and != 0xff); + alpha_and &= _mm_movemask_epi8(_mm_cmpeq_epi8(all_alphas8, all_0xff)) & 0xff; + return (alpha_and != 0xff || + _mm_movemask_epi8(_mm_cmpeq_epi8(all_alphas16, all_0xff)) != 0xffff); } static void DispatchAlphaToGreen_SSE2(const uint8_t* WEBP_RESTRICT alpha, diff --git a/libwebp/src/dsp/alpha_processing_sse41.c b/libwebp/src/dsp/alpha_processing_sse41.c index 1156ac34..ed95ea4e 100644 --- a/libwebp/src/dsp/alpha_processing_sse41.c +++ b/libwebp/src/dsp/alpha_processing_sse41.c @@ -11,10 +11,12 @@ // // Author: Skal (pascal.massimino@gmail.com) +#include "src/dsp/cpu.h" +#include "src/webp/types.h" #include "src/dsp/dsp.h" #if defined(WEBP_USE_SSE41) - +#include #include //------------------------------------------------------------------------------ diff --git a/libwebp/src/dsp/cost.c b/libwebp/src/dsp/cost.c deleted file mode 100644 index 73d21401..00000000 --- a/libwebp/src/dsp/cost.c +++ /dev/null @@ -1,412 +0,0 @@ -// Copyright 2014 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Author: Skal (pascal.massimino@gmail.com) - -#include "src/dsp/dsp.h" -#include "src/enc/cost_enc.h" - -//------------------------------------------------------------------------------ -// Boolean-cost cost table - -const uint16_t VP8EntropyCost[256] = { - 1792, 1792, 1792, 1536, 1536, 1408, 1366, 1280, 1280, 1216, - 1178, 1152, 1110, 1076, 1061, 1024, 1024, 992, 968, 951, - 939, 911, 896, 878, 871, 854, 838, 820, 811, 794, - 786, 768, 768, 752, 740, 732, 720, 709, 704, 690, - 683, 672, 666, 655, 647, 640, 631, 622, 615, 607, - 598, 592, 586, 576, 572, 564, 559, 555, 547, 541, - 534, 528, 522, 512, 512, 504, 500, 494, 488, 483, - 477, 473, 467, 461, 458, 452, 448, 443, 438, 434, - 427, 424, 419, 415, 410, 406, 403, 399, 394, 390, - 384, 384, 377, 374, 370, 366, 362, 359, 355, 351, - 347, 342, 342, 336, 333, 330, 326, 323, 320, 316, - 312, 308, 305, 302, 299, 296, 293, 288, 287, 283, - 280, 277, 274, 272, 268, 266, 262, 256, 256, 256, - 251, 248, 245, 242, 240, 237, 234, 232, 228, 226, - 223, 221, 218, 216, 214, 211, 208, 205, 203, 201, - 198, 196, 192, 191, 188, 187, 183, 181, 179, 176, - 175, 171, 171, 168, 165, 163, 160, 159, 156, 154, - 152, 150, 148, 146, 144, 142, 139, 138, 135, 133, - 131, 128, 128, 125, 123, 121, 119, 117, 115, 113, - 111, 110, 107, 105, 103, 102, 100, 98, 96, 94, - 92, 91, 89, 86, 86, 83, 82, 80, 77, 76, - 74, 73, 71, 69, 67, 66, 64, 63, 61, 59, - 57, 55, 54, 52, 51, 49, 47, 46, 44, 43, - 41, 40, 38, 36, 35, 33, 32, 30, 29, 27, - 25, 24, 22, 21, 19, 18, 16, 15, 13, 12, - 10, 9, 7, 6, 4, 3 -}; - -//------------------------------------------------------------------------------ -// Level cost tables - -// fixed costs for coding levels, deduce from the coding tree. -// This is only the part that doesn't depend on the probability state. -const uint16_t VP8LevelFixedCosts[MAX_LEVEL + 1] = { - 0, 256, 256, 256, 256, 432, 618, 630, - 731, 640, 640, 828, 901, 948, 1021, 1101, - 1174, 1221, 1294, 1042, 1085, 1115, 1158, 1202, - 1245, 1275, 1318, 1337, 1380, 1410, 1453, 1497, - 1540, 1570, 1613, 1280, 1295, 1317, 1332, 1358, - 1373, 1395, 1410, 1454, 1469, 1491, 1506, 1532, - 1547, 1569, 1584, 1601, 1616, 1638, 1653, 1679, - 1694, 1716, 1731, 1775, 1790, 1812, 1827, 1853, - 1868, 1890, 1905, 1727, 1733, 1742, 1748, 1759, - 1765, 1774, 1780, 1800, 1806, 1815, 1821, 1832, - 1838, 1847, 1853, 1878, 1884, 1893, 1899, 1910, - 1916, 1925, 1931, 1951, 1957, 1966, 1972, 1983, - 1989, 1998, 2004, 2027, 2033, 2042, 2048, 2059, - 2065, 2074, 2080, 2100, 2106, 2115, 2121, 2132, - 2138, 2147, 2153, 2178, 2184, 2193, 2199, 2210, - 2216, 2225, 2231, 2251, 2257, 2266, 2272, 2283, - 2289, 2298, 2304, 2168, 2174, 2183, 2189, 2200, - 2206, 2215, 2221, 2241, 2247, 2256, 2262, 2273, - 2279, 2288, 2294, 2319, 2325, 2334, 2340, 2351, - 2357, 2366, 2372, 2392, 2398, 2407, 2413, 2424, - 2430, 2439, 2445, 2468, 2474, 2483, 2489, 2500, - 2506, 2515, 2521, 2541, 2547, 2556, 2562, 2573, - 2579, 2588, 2594, 2619, 2625, 2634, 2640, 2651, - 2657, 2666, 2672, 2692, 2698, 2707, 2713, 2724, - 2730, 2739, 2745, 2540, 2546, 2555, 2561, 2572, - 2578, 2587, 2593, 2613, 2619, 2628, 2634, 2645, - 2651, 2660, 2666, 2691, 2697, 2706, 2712, 2723, - 2729, 2738, 2744, 2764, 2770, 2779, 2785, 2796, - 2802, 2811, 2817, 2840, 2846, 2855, 2861, 2872, - 2878, 2887, 2893, 2913, 2919, 2928, 2934, 2945, - 2951, 2960, 2966, 2991, 2997, 3006, 3012, 3023, - 3029, 3038, 3044, 3064, 3070, 3079, 3085, 3096, - 3102, 3111, 3117, 2981, 2987, 2996, 3002, 3013, - 3019, 3028, 3034, 3054, 3060, 3069, 3075, 3086, - 3092, 3101, 3107, 3132, 3138, 3147, 3153, 3164, - 3170, 3179, 3185, 3205, 3211, 3220, 3226, 3237, - 3243, 3252, 3258, 3281, 3287, 3296, 3302, 3313, - 3319, 3328, 3334, 3354, 3360, 3369, 3375, 3386, - 3392, 3401, 3407, 3432, 3438, 3447, 3453, 3464, - 3470, 3479, 3485, 3505, 3511, 3520, 3526, 3537, - 3543, 3552, 3558, 2816, 2822, 2831, 2837, 2848, - 2854, 2863, 2869, 2889, 2895, 2904, 2910, 2921, - 2927, 2936, 2942, 2967, 2973, 2982, 2988, 2999, - 3005, 3014, 3020, 3040, 3046, 3055, 3061, 3072, - 3078, 3087, 3093, 3116, 3122, 3131, 3137, 3148, - 3154, 3163, 3169, 3189, 3195, 3204, 3210, 3221, - 3227, 3236, 3242, 3267, 3273, 3282, 3288, 3299, - 3305, 3314, 3320, 3340, 3346, 3355, 3361, 3372, - 3378, 3387, 3393, 3257, 3263, 3272, 3278, 3289, - 3295, 3304, 3310, 3330, 3336, 3345, 3351, 3362, - 3368, 3377, 3383, 3408, 3414, 3423, 3429, 3440, - 3446, 3455, 3461, 3481, 3487, 3496, 3502, 3513, - 3519, 3528, 3534, 3557, 3563, 3572, 3578, 3589, - 3595, 3604, 3610, 3630, 3636, 3645, 3651, 3662, - 3668, 3677, 3683, 3708, 3714, 3723, 3729, 3740, - 3746, 3755, 3761, 3781, 3787, 3796, 3802, 3813, - 3819, 3828, 3834, 3629, 3635, 3644, 3650, 3661, - 3667, 3676, 3682, 3702, 3708, 3717, 3723, 3734, - 3740, 3749, 3755, 3780, 3786, 3795, 3801, 3812, - 3818, 3827, 3833, 3853, 3859, 3868, 3874, 3885, - 3891, 3900, 3906, 3929, 3935, 3944, 3950, 3961, - 3967, 3976, 3982, 4002, 4008, 4017, 4023, 4034, - 4040, 4049, 4055, 4080, 4086, 4095, 4101, 4112, - 4118, 4127, 4133, 4153, 4159, 4168, 4174, 4185, - 4191, 4200, 4206, 4070, 4076, 4085, 4091, 4102, - 4108, 4117, 4123, 4143, 4149, 4158, 4164, 4175, - 4181, 4190, 4196, 4221, 4227, 4236, 4242, 4253, - 4259, 4268, 4274, 4294, 4300, 4309, 4315, 4326, - 4332, 4341, 4347, 4370, 4376, 4385, 4391, 4402, - 4408, 4417, 4423, 4443, 4449, 4458, 4464, 4475, - 4481, 4490, 4496, 4521, 4527, 4536, 4542, 4553, - 4559, 4568, 4574, 4594, 4600, 4609, 4615, 4626, - 4632, 4641, 4647, 3515, 3521, 3530, 3536, 3547, - 3553, 3562, 3568, 3588, 3594, 3603, 3609, 3620, - 3626, 3635, 3641, 3666, 3672, 3681, 3687, 3698, - 3704, 3713, 3719, 3739, 3745, 3754, 3760, 3771, - 3777, 3786, 3792, 3815, 3821, 3830, 3836, 3847, - 3853, 3862, 3868, 3888, 3894, 3903, 3909, 3920, - 3926, 3935, 3941, 3966, 3972, 3981, 3987, 3998, - 4004, 4013, 4019, 4039, 4045, 4054, 4060, 4071, - 4077, 4086, 4092, 3956, 3962, 3971, 3977, 3988, - 3994, 4003, 4009, 4029, 4035, 4044, 4050, 4061, - 4067, 4076, 4082, 4107, 4113, 4122, 4128, 4139, - 4145, 4154, 4160, 4180, 4186, 4195, 4201, 4212, - 4218, 4227, 4233, 4256, 4262, 4271, 4277, 4288, - 4294, 4303, 4309, 4329, 4335, 4344, 4350, 4361, - 4367, 4376, 4382, 4407, 4413, 4422, 4428, 4439, - 4445, 4454, 4460, 4480, 4486, 4495, 4501, 4512, - 4518, 4527, 4533, 4328, 4334, 4343, 4349, 4360, - 4366, 4375, 4381, 4401, 4407, 4416, 4422, 4433, - 4439, 4448, 4454, 4479, 4485, 4494, 4500, 4511, - 4517, 4526, 4532, 4552, 4558, 4567, 4573, 4584, - 4590, 4599, 4605, 4628, 4634, 4643, 4649, 4660, - 4666, 4675, 4681, 4701, 4707, 4716, 4722, 4733, - 4739, 4748, 4754, 4779, 4785, 4794, 4800, 4811, - 4817, 4826, 4832, 4852, 4858, 4867, 4873, 4884, - 4890, 4899, 4905, 4769, 4775, 4784, 4790, 4801, - 4807, 4816, 4822, 4842, 4848, 4857, 4863, 4874, - 4880, 4889, 4895, 4920, 4926, 4935, 4941, 4952, - 4958, 4967, 4973, 4993, 4999, 5008, 5014, 5025, - 5031, 5040, 5046, 5069, 5075, 5084, 5090, 5101, - 5107, 5116, 5122, 5142, 5148, 5157, 5163, 5174, - 5180, 5189, 5195, 5220, 5226, 5235, 5241, 5252, - 5258, 5267, 5273, 5293, 5299, 5308, 5314, 5325, - 5331, 5340, 5346, 4604, 4610, 4619, 4625, 4636, - 4642, 4651, 4657, 4677, 4683, 4692, 4698, 4709, - 4715, 4724, 4730, 4755, 4761, 4770, 4776, 4787, - 4793, 4802, 4808, 4828, 4834, 4843, 4849, 4860, - 4866, 4875, 4881, 4904, 4910, 4919, 4925, 4936, - 4942, 4951, 4957, 4977, 4983, 4992, 4998, 5009, - 5015, 5024, 5030, 5055, 5061, 5070, 5076, 5087, - 5093, 5102, 5108, 5128, 5134, 5143, 5149, 5160, - 5166, 5175, 5181, 5045, 5051, 5060, 5066, 5077, - 5083, 5092, 5098, 5118, 5124, 5133, 5139, 5150, - 5156, 5165, 5171, 5196, 5202, 5211, 5217, 5228, - 5234, 5243, 5249, 5269, 5275, 5284, 5290, 5301, - 5307, 5316, 5322, 5345, 5351, 5360, 5366, 5377, - 5383, 5392, 5398, 5418, 5424, 5433, 5439, 5450, - 5456, 5465, 5471, 5496, 5502, 5511, 5517, 5528, - 5534, 5543, 5549, 5569, 5575, 5584, 5590, 5601, - 5607, 5616, 5622, 5417, 5423, 5432, 5438, 5449, - 5455, 5464, 5470, 5490, 5496, 5505, 5511, 5522, - 5528, 5537, 5543, 5568, 5574, 5583, 5589, 5600, - 5606, 5615, 5621, 5641, 5647, 5656, 5662, 5673, - 5679, 5688, 5694, 5717, 5723, 5732, 5738, 5749, - 5755, 5764, 5770, 5790, 5796, 5805, 5811, 5822, - 5828, 5837, 5843, 5868, 5874, 5883, 5889, 5900, - 5906, 5915, 5921, 5941, 5947, 5956, 5962, 5973, - 5979, 5988, 5994, 5858, 5864, 5873, 5879, 5890, - 5896, 5905, 5911, 5931, 5937, 5946, 5952, 5963, - 5969, 5978, 5984, 6009, 6015, 6024, 6030, 6041, - 6047, 6056, 6062, 6082, 6088, 6097, 6103, 6114, - 6120, 6129, 6135, 6158, 6164, 6173, 6179, 6190, - 6196, 6205, 6211, 6231, 6237, 6246, 6252, 6263, - 6269, 6278, 6284, 6309, 6315, 6324, 6330, 6341, - 6347, 6356, 6362, 6382, 6388, 6397, 6403, 6414, - 6420, 6429, 6435, 3515, 3521, 3530, 3536, 3547, - 3553, 3562, 3568, 3588, 3594, 3603, 3609, 3620, - 3626, 3635, 3641, 3666, 3672, 3681, 3687, 3698, - 3704, 3713, 3719, 3739, 3745, 3754, 3760, 3771, - 3777, 3786, 3792, 3815, 3821, 3830, 3836, 3847, - 3853, 3862, 3868, 3888, 3894, 3903, 3909, 3920, - 3926, 3935, 3941, 3966, 3972, 3981, 3987, 3998, - 4004, 4013, 4019, 4039, 4045, 4054, 4060, 4071, - 4077, 4086, 4092, 3956, 3962, 3971, 3977, 3988, - 3994, 4003, 4009, 4029, 4035, 4044, 4050, 4061, - 4067, 4076, 4082, 4107, 4113, 4122, 4128, 4139, - 4145, 4154, 4160, 4180, 4186, 4195, 4201, 4212, - 4218, 4227, 4233, 4256, 4262, 4271, 4277, 4288, - 4294, 4303, 4309, 4329, 4335, 4344, 4350, 4361, - 4367, 4376, 4382, 4407, 4413, 4422, 4428, 4439, - 4445, 4454, 4460, 4480, 4486, 4495, 4501, 4512, - 4518, 4527, 4533, 4328, 4334, 4343, 4349, 4360, - 4366, 4375, 4381, 4401, 4407, 4416, 4422, 4433, - 4439, 4448, 4454, 4479, 4485, 4494, 4500, 4511, - 4517, 4526, 4532, 4552, 4558, 4567, 4573, 4584, - 4590, 4599, 4605, 4628, 4634, 4643, 4649, 4660, - 4666, 4675, 4681, 4701, 4707, 4716, 4722, 4733, - 4739, 4748, 4754, 4779, 4785, 4794, 4800, 4811, - 4817, 4826, 4832, 4852, 4858, 4867, 4873, 4884, - 4890, 4899, 4905, 4769, 4775, 4784, 4790, 4801, - 4807, 4816, 4822, 4842, 4848, 4857, 4863, 4874, - 4880, 4889, 4895, 4920, 4926, 4935, 4941, 4952, - 4958, 4967, 4973, 4993, 4999, 5008, 5014, 5025, - 5031, 5040, 5046, 5069, 5075, 5084, 5090, 5101, - 5107, 5116, 5122, 5142, 5148, 5157, 5163, 5174, - 5180, 5189, 5195, 5220, 5226, 5235, 5241, 5252, - 5258, 5267, 5273, 5293, 5299, 5308, 5314, 5325, - 5331, 5340, 5346, 4604, 4610, 4619, 4625, 4636, - 4642, 4651, 4657, 4677, 4683, 4692, 4698, 4709, - 4715, 4724, 4730, 4755, 4761, 4770, 4776, 4787, - 4793, 4802, 4808, 4828, 4834, 4843, 4849, 4860, - 4866, 4875, 4881, 4904, 4910, 4919, 4925, 4936, - 4942, 4951, 4957, 4977, 4983, 4992, 4998, 5009, - 5015, 5024, 5030, 5055, 5061, 5070, 5076, 5087, - 5093, 5102, 5108, 5128, 5134, 5143, 5149, 5160, - 5166, 5175, 5181, 5045, 5051, 5060, 5066, 5077, - 5083, 5092, 5098, 5118, 5124, 5133, 5139, 5150, - 5156, 5165, 5171, 5196, 5202, 5211, 5217, 5228, - 5234, 5243, 5249, 5269, 5275, 5284, 5290, 5301, - 5307, 5316, 5322, 5345, 5351, 5360, 5366, 5377, - 5383, 5392, 5398, 5418, 5424, 5433, 5439, 5450, - 5456, 5465, 5471, 5496, 5502, 5511, 5517, 5528, - 5534, 5543, 5549, 5569, 5575, 5584, 5590, 5601, - 5607, 5616, 5622, 5417, 5423, 5432, 5438, 5449, - 5455, 5464, 5470, 5490, 5496, 5505, 5511, 5522, - 5528, 5537, 5543, 5568, 5574, 5583, 5589, 5600, - 5606, 5615, 5621, 5641, 5647, 5656, 5662, 5673, - 5679, 5688, 5694, 5717, 5723, 5732, 5738, 5749, - 5755, 5764, 5770, 5790, 5796, 5805, 5811, 5822, - 5828, 5837, 5843, 5868, 5874, 5883, 5889, 5900, - 5906, 5915, 5921, 5941, 5947, 5956, 5962, 5973, - 5979, 5988, 5994, 5858, 5864, 5873, 5879, 5890, - 5896, 5905, 5911, 5931, 5937, 5946, 5952, 5963, - 5969, 5978, 5984, 6009, 6015, 6024, 6030, 6041, - 6047, 6056, 6062, 6082, 6088, 6097, 6103, 6114, - 6120, 6129, 6135, 6158, 6164, 6173, 6179, 6190, - 6196, 6205, 6211, 6231, 6237, 6246, 6252, 6263, - 6269, 6278, 6284, 6309, 6315, 6324, 6330, 6341, - 6347, 6356, 6362, 6382, 6388, 6397, 6403, 6414, - 6420, 6429, 6435, 5303, 5309, 5318, 5324, 5335, - 5341, 5350, 5356, 5376, 5382, 5391, 5397, 5408, - 5414, 5423, 5429, 5454, 5460, 5469, 5475, 5486, - 5492, 5501, 5507, 5527, 5533, 5542, 5548, 5559, - 5565, 5574, 5580, 5603, 5609, 5618, 5624, 5635, - 5641, 5650, 5656, 5676, 5682, 5691, 5697, 5708, - 5714, 5723, 5729, 5754, 5760, 5769, 5775, 5786, - 5792, 5801, 5807, 5827, 5833, 5842, 5848, 5859, - 5865, 5874, 5880, 5744, 5750, 5759, 5765, 5776, - 5782, 5791, 5797, 5817, 5823, 5832, 5838, 5849, - 5855, 5864, 5870, 5895, 5901, 5910, 5916, 5927, - 5933, 5942, 5948, 5968, 5974, 5983, 5989, 6000, - 6006, 6015, 6021, 6044, 6050, 6059, 6065, 6076, - 6082, 6091, 6097, 6117, 6123, 6132, 6138, 6149, - 6155, 6164, 6170, 6195, 6201, 6210, 6216, 6227, - 6233, 6242, 6248, 6268, 6274, 6283, 6289, 6300, - 6306, 6315, 6321, 6116, 6122, 6131, 6137, 6148, - 6154, 6163, 6169, 6189, 6195, 6204, 6210, 6221, - 6227, 6236, 6242, 6267, 6273, 6282, 6288, 6299, - 6305, 6314, 6320, 6340, 6346, 6355, 6361, 6372, - 6378, 6387, 6393, 6416, 6422, 6431, 6437, 6448, - 6454, 6463, 6469, 6489, 6495, 6504, 6510, 6521, - 6527, 6536, 6542, 6567, 6573, 6582, 6588, 6599, - 6605, 6614, 6620, 6640, 6646, 6655, 6661, 6672, - 6678, 6687, 6693, 6557, 6563, 6572, 6578, 6589, - 6595, 6604, 6610, 6630, 6636, 6645, 6651, 6662, - 6668, 6677, 6683, 6708, 6714, 6723, 6729, 6740, - 6746, 6755, 6761, 6781, 6787, 6796, 6802, 6813, - 6819, 6828, 6834, 6857, 6863, 6872, 6878, 6889, - 6895, 6904, 6910, 6930, 6936, 6945, 6951, 6962, - 6968, 6977, 6983, 7008, 7014, 7023, 7029, 7040, - 7046, 7055, 7061, 7081, 7087, 7096, 7102, 7113, - 7119, 7128, 7134, 6392, 6398, 6407, 6413, 6424, - 6430, 6439, 6445, 6465, 6471, 6480, 6486, 6497, - 6503, 6512, 6518, 6543, 6549, 6558, 6564, 6575, - 6581, 6590, 6596, 6616, 6622, 6631, 6637, 6648, - 6654, 6663, 6669, 6692, 6698, 6707, 6713, 6724, - 6730, 6739, 6745, 6765, 6771, 6780, 6786, 6797, - 6803, 6812, 6818, 6843, 6849, 6858, 6864, 6875, - 6881, 6890, 6896, 6916, 6922, 6931, 6937, 6948, - 6954, 6963, 6969, 6833, 6839, 6848, 6854, 6865, - 6871, 6880, 6886, 6906, 6912, 6921, 6927, 6938, - 6944, 6953, 6959, 6984, 6990, 6999, 7005, 7016, - 7022, 7031, 7037, 7057, 7063, 7072, 7078, 7089, - 7095, 7104, 7110, 7133, 7139, 7148, 7154, 7165, - 7171, 7180, 7186, 7206, 7212, 7221, 7227, 7238, - 7244, 7253, 7259, 7284, 7290, 7299, 7305, 7316, - 7322, 7331, 7337, 7357, 7363, 7372, 7378, 7389, - 7395, 7404, 7410, 7205, 7211, 7220, 7226, 7237, - 7243, 7252, 7258, 7278, 7284, 7293, 7299, 7310, - 7316, 7325, 7331, 7356, 7362, 7371, 7377, 7388, - 7394, 7403, 7409, 7429, 7435, 7444, 7450, 7461, - 7467, 7476, 7482, 7505, 7511, 7520, 7526, 7537, - 7543, 7552, 7558, 7578, 7584, 7593, 7599, 7610, - 7616, 7625, 7631, 7656, 7662, 7671, 7677, 7688, - 7694, 7703, 7709, 7729, 7735, 7744, 7750, 7761 -}; - -//------------------------------------------------------------------------------ -// Tables for level coding - -const uint8_t VP8EncBands[16 + 1] = { - 0, 1, 2, 3, 6, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, - 0 // sentinel -}; - -//------------------------------------------------------------------------------ -// Mode costs - -static int GetResidualCost_C(int ctx0, const VP8Residual* const res) { - int n = res->first; - // should be prob[VP8EncBands[n]], but it's equivalent for n=0 or 1 - const int p0 = res->prob[n][ctx0][0]; - CostArrayPtr const costs = res->costs; - const uint16_t* t = costs[n][ctx0]; - // bit_cost(1, p0) is already incorporated in t[] tables, but only if ctx != 0 - // (as required by the syntax). For ctx0 == 0, we need to add it here or it'll - // be missing during the loop. - int cost = (ctx0 == 0) ? VP8BitCost(1, p0) : 0; - - if (res->last < 0) { - return VP8BitCost(0, p0); - } - for (; n < res->last; ++n) { - const int v = abs(res->coeffs[n]); - const int ctx = (v >= 2) ? 2 : v; - cost += VP8LevelCost(t, v); - t = costs[n + 1][ctx]; - } - // Last coefficient is always non-zero - { - const int v = abs(res->coeffs[n]); - assert(v != 0); - cost += VP8LevelCost(t, v); - if (n < 15) { - const int b = VP8EncBands[n + 1]; - const int ctx = (v == 1) ? 1 : 2; - const int last_p0 = res->prob[b][ctx][0]; - cost += VP8BitCost(0, last_p0); - } - } - return cost; -} - -static void SetResidualCoeffs_C(const int16_t* const coeffs, - VP8Residual* const res) { - int n; - res->last = -1; - assert(res->first == 0 || coeffs[0] == 0); - for (n = 15; n >= 0; --n) { - if (coeffs[n]) { - res->last = n; - break; - } - } - res->coeffs = coeffs; -} - -//------------------------------------------------------------------------------ -// init function - -VP8GetResidualCostFunc VP8GetResidualCost; -VP8SetResidualCoeffsFunc VP8SetResidualCoeffs; - -extern VP8CPUInfo VP8GetCPUInfo; -extern void VP8EncDspCostInitMIPS32(void); -extern void VP8EncDspCostInitMIPSdspR2(void); -extern void VP8EncDspCostInitSSE2(void); -extern void VP8EncDspCostInitNEON(void); - -WEBP_DSP_INIT_FUNC(VP8EncDspCostInit) { - VP8GetResidualCost = GetResidualCost_C; - VP8SetResidualCoeffs = SetResidualCoeffs_C; - - // If defined, use CPUInfo() to overwrite some pointers with faster versions. - if (VP8GetCPUInfo != NULL) { -#if defined(WEBP_USE_MIPS32) - if (VP8GetCPUInfo(kMIPS32)) { - VP8EncDspCostInitMIPS32(); - } -#endif -#if defined(WEBP_USE_MIPS_DSP_R2) - if (VP8GetCPUInfo(kMIPSdspR2)) { - VP8EncDspCostInitMIPSdspR2(); - } -#endif -#if defined(WEBP_HAVE_SSE2) - if (VP8GetCPUInfo(kSSE2)) { - VP8EncDspCostInitSSE2(); - } -#endif -#if defined(WEBP_HAVE_NEON) - if (VP8GetCPUInfo(kNEON)) { - VP8EncDspCostInitNEON(); - } -#endif - } -} - -//------------------------------------------------------------------------------ diff --git a/libwebp/src/dsp/cost_mips32.c b/libwebp/src/dsp/cost_mips32.c deleted file mode 100644 index 0500f88c..00000000 --- a/libwebp/src/dsp/cost_mips32.c +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright 2014 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Author: Djordje Pesut (djordje.pesut@imgtec.com) - -#include "src/dsp/dsp.h" - -#if defined(WEBP_USE_MIPS32) - -#include "src/enc/cost_enc.h" - -static int GetResidualCost_MIPS32(int ctx0, const VP8Residual* const res) { - int temp0, temp1; - int v_reg, ctx_reg; - int n = res->first; - // should be prob[VP8EncBands[n]], but it's equivalent for n=0 or 1 - int p0 = res->prob[n][ctx0][0]; - CostArrayPtr const costs = res->costs; - const uint16_t* t = costs[n][ctx0]; - // bit_cost(1, p0) is already incorporated in t[] tables, but only if ctx != 0 - // (as required by the syntax). For ctx0 == 0, we need to add it here or it'll - // be missing during the loop. - int cost = (ctx0 == 0) ? VP8BitCost(1, p0) : 0; - const int16_t* res_coeffs = res->coeffs; - const int res_last = res->last; - const int const_max_level = MAX_VARIABLE_LEVEL; - const int const_2 = 2; - const uint16_t** p_costs = &costs[n][0]; - const size_t inc_p_costs = NUM_CTX * sizeof(*p_costs); - - if (res->last < 0) { - return VP8BitCost(0, p0); - } - - __asm__ volatile ( - ".set push \n\t" - ".set noreorder \n\t" - "subu %[temp1], %[res_last], %[n] \n\t" - "sll %[temp0], %[n], 1 \n\t" - "blez %[temp1], 2f \n\t" - " addu %[res_coeffs], %[res_coeffs], %[temp0] \n\t" - "1: \n\t" - "lh %[v_reg], 0(%[res_coeffs]) \n\t" - "addiu %[n], %[n], 1 \n\t" - "negu %[temp0], %[v_reg] \n\t" - "slti %[temp1], %[v_reg], 0 \n\t" - "movn %[v_reg], %[temp0], %[temp1] \n\t" - "sltiu %[temp0], %[v_reg], 2 \n\t" - "move %[ctx_reg], %[v_reg] \n\t" - "movz %[ctx_reg], %[const_2], %[temp0] \n\t" - "sll %[temp1], %[v_reg], 1 \n\t" - "addu %[temp1], %[temp1], %[VP8LevelFixedCosts] \n\t" - "lhu %[temp1], 0(%[temp1]) \n\t" - "slt %[temp0], %[v_reg], %[const_max_level] \n\t" - "movz %[v_reg], %[const_max_level], %[temp0] \n\t" - "addu %[cost], %[cost], %[temp1] \n\t" - "sll %[v_reg], %[v_reg], 1 \n\t" - "sll %[ctx_reg], %[ctx_reg], 2 \n\t" - "addu %[v_reg], %[v_reg], %[t] \n\t" - "lhu %[temp0], 0(%[v_reg]) \n\t" - "addu %[p_costs], %[p_costs], %[inc_p_costs] \n\t" - "addu %[t], %[p_costs], %[ctx_reg] \n\t" - "addu %[cost], %[cost], %[temp0] \n\t" - "addiu %[res_coeffs], %[res_coeffs], 2 \n\t" - "bne %[n], %[res_last], 1b \n\t" - " lw %[t], 0(%[t]) \n\t" - "2: \n\t" - ".set pop \n\t" - : [cost]"+&r"(cost), [t]"+&r"(t), [n]"+&r"(n), [v_reg]"=&r"(v_reg), - [ctx_reg]"=&r"(ctx_reg), [p_costs]"+&r"(p_costs), [temp0]"=&r"(temp0), - [temp1]"=&r"(temp1), [res_coeffs]"+&r"(res_coeffs) - : [const_2]"r"(const_2), [const_max_level]"r"(const_max_level), - [VP8LevelFixedCosts]"r"(VP8LevelFixedCosts), [res_last]"r"(res_last), - [inc_p_costs]"r"(inc_p_costs) - : "memory" - ); - - // Last coefficient is always non-zero - { - const int v = abs(res->coeffs[n]); - assert(v != 0); - cost += VP8LevelCost(t, v); - if (n < 15) { - const int b = VP8EncBands[n + 1]; - const int ctx = (v == 1) ? 1 : 2; - const int last_p0 = res->prob[b][ctx][0]; - cost += VP8BitCost(0, last_p0); - } - } - return cost; -} - -static void SetResidualCoeffs_MIPS32(const int16_t* const coeffs, - VP8Residual* const res) { - const int16_t* p_coeffs = (int16_t*)coeffs; - int temp0, temp1, temp2, n, n1; - assert(res->first == 0 || coeffs[0] == 0); - - __asm__ volatile ( - ".set push \n\t" - ".set noreorder \n\t" - "addiu %[p_coeffs], %[p_coeffs], 28 \n\t" - "li %[n], 15 \n\t" - "li %[temp2], -1 \n\t" - "0: \n\t" - "ulw %[temp0], 0(%[p_coeffs]) \n\t" - "beqz %[temp0], 1f \n\t" -#if defined(WORDS_BIGENDIAN) - " sll %[temp1], %[temp0], 16 \n\t" -#else - " srl %[temp1], %[temp0], 16 \n\t" -#endif - "addiu %[n1], %[n], -1 \n\t" - "movz %[temp0], %[n1], %[temp1] \n\t" - "movn %[temp0], %[n], %[temp1] \n\t" - "j 2f \n\t" - " addiu %[temp2], %[temp0], 0 \n\t" - "1: \n\t" - "addiu %[n], %[n], -2 \n\t" - "bgtz %[n], 0b \n\t" - " addiu %[p_coeffs], %[p_coeffs], -4 \n\t" - "2: \n\t" - ".set pop \n\t" - : [p_coeffs]"+&r"(p_coeffs), [temp0]"=&r"(temp0), - [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), - [n]"=&r"(n), [n1]"=&r"(n1) - : - : "memory" - ); - res->last = temp2; - res->coeffs = coeffs; -} - -//------------------------------------------------------------------------------ -// Entry point - -extern void VP8EncDspCostInitMIPS32(void); - -WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspCostInitMIPS32(void) { - VP8GetResidualCost = GetResidualCost_MIPS32; - VP8SetResidualCoeffs = SetResidualCoeffs_MIPS32; -} - -#else // !WEBP_USE_MIPS32 - -WEBP_DSP_INIT_STUB(VP8EncDspCostInitMIPS32) - -#endif // WEBP_USE_MIPS32 diff --git a/libwebp/src/dsp/cost_mips_dsp_r2.c b/libwebp/src/dsp/cost_mips_dsp_r2.c deleted file mode 100644 index 51248de7..00000000 --- a/libwebp/src/dsp/cost_mips_dsp_r2.c +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 2014 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Author: Djordje Pesut (djordje.pesut@imgtec.com) - -#include "src/dsp/dsp.h" - -#if defined(WEBP_USE_MIPS_DSP_R2) - -#include "src/enc/cost_enc.h" - -static int GetResidualCost_MIPSdspR2(int ctx0, const VP8Residual* const res) { - int temp0, temp1; - int v_reg, ctx_reg; - int n = res->first; - // should be prob[VP8EncBands[n]], but it's equivalent for n=0 or 1 - int p0 = res->prob[n][ctx0][0]; - CostArrayPtr const costs = res->costs; - const uint16_t* t = costs[n][ctx0]; - // bit_cost(1, p0) is already incorporated in t[] tables, but only if ctx != 0 - // (as required by the syntax). For ctx0 == 0, we need to add it here or it'll - // be missing during the loop. - int cost = (ctx0 == 0) ? VP8BitCost(1, p0) : 0; - const int16_t* res_coeffs = res->coeffs; - const int res_last = res->last; - const int const_max_level = MAX_VARIABLE_LEVEL; - const int const_2 = 2; - const uint16_t** p_costs = &costs[n][0]; - const size_t inc_p_costs = NUM_CTX * sizeof(*p_costs); - - if (res->last < 0) { - return VP8BitCost(0, p0); - } - - __asm__ volatile ( - ".set push \n\t" - ".set noreorder \n\t" - "subu %[temp1], %[res_last], %[n] \n\t" - "blez %[temp1], 2f \n\t" - " nop \n\t" - "1: \n\t" - "sll %[temp0], %[n], 1 \n\t" - "lhx %[v_reg], %[temp0](%[res_coeffs]) \n\t" - "addiu %[n], %[n], 1 \n\t" - "absq_s.w %[v_reg], %[v_reg] \n\t" - "sltiu %[temp0], %[v_reg], 2 \n\t" - "move %[ctx_reg], %[v_reg] \n\t" - "movz %[ctx_reg], %[const_2], %[temp0] \n\t" - "sll %[temp1], %[v_reg], 1 \n\t" - "lhx %[temp1], %[temp1](%[VP8LevelFixedCosts]) \n\t" - "slt %[temp0], %[v_reg], %[const_max_level] \n\t" - "movz %[v_reg], %[const_max_level], %[temp0] \n\t" - "addu %[cost], %[cost], %[temp1] \n\t" - "sll %[v_reg], %[v_reg], 1 \n\t" - "sll %[ctx_reg], %[ctx_reg], 2 \n\t" - "lhx %[temp0], %[v_reg](%[t]) \n\t" - "addu %[p_costs], %[p_costs], %[inc_p_costs] \n\t" - "addu %[t], %[p_costs], %[ctx_reg] \n\t" - "addu %[cost], %[cost], %[temp0] \n\t" - "bne %[n], %[res_last], 1b \n\t" - " lw %[t], 0(%[t]) \n\t" - "2: \n\t" - ".set pop \n\t" - : [cost]"+&r"(cost), [t]"+&r"(t), [n]"+&r"(n), [v_reg]"=&r"(v_reg), - [ctx_reg]"=&r"(ctx_reg), [p_costs]"+&r"(p_costs), [temp0]"=&r"(temp0), - [temp1]"=&r"(temp1) - : [const_2]"r"(const_2), [const_max_level]"r"(const_max_level), - [VP8LevelFixedCosts]"r"(VP8LevelFixedCosts), [res_last]"r"(res_last), - [res_coeffs]"r"(res_coeffs), [inc_p_costs]"r"(inc_p_costs) - : "memory" - ); - - // Last coefficient is always non-zero - { - const int v = abs(res->coeffs[n]); - assert(v != 0); - cost += VP8LevelCost(t, v); - if (n < 15) { - const int b = VP8EncBands[n + 1]; - const int ctx = (v == 1) ? 1 : 2; - const int last_p0 = res->prob[b][ctx][0]; - cost += VP8BitCost(0, last_p0); - } - } - return cost; -} - -//------------------------------------------------------------------------------ -// Entry point - -extern void VP8EncDspCostInitMIPSdspR2(void); - -WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspCostInitMIPSdspR2(void) { - VP8GetResidualCost = GetResidualCost_MIPSdspR2; -} - -#else // !WEBP_USE_MIPS_DSP_R2 - -WEBP_DSP_INIT_STUB(VP8EncDspCostInitMIPSdspR2) - -#endif // WEBP_USE_MIPS_DSP_R2 diff --git a/libwebp/src/dsp/cost_neon.c b/libwebp/src/dsp/cost_neon.c deleted file mode 100644 index 6582669c..00000000 --- a/libwebp/src/dsp/cost_neon.c +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2018 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// ARM NEON version of cost functions - -#include "src/dsp/dsp.h" - -#if defined(WEBP_USE_NEON) - -#include "src/dsp/neon.h" -#include "src/enc/cost_enc.h" - -static const uint8_t position[16] = { 1, 2, 3, 4, 5, 6, 7, 8, - 9, 10, 11, 12, 13, 14, 15, 16 }; - -static void SetResidualCoeffs_NEON(const int16_t* const coeffs, - VP8Residual* const res) { - const int16x8_t minus_one = vdupq_n_s16(-1); - const int16x8_t coeffs_0 = vld1q_s16(coeffs); - const int16x8_t coeffs_1 = vld1q_s16(coeffs + 8); - const uint16x8_t eob_0 = vtstq_s16(coeffs_0, minus_one); - const uint16x8_t eob_1 = vtstq_s16(coeffs_1, minus_one); - const uint8x16_t eob = vcombine_u8(vqmovn_u16(eob_0), vqmovn_u16(eob_1)); - const uint8x16_t masked = vandq_u8(eob, vld1q_u8(position)); - -#if WEBP_AARCH64 - res->last = vmaxvq_u8(masked) - 1; -#else - const uint8x8_t eob_8x8 = vmax_u8(vget_low_u8(masked), vget_high_u8(masked)); - const uint16x8_t eob_16x8 = vmovl_u8(eob_8x8); - const uint16x4_t eob_16x4 = - vmax_u16(vget_low_u16(eob_16x8), vget_high_u16(eob_16x8)); - const uint32x4_t eob_32x4 = vmovl_u16(eob_16x4); - uint32x2_t eob_32x2 = - vmax_u32(vget_low_u32(eob_32x4), vget_high_u32(eob_32x4)); - eob_32x2 = vpmax_u32(eob_32x2, eob_32x2); - - vst1_lane_s32(&res->last, vreinterpret_s32_u32(eob_32x2), 0); - --res->last; -#endif // WEBP_AARCH64 - - res->coeffs = coeffs; -} - -static int GetResidualCost_NEON(int ctx0, const VP8Residual* const res) { - uint8_t levels[16], ctxs[16]; - uint16_t abs_levels[16]; - int n = res->first; - // should be prob[VP8EncBands[n]], but it's equivalent for n=0 or 1 - const int p0 = res->prob[n][ctx0][0]; - CostArrayPtr const costs = res->costs; - const uint16_t* t = costs[n][ctx0]; - // bit_cost(1, p0) is already incorporated in t[] tables, but only if ctx != 0 - // (as required by the syntax). For ctx0 == 0, we need to add it here or it'll - // be missing during the loop. - int cost = (ctx0 == 0) ? VP8BitCost(1, p0) : 0; - - if (res->last < 0) { - return VP8BitCost(0, p0); - } - - { // precompute clamped levels and contexts, packed to 8b. - const uint8x16_t kCst2 = vdupq_n_u8(2); - const uint8x16_t kCst67 = vdupq_n_u8(MAX_VARIABLE_LEVEL); - const int16x8_t c0 = vld1q_s16(res->coeffs); - const int16x8_t c1 = vld1q_s16(res->coeffs + 8); - const uint16x8_t E0 = vreinterpretq_u16_s16(vabsq_s16(c0)); - const uint16x8_t E1 = vreinterpretq_u16_s16(vabsq_s16(c1)); - const uint8x16_t F = vcombine_u8(vqmovn_u16(E0), vqmovn_u16(E1)); - const uint8x16_t G = vminq_u8(F, kCst2); // context = 0,1,2 - const uint8x16_t H = vminq_u8(F, kCst67); // clamp_level in [0..67] - - vst1q_u8(ctxs, G); - vst1q_u8(levels, H); - - vst1q_u16(abs_levels, E0); - vst1q_u16(abs_levels + 8, E1); - } - for (; n < res->last; ++n) { - const int ctx = ctxs[n]; - const int level = levels[n]; - const int flevel = abs_levels[n]; // full level - cost += VP8LevelFixedCosts[flevel] + t[level]; // simplified VP8LevelCost() - t = costs[n + 1][ctx]; - } - // Last coefficient is always non-zero - { - const int level = levels[n]; - const int flevel = abs_levels[n]; - assert(flevel != 0); - cost += VP8LevelFixedCosts[flevel] + t[level]; - if (n < 15) { - const int b = VP8EncBands[n + 1]; - const int ctx = ctxs[n]; - const int last_p0 = res->prob[b][ctx][0]; - cost += VP8BitCost(0, last_p0); - } - } - return cost; -} - -//------------------------------------------------------------------------------ -// Entry point - -extern void VP8EncDspCostInitNEON(void); - -WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspCostInitNEON(void) { - VP8SetResidualCoeffs = SetResidualCoeffs_NEON; - VP8GetResidualCost = GetResidualCost_NEON; -} - -#else // !WEBP_USE_NEON - -WEBP_DSP_INIT_STUB(VP8EncDspCostInitNEON) - -#endif // WEBP_USE_NEON diff --git a/libwebp/src/dsp/cost_sse2.c b/libwebp/src/dsp/cost_sse2.c deleted file mode 100644 index 487a0799..00000000 --- a/libwebp/src/dsp/cost_sse2.c +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2015 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// SSE2 version of cost functions -// -// Author: Skal (pascal.massimino@gmail.com) - -#include "src/dsp/dsp.h" - -#if defined(WEBP_USE_SSE2) -#include - -#include "src/enc/cost_enc.h" -#include "src/enc/vp8i_enc.h" -#include "src/utils/utils.h" - -//------------------------------------------------------------------------------ - -static void SetResidualCoeffs_SSE2(const int16_t* const coeffs, - VP8Residual* const res) { - const __m128i c0 = _mm_loadu_si128((const __m128i*)(coeffs + 0)); - const __m128i c1 = _mm_loadu_si128((const __m128i*)(coeffs + 8)); - // Use SSE2 to compare 16 values with a single instruction. - const __m128i zero = _mm_setzero_si128(); - const __m128i m0 = _mm_packs_epi16(c0, c1); - const __m128i m1 = _mm_cmpeq_epi8(m0, zero); - // Get the comparison results as a bitmask into 16bits. Negate the mask to get - // the position of entries that are not equal to zero. We don't need to mask - // out least significant bits according to res->first, since coeffs[0] is 0 - // if res->first > 0. - const uint32_t mask = 0x0000ffffu ^ (uint32_t)_mm_movemask_epi8(m1); - // The position of the most significant non-zero bit indicates the position of - // the last non-zero value. - assert(res->first == 0 || coeffs[0] == 0); - res->last = mask ? BitsLog2Floor(mask) : -1; - res->coeffs = coeffs; -} - -static int GetResidualCost_SSE2(int ctx0, const VP8Residual* const res) { - uint8_t levels[16], ctxs[16]; - uint16_t abs_levels[16]; - int n = res->first; - // should be prob[VP8EncBands[n]], but it's equivalent for n=0 or 1 - const int p0 = res->prob[n][ctx0][0]; - CostArrayPtr const costs = res->costs; - const uint16_t* t = costs[n][ctx0]; - // bit_cost(1, p0) is already incorporated in t[] tables, but only if ctx != 0 - // (as required by the syntax). For ctx0 == 0, we need to add it here or it'll - // be missing during the loop. - int cost = (ctx0 == 0) ? VP8BitCost(1, p0) : 0; - - if (res->last < 0) { - return VP8BitCost(0, p0); - } - - { // precompute clamped levels and contexts, packed to 8b. - const __m128i zero = _mm_setzero_si128(); - const __m128i kCst2 = _mm_set1_epi8(2); - const __m128i kCst67 = _mm_set1_epi8(MAX_VARIABLE_LEVEL); - const __m128i c0 = _mm_loadu_si128((const __m128i*)&res->coeffs[0]); - const __m128i c1 = _mm_loadu_si128((const __m128i*)&res->coeffs[8]); - const __m128i D0 = _mm_sub_epi16(zero, c0); - const __m128i D1 = _mm_sub_epi16(zero, c1); - const __m128i E0 = _mm_max_epi16(c0, D0); // abs(v), 16b - const __m128i E1 = _mm_max_epi16(c1, D1); - const __m128i F = _mm_packs_epi16(E0, E1); - const __m128i G = _mm_min_epu8(F, kCst2); // context = 0,1,2 - const __m128i H = _mm_min_epu8(F, kCst67); // clamp_level in [0..67] - - _mm_storeu_si128((__m128i*)&ctxs[0], G); - _mm_storeu_si128((__m128i*)&levels[0], H); - - _mm_storeu_si128((__m128i*)&abs_levels[0], E0); - _mm_storeu_si128((__m128i*)&abs_levels[8], E1); - } - for (; n < res->last; ++n) { - const int ctx = ctxs[n]; - const int level = levels[n]; - const int flevel = abs_levels[n]; // full level - cost += VP8LevelFixedCosts[flevel] + t[level]; // simplified VP8LevelCost() - t = costs[n + 1][ctx]; - } - // Last coefficient is always non-zero - { - const int level = levels[n]; - const int flevel = abs_levels[n]; - assert(flevel != 0); - cost += VP8LevelFixedCosts[flevel] + t[level]; - if (n < 15) { - const int b = VP8EncBands[n + 1]; - const int ctx = ctxs[n]; - const int last_p0 = res->prob[b][ctx][0]; - cost += VP8BitCost(0, last_p0); - } - } - return cost; -} - -//------------------------------------------------------------------------------ -// Entry point - -extern void VP8EncDspCostInitSSE2(void); - -WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspCostInitSSE2(void) { - VP8SetResidualCoeffs = SetResidualCoeffs_SSE2; - VP8GetResidualCost = GetResidualCost_SSE2; -} - -#else // !WEBP_USE_SSE2 - -WEBP_DSP_INIT_STUB(VP8EncDspCostInitSSE2) - -#endif // WEBP_USE_SSE2 diff --git a/libwebp/src/dsp/cpu.c b/libwebp/src/dsp/cpu.c index 8ba8f683..816892fb 100644 --- a/libwebp/src/dsp/cpu.c +++ b/libwebp/src/dsp/cpu.c @@ -22,6 +22,10 @@ #include #endif +#include + +#include "src/webp/types.h" + //------------------------------------------------------------------------------ // SSE2 detection. // diff --git a/libwebp/src/dsp/cpu.h b/libwebp/src/dsp/cpu.h index ecef9ba1..7f87d7da 100644 --- a/libwebp/src/dsp/cpu.h +++ b/libwebp/src/dsp/cpu.h @@ -49,14 +49,17 @@ #if !defined(HAVE_CONFIG_H) #if defined(_MSC_VER) && _MSC_VER > 1310 && \ (defined(_M_X64) || defined(_M_IX86)) -//VOID: sse2 shows garbage in webp files with an alpha channel -//#define WEBP_MSC_SSE2 // Visual C++ SSE2 targets +#define WEBP_MSC_SSE2 // Visual C++ SSE2 targets #endif #if defined(_MSC_VER) && _MSC_VER >= 1500 && \ (defined(_M_X64) || defined(_M_IX86)) -//VOID: -//#define WEBP_MSC_SSE41 // Visual C++ SSE4.1 targets +#define WEBP_MSC_SSE41 // Visual C++ SSE4.1 targets +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1700 && \ + (defined(_M_X64) || defined(_M_IX86)) +#define WEBP_MSC_AVX2 // Visual C++ AVX2 targets #endif #endif @@ -82,6 +85,16 @@ #define WEBP_HAVE_SSE41 #endif +#if (defined(__AVX2__) || defined(WEBP_MSC_AVX2)) && \ + (!defined(HAVE_CONFIG_H) || defined(WEBP_HAVE_AVX2)) +#define WEBP_USE_AVX2 +#endif + +#if defined(WEBP_USE_AVX2) && !defined(WEBP_HAVE_AVX2) +#define WEBP_HAVE_AVX2 +#endif + +#undef WEBP_MSC_AVX2 #undef WEBP_MSC_SSE41 #undef WEBP_MSC_SSE2 diff --git a/libwebp/src/dsp/dec.c b/libwebp/src/dsp/dec.c index 451d649d..4f383099 100644 --- a/libwebp/src/dsp/dec.c +++ b/libwebp/src/dsp/dec.c @@ -12,10 +12,15 @@ // Author: Skal (pascal.massimino@gmail.com) #include +#include +#include -#include "src/dsp/dsp.h" +#include "src/dec/common_dec.h" #include "src/dec/vp8i_dec.h" +#include "src/dsp/cpu.h" +#include "src/dsp/dsp.h" #include "src/utils/utils.h" +#include "src/webp/types.h" //------------------------------------------------------------------------------ @@ -38,7 +43,8 @@ static WEBP_INLINE uint8_t clip_8b(int v) { } while (0) #if !WEBP_NEON_OMIT_C_CODE -static void TransformOne_C(const int16_t* in, uint8_t* dst) { +static void TransformOne_C(const int16_t* WEBP_RESTRICT in, + uint8_t* WEBP_RESTRICT dst) { int C[4 * 4], *tmp; int i; tmp = C; @@ -82,7 +88,8 @@ static void TransformOne_C(const int16_t* in, uint8_t* dst) { } // Simplified transform when only in[0], in[1] and in[4] are non-zero -static void TransformAC3_C(const int16_t* in, uint8_t* dst) { +static void TransformAC3_C(const int16_t* WEBP_RESTRICT in, + uint8_t* WEBP_RESTRICT dst) { const int a = in[0] + 4; const int c4 = WEBP_TRANSFORM_AC3_MUL2(in[4]); const int d4 = WEBP_TRANSFORM_AC3_MUL1(in[4]); @@ -95,7 +102,8 @@ static void TransformAC3_C(const int16_t* in, uint8_t* dst) { } #undef STORE2 -static void TransformTwo_C(const int16_t* in, uint8_t* dst, int do_two) { +static void TransformTwo_C(const int16_t* WEBP_RESTRICT in, + uint8_t* WEBP_RESTRICT dst, int do_two) { TransformOne_C(in, dst); if (do_two) { TransformOne_C(in + 16, dst + 4); @@ -103,13 +111,15 @@ static void TransformTwo_C(const int16_t* in, uint8_t* dst, int do_two) { } #endif // !WEBP_NEON_OMIT_C_CODE -static void TransformUV_C(const int16_t* in, uint8_t* dst) { +static void TransformUV_C(const int16_t* WEBP_RESTRICT in, + uint8_t* WEBP_RESTRICT dst) { VP8Transform(in + 0 * 16, dst, 1); VP8Transform(in + 2 * 16, dst + 4 * BPS, 1); } #if !WEBP_NEON_OMIT_C_CODE -static void TransformDC_C(const int16_t* in, uint8_t* dst) { +static void TransformDC_C(const int16_t* WEBP_RESTRICT in, + uint8_t* WEBP_RESTRICT dst) { const int DC = in[0] + 4; int i, j; for (j = 0; j < 4; ++j) { @@ -120,7 +130,8 @@ static void TransformDC_C(const int16_t* in, uint8_t* dst) { } #endif // !WEBP_NEON_OMIT_C_CODE -static void TransformDCUV_C(const int16_t* in, uint8_t* dst) { +static void TransformDCUV_C(const int16_t* WEBP_RESTRICT in, + uint8_t* WEBP_RESTRICT dst) { if (in[0 * 16]) VP8TransformDC(in + 0 * 16, dst); if (in[1 * 16]) VP8TransformDC(in + 1 * 16, dst + 4); if (in[2 * 16]) VP8TransformDC(in + 2 * 16, dst + 4 * BPS); @@ -133,7 +144,8 @@ static void TransformDCUV_C(const int16_t* in, uint8_t* dst) { // Paragraph 14.3 #if !WEBP_NEON_OMIT_C_CODE -static void TransformWHT_C(const int16_t* in, int16_t* out) { +static void TransformWHT_C(const int16_t* WEBP_RESTRICT in, + int16_t* WEBP_RESTRICT out) { int tmp[16]; int i; for (i = 0; i < 4; ++i) { @@ -161,7 +173,7 @@ static void TransformWHT_C(const int16_t* in, int16_t* out) { } #endif // !WEBP_NEON_OMIT_C_CODE -void (*VP8TransformWHT)(const int16_t* in, int16_t* out); +VP8WHT VP8TransformWHT; //------------------------------------------------------------------------------ // Intra predictions @@ -661,32 +673,32 @@ static void HFilter16i_C(uint8_t* p, int stride, #if !WEBP_NEON_OMIT_C_CODE // 8-pixels wide variant, for chroma filtering -static void VFilter8_C(uint8_t* u, uint8_t* v, int stride, - int thresh, int ithresh, int hev_thresh) { +static void VFilter8_C(uint8_t* WEBP_RESTRICT u, uint8_t* WEBP_RESTRICT v, + int stride, int thresh, int ithresh, int hev_thresh) { FilterLoop26_C(u, stride, 1, 8, thresh, ithresh, hev_thresh); FilterLoop26_C(v, stride, 1, 8, thresh, ithresh, hev_thresh); } #endif // !WEBP_NEON_OMIT_C_CODE #if !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC -static void HFilter8_C(uint8_t* u, uint8_t* v, int stride, - int thresh, int ithresh, int hev_thresh) { +static void HFilter8_C(uint8_t* WEBP_RESTRICT u, uint8_t* WEBP_RESTRICT v, + int stride, int thresh, int ithresh, int hev_thresh) { FilterLoop26_C(u, 1, stride, 8, thresh, ithresh, hev_thresh); FilterLoop26_C(v, 1, stride, 8, thresh, ithresh, hev_thresh); } #endif // !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC #if !WEBP_NEON_OMIT_C_CODE -static void VFilter8i_C(uint8_t* u, uint8_t* v, int stride, - int thresh, int ithresh, int hev_thresh) { +static void VFilter8i_C(uint8_t* WEBP_RESTRICT u, uint8_t* WEBP_RESTRICT v, + int stride, int thresh, int ithresh, int hev_thresh) { FilterLoop24_C(u + 4 * stride, stride, 1, 8, thresh, ithresh, hev_thresh); FilterLoop24_C(v + 4 * stride, stride, 1, 8, thresh, ithresh, hev_thresh); } #endif // !WEBP_NEON_OMIT_C_CODE #if !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC -static void HFilter8i_C(uint8_t* u, uint8_t* v, int stride, - int thresh, int ithresh, int hev_thresh) { +static void HFilter8i_C(uint8_t* WEBP_RESTRICT u, uint8_t* WEBP_RESTRICT v, + int stride, int thresh, int ithresh, int hev_thresh) { FilterLoop24_C(u + 4, 1, stride, 8, thresh, ithresh, hev_thresh); FilterLoop24_C(v + 4, 1, stride, 8, thresh, ithresh, hev_thresh); } @@ -694,8 +706,8 @@ static void HFilter8i_C(uint8_t* u, uint8_t* v, int stride, //------------------------------------------------------------------------------ -static void DitherCombine8x8_C(const uint8_t* dither, uint8_t* dst, - int dst_stride) { +static void DitherCombine8x8_C(const uint8_t* WEBP_RESTRICT dither, + uint8_t* WEBP_RESTRICT dst, int dst_stride) { int i, j; for (j = 0; j < 8; ++j) { for (i = 0; i < 8; ++i) { @@ -730,8 +742,8 @@ VP8SimpleFilterFunc VP8SimpleHFilter16; VP8SimpleFilterFunc VP8SimpleVFilter16i; VP8SimpleFilterFunc VP8SimpleHFilter16i; -void (*VP8DitherCombine8x8)(const uint8_t* dither, uint8_t* dst, - int dst_stride); +void (*VP8DitherCombine8x8)(const uint8_t* WEBP_RESTRICT dither, + uint8_t* WEBP_RESTRICT dst, int dst_stride); extern VP8CPUInfo VP8GetCPUInfo; extern void VP8DspInitSSE2(void); diff --git a/libwebp/src/dsp/dec_clip_tables.c b/libwebp/src/dsp/dec_clip_tables.c index 427b74f7..4c816ddb 100644 --- a/libwebp/src/dsp/dec_clip_tables.c +++ b/libwebp/src/dsp/dec_clip_tables.c @@ -11,6 +11,8 @@ // // Author: Skal (pascal.massimino@gmail.com) +#include "src/dsp/cpu.h" +#include "src/webp/types.h" #include "src/dsp/dsp.h" // define to 0 to have run-time table initialization diff --git a/libwebp/src/dsp/dec_mips32.c b/libwebp/src/dsp/dec_mips32.c index f0e7de4a..89fe9009 100644 --- a/libwebp/src/dsp/dec_mips32.c +++ b/libwebp/src/dsp/dec_mips32.c @@ -133,26 +133,26 @@ static void HFilter16(uint8_t* p, int stride, } // 8-pixels wide variant, for chroma filtering -static void VFilter8(uint8_t* u, uint8_t* v, int stride, - int thresh, int ithresh, int hev_thresh) { +static void VFilter8(uint8_t* WEBP_RESTRICT u, uint8_t* WEBP_RESTRICT v, + int stride, int thresh, int ithresh, int hev_thresh) { FilterLoop26(u, stride, 1, 8, thresh, ithresh, hev_thresh); FilterLoop26(v, stride, 1, 8, thresh, ithresh, hev_thresh); } -static void HFilter8(uint8_t* u, uint8_t* v, int stride, - int thresh, int ithresh, int hev_thresh) { +static void HFilter8(uint8_t* WEBP_RESTRICT u, uint8_t* WEBP_RESTRICT v, + int stride, int thresh, int ithresh, int hev_thresh) { FilterLoop26(u, 1, stride, 8, thresh, ithresh, hev_thresh); FilterLoop26(v, 1, stride, 8, thresh, ithresh, hev_thresh); } -static void VFilter8i(uint8_t* u, uint8_t* v, int stride, - int thresh, int ithresh, int hev_thresh) { +static void VFilter8i(uint8_t* WEBP_RESTRICT u, uint8_t* WEBP_RESTRICT v, + int stride, int thresh, int ithresh, int hev_thresh) { FilterLoop24(u + 4 * stride, stride, 1, 8, thresh, ithresh, hev_thresh); FilterLoop24(v + 4 * stride, stride, 1, 8, thresh, ithresh, hev_thresh); } -static void HFilter8i(uint8_t* u, uint8_t* v, int stride, - int thresh, int ithresh, int hev_thresh) { +static void HFilter8i(uint8_t* WEBP_RESTRICT u, uint8_t* WEBP_RESTRICT v, + int stride, int thresh, int ithresh, int hev_thresh) { FilterLoop24(u + 4, 1, stride, 8, thresh, ithresh, hev_thresh); FilterLoop24(v + 4, 1, stride, 8, thresh, ithresh, hev_thresh); } @@ -215,7 +215,8 @@ static void SimpleHFilter16i(uint8_t* p, int stride, int thresh) { } } -static void TransformOne(const int16_t* in, uint8_t* dst) { +static void TransformOne(const int16_t* WEBP_RESTRICT in, + uint8_t* WEBP_RESTRICT dst) { int temp0, temp1, temp2, temp3, temp4; int temp5, temp6, temp7, temp8, temp9; int temp10, temp11, temp12, temp13, temp14; @@ -532,7 +533,8 @@ static void TransformOne(const int16_t* in, uint8_t* dst) { ); } -static void TransformTwo(const int16_t* in, uint8_t* dst, int do_two) { +static void TransformTwo(const int16_t* WEBP_RESTRICT in, + uint8_t* WEBP_RESTRICT dst, int do_two) { TransformOne(in, dst); if (do_two) { TransformOne(in + 16, dst + 4); diff --git a/libwebp/src/dsp/dec_mips_dsp_r2.c b/libwebp/src/dsp/dec_mips_dsp_r2.c index 0ba706a2..03b5f122 100644 --- a/libwebp/src/dsp/dec_mips_dsp_r2.c +++ b/libwebp/src/dsp/dec_mips_dsp_r2.c @@ -21,7 +21,8 @@ static const int kC1 = WEBP_TRANSFORM_AC3_C1; static const int kC2 = WEBP_TRANSFORM_AC3_C2; -static void TransformDC(const int16_t* in, uint8_t* dst) { +static void TransformDC(const int16_t* WEBP_RESTRICT in, + uint8_t* WEBP_RESTRICT dst) { int temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8, temp9, temp10; __asm__ volatile ( @@ -45,7 +46,8 @@ static void TransformDC(const int16_t* in, uint8_t* dst) { ); } -static void TransformAC3(const int16_t* in, uint8_t* dst) { +static void TransformAC3(const int16_t* WEBP_RESTRICT in, + uint8_t* WEBP_RESTRICT dst) { const int a = in[0] + 4; int c4 = WEBP_TRANSFORM_AC3_MUL2(in[4]); const int d4 = WEBP_TRANSFORM_AC3_MUL1(in[4]); @@ -81,7 +83,8 @@ static void TransformAC3(const int16_t* in, uint8_t* dst) { ); } -static void TransformOne(const int16_t* in, uint8_t* dst) { +static void TransformOne(const int16_t* WEBP_RESTRICT in, + uint8_t* WEBP_RESTRICT dst) { int temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8, temp9; int temp10, temp11, temp12, temp13, temp14, temp15, temp16, temp17, temp18; @@ -148,7 +151,8 @@ static void TransformOne(const int16_t* in, uint8_t* dst) { ); } -static void TransformTwo(const int16_t* in, uint8_t* dst, int do_two) { +static void TransformTwo(const int16_t* WEBP_RESTRICT in, + uint8_t* WEBP_RESTRICT dst, int do_two) { TransformOne(in, dst); if (do_two) { TransformOne(in + 16, dst + 4); @@ -434,14 +438,14 @@ static void HFilter16(uint8_t* p, int stride, } // 8-pixels wide variant, for chroma filtering -static void VFilter8(uint8_t* u, uint8_t* v, int stride, - int thresh, int ithresh, int hev_thresh) { +static void VFilter8(uint8_t* WEBP_RESTRICT u, uint8_t* WEBP_RESTRICT v, + int stride, int thresh, int ithresh, int hev_thresh) { FilterLoop26(u, stride, 1, 8, thresh, ithresh, hev_thresh); FilterLoop26(v, stride, 1, 8, thresh, ithresh, hev_thresh); } -static void HFilter8(uint8_t* u, uint8_t* v, int stride, - int thresh, int ithresh, int hev_thresh) { +static void HFilter8(uint8_t* WEBP_RESTRICT u, uint8_t* WEBP_RESTRICT v, + int stride, int thresh, int ithresh, int hev_thresh) { FilterLoop26(u, 1, stride, 8, thresh, ithresh, hev_thresh); FilterLoop26(v, 1, stride, 8, thresh, ithresh, hev_thresh); } @@ -465,14 +469,14 @@ static void HFilter16i(uint8_t* p, int stride, } } -static void VFilter8i(uint8_t* u, uint8_t* v, int stride, - int thresh, int ithresh, int hev_thresh) { +static void VFilter8i(uint8_t* WEBP_RESTRICT u, uint8_t* WEBP_RESTRICT v, + int stride, int thresh, int ithresh, int hev_thresh) { FilterLoop24(u + 4 * stride, stride, 1, 8, thresh, ithresh, hev_thresh); FilterLoop24(v + 4 * stride, stride, 1, 8, thresh, ithresh, hev_thresh); } -static void HFilter8i(uint8_t* u, uint8_t* v, int stride, - int thresh, int ithresh, int hev_thresh) { +static void HFilter8i(uint8_t* WEBP_RESTRICT u, uint8_t* WEBP_RESTRICT v, + int stride, int thresh, int ithresh, int hev_thresh) { FilterLoop24(u + 4, 1, stride, 8, thresh, ithresh, hev_thresh); FilterLoop24(v + 4, 1, stride, 8, thresh, ithresh, hev_thresh); } diff --git a/libwebp/src/dsp/dec_msa.c b/libwebp/src/dsp/dec_msa.c index 58d17301..422b3632 100644 --- a/libwebp/src/dsp/dec_msa.c +++ b/libwebp/src/dsp/dec_msa.c @@ -38,7 +38,8 @@ BUTTERFLY_4(a1_m, b1_m, c1_m, d1_m, out0, out1, out2, out3); \ } -static void TransformOne(const int16_t* in, uint8_t* dst) { +static void TransformOne(const int16_t* WEBP_RESTRICT in, + uint8_t* WEBP_RESTRICT dst) { v8i16 input0, input1; v4i32 in0, in1, in2, in3, hz0, hz1, hz2, hz3, vt0, vt1, vt2, vt3; v4i32 res0, res1, res2, res3; @@ -65,14 +66,16 @@ static void TransformOne(const int16_t* in, uint8_t* dst) { ST4x4_UB(res0, res0, 3, 2, 1, 0, dst, BPS); } -static void TransformTwo(const int16_t* in, uint8_t* dst, int do_two) { +static void TransformTwo(const int16_t* WEBP_RESTRICT in, + uint8_t* WEBP_RESTRICT dst, int do_two) { TransformOne(in, dst); if (do_two) { TransformOne(in + 16, dst + 4); } } -static void TransformWHT(const int16_t* in, int16_t* out) { +static void TransformWHT(const int16_t* WEBP_RESTRICT in, + int16_t* WEBP_RESTRICT out) { v8i16 input0, input1; const v8i16 mask0 = { 0, 1, 2, 3, 8, 9, 10, 11 }; const v8i16 mask1 = { 4, 5, 6, 7, 12, 13, 14, 15 }; @@ -114,13 +117,15 @@ static void TransformWHT(const int16_t* in, int16_t* out) { out[240] = __msa_copy_s_h(out1, 7); } -static void TransformDC(const int16_t* in, uint8_t* dst) { +static void TransformDC(const int16_t* WEBP_RESTRICT in, + uint8_t* WEBP_RESTRICT dst) { const int DC = (in[0] + 4) >> 3; const v8i16 tmp0 = __msa_fill_h(DC); ADDBLK_ST4x4_UB(tmp0, tmp0, tmp0, tmp0, dst, BPS); } -static void TransformAC3(const int16_t* in, uint8_t* dst) { +static void TransformAC3(const int16_t* WEBP_RESTRICT in, + uint8_t* WEBP_RESTRICT dst) { const int a = in[0] + 4; const int c4 = WEBP_TRANSFORM_AC3_MUL2(in[4]); const int d4 = WEBP_TRANSFORM_AC3_MUL1(in[4]); @@ -475,8 +480,8 @@ static void HFilter16i(uint8_t* src_y, int stride, } // 8-pixels wide variants, for chroma filtering -static void VFilter8(uint8_t* src_u, uint8_t* src_v, int stride, - int b_limit_in, int limit_in, int thresh_in) { +static void VFilter8(uint8_t* WEBP_RESTRICT src_u, uint8_t* WEBP_RESTRICT src_v, + int stride, int b_limit_in, int limit_in, int thresh_in) { uint8_t* ptmp_src_u = src_u - 4 * stride; uint8_t* ptmp_src_v = src_v - 4 * stride; uint64_t p2_d, p1_d, p0_d, q0_d, q1_d, q2_d; @@ -520,8 +525,8 @@ static void VFilter8(uint8_t* src_u, uint8_t* src_v, int stride, SD(q2_d, ptmp_src_v); } -static void HFilter8(uint8_t* src_u, uint8_t* src_v, int stride, - int b_limit_in, int limit_in, int thresh_in) { +static void HFilter8(uint8_t* WEBP_RESTRICT src_u, uint8_t* WEBP_RESTRICT src_v, + int stride, int b_limit_in, int limit_in, int thresh_in) { uint8_t* ptmp_src_u = src_u - 4; uint8_t* ptmp_src_v = src_v - 4; v16u8 p3, p2, p1, p0, q3, q2, q1, q0, mask, hev; @@ -556,7 +561,8 @@ static void HFilter8(uint8_t* src_u, uint8_t* src_v, int stride, ST6x4_UB(tmp7, 0, tmp5, 4, ptmp_src_v, stride); } -static void VFilter8i(uint8_t* src_u, uint8_t* src_v, int stride, +static void VFilter8i(uint8_t* WEBP_RESTRICT src_u, + uint8_t* WEBP_RESTRICT src_v, int stride, int b_limit_in, int limit_in, int thresh_in) { uint64_t p1_d, p0_d, q0_d, q1_d; v16u8 p3, p2, p1, p0, q3, q2, q1, q0, mask, hev; @@ -587,7 +593,8 @@ static void VFilter8i(uint8_t* src_u, uint8_t* src_v, int stride, SD4(q1_d, q0_d, p0_d, p1_d, src_v, -stride); } -static void HFilter8i(uint8_t* src_u, uint8_t* src_v, int stride, +static void HFilter8i(uint8_t* WEBP_RESTRICT src_u, + uint8_t* WEBP_RESTRICT src_v, int stride, int b_limit_in, int limit_in, int thresh_in) { v16u8 p3, p2, p1, p0, q3, q2, q1, q0, mask, hev; v16u8 row0, row1, row2, row3, row4, row5, row6, row7, row8; diff --git a/libwebp/src/dsp/dec_neon.c b/libwebp/src/dsp/dec_neon.c index 83b3a1f9..f150692a 100644 --- a/libwebp/src/dsp/dec_neon.c +++ b/libwebp/src/dsp/dec_neon.c @@ -916,8 +916,8 @@ static void HFilter16i_NEON(uint8_t* p, int stride, #endif // !WORK_AROUND_GCC // 8-pixels wide variant, for chroma filtering -static void VFilter8_NEON(uint8_t* u, uint8_t* v, int stride, - int thresh, int ithresh, int hev_thresh) { +static void VFilter8_NEON(uint8_t* WEBP_RESTRICT u, uint8_t* WEBP_RESTRICT v, + int stride, int thresh, int ithresh, int hev_thresh) { uint8x16_t p3, p2, p1, p0, q0, q1, q2, q3; Load8x8x2_NEON(u, v, stride, &p3, &p2, &p1, &p0, &q0, &q1, &q2, &q3); { @@ -932,7 +932,8 @@ static void VFilter8_NEON(uint8_t* u, uint8_t* v, int stride, Store8x2x2_NEON(oq1, oq2, u + 2 * stride, v + 2 * stride, stride); } } -static void VFilter8i_NEON(uint8_t* u, uint8_t* v, int stride, +static void VFilter8i_NEON(uint8_t* WEBP_RESTRICT u, uint8_t* WEBP_RESTRICT v, + int stride, int thresh, int ithresh, int hev_thresh) { uint8x16_t p3, p2, p1, p0, q0, q1, q2, q3; u += 4 * stride; @@ -949,8 +950,8 @@ static void VFilter8i_NEON(uint8_t* u, uint8_t* v, int stride, } #if !defined(WORK_AROUND_GCC) -static void HFilter8_NEON(uint8_t* u, uint8_t* v, int stride, - int thresh, int ithresh, int hev_thresh) { +static void HFilter8_NEON(uint8_t* WEBP_RESTRICT u, uint8_t* WEBP_RESTRICT v, + int stride, int thresh, int ithresh, int hev_thresh) { uint8x16_t p3, p2, p1, p0, q0, q1, q2, q3; Load8x8x2T_NEON(u, v, stride, &p3, &p2, &p1, &p0, &q0, &q1, &q2, &q3); { @@ -964,7 +965,8 @@ static void HFilter8_NEON(uint8_t* u, uint8_t* v, int stride, } } -static void HFilter8i_NEON(uint8_t* u, uint8_t* v, int stride, +static void HFilter8i_NEON(uint8_t* WEBP_RESTRICT u, uint8_t* WEBP_RESTRICT v, + int stride, int thresh, int ithresh, int hev_thresh) { uint8x16_t p3, p2, p1, p0, q0, q1, q2, q3; u += 4; @@ -1041,7 +1043,8 @@ static WEBP_INLINE void TransformPass_NEON(int16x8x2_t* const rows) { Transpose8x2_NEON(E0, E1, rows); } -static void TransformOne_NEON(const int16_t* in, uint8_t* dst) { +static void TransformOne_NEON(const int16_t* WEBP_RESTRICT in, + uint8_t* WEBP_RESTRICT dst) { int16x8x2_t rows; INIT_VECTOR2(rows, vld1q_s16(in + 0), vld1q_s16(in + 8)); TransformPass_NEON(&rows); @@ -1051,7 +1054,8 @@ static void TransformOne_NEON(const int16_t* in, uint8_t* dst) { #else -static void TransformOne_NEON(const int16_t* in, uint8_t* dst) { +static void TransformOne_NEON(const int16_t* WEBP_RESTRICT in, + uint8_t* WEBP_RESTRICT dst) { const int kBPS = BPS; // kC1, kC2. Padded because vld1.16 loads 8 bytes const int16_t constants[4] = { kC1, kC2, 0, 0 }; @@ -1184,14 +1188,16 @@ static void TransformOne_NEON(const int16_t* in, uint8_t* dst) { #endif // WEBP_USE_INTRINSICS -static void TransformTwo_NEON(const int16_t* in, uint8_t* dst, int do_two) { +static void TransformTwo_NEON(const int16_t* WEBP_RESTRICT in, + uint8_t* WEBP_RESTRICT dst, int do_two) { TransformOne_NEON(in, dst); if (do_two) { TransformOne_NEON(in + 16, dst + 4); } } -static void TransformDC_NEON(const int16_t* in, uint8_t* dst) { +static void TransformDC_NEON(const int16_t* WEBP_RESTRICT in, + uint8_t* WEBP_RESTRICT dst) { const int16x8_t DC = vdupq_n_s16(in[0]); Add4x4_NEON(DC, DC, dst); } @@ -1205,7 +1211,8 @@ static void TransformDC_NEON(const int16_t* in, uint8_t* dst) { *dst = vgetq_lane_s32(rows.val[3], col); (dst) += 16; \ } while (0) -static void TransformWHT_NEON(const int16_t* in, int16_t* out) { +static void TransformWHT_NEON(const int16_t* WEBP_RESTRICT in, + int16_t* WEBP_RESTRICT out) { int32x4x4_t tmp; { @@ -1256,7 +1263,8 @@ static void TransformWHT_NEON(const int16_t* in, int16_t* out) { //------------------------------------------------------------------------------ -static void TransformAC3_NEON(const int16_t* in, uint8_t* dst) { +static void TransformAC3_NEON(const int16_t* WEBP_RESTRICT in, + uint8_t* WEBP_RESTRICT dst) { const int16x4_t A = vld1_dup_s16(in); const int16x4_t c4 = vdup_n_s16(WEBP_TRANSFORM_AC3_MUL2(in[4])); const int16x4_t d4 = vdup_n_s16(WEBP_TRANSFORM_AC3_MUL1(in[4])); @@ -1300,18 +1308,19 @@ static void DC4_NEON(uint8_t* dst) { // DC static WEBP_INLINE void TrueMotion_NEON(uint8_t* dst, int size) { const uint8x8_t TL = vld1_dup_u8(dst - BPS - 1); // top-left pixel 'A[-1]' const uint8x8_t T = vld1_u8(dst - BPS); // top row 'A[0..3]' - const int16x8_t d = vreinterpretq_s16_u16(vsubl_u8(T, TL)); // A[c] - A[-1] + const uint16x8_t d = vsubl_u8(T, TL); // A[c] - A[-1] int y; for (y = 0; y < size; y += 4) { // left edge - const int16x8_t L0 = ConvertU8ToS16_NEON(vld1_dup_u8(dst + 0 * BPS - 1)); - const int16x8_t L1 = ConvertU8ToS16_NEON(vld1_dup_u8(dst + 1 * BPS - 1)); - const int16x8_t L2 = ConvertU8ToS16_NEON(vld1_dup_u8(dst + 2 * BPS - 1)); - const int16x8_t L3 = ConvertU8ToS16_NEON(vld1_dup_u8(dst + 3 * BPS - 1)); - const int16x8_t r0 = vaddq_s16(L0, d); // L[r] + A[c] - A[-1] - const int16x8_t r1 = vaddq_s16(L1, d); - const int16x8_t r2 = vaddq_s16(L2, d); - const int16x8_t r3 = vaddq_s16(L3, d); + const uint8x8_t L0 = vld1_dup_u8(dst + 0 * BPS - 1); + const uint8x8_t L1 = vld1_dup_u8(dst + 1 * BPS - 1); + const uint8x8_t L2 = vld1_dup_u8(dst + 2 * BPS - 1); + const uint8x8_t L3 = vld1_dup_u8(dst + 3 * BPS - 1); + // L[r] + A[c] - A[-1] + const int16x8_t r0 = vreinterpretq_s16_u16(vaddw_u8(d, L0)); + const int16x8_t r1 = vreinterpretq_s16_u16(vaddw_u8(d, L1)); + const int16x8_t r2 = vreinterpretq_s16_u16(vaddw_u8(d, L2)); + const int16x8_t r3 = vreinterpretq_s16_u16(vaddw_u8(d, L3)); // Saturate and store the result. const uint32x2_t r0_u32 = vreinterpret_u32_u8(vqmovun_s16(r0)); const uint32x2_t r1_u32 = vreinterpret_u32_u8(vqmovun_s16(r1)); @@ -1572,23 +1581,24 @@ static void TM16_NEON(uint8_t* dst) { const uint8x8_t TL = vld1_dup_u8(dst - BPS - 1); // top-left pixel 'A[-1]' const uint8x16_t T = vld1q_u8(dst - BPS); // top row 'A[0..15]' // A[c] - A[-1] - const int16x8_t d_lo = vreinterpretq_s16_u16(vsubl_u8(vget_low_u8(T), TL)); - const int16x8_t d_hi = vreinterpretq_s16_u16(vsubl_u8(vget_high_u8(T), TL)); + const uint16x8_t d_lo = vsubl_u8(vget_low_u8(T), TL); + const uint16x8_t d_hi = vsubl_u8(vget_high_u8(T), TL); int y; for (y = 0; y < 16; y += 4) { // left edge - const int16x8_t L0 = ConvertU8ToS16_NEON(vld1_dup_u8(dst + 0 * BPS - 1)); - const int16x8_t L1 = ConvertU8ToS16_NEON(vld1_dup_u8(dst + 1 * BPS - 1)); - const int16x8_t L2 = ConvertU8ToS16_NEON(vld1_dup_u8(dst + 2 * BPS - 1)); - const int16x8_t L3 = ConvertU8ToS16_NEON(vld1_dup_u8(dst + 3 * BPS - 1)); - const int16x8_t r0_lo = vaddq_s16(L0, d_lo); // L[r] + A[c] - A[-1] - const int16x8_t r1_lo = vaddq_s16(L1, d_lo); - const int16x8_t r2_lo = vaddq_s16(L2, d_lo); - const int16x8_t r3_lo = vaddq_s16(L3, d_lo); - const int16x8_t r0_hi = vaddq_s16(L0, d_hi); - const int16x8_t r1_hi = vaddq_s16(L1, d_hi); - const int16x8_t r2_hi = vaddq_s16(L2, d_hi); - const int16x8_t r3_hi = vaddq_s16(L3, d_hi); + const uint8x8_t L0 = vld1_dup_u8(dst + 0 * BPS - 1); + const uint8x8_t L1 = vld1_dup_u8(dst + 1 * BPS - 1); + const uint8x8_t L2 = vld1_dup_u8(dst + 2 * BPS - 1); + const uint8x8_t L3 = vld1_dup_u8(dst + 3 * BPS - 1); + // L[r] + A[c] - A[-1] + const int16x8_t r0_lo = vreinterpretq_s16_u16(vaddw_u8(d_lo, L0)); + const int16x8_t r1_lo = vreinterpretq_s16_u16(vaddw_u8(d_lo, L1)); + const int16x8_t r2_lo = vreinterpretq_s16_u16(vaddw_u8(d_lo, L2)); + const int16x8_t r3_lo = vreinterpretq_s16_u16(vaddw_u8(d_lo, L3)); + const int16x8_t r0_hi = vreinterpretq_s16_u16(vaddw_u8(d_hi, L0)); + const int16x8_t r1_hi = vreinterpretq_s16_u16(vaddw_u8(d_hi, L1)); + const int16x8_t r2_hi = vreinterpretq_s16_u16(vaddw_u8(d_hi, L2)); + const int16x8_t r3_hi = vreinterpretq_s16_u16(vaddw_u8(d_hi, L3)); // Saturate and store the result. const uint8x16_t row0 = vcombine_u8(vqmovun_s16(r0_lo), vqmovun_s16(r0_hi)); const uint8x16_t row1 = vcombine_u8(vqmovun_s16(r1_lo), vqmovun_s16(r1_hi)); diff --git a/libwebp/src/dsp/dec_sse2.c b/libwebp/src/dsp/dec_sse2.c index ff3a2855..d5f273e3 100644 --- a/libwebp/src/dsp/dec_sse2.c +++ b/libwebp/src/dsp/dec_sse2.c @@ -23,14 +23,18 @@ #endif #include -#include "src/dsp/common_sse2.h" + #include "src/dec/vp8i_dec.h" +#include "src/dsp/common_sse2.h" +#include "src/dsp/cpu.h" #include "src/utils/utils.h" +#include "src/webp/types.h" //------------------------------------------------------------------------------ // Transforms (Paragraph 14.4) -static void Transform_SSE2(const int16_t* in, uint8_t* dst, int do_two) { +static void Transform_SSE2(const int16_t* WEBP_RESTRICT in, + uint8_t* WEBP_RESTRICT dst, int do_two) { // This implementation makes use of 16-bit fixed point versions of two // multiply constants: // K1 = sqrt(2) * cos (pi/8) ~= 85627 / 2^16 @@ -197,7 +201,8 @@ static void Transform_SSE2(const int16_t* in, uint8_t* dst, int do_two) { #if (USE_TRANSFORM_AC3 == 1) -static void TransformAC3(const int16_t* in, uint8_t* dst) { +static void TransformAC3_SSE2(const int16_t* WEBP_RESTRICT in, + uint8_t* WEBP_RESTRICT dst) { const __m128i A = _mm_set1_epi16(in[0] + 4); const __m128i c4 = _mm_set1_epi16(WEBP_TRANSFORM_AC3_MUL2(in[4])); const __m128i d4 = _mm_set1_epi16(WEBP_TRANSFORM_AC3_MUL1(in[4])); @@ -792,8 +797,8 @@ static void HFilter16i_SSE2(uint8_t* p, int stride, } // 8-pixels wide variant, for chroma filtering -static void VFilter8_SSE2(uint8_t* u, uint8_t* v, int stride, - int thresh, int ithresh, int hev_thresh) { +static void VFilter8_SSE2(uint8_t* WEBP_RESTRICT u, uint8_t* WEBP_RESTRICT v, + int stride, int thresh, int ithresh, int hev_thresh) { __m128i mask; __m128i t1, p2, p1, p0, q0, q1, q2; @@ -817,8 +822,8 @@ static void VFilter8_SSE2(uint8_t* u, uint8_t* v, int stride, STOREUV(q2, u, v, 2 * stride); } -static void HFilter8_SSE2(uint8_t* u, uint8_t* v, int stride, - int thresh, int ithresh, int hev_thresh) { +static void HFilter8_SSE2(uint8_t* WEBP_RESTRICT u, uint8_t* WEBP_RESTRICT v, + int stride, int thresh, int ithresh, int hev_thresh) { __m128i mask; __m128i p3, p2, p1, p0, q0, q1, q2, q3; @@ -837,7 +842,8 @@ static void HFilter8_SSE2(uint8_t* u, uint8_t* v, int stride, Store16x4_SSE2(&q0, &q1, &q2, &q3, u, v, stride); } -static void VFilter8i_SSE2(uint8_t* u, uint8_t* v, int stride, +static void VFilter8i_SSE2(uint8_t* WEBP_RESTRICT u, uint8_t* WEBP_RESTRICT v, + int stride, int thresh, int ithresh, int hev_thresh) { __m128i mask; __m128i t1, t2, p1, p0, q0, q1; @@ -863,7 +869,8 @@ static void VFilter8i_SSE2(uint8_t* u, uint8_t* v, int stride, STOREUV(q1, u, v, 1 * stride); } -static void HFilter8i_SSE2(uint8_t* u, uint8_t* v, int stride, +static void HFilter8i_SSE2(uint8_t* WEBP_RESTRICT u, uint8_t* WEBP_RESTRICT v, + int stride, int thresh, int ithresh, int hev_thresh) { __m128i mask; __m128i t1, t2, p1, p0, q0, q1; diff --git a/libwebp/src/dsp/dec_sse41.c b/libwebp/src/dsp/dec_sse41.c index 08a36302..4f514b9b 100644 --- a/libwebp/src/dsp/dec_sse41.c +++ b/libwebp/src/dsp/dec_sse41.c @@ -14,9 +14,12 @@ #include "src/dsp/dsp.h" #if defined(WEBP_USE_SSE41) - +#include #include + +#include "src/webp/types.h" #include "src/dec/vp8i_dec.h" +#include "src/dsp/cpu.h" #include "src/utils/utils.h" static void HE16_SSE41(uint8_t* dst) { // horizontal diff --git a/libwebp/src/dsp/dsp.h b/libwebp/src/dsp/dsp.h index 23bc2965..1b37ef4b 100644 --- a/libwebp/src/dsp/dsp.h +++ b/libwebp/src/dsp/dsp.h @@ -60,53 +60,66 @@ extern "C" { // Transforms // VP8Idct: Does one of two inverse transforms. If do_two is set, the transforms // will be done for (ref, in, dst) and (ref + 4, in + 16, dst + 4). -typedef void (*VP8Idct)(const uint8_t* ref, const int16_t* in, uint8_t* dst, - int do_two); -typedef void (*VP8Fdct)(const uint8_t* src, const uint8_t* ref, int16_t* out); -typedef void (*VP8WHT)(const int16_t* in, int16_t* out); +typedef void (*VP8Idct)(const uint8_t* WEBP_RESTRICT ref, + const int16_t* WEBP_RESTRICT in, + uint8_t* WEBP_RESTRICT dst, int do_two); +typedef void (*VP8Fdct)(const uint8_t* WEBP_RESTRICT src, + const uint8_t* WEBP_RESTRICT ref, + int16_t* WEBP_RESTRICT out); +typedef void (*VP8WHT)(const int16_t* WEBP_RESTRICT in, + int16_t* WEBP_RESTRICT out); extern VP8Idct VP8ITransform; extern VP8Fdct VP8FTransform; extern VP8Fdct VP8FTransform2; // performs two transforms at a time extern VP8WHT VP8FTransformWHT; // Predictions // *dst is the destination block. *top and *left can be NULL. -typedef void (*VP8IntraPreds)(uint8_t* dst, const uint8_t* left, - const uint8_t* top); -typedef void (*VP8Intra4Preds)(uint8_t* dst, const uint8_t* top); +typedef void (*VP8IntraPreds)(uint8_t* WEBP_RESTRICT dst, + const uint8_t* WEBP_RESTRICT left, + const uint8_t* WEBP_RESTRICT top); +typedef void (*VP8Intra4Preds)(uint8_t* WEBP_RESTRICT dst, + const uint8_t* WEBP_RESTRICT top); extern VP8Intra4Preds VP8EncPredLuma4; extern VP8IntraPreds VP8EncPredLuma16; extern VP8IntraPreds VP8EncPredChroma8; -typedef int (*VP8Metric)(const uint8_t* pix, const uint8_t* ref); +typedef int (*VP8Metric)(const uint8_t* WEBP_RESTRICT pix, + const uint8_t* WEBP_RESTRICT ref); extern VP8Metric VP8SSE16x16, VP8SSE16x8, VP8SSE8x8, VP8SSE4x4; -typedef int (*VP8WMetric)(const uint8_t* pix, const uint8_t* ref, - const uint16_t* const weights); +typedef int (*VP8WMetric)(const uint8_t* WEBP_RESTRICT pix, + const uint8_t* WEBP_RESTRICT ref, + const uint16_t* WEBP_RESTRICT const weights); // The weights for VP8TDisto4x4 and VP8TDisto16x16 contain a row-major // 4 by 4 symmetric matrix. extern VP8WMetric VP8TDisto4x4, VP8TDisto16x16; // Compute the average (DC) of four 4x4 blocks. // Each sub-4x4 block #i sum is stored in dc[i]. -typedef void (*VP8MeanMetric)(const uint8_t* ref, uint32_t dc[4]); +typedef void (*VP8MeanMetric)(const uint8_t* WEBP_RESTRICT ref, + uint32_t dc[4]); extern VP8MeanMetric VP8Mean16x4; -typedef void (*VP8BlockCopy)(const uint8_t* src, uint8_t* dst); +typedef void (*VP8BlockCopy)(const uint8_t* WEBP_RESTRICT src, + uint8_t* WEBP_RESTRICT dst); extern VP8BlockCopy VP8Copy4x4; extern VP8BlockCopy VP8Copy16x8; // Quantization struct VP8Matrix; // forward declaration -typedef int (*VP8QuantizeBlock)(int16_t in[16], int16_t out[16], - const struct VP8Matrix* const mtx); +typedef int (*VP8QuantizeBlock)( + int16_t in[16], int16_t out[16], + const struct VP8Matrix* WEBP_RESTRICT const mtx); // Same as VP8QuantizeBlock, but quantizes two consecutive blocks. -typedef int (*VP8Quantize2Blocks)(int16_t in[32], int16_t out[32], - const struct VP8Matrix* const mtx); +typedef int (*VP8Quantize2Blocks)( + int16_t in[32], int16_t out[32], + const struct VP8Matrix* WEBP_RESTRICT const mtx); extern VP8QuantizeBlock VP8EncQuantizeBlock; extern VP8Quantize2Blocks VP8EncQuantize2Blocks; // specific to 2nd transform: -typedef int (*VP8QuantizeBlockWHT)(int16_t in[16], int16_t out[16], - const struct VP8Matrix* const mtx); +typedef int (*VP8QuantizeBlockWHT)( + int16_t in[16], int16_t out[16], + const struct VP8Matrix* WEBP_RESTRICT const mtx); extern VP8QuantizeBlockWHT VP8EncQuantizeBlockWHT; extern const int VP8DspScan[16 + 4 + 4]; @@ -118,9 +131,10 @@ typedef struct { int max_value; int last_non_zero; } VP8Histogram; -typedef void (*VP8CHisto)(const uint8_t* ref, const uint8_t* pred, +typedef void (*VP8CHisto)(const uint8_t* WEBP_RESTRICT ref, + const uint8_t* WEBP_RESTRICT pred, int start_block, int end_block, - VP8Histogram* const histo); + VP8Histogram* WEBP_RESTRICT const histo); extern VP8CHisto VP8CollectHistogram; // General-purpose util function to help VP8CollectHistogram(). void VP8SetHistogramData(const int distribution[MAX_COEFF_THRESH + 1], @@ -138,8 +152,9 @@ extern const uint16_t VP8LevelFixedCosts[2047 /*MAX_LEVEL*/ + 1]; extern const uint8_t VP8EncBands[16 + 1]; struct VP8Residual; -typedef void (*VP8SetResidualCoeffsFunc)(const int16_t* const coeffs, - struct VP8Residual* const res); +typedef void (*VP8SetResidualCoeffsFunc)( + const int16_t* WEBP_RESTRICT const coeffs, + struct VP8Residual* WEBP_RESTRICT const res); extern VP8SetResidualCoeffsFunc VP8SetResidualCoeffs; // Cost calculation function. @@ -193,9 +208,11 @@ void VP8SSIMDspInit(void); //------------------------------------------------------------------------------ // Decoding -typedef void (*VP8DecIdct)(const int16_t* coeffs, uint8_t* dst); +typedef void (*VP8DecIdct)(const int16_t* WEBP_RESTRICT coeffs, + uint8_t* WEBP_RESTRICT dst); // when doing two transforms, coeffs is actually int16_t[2][16]. -typedef void (*VP8DecIdct2)(const int16_t* coeffs, uint8_t* dst, int do_two); +typedef void (*VP8DecIdct2)(const int16_t* WEBP_RESTRICT coeffs, + uint8_t* WEBP_RESTRICT dst, int do_two); extern VP8DecIdct2 VP8Transform; extern VP8DecIdct VP8TransformAC3; extern VP8DecIdct VP8TransformUV; @@ -233,7 +250,8 @@ extern VP8SimpleFilterFunc VP8SimpleHFilter16i; // regular filter (on both macroblock edges and inner edges) typedef void (*VP8LumaFilterFunc)(uint8_t* luma, int stride, int thresh, int ithresh, int hev_t); -typedef void (*VP8ChromaFilterFunc)(uint8_t* u, uint8_t* v, int stride, +typedef void (*VP8ChromaFilterFunc)(uint8_t* WEBP_RESTRICT u, + uint8_t* WEBP_RESTRICT v, int stride, int thresh, int ithresh, int hev_t); // on outer edge extern VP8LumaFilterFunc VP8VFilter16; @@ -253,8 +271,8 @@ extern VP8ChromaFilterFunc VP8HFilter8i; #define VP8_DITHER_DESCALE_ROUNDER (1 << (VP8_DITHER_DESCALE - 1)) #define VP8_DITHER_AMP_BITS 7 #define VP8_DITHER_AMP_CENTER (1 << VP8_DITHER_AMP_BITS) -extern void (*VP8DitherCombine8x8)(const uint8_t* dither, uint8_t* dst, - int dst_stride); +extern void (*VP8DitherCombine8x8)(const uint8_t* WEBP_RESTRICT dither, + uint8_t* WEBP_RESTRICT dst, int dst_stride); // must be called before anything using the above void VP8DspInit(void); @@ -267,10 +285,10 @@ void VP8DspInit(void); // Convert a pair of y/u/v lines together to the output rgb/a colorspace. // bottom_y can be NULL if only one line of output is needed (at top/bottom). typedef void (*WebPUpsampleLinePairFunc)( - const uint8_t* top_y, const uint8_t* bottom_y, - const uint8_t* top_u, const uint8_t* top_v, - const uint8_t* cur_u, const uint8_t* cur_v, - uint8_t* top_dst, uint8_t* bottom_dst, int len); + const uint8_t* WEBP_RESTRICT top_y, const uint8_t* WEBP_RESTRICT bottom_y, + const uint8_t* WEBP_RESTRICT top_u, const uint8_t* WEBP_RESTRICT top_v, + const uint8_t* WEBP_RESTRICT cur_u, const uint8_t* WEBP_RESTRICT cur_v, + uint8_t* WEBP_RESTRICT top_dst, uint8_t* WEBP_RESTRICT bottom_dst, int len); #ifdef FANCY_UPSAMPLING @@ -280,13 +298,15 @@ extern WebPUpsampleLinePairFunc WebPUpsamplers[/* MODE_LAST */]; #endif // FANCY_UPSAMPLING // Per-row point-sampling methods. -typedef void (*WebPSamplerRowFunc)(const uint8_t* y, - const uint8_t* u, const uint8_t* v, - uint8_t* dst, int len); +typedef void (*WebPSamplerRowFunc)(const uint8_t* WEBP_RESTRICT y, + const uint8_t* WEBP_RESTRICT u, + const uint8_t* WEBP_RESTRICT v, + uint8_t* WEBP_RESTRICT dst, int len); // Generic function to apply 'WebPSamplerRowFunc' to the whole plane: -void WebPSamplerProcessPlane(const uint8_t* y, int y_stride, - const uint8_t* u, const uint8_t* v, int uv_stride, - uint8_t* dst, int dst_stride, +void WebPSamplerProcessPlane(const uint8_t* WEBP_RESTRICT y, int y_stride, + const uint8_t* WEBP_RESTRICT u, + const uint8_t* WEBP_RESTRICT v, int uv_stride, + uint8_t* WEBP_RESTRICT dst, int dst_stride, int width, int height, WebPSamplerRowFunc func); // Sampling functions to convert rows of YUV to RGB(A) @@ -298,9 +318,10 @@ extern WebPSamplerRowFunc WebPSamplers[/* MODE_LAST */]; WebPUpsampleLinePairFunc WebPGetLinePairConverter(int alpha_is_last); // YUV444->RGB converters -typedef void (*WebPYUV444Converter)(const uint8_t* y, - const uint8_t* u, const uint8_t* v, - uint8_t* dst, int len); +typedef void (*WebPYUV444Converter)(const uint8_t* WEBP_RESTRICT y, + const uint8_t* WEBP_RESTRICT u, + const uint8_t* WEBP_RESTRICT v, + uint8_t* WEBP_RESTRICT dst, int len); extern WebPYUV444Converter WebPYUV444Converters[/* MODE_LAST */]; @@ -316,26 +337,35 @@ void WebPInitYUV444Converters(void); // ARGB -> YUV converters // Convert ARGB samples to luma Y. -extern void (*WebPConvertARGBToY)(const uint32_t* argb, uint8_t* y, int width); +extern void (*WebPConvertARGBToY)(const uint32_t* WEBP_RESTRICT argb, + uint8_t* WEBP_RESTRICT y, int width); // Convert ARGB samples to U/V with downsampling. do_store should be '1' for // even lines and '0' for odd ones. 'src_width' is the original width, not // the U/V one. -extern void (*WebPConvertARGBToUV)(const uint32_t* argb, uint8_t* u, uint8_t* v, +extern void (*WebPConvertARGBToUV)(const uint32_t* WEBP_RESTRICT argb, + uint8_t* WEBP_RESTRICT u, + uint8_t* WEBP_RESTRICT v, int src_width, int do_store); // Convert a row of accumulated (four-values) of rgba32 toward U/V -extern void (*WebPConvertRGBA32ToUV)(const uint16_t* rgb, - uint8_t* u, uint8_t* v, int width); +extern void (*WebPConvertRGBA32ToUV)(const uint16_t* WEBP_RESTRICT rgb, + uint8_t* WEBP_RESTRICT u, + uint8_t* WEBP_RESTRICT v, int width); // Convert RGB or BGR to Y -extern void (*WebPConvertRGB24ToY)(const uint8_t* rgb, uint8_t* y, int width); -extern void (*WebPConvertBGR24ToY)(const uint8_t* bgr, uint8_t* y, int width); +extern void (*WebPConvertRGB24ToY)(const uint8_t* WEBP_RESTRICT rgb, + uint8_t* WEBP_RESTRICT y, int width); +extern void (*WebPConvertBGR24ToY)(const uint8_t* WEBP_RESTRICT bgr, + uint8_t* WEBP_RESTRICT y, int width); // used for plain-C fallback. -extern void WebPConvertARGBToUV_C(const uint32_t* argb, uint8_t* u, uint8_t* v, +extern void WebPConvertARGBToUV_C(const uint32_t* WEBP_RESTRICT argb, + uint8_t* WEBP_RESTRICT u, + uint8_t* WEBP_RESTRICT v, int src_width, int do_store); -extern void WebPConvertRGBA32ToUV_C(const uint16_t* rgb, - uint8_t* u, uint8_t* v, int width); +extern void WebPConvertRGBA32ToUV_C(const uint16_t* WEBP_RESTRICT rgb, + uint8_t* WEBP_RESTRICT u, + uint8_t* WEBP_RESTRICT v, int width); // Must be called before using the above. void WebPInitConvertARGBToYUV(void); @@ -348,8 +378,9 @@ struct WebPRescaler; // Import a row of data and save its contribution in the rescaler. // 'channel' denotes the channel number to be imported. 'Expand' corresponds to // the wrk->x_expand case. Otherwise, 'Shrink' is to be used. -typedef void (*WebPRescalerImportRowFunc)(struct WebPRescaler* const wrk, - const uint8_t* src); +typedef void (*WebPRescalerImportRowFunc)( + struct WebPRescaler* WEBP_RESTRICT const wrk, + const uint8_t* WEBP_RESTRICT src); extern WebPRescalerImportRowFunc WebPRescalerImportRowExpand; extern WebPRescalerImportRowFunc WebPRescalerImportRowShrink; @@ -362,16 +393,19 @@ extern WebPRescalerExportRowFunc WebPRescalerExportRowExpand; extern WebPRescalerExportRowFunc WebPRescalerExportRowShrink; // Plain-C implementation, as fall-back. -extern void WebPRescalerImportRowExpand_C(struct WebPRescaler* const wrk, - const uint8_t* src); -extern void WebPRescalerImportRowShrink_C(struct WebPRescaler* const wrk, - const uint8_t* src); +extern void WebPRescalerImportRowExpand_C( + struct WebPRescaler* WEBP_RESTRICT const wrk, + const uint8_t* WEBP_RESTRICT src); +extern void WebPRescalerImportRowShrink_C( + struct WebPRescaler* WEBP_RESTRICT const wrk, + const uint8_t* WEBP_RESTRICT src); extern void WebPRescalerExportRowExpand_C(struct WebPRescaler* const wrk); extern void WebPRescalerExportRowShrink_C(struct WebPRescaler* const wrk); // Main entry calls: -extern void WebPRescalerImportRow(struct WebPRescaler* const wrk, - const uint8_t* src); +extern void WebPRescalerImportRow( + struct WebPRescaler* WEBP_RESTRICT const wrk, + const uint8_t* WEBP_RESTRICT src); // Export one row (starting at x_out position) from rescaler. extern void WebPRescalerExportRow(struct WebPRescaler* const wrk); @@ -480,8 +514,9 @@ typedef enum { // Filter types. WEBP_FILTER_FAST } WEBP_FILTER_TYPE; -typedef void (*WebPFilterFunc)(const uint8_t* in, int width, int height, - int stride, uint8_t* out); +typedef void (*WebPFilterFunc)(const uint8_t* WEBP_RESTRICT in, + int width, int height, int stride, + uint8_t* WEBP_RESTRICT out); // In-place un-filtering. // Warning! 'prev_line' pointer can be equal to 'cur_line' or 'preds'. typedef void (*WebPUnfilterFunc)(const uint8_t* prev_line, const uint8_t* preds, diff --git a/libwebp/src/dsp/enc.c b/libwebp/src/dsp/enc.c deleted file mode 100644 index 395ad05b..00000000 --- a/libwebp/src/dsp/enc.c +++ /dev/null @@ -1,830 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Speed-critical encoding functions. -// -// Author: Skal (pascal.massimino@gmail.com) - -#include -#include // for abs() - -#include "src/dsp/dsp.h" -#include "src/enc/vp8i_enc.h" - -static WEBP_INLINE uint8_t clip_8b(int v) { - return (!(v & ~0xff)) ? v : (v < 0) ? 0 : 255; -} - -#if !WEBP_NEON_OMIT_C_CODE -static WEBP_INLINE int clip_max(int v, int max) { - return (v > max) ? max : v; -} -#endif // !WEBP_NEON_OMIT_C_CODE - -//------------------------------------------------------------------------------ -// Compute susceptibility based on DCT-coeff histograms: -// the higher, the "easier" the macroblock is to compress. - -const int VP8DspScan[16 + 4 + 4] = { - // Luma - 0 + 0 * BPS, 4 + 0 * BPS, 8 + 0 * BPS, 12 + 0 * BPS, - 0 + 4 * BPS, 4 + 4 * BPS, 8 + 4 * BPS, 12 + 4 * BPS, - 0 + 8 * BPS, 4 + 8 * BPS, 8 + 8 * BPS, 12 + 8 * BPS, - 0 + 12 * BPS, 4 + 12 * BPS, 8 + 12 * BPS, 12 + 12 * BPS, - - 0 + 0 * BPS, 4 + 0 * BPS, 0 + 4 * BPS, 4 + 4 * BPS, // U - 8 + 0 * BPS, 12 + 0 * BPS, 8 + 4 * BPS, 12 + 4 * BPS // V -}; - -// general-purpose util function -void VP8SetHistogramData(const int distribution[MAX_COEFF_THRESH + 1], - VP8Histogram* const histo) { - int max_value = 0, last_non_zero = 1; - int k; - for (k = 0; k <= MAX_COEFF_THRESH; ++k) { - const int value = distribution[k]; - if (value > 0) { - if (value > max_value) max_value = value; - last_non_zero = k; - } - } - histo->max_value = max_value; - histo->last_non_zero = last_non_zero; -} - -#if !WEBP_NEON_OMIT_C_CODE -static void CollectHistogram_C(const uint8_t* ref, const uint8_t* pred, - int start_block, int end_block, - VP8Histogram* const histo) { - int j; - int distribution[MAX_COEFF_THRESH + 1] = { 0 }; - for (j = start_block; j < end_block; ++j) { - int k; - int16_t out[16]; - - VP8FTransform(ref + VP8DspScan[j], pred + VP8DspScan[j], out); - - // Convert coefficients to bin. - for (k = 0; k < 16; ++k) { - const int v = abs(out[k]) >> 3; - const int clipped_value = clip_max(v, MAX_COEFF_THRESH); - ++distribution[clipped_value]; - } - } - VP8SetHistogramData(distribution, histo); -} -#endif // !WEBP_NEON_OMIT_C_CODE - -//------------------------------------------------------------------------------ -// run-time tables (~4k) - -static uint8_t clip1[255 + 510 + 1]; // clips [-255,510] to [0,255] - -// We declare this variable 'volatile' to prevent instruction reordering -// and make sure it's set to true _last_ (so as to be thread-safe) -static volatile int tables_ok = 0; - -static WEBP_TSAN_IGNORE_FUNCTION void InitTables(void) { - if (!tables_ok) { - int i; - for (i = -255; i <= 255 + 255; ++i) { - clip1[255 + i] = clip_8b(i); - } - tables_ok = 1; - } -} - - -//------------------------------------------------------------------------------ -// Transforms (Paragraph 14.4) - -#if !WEBP_NEON_OMIT_C_CODE - -#define STORE(x, y, v) \ - dst[(x) + (y) * BPS] = clip_8b(ref[(x) + (y) * BPS] + ((v) >> 3)) - -static WEBP_INLINE void ITransformOne(const uint8_t* ref, const int16_t* in, - uint8_t* dst) { - int C[4 * 4], *tmp; - int i; - tmp = C; - for (i = 0; i < 4; ++i) { // vertical pass - const int a = in[0] + in[8]; - const int b = in[0] - in[8]; - const int c = - WEBP_TRANSFORM_AC3_MUL2(in[4]) - WEBP_TRANSFORM_AC3_MUL1(in[12]); - const int d = - WEBP_TRANSFORM_AC3_MUL1(in[4]) + WEBP_TRANSFORM_AC3_MUL2(in[12]); - tmp[0] = a + d; - tmp[1] = b + c; - tmp[2] = b - c; - tmp[3] = a - d; - tmp += 4; - in++; - } - - tmp = C; - for (i = 0; i < 4; ++i) { // horizontal pass - const int dc = tmp[0] + 4; - const int a = dc + tmp[8]; - const int b = dc - tmp[8]; - const int c = - WEBP_TRANSFORM_AC3_MUL2(tmp[4]) - WEBP_TRANSFORM_AC3_MUL1(tmp[12]); - const int d = - WEBP_TRANSFORM_AC3_MUL1(tmp[4]) + WEBP_TRANSFORM_AC3_MUL2(tmp[12]); - STORE(0, i, a + d); - STORE(1, i, b + c); - STORE(2, i, b - c); - STORE(3, i, a - d); - tmp++; - } -} - -static void ITransform_C(const uint8_t* ref, const int16_t* in, uint8_t* dst, - int do_two) { - ITransformOne(ref, in, dst); - if (do_two) { - ITransformOne(ref + 4, in + 16, dst + 4); - } -} - -static void FTransform_C(const uint8_t* src, const uint8_t* ref, int16_t* out) { - int i; - int tmp[16]; - for (i = 0; i < 4; ++i, src += BPS, ref += BPS) { - const int d0 = src[0] - ref[0]; // 9bit dynamic range ([-255,255]) - const int d1 = src[1] - ref[1]; - const int d2 = src[2] - ref[2]; - const int d3 = src[3] - ref[3]; - const int a0 = (d0 + d3); // 10b [-510,510] - const int a1 = (d1 + d2); - const int a2 = (d1 - d2); - const int a3 = (d0 - d3); - tmp[0 + i * 4] = (a0 + a1) * 8; // 14b [-8160,8160] - tmp[1 + i * 4] = (a2 * 2217 + a3 * 5352 + 1812) >> 9; // [-7536,7542] - tmp[2 + i * 4] = (a0 - a1) * 8; - tmp[3 + i * 4] = (a3 * 2217 - a2 * 5352 + 937) >> 9; - } - for (i = 0; i < 4; ++i) { - const int a0 = (tmp[0 + i] + tmp[12 + i]); // 15b - const int a1 = (tmp[4 + i] + tmp[ 8 + i]); - const int a2 = (tmp[4 + i] - tmp[ 8 + i]); - const int a3 = (tmp[0 + i] - tmp[12 + i]); - out[0 + i] = (a0 + a1 + 7) >> 4; // 12b - out[4 + i] = ((a2 * 2217 + a3 * 5352 + 12000) >> 16) + (a3 != 0); - out[8 + i] = (a0 - a1 + 7) >> 4; - out[12+ i] = ((a3 * 2217 - a2 * 5352 + 51000) >> 16); - } -} -#endif // !WEBP_NEON_OMIT_C_CODE - -static void FTransform2_C(const uint8_t* src, const uint8_t* ref, - int16_t* out) { - VP8FTransform(src, ref, out); - VP8FTransform(src + 4, ref + 4, out + 16); -} - -#if !WEBP_NEON_OMIT_C_CODE -static void FTransformWHT_C(const int16_t* in, int16_t* out) { - // input is 12b signed - int32_t tmp[16]; - int i; - for (i = 0; i < 4; ++i, in += 64) { - const int a0 = (in[0 * 16] + in[2 * 16]); // 13b - const int a1 = (in[1 * 16] + in[3 * 16]); - const int a2 = (in[1 * 16] - in[3 * 16]); - const int a3 = (in[0 * 16] - in[2 * 16]); - tmp[0 + i * 4] = a0 + a1; // 14b - tmp[1 + i * 4] = a3 + a2; - tmp[2 + i * 4] = a3 - a2; - tmp[3 + i * 4] = a0 - a1; - } - for (i = 0; i < 4; ++i) { - const int a0 = (tmp[0 + i] + tmp[8 + i]); // 15b - const int a1 = (tmp[4 + i] + tmp[12+ i]); - const int a2 = (tmp[4 + i] - tmp[12+ i]); - const int a3 = (tmp[0 + i] - tmp[8 + i]); - const int b0 = a0 + a1; // 16b - const int b1 = a3 + a2; - const int b2 = a3 - a2; - const int b3 = a0 - a1; - out[ 0 + i] = b0 >> 1; // 15b - out[ 4 + i] = b1 >> 1; - out[ 8 + i] = b2 >> 1; - out[12 + i] = b3 >> 1; - } -} -#endif // !WEBP_NEON_OMIT_C_CODE - -#undef STORE - -//------------------------------------------------------------------------------ -// Intra predictions - -static WEBP_INLINE void Fill(uint8_t* dst, int value, int size) { - int j; - for (j = 0; j < size; ++j) { - memset(dst + j * BPS, value, size); - } -} - -static WEBP_INLINE void VerticalPred(uint8_t* dst, - const uint8_t* top, int size) { - int j; - if (top != NULL) { - for (j = 0; j < size; ++j) memcpy(dst + j * BPS, top, size); - } else { - Fill(dst, 127, size); - } -} - -static WEBP_INLINE void HorizontalPred(uint8_t* dst, - const uint8_t* left, int size) { - if (left != NULL) { - int j; - for (j = 0; j < size; ++j) { - memset(dst + j * BPS, left[j], size); - } - } else { - Fill(dst, 129, size); - } -} - -static WEBP_INLINE void TrueMotion(uint8_t* dst, const uint8_t* left, - const uint8_t* top, int size) { - int y; - if (left != NULL) { - if (top != NULL) { - const uint8_t* const clip = clip1 + 255 - left[-1]; - for (y = 0; y < size; ++y) { - const uint8_t* const clip_table = clip + left[y]; - int x; - for (x = 0; x < size; ++x) { - dst[x] = clip_table[top[x]]; - } - dst += BPS; - } - } else { - HorizontalPred(dst, left, size); - } - } else { - // true motion without left samples (hence: with default 129 value) - // is equivalent to VE prediction where you just copy the top samples. - // Note that if top samples are not available, the default value is - // then 129, and not 127 as in the VerticalPred case. - if (top != NULL) { - VerticalPred(dst, top, size); - } else { - Fill(dst, 129, size); - } - } -} - -static WEBP_INLINE void DCMode(uint8_t* dst, const uint8_t* left, - const uint8_t* top, - int size, int round, int shift) { - int DC = 0; - int j; - if (top != NULL) { - for (j = 0; j < size; ++j) DC += top[j]; - if (left != NULL) { // top and left present - for (j = 0; j < size; ++j) DC += left[j]; - } else { // top, but no left - DC += DC; - } - DC = (DC + round) >> shift; - } else if (left != NULL) { // left but no top - for (j = 0; j < size; ++j) DC += left[j]; - DC += DC; - DC = (DC + round) >> shift; - } else { // no top, no left, nothing. - DC = 0x80; - } - Fill(dst, DC, size); -} - -//------------------------------------------------------------------------------ -// Chroma 8x8 prediction (paragraph 12.2) - -static void IntraChromaPreds_C(uint8_t* dst, const uint8_t* left, - const uint8_t* top) { - // U block - DCMode(C8DC8 + dst, left, top, 8, 8, 4); - VerticalPred(C8VE8 + dst, top, 8); - HorizontalPred(C8HE8 + dst, left, 8); - TrueMotion(C8TM8 + dst, left, top, 8); - // V block - dst += 8; - if (top != NULL) top += 8; - if (left != NULL) left += 16; - DCMode(C8DC8 + dst, left, top, 8, 8, 4); - VerticalPred(C8VE8 + dst, top, 8); - HorizontalPred(C8HE8 + dst, left, 8); - TrueMotion(C8TM8 + dst, left, top, 8); -} - -//------------------------------------------------------------------------------ -// luma 16x16 prediction (paragraph 12.3) - -static void Intra16Preds_C(uint8_t* dst, - const uint8_t* left, const uint8_t* top) { - DCMode(I16DC16 + dst, left, top, 16, 16, 5); - VerticalPred(I16VE16 + dst, top, 16); - HorizontalPred(I16HE16 + dst, left, 16); - TrueMotion(I16TM16 + dst, left, top, 16); -} - -//------------------------------------------------------------------------------ -// luma 4x4 prediction - -#define DST(x, y) dst[(x) + (y) * BPS] -#define AVG3(a, b, c) ((uint8_t)(((a) + 2 * (b) + (c) + 2) >> 2)) -#define AVG2(a, b) (((a) + (b) + 1) >> 1) - -static void VE4(uint8_t* dst, const uint8_t* top) { // vertical - const uint8_t vals[4] = { - AVG3(top[-1], top[0], top[1]), - AVG3(top[ 0], top[1], top[2]), - AVG3(top[ 1], top[2], top[3]), - AVG3(top[ 2], top[3], top[4]) - }; - int i; - for (i = 0; i < 4; ++i) { - memcpy(dst + i * BPS, vals, 4); - } -} - -static void HE4(uint8_t* dst, const uint8_t* top) { // horizontal - const int X = top[-1]; - const int I = top[-2]; - const int J = top[-3]; - const int K = top[-4]; - const int L = top[-5]; - WebPUint32ToMem(dst + 0 * BPS, 0x01010101U * AVG3(X, I, J)); - WebPUint32ToMem(dst + 1 * BPS, 0x01010101U * AVG3(I, J, K)); - WebPUint32ToMem(dst + 2 * BPS, 0x01010101U * AVG3(J, K, L)); - WebPUint32ToMem(dst + 3 * BPS, 0x01010101U * AVG3(K, L, L)); -} - -static void DC4(uint8_t* dst, const uint8_t* top) { - uint32_t dc = 4; - int i; - for (i = 0; i < 4; ++i) dc += top[i] + top[-5 + i]; - Fill(dst, dc >> 3, 4); -} - -static void RD4(uint8_t* dst, const uint8_t* top) { - const int X = top[-1]; - const int I = top[-2]; - const int J = top[-3]; - const int K = top[-4]; - const int L = top[-5]; - const int A = top[0]; - const int B = top[1]; - const int C = top[2]; - const int D = top[3]; - DST(0, 3) = AVG3(J, K, L); - DST(0, 2) = DST(1, 3) = AVG3(I, J, K); - DST(0, 1) = DST(1, 2) = DST(2, 3) = AVG3(X, I, J); - DST(0, 0) = DST(1, 1) = DST(2, 2) = DST(3, 3) = AVG3(A, X, I); - DST(1, 0) = DST(2, 1) = DST(3, 2) = AVG3(B, A, X); - DST(2, 0) = DST(3, 1) = AVG3(C, B, A); - DST(3, 0) = AVG3(D, C, B); -} - -static void LD4(uint8_t* dst, const uint8_t* top) { - const int A = top[0]; - const int B = top[1]; - const int C = top[2]; - const int D = top[3]; - const int E = top[4]; - const int F = top[5]; - const int G = top[6]; - const int H = top[7]; - DST(0, 0) = AVG3(A, B, C); - DST(1, 0) = DST(0, 1) = AVG3(B, C, D); - DST(2, 0) = DST(1, 1) = DST(0, 2) = AVG3(C, D, E); - DST(3, 0) = DST(2, 1) = DST(1, 2) = DST(0, 3) = AVG3(D, E, F); - DST(3, 1) = DST(2, 2) = DST(1, 3) = AVG3(E, F, G); - DST(3, 2) = DST(2, 3) = AVG3(F, G, H); - DST(3, 3) = AVG3(G, H, H); -} - -static void VR4(uint8_t* dst, const uint8_t* top) { - const int X = top[-1]; - const int I = top[-2]; - const int J = top[-3]; - const int K = top[-4]; - const int A = top[0]; - const int B = top[1]; - const int C = top[2]; - const int D = top[3]; - DST(0, 0) = DST(1, 2) = AVG2(X, A); - DST(1, 0) = DST(2, 2) = AVG2(A, B); - DST(2, 0) = DST(3, 2) = AVG2(B, C); - DST(3, 0) = AVG2(C, D); - - DST(0, 3) = AVG3(K, J, I); - DST(0, 2) = AVG3(J, I, X); - DST(0, 1) = DST(1, 3) = AVG3(I, X, A); - DST(1, 1) = DST(2, 3) = AVG3(X, A, B); - DST(2, 1) = DST(3, 3) = AVG3(A, B, C); - DST(3, 1) = AVG3(B, C, D); -} - -static void VL4(uint8_t* dst, const uint8_t* top) { - const int A = top[0]; - const int B = top[1]; - const int C = top[2]; - const int D = top[3]; - const int E = top[4]; - const int F = top[5]; - const int G = top[6]; - const int H = top[7]; - DST(0, 0) = AVG2(A, B); - DST(1, 0) = DST(0, 2) = AVG2(B, C); - DST(2, 0) = DST(1, 2) = AVG2(C, D); - DST(3, 0) = DST(2, 2) = AVG2(D, E); - - DST(0, 1) = AVG3(A, B, C); - DST(1, 1) = DST(0, 3) = AVG3(B, C, D); - DST(2, 1) = DST(1, 3) = AVG3(C, D, E); - DST(3, 1) = DST(2, 3) = AVG3(D, E, F); - DST(3, 2) = AVG3(E, F, G); - DST(3, 3) = AVG3(F, G, H); -} - -static void HU4(uint8_t* dst, const uint8_t* top) { - const int I = top[-2]; - const int J = top[-3]; - const int K = top[-4]; - const int L = top[-5]; - DST(0, 0) = AVG2(I, J); - DST(2, 0) = DST(0, 1) = AVG2(J, K); - DST(2, 1) = DST(0, 2) = AVG2(K, L); - DST(1, 0) = AVG3(I, J, K); - DST(3, 0) = DST(1, 1) = AVG3(J, K, L); - DST(3, 1) = DST(1, 2) = AVG3(K, L, L); - DST(3, 2) = DST(2, 2) = - DST(0, 3) = DST(1, 3) = DST(2, 3) = DST(3, 3) = L; -} - -static void HD4(uint8_t* dst, const uint8_t* top) { - const int X = top[-1]; - const int I = top[-2]; - const int J = top[-3]; - const int K = top[-4]; - const int L = top[-5]; - const int A = top[0]; - const int B = top[1]; - const int C = top[2]; - - DST(0, 0) = DST(2, 1) = AVG2(I, X); - DST(0, 1) = DST(2, 2) = AVG2(J, I); - DST(0, 2) = DST(2, 3) = AVG2(K, J); - DST(0, 3) = AVG2(L, K); - - DST(3, 0) = AVG3(A, B, C); - DST(2, 0) = AVG3(X, A, B); - DST(1, 0) = DST(3, 1) = AVG3(I, X, A); - DST(1, 1) = DST(3, 2) = AVG3(J, I, X); - DST(1, 2) = DST(3, 3) = AVG3(K, J, I); - DST(1, 3) = AVG3(L, K, J); -} - -static void TM4(uint8_t* dst, const uint8_t* top) { - int x, y; - const uint8_t* const clip = clip1 + 255 - top[-1]; - for (y = 0; y < 4; ++y) { - const uint8_t* const clip_table = clip + top[-2 - y]; - for (x = 0; x < 4; ++x) { - dst[x] = clip_table[top[x]]; - } - dst += BPS; - } -} - -#undef DST -#undef AVG3 -#undef AVG2 - -// Left samples are top[-5 .. -2], top_left is top[-1], top are -// located at top[0..3], and top right is top[4..7] -static void Intra4Preds_C(uint8_t* dst, const uint8_t* top) { - DC4(I4DC4 + dst, top); - TM4(I4TM4 + dst, top); - VE4(I4VE4 + dst, top); - HE4(I4HE4 + dst, top); - RD4(I4RD4 + dst, top); - VR4(I4VR4 + dst, top); - LD4(I4LD4 + dst, top); - VL4(I4VL4 + dst, top); - HD4(I4HD4 + dst, top); - HU4(I4HU4 + dst, top); -} - -//------------------------------------------------------------------------------ -// Metric - -#if !WEBP_NEON_OMIT_C_CODE -static WEBP_INLINE int GetSSE(const uint8_t* a, const uint8_t* b, - int w, int h) { - int count = 0; - int y, x; - for (y = 0; y < h; ++y) { - for (x = 0; x < w; ++x) { - const int diff = (int)a[x] - b[x]; - count += diff * diff; - } - a += BPS; - b += BPS; - } - return count; -} - -static int SSE16x16_C(const uint8_t* a, const uint8_t* b) { - return GetSSE(a, b, 16, 16); -} -static int SSE16x8_C(const uint8_t* a, const uint8_t* b) { - return GetSSE(a, b, 16, 8); -} -static int SSE8x8_C(const uint8_t* a, const uint8_t* b) { - return GetSSE(a, b, 8, 8); -} -static int SSE4x4_C(const uint8_t* a, const uint8_t* b) { - return GetSSE(a, b, 4, 4); -} -#endif // !WEBP_NEON_OMIT_C_CODE - -static void Mean16x4_C(const uint8_t* ref, uint32_t dc[4]) { - int k, x, y; - for (k = 0; k < 4; ++k) { - uint32_t avg = 0; - for (y = 0; y < 4; ++y) { - for (x = 0; x < 4; ++x) { - avg += ref[x + y * BPS]; - } - } - dc[k] = avg; - ref += 4; // go to next 4x4 block. - } -} - -//------------------------------------------------------------------------------ -// Texture distortion -// -// We try to match the spectral content (weighted) between source and -// reconstructed samples. - -#if !WEBP_NEON_OMIT_C_CODE -// Hadamard transform -// Returns the weighted sum of the absolute value of transformed coefficients. -// w[] contains a row-major 4 by 4 symmetric matrix. -static int TTransform(const uint8_t* in, const uint16_t* w) { - int sum = 0; - int tmp[16]; - int i; - // horizontal pass - for (i = 0; i < 4; ++i, in += BPS) { - const int a0 = in[0] + in[2]; - const int a1 = in[1] + in[3]; - const int a2 = in[1] - in[3]; - const int a3 = in[0] - in[2]; - tmp[0 + i * 4] = a0 + a1; - tmp[1 + i * 4] = a3 + a2; - tmp[2 + i * 4] = a3 - a2; - tmp[3 + i * 4] = a0 - a1; - } - // vertical pass - for (i = 0; i < 4; ++i, ++w) { - const int a0 = tmp[0 + i] + tmp[8 + i]; - const int a1 = tmp[4 + i] + tmp[12+ i]; - const int a2 = tmp[4 + i] - tmp[12+ i]; - const int a3 = tmp[0 + i] - tmp[8 + i]; - const int b0 = a0 + a1; - const int b1 = a3 + a2; - const int b2 = a3 - a2; - const int b3 = a0 - a1; - - sum += w[ 0] * abs(b0); - sum += w[ 4] * abs(b1); - sum += w[ 8] * abs(b2); - sum += w[12] * abs(b3); - } - return sum; -} - -static int Disto4x4_C(const uint8_t* const a, const uint8_t* const b, - const uint16_t* const w) { - const int sum1 = TTransform(a, w); - const int sum2 = TTransform(b, w); - return abs(sum2 - sum1) >> 5; -} - -static int Disto16x16_C(const uint8_t* const a, const uint8_t* const b, - const uint16_t* const w) { - int D = 0; - int x, y; - for (y = 0; y < 16 * BPS; y += 4 * BPS) { - for (x = 0; x < 16; x += 4) { - D += Disto4x4_C(a + x + y, b + x + y, w); - } - } - return D; -} -#endif // !WEBP_NEON_OMIT_C_CODE - -//------------------------------------------------------------------------------ -// Quantization -// - -static const uint8_t kZigzag[16] = { - 0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15 -}; - -// Simple quantization -static int QuantizeBlock_C(int16_t in[16], int16_t out[16], - const VP8Matrix* const mtx) { - int last = -1; - int n; - for (n = 0; n < 16; ++n) { - const int j = kZigzag[n]; - const int sign = (in[j] < 0); - const uint32_t coeff = (sign ? -in[j] : in[j]) + mtx->sharpen_[j]; - if (coeff > mtx->zthresh_[j]) { - const uint32_t Q = mtx->q_[j]; - const uint32_t iQ = mtx->iq_[j]; - const uint32_t B = mtx->bias_[j]; - int level = QUANTDIV(coeff, iQ, B); - if (level > MAX_LEVEL) level = MAX_LEVEL; - if (sign) level = -level; - in[j] = level * (int)Q; - out[n] = level; - if (level) last = n; - } else { - out[n] = 0; - in[j] = 0; - } - } - return (last >= 0); -} - -#if !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC -static int Quantize2Blocks_C(int16_t in[32], int16_t out[32], - const VP8Matrix* const mtx) { - int nz; - nz = VP8EncQuantizeBlock(in + 0 * 16, out + 0 * 16, mtx) << 0; - nz |= VP8EncQuantizeBlock(in + 1 * 16, out + 1 * 16, mtx) << 1; - return nz; -} -#endif // !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC - -//------------------------------------------------------------------------------ -// Block copy - -static WEBP_INLINE void Copy(const uint8_t* src, uint8_t* dst, int w, int h) { - int y; - for (y = 0; y < h; ++y) { - memcpy(dst, src, w); - src += BPS; - dst += BPS; - } -} - -static void Copy4x4_C(const uint8_t* src, uint8_t* dst) { - Copy(src, dst, 4, 4); -} - -static void Copy16x8_C(const uint8_t* src, uint8_t* dst) { - Copy(src, dst, 16, 8); -} - -//------------------------------------------------------------------------------ -// Initialization - -// Speed-critical function pointers. We have to initialize them to the default -// implementations within VP8EncDspInit(). -VP8CHisto VP8CollectHistogram; -VP8Idct VP8ITransform; -VP8Fdct VP8FTransform; -VP8Fdct VP8FTransform2; -VP8WHT VP8FTransformWHT; -VP8Intra4Preds VP8EncPredLuma4; -VP8IntraPreds VP8EncPredLuma16; -VP8IntraPreds VP8EncPredChroma8; -VP8Metric VP8SSE16x16; -VP8Metric VP8SSE8x8; -VP8Metric VP8SSE16x8; -VP8Metric VP8SSE4x4; -VP8WMetric VP8TDisto4x4; -VP8WMetric VP8TDisto16x16; -VP8MeanMetric VP8Mean16x4; -VP8QuantizeBlock VP8EncQuantizeBlock; -VP8Quantize2Blocks VP8EncQuantize2Blocks; -VP8QuantizeBlockWHT VP8EncQuantizeBlockWHT; -VP8BlockCopy VP8Copy4x4; -VP8BlockCopy VP8Copy16x8; - -extern VP8CPUInfo VP8GetCPUInfo; -extern void VP8EncDspInitSSE2(void); -extern void VP8EncDspInitSSE41(void); -extern void VP8EncDspInitNEON(void); -extern void VP8EncDspInitMIPS32(void); -extern void VP8EncDspInitMIPSdspR2(void); -extern void VP8EncDspInitMSA(void); - -WEBP_DSP_INIT_FUNC(VP8EncDspInit) { - VP8DspInit(); // common inverse transforms - InitTables(); - - // default C implementations -#if !WEBP_NEON_OMIT_C_CODE - VP8ITransform = ITransform_C; - VP8FTransform = FTransform_C; - VP8FTransformWHT = FTransformWHT_C; - VP8TDisto4x4 = Disto4x4_C; - VP8TDisto16x16 = Disto16x16_C; - VP8CollectHistogram = CollectHistogram_C; - VP8SSE16x16 = SSE16x16_C; - VP8SSE16x8 = SSE16x8_C; - VP8SSE8x8 = SSE8x8_C; - VP8SSE4x4 = SSE4x4_C; -#endif - -#if !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC - VP8EncQuantizeBlock = QuantizeBlock_C; - VP8EncQuantize2Blocks = Quantize2Blocks_C; -#endif - - VP8FTransform2 = FTransform2_C; - VP8EncPredLuma4 = Intra4Preds_C; - VP8EncPredLuma16 = Intra16Preds_C; - VP8EncPredChroma8 = IntraChromaPreds_C; - VP8Mean16x4 = Mean16x4_C; - VP8EncQuantizeBlockWHT = QuantizeBlock_C; - VP8Copy4x4 = Copy4x4_C; - VP8Copy16x8 = Copy16x8_C; - - // If defined, use CPUInfo() to overwrite some pointers with faster versions. - if (VP8GetCPUInfo != NULL) { -#if defined(WEBP_HAVE_SSE2) - if (VP8GetCPUInfo(kSSE2)) { - VP8EncDspInitSSE2(); -#if defined(WEBP_HAVE_SSE41) - if (VP8GetCPUInfo(kSSE4_1)) { - VP8EncDspInitSSE41(); - } -#endif - } -#endif -#if defined(WEBP_USE_MIPS32) - if (VP8GetCPUInfo(kMIPS32)) { - VP8EncDspInitMIPS32(); - } -#endif -#if defined(WEBP_USE_MIPS_DSP_R2) - if (VP8GetCPUInfo(kMIPSdspR2)) { - VP8EncDspInitMIPSdspR2(); - } -#endif -#if defined(WEBP_USE_MSA) - if (VP8GetCPUInfo(kMSA)) { - VP8EncDspInitMSA(); - } -#endif - } - -#if defined(WEBP_HAVE_NEON) - if (WEBP_NEON_OMIT_C_CODE || - (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) { - VP8EncDspInitNEON(); - } -#endif - - assert(VP8ITransform != NULL); - assert(VP8FTransform != NULL); - assert(VP8FTransformWHT != NULL); - assert(VP8TDisto4x4 != NULL); - assert(VP8TDisto16x16 != NULL); - assert(VP8CollectHistogram != NULL); - assert(VP8SSE16x16 != NULL); - assert(VP8SSE16x8 != NULL); - assert(VP8SSE8x8 != NULL); - assert(VP8SSE4x4 != NULL); - assert(VP8EncQuantizeBlock != NULL); - assert(VP8EncQuantize2Blocks != NULL); - assert(VP8FTransform2 != NULL); - assert(VP8EncPredLuma4 != NULL); - assert(VP8EncPredLuma16 != NULL); - assert(VP8EncPredChroma8 != NULL); - assert(VP8Mean16x4 != NULL); - assert(VP8EncQuantizeBlockWHT != NULL); - assert(VP8Copy4x4 != NULL); - assert(VP8Copy16x8 != NULL); -} diff --git a/libwebp/src/dsp/enc_mips32.c b/libwebp/src/dsp/enc_mips32.c deleted file mode 100644 index 50518a5f..00000000 --- a/libwebp/src/dsp/enc_mips32.c +++ /dev/null @@ -1,673 +0,0 @@ -// Copyright 2014 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// MIPS version of speed-critical encoding functions. -// -// Author(s): Djordje Pesut (djordje.pesut@imgtec.com) -// Jovan Zelincevic (jovan.zelincevic@imgtec.com) -// Slobodan Prijic (slobodan.prijic@imgtec.com) - -#include "src/dsp/dsp.h" - -#if defined(WEBP_USE_MIPS32) - -#include "src/dsp/mips_macro.h" -#include "src/enc/vp8i_enc.h" -#include "src/enc/cost_enc.h" - -static const int kC1 = WEBP_TRANSFORM_AC3_C1; -static const int kC2 = WEBP_TRANSFORM_AC3_C2; - -// macro for one vertical pass in ITransformOne -// MUL macro inlined -// temp0..temp15 holds tmp[0]..tmp[15] -// A..D - offsets in bytes to load from in buffer -// TEMP0..TEMP3 - registers for corresponding tmp elements -// TEMP4..TEMP5 - temporary registers -#define VERTICAL_PASS(A, B, C, D, TEMP4, TEMP0, TEMP1, TEMP2, TEMP3) \ - "lh %[temp16], " #A "(%[temp20]) \n\t" \ - "lh %[temp18], " #B "(%[temp20]) \n\t" \ - "lh %[temp17], " #C "(%[temp20]) \n\t" \ - "lh %[temp19], " #D "(%[temp20]) \n\t" \ - "addu %[" #TEMP4 "], %[temp16], %[temp18] \n\t" \ - "subu %[temp16], %[temp16], %[temp18] \n\t" \ - "mul %[" #TEMP0 "], %[temp17], %[kC2] \n\t" \ - MUL_SHIFT_C1_IO(temp17, temp18) \ - MUL_SHIFT_C1(temp18, temp19) \ - "mul %[temp19], %[temp19], %[kC2] \n\t" \ - "sra %[" #TEMP0 "], %[" #TEMP0 "], 16 \n\n" \ - "sra %[temp19], %[temp19], 16 \n\n" \ - "subu %[" #TEMP2 "], %[" #TEMP0 "], %[temp18] \n\t" \ - "addu %[" #TEMP3 "], %[temp17], %[temp19] \n\t" \ - "addu %[" #TEMP0 "], %[" #TEMP4 "], %[" #TEMP3 "] \n\t" \ - "addu %[" #TEMP1 "], %[temp16], %[" #TEMP2 "] \n\t" \ - "subu %[" #TEMP2 "], %[temp16], %[" #TEMP2 "] \n\t" \ - "subu %[" #TEMP3 "], %[" #TEMP4 "], %[" #TEMP3 "] \n\t" - -// macro for one horizontal pass in ITransformOne -// MUL and STORE macros inlined -// a = clip_8b(a) is replaced with: a = max(a, 0); a = min(a, 255) -// temp0..temp15 holds tmp[0]..tmp[15] -// A - offset in bytes to load from ref and store to dst buffer -// TEMP0, TEMP4, TEMP8 and TEMP12 - registers for corresponding tmp elements -#define HORIZONTAL_PASS(A, TEMP0, TEMP4, TEMP8, TEMP12) \ - "addiu %[" #TEMP0 "], %[" #TEMP0 "], 4 \n\t" \ - "addu %[temp16], %[" #TEMP0 "], %[" #TEMP8 "] \n\t" \ - "subu %[temp17], %[" #TEMP0 "], %[" #TEMP8 "] \n\t" \ - "mul %[" #TEMP0 "], %[" #TEMP4 "], %[kC2] \n\t" \ - MUL_SHIFT_C1_IO(TEMP4, TEMP8) \ - MUL_SHIFT_C1(TEMP8, TEMP12) \ - "mul %[" #TEMP12 "], %[" #TEMP12 "], %[kC2] \n\t" \ - "sra %[" #TEMP0 "], %[" #TEMP0 "], 16 \n\t" \ - "sra %[" #TEMP12 "], %[" #TEMP12 "], 16 \n\t" \ - "subu %[temp18], %[" #TEMP0 "], %[" #TEMP8 "] \n\t" \ - "addu %[temp19], %[" #TEMP4 "], %[" #TEMP12 "] \n\t" \ - "addu %[" #TEMP0 "], %[temp16], %[temp19] \n\t" \ - "addu %[" #TEMP4 "], %[temp17], %[temp18] \n\t" \ - "subu %[" #TEMP8 "], %[temp17], %[temp18] \n\t" \ - "subu %[" #TEMP12 "], %[temp16], %[temp19] \n\t" \ - "lw %[temp20], 0(%[args]) \n\t" \ - "sra %[" #TEMP0 "], %[" #TEMP0 "], 3 \n\t" \ - "sra %[" #TEMP4 "], %[" #TEMP4 "], 3 \n\t" \ - "sra %[" #TEMP8 "], %[" #TEMP8 "], 3 \n\t" \ - "sra %[" #TEMP12 "], %[" #TEMP12 "], 3 \n\t" \ - "lbu %[temp16], 0+" XSTR(BPS) "*" #A "(%[temp20]) \n\t" \ - "lbu %[temp17], 1+" XSTR(BPS) "*" #A "(%[temp20]) \n\t" \ - "lbu %[temp18], 2+" XSTR(BPS) "*" #A "(%[temp20]) \n\t" \ - "lbu %[temp19], 3+" XSTR(BPS) "*" #A "(%[temp20]) \n\t" \ - "addu %[" #TEMP0 "], %[temp16], %[" #TEMP0 "] \n\t" \ - "addu %[" #TEMP4 "], %[temp17], %[" #TEMP4 "] \n\t" \ - "addu %[" #TEMP8 "], %[temp18], %[" #TEMP8 "] \n\t" \ - "addu %[" #TEMP12 "], %[temp19], %[" #TEMP12 "] \n\t" \ - "slt %[temp16], %[" #TEMP0 "], $zero \n\t" \ - "slt %[temp17], %[" #TEMP4 "], $zero \n\t" \ - "slt %[temp18], %[" #TEMP8 "], $zero \n\t" \ - "slt %[temp19], %[" #TEMP12 "], $zero \n\t" \ - "movn %[" #TEMP0 "], $zero, %[temp16] \n\t" \ - "movn %[" #TEMP4 "], $zero, %[temp17] \n\t" \ - "movn %[" #TEMP8 "], $zero, %[temp18] \n\t" \ - "movn %[" #TEMP12 "], $zero, %[temp19] \n\t" \ - "addiu %[temp20], $zero, 255 \n\t" \ - "slt %[temp16], %[" #TEMP0 "], %[temp20] \n\t" \ - "slt %[temp17], %[" #TEMP4 "], %[temp20] \n\t" \ - "slt %[temp18], %[" #TEMP8 "], %[temp20] \n\t" \ - "slt %[temp19], %[" #TEMP12 "], %[temp20] \n\t" \ - "movz %[" #TEMP0 "], %[temp20], %[temp16] \n\t" \ - "movz %[" #TEMP4 "], %[temp20], %[temp17] \n\t" \ - "lw %[temp16], 8(%[args]) \n\t" \ - "movz %[" #TEMP8 "], %[temp20], %[temp18] \n\t" \ - "movz %[" #TEMP12 "], %[temp20], %[temp19] \n\t" \ - "sb %[" #TEMP0 "], 0+" XSTR(BPS) "*" #A "(%[temp16]) \n\t" \ - "sb %[" #TEMP4 "], 1+" XSTR(BPS) "*" #A "(%[temp16]) \n\t" \ - "sb %[" #TEMP8 "], 2+" XSTR(BPS) "*" #A "(%[temp16]) \n\t" \ - "sb %[" #TEMP12 "], 3+" XSTR(BPS) "*" #A "(%[temp16]) \n\t" - -// Does one or two inverse transforms. -static WEBP_INLINE void ITransformOne_MIPS32(const uint8_t* ref, - const int16_t* in, - uint8_t* dst) { - int temp0, temp1, temp2, temp3, temp4, temp5, temp6; - int temp7, temp8, temp9, temp10, temp11, temp12, temp13; - int temp14, temp15, temp16, temp17, temp18, temp19, temp20; - const int* args[3] = {(const int*)ref, (const int*)in, (const int*)dst}; - - __asm__ volatile( - "lw %[temp20], 4(%[args]) \n\t" - VERTICAL_PASS(0, 16, 8, 24, temp4, temp0, temp1, temp2, temp3) - VERTICAL_PASS(2, 18, 10, 26, temp8, temp4, temp5, temp6, temp7) - VERTICAL_PASS(4, 20, 12, 28, temp12, temp8, temp9, temp10, temp11) - VERTICAL_PASS(6, 22, 14, 30, temp20, temp12, temp13, temp14, temp15) - - HORIZONTAL_PASS(0, temp0, temp4, temp8, temp12) - HORIZONTAL_PASS(1, temp1, temp5, temp9, temp13) - HORIZONTAL_PASS(2, temp2, temp6, temp10, temp14) - HORIZONTAL_PASS(3, temp3, temp7, temp11, temp15) - - : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), - [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), - [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8), - [temp9]"=&r"(temp9), [temp10]"=&r"(temp10), [temp11]"=&r"(temp11), - [temp12]"=&r"(temp12), [temp13]"=&r"(temp13), [temp14]"=&r"(temp14), - [temp15]"=&r"(temp15), [temp16]"=&r"(temp16), [temp17]"=&r"(temp17), - [temp18]"=&r"(temp18), [temp19]"=&r"(temp19), [temp20]"=&r"(temp20) - : [args]"r"(args), [kC1]"r"(kC1), [kC2]"r"(kC2) - : "memory", "hi", "lo" - ); -} - -static void ITransform_MIPS32(const uint8_t* ref, const int16_t* in, - uint8_t* dst, int do_two) { - ITransformOne_MIPS32(ref, in, dst); - if (do_two) { - ITransformOne_MIPS32(ref + 4, in + 16, dst + 4); - } -} - -#undef VERTICAL_PASS -#undef HORIZONTAL_PASS - -// macro for one pass through for loop in QuantizeBlock -// QUANTDIV macro inlined -// J - offset in bytes (kZigzag[n] * 2) -// K - offset in bytes (kZigzag[n] * 4) -// N - offset in bytes (n * 2) -#define QUANTIZE_ONE(J, K, N) \ - "lh %[temp0], " #J "(%[ppin]) \n\t" \ - "lhu %[temp1], " #J "(%[ppsharpen]) \n\t" \ - "lw %[temp2], " #K "(%[ppzthresh]) \n\t" \ - "sra %[sign], %[temp0], 15 \n\t" \ - "xor %[coeff], %[temp0], %[sign] \n\t" \ - "subu %[coeff], %[coeff], %[sign] \n\t" \ - "addu %[coeff], %[coeff], %[temp1] \n\t" \ - "slt %[temp4], %[temp2], %[coeff] \n\t" \ - "addiu %[temp5], $zero, 0 \n\t" \ - "addiu %[level], $zero, 0 \n\t" \ - "beqz %[temp4], 2f \n\t" \ - "lhu %[temp1], " #J "(%[ppiq]) \n\t" \ - "lw %[temp2], " #K "(%[ppbias]) \n\t" \ - "lhu %[temp3], " #J "(%[ppq]) \n\t" \ - "mul %[level], %[coeff], %[temp1] \n\t" \ - "addu %[level], %[level], %[temp2] \n\t" \ - "sra %[level], %[level], 17 \n\t" \ - "slt %[temp4], %[max_level], %[level] \n\t" \ - "movn %[level], %[max_level], %[temp4] \n\t" \ - "xor %[level], %[level], %[sign] \n\t" \ - "subu %[level], %[level], %[sign] \n\t" \ - "mul %[temp5], %[level], %[temp3] \n\t" \ -"2: \n\t" \ - "sh %[temp5], " #J "(%[ppin]) \n\t" \ - "sh %[level], " #N "(%[pout]) \n\t" - -static int QuantizeBlock_MIPS32(int16_t in[16], int16_t out[16], - const VP8Matrix* const mtx) { - int temp0, temp1, temp2, temp3, temp4, temp5; - int sign, coeff, level, i; - int max_level = MAX_LEVEL; - - int16_t* ppin = &in[0]; - int16_t* pout = &out[0]; - const uint16_t* ppsharpen = &mtx->sharpen_[0]; - const uint32_t* ppzthresh = &mtx->zthresh_[0]; - const uint16_t* ppq = &mtx->q_[0]; - const uint16_t* ppiq = &mtx->iq_[0]; - const uint32_t* ppbias = &mtx->bias_[0]; - - __asm__ volatile( - QUANTIZE_ONE( 0, 0, 0) - QUANTIZE_ONE( 2, 4, 2) - QUANTIZE_ONE( 8, 16, 4) - QUANTIZE_ONE(16, 32, 6) - QUANTIZE_ONE(10, 20, 8) - QUANTIZE_ONE( 4, 8, 10) - QUANTIZE_ONE( 6, 12, 12) - QUANTIZE_ONE(12, 24, 14) - QUANTIZE_ONE(18, 36, 16) - QUANTIZE_ONE(24, 48, 18) - QUANTIZE_ONE(26, 52, 20) - QUANTIZE_ONE(20, 40, 22) - QUANTIZE_ONE(14, 28, 24) - QUANTIZE_ONE(22, 44, 26) - QUANTIZE_ONE(28, 56, 28) - QUANTIZE_ONE(30, 60, 30) - - : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), - [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), - [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), - [sign]"=&r"(sign), [coeff]"=&r"(coeff), - [level]"=&r"(level) - : [pout]"r"(pout), [ppin]"r"(ppin), - [ppiq]"r"(ppiq), [max_level]"r"(max_level), - [ppbias]"r"(ppbias), [ppzthresh]"r"(ppzthresh), - [ppsharpen]"r"(ppsharpen), [ppq]"r"(ppq) - : "memory", "hi", "lo" - ); - - // moved out from macro to increase possibility for earlier breaking - for (i = 15; i >= 0; i--) { - if (out[i]) return 1; - } - return 0; -} - -static int Quantize2Blocks_MIPS32(int16_t in[32], int16_t out[32], - const VP8Matrix* const mtx) { - int nz; - nz = QuantizeBlock_MIPS32(in + 0 * 16, out + 0 * 16, mtx) << 0; - nz |= QuantizeBlock_MIPS32(in + 1 * 16, out + 1 * 16, mtx) << 1; - return nz; -} - -#undef QUANTIZE_ONE - -// macro for one horizontal pass in Disto4x4 (TTransform) -// two calls of function TTransform are merged into single one -// A - offset in bytes to load from a and b buffers -// E..H - offsets in bytes to store first results to tmp buffer -// E1..H1 - offsets in bytes to store second results to tmp buffer -#define HORIZONTAL_PASS(A, E, F, G, H, E1, F1, G1, H1) \ - "lbu %[temp0], 0+" XSTR(BPS) "*" #A "(%[a]) \n\t" \ - "lbu %[temp1], 1+" XSTR(BPS) "*" #A "(%[a]) \n\t" \ - "lbu %[temp2], 2+" XSTR(BPS) "*" #A "(%[a]) \n\t" \ - "lbu %[temp3], 3+" XSTR(BPS) "*" #A "(%[a]) \n\t" \ - "lbu %[temp4], 0+" XSTR(BPS) "*" #A "(%[b]) \n\t" \ - "lbu %[temp5], 1+" XSTR(BPS) "*" #A "(%[b]) \n\t" \ - "lbu %[temp6], 2+" XSTR(BPS) "*" #A "(%[b]) \n\t" \ - "lbu %[temp7], 3+" XSTR(BPS) "*" #A "(%[b]) \n\t" \ - "addu %[temp8], %[temp0], %[temp2] \n\t" \ - "subu %[temp0], %[temp0], %[temp2] \n\t" \ - "addu %[temp2], %[temp1], %[temp3] \n\t" \ - "subu %[temp1], %[temp1], %[temp3] \n\t" \ - "addu %[temp3], %[temp4], %[temp6] \n\t" \ - "subu %[temp4], %[temp4], %[temp6] \n\t" \ - "addu %[temp6], %[temp5], %[temp7] \n\t" \ - "subu %[temp5], %[temp5], %[temp7] \n\t" \ - "addu %[temp7], %[temp8], %[temp2] \n\t" \ - "subu %[temp2], %[temp8], %[temp2] \n\t" \ - "addu %[temp8], %[temp0], %[temp1] \n\t" \ - "subu %[temp0], %[temp0], %[temp1] \n\t" \ - "addu %[temp1], %[temp3], %[temp6] \n\t" \ - "subu %[temp3], %[temp3], %[temp6] \n\t" \ - "addu %[temp6], %[temp4], %[temp5] \n\t" \ - "subu %[temp4], %[temp4], %[temp5] \n\t" \ - "sw %[temp7], " #E "(%[tmp]) \n\t" \ - "sw %[temp2], " #H "(%[tmp]) \n\t" \ - "sw %[temp8], " #F "(%[tmp]) \n\t" \ - "sw %[temp0], " #G "(%[tmp]) \n\t" \ - "sw %[temp1], " #E1 "(%[tmp]) \n\t" \ - "sw %[temp3], " #H1 "(%[tmp]) \n\t" \ - "sw %[temp6], " #F1 "(%[tmp]) \n\t" \ - "sw %[temp4], " #G1 "(%[tmp]) \n\t" - -// macro for one vertical pass in Disto4x4 (TTransform) -// two calls of function TTransform are merged into single one -// since only one accu is available in mips32r1 instruction set -// first is done second call of function TTransform and after -// that first one. -// const int sum1 = TTransform(a, w); -// const int sum2 = TTransform(b, w); -// return abs(sum2 - sum1) >> 5; -// (sum2 - sum1) is calculated with madds (sub2) and msubs (sub1) -// A..D - offsets in bytes to load first results from tmp buffer -// A1..D1 - offsets in bytes to load second results from tmp buffer -// E..H - offsets in bytes to load from w buffer -#define VERTICAL_PASS(A, B, C, D, A1, B1, C1, D1, E, F, G, H) \ - "lw %[temp0], " #A1 "(%[tmp]) \n\t" \ - "lw %[temp1], " #C1 "(%[tmp]) \n\t" \ - "lw %[temp2], " #B1 "(%[tmp]) \n\t" \ - "lw %[temp3], " #D1 "(%[tmp]) \n\t" \ - "addu %[temp8], %[temp0], %[temp1] \n\t" \ - "subu %[temp0], %[temp0], %[temp1] \n\t" \ - "addu %[temp1], %[temp2], %[temp3] \n\t" \ - "subu %[temp2], %[temp2], %[temp3] \n\t" \ - "addu %[temp3], %[temp8], %[temp1] \n\t" \ - "subu %[temp8], %[temp8], %[temp1] \n\t" \ - "addu %[temp1], %[temp0], %[temp2] \n\t" \ - "subu %[temp0], %[temp0], %[temp2] \n\t" \ - "sra %[temp4], %[temp3], 31 \n\t" \ - "sra %[temp5], %[temp1], 31 \n\t" \ - "sra %[temp6], %[temp0], 31 \n\t" \ - "sra %[temp7], %[temp8], 31 \n\t" \ - "xor %[temp3], %[temp3], %[temp4] \n\t" \ - "xor %[temp1], %[temp1], %[temp5] \n\t" \ - "xor %[temp0], %[temp0], %[temp6] \n\t" \ - "xor %[temp8], %[temp8], %[temp7] \n\t" \ - "subu %[temp3], %[temp3], %[temp4] \n\t" \ - "subu %[temp1], %[temp1], %[temp5] \n\t" \ - "subu %[temp0], %[temp0], %[temp6] \n\t" \ - "subu %[temp8], %[temp8], %[temp7] \n\t" \ - "lhu %[temp4], " #E "(%[w]) \n\t" \ - "lhu %[temp5], " #F "(%[w]) \n\t" \ - "lhu %[temp6], " #G "(%[w]) \n\t" \ - "lhu %[temp7], " #H "(%[w]) \n\t" \ - "madd %[temp4], %[temp3] \n\t" \ - "madd %[temp5], %[temp1] \n\t" \ - "madd %[temp6], %[temp0] \n\t" \ - "madd %[temp7], %[temp8] \n\t" \ - "lw %[temp0], " #A "(%[tmp]) \n\t" \ - "lw %[temp1], " #C "(%[tmp]) \n\t" \ - "lw %[temp2], " #B "(%[tmp]) \n\t" \ - "lw %[temp3], " #D "(%[tmp]) \n\t" \ - "addu %[temp8], %[temp0], %[temp1] \n\t" \ - "subu %[temp0], %[temp0], %[temp1] \n\t" \ - "addu %[temp1], %[temp2], %[temp3] \n\t" \ - "subu %[temp2], %[temp2], %[temp3] \n\t" \ - "addu %[temp3], %[temp8], %[temp1] \n\t" \ - "subu %[temp1], %[temp8], %[temp1] \n\t" \ - "addu %[temp8], %[temp0], %[temp2] \n\t" \ - "subu %[temp0], %[temp0], %[temp2] \n\t" \ - "sra %[temp2], %[temp3], 31 \n\t" \ - "xor %[temp3], %[temp3], %[temp2] \n\t" \ - "subu %[temp3], %[temp3], %[temp2] \n\t" \ - "msub %[temp4], %[temp3] \n\t" \ - "sra %[temp2], %[temp8], 31 \n\t" \ - "sra %[temp3], %[temp0], 31 \n\t" \ - "sra %[temp4], %[temp1], 31 \n\t" \ - "xor %[temp8], %[temp8], %[temp2] \n\t" \ - "xor %[temp0], %[temp0], %[temp3] \n\t" \ - "xor %[temp1], %[temp1], %[temp4] \n\t" \ - "subu %[temp8], %[temp8], %[temp2] \n\t" \ - "subu %[temp0], %[temp0], %[temp3] \n\t" \ - "subu %[temp1], %[temp1], %[temp4] \n\t" \ - "msub %[temp5], %[temp8] \n\t" \ - "msub %[temp6], %[temp0] \n\t" \ - "msub %[temp7], %[temp1] \n\t" - -static int Disto4x4_MIPS32(const uint8_t* const a, const uint8_t* const b, - const uint16_t* const w) { - int tmp[32]; - int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8; - - __asm__ volatile( - HORIZONTAL_PASS(0, 0, 4, 8, 12, 64, 68, 72, 76) - HORIZONTAL_PASS(1, 16, 20, 24, 28, 80, 84, 88, 92) - HORIZONTAL_PASS(2, 32, 36, 40, 44, 96, 100, 104, 108) - HORIZONTAL_PASS(3, 48, 52, 56, 60, 112, 116, 120, 124) - "mthi $zero \n\t" - "mtlo $zero \n\t" - VERTICAL_PASS( 0, 16, 32, 48, 64, 80, 96, 112, 0, 8, 16, 24) - VERTICAL_PASS( 4, 20, 36, 52, 68, 84, 100, 116, 2, 10, 18, 26) - VERTICAL_PASS( 8, 24, 40, 56, 72, 88, 104, 120, 4, 12, 20, 28) - VERTICAL_PASS(12, 28, 44, 60, 76, 92, 108, 124, 6, 14, 22, 30) - "mflo %[temp0] \n\t" - "sra %[temp1], %[temp0], 31 \n\t" - "xor %[temp0], %[temp0], %[temp1] \n\t" - "subu %[temp0], %[temp0], %[temp1] \n\t" - "sra %[temp0], %[temp0], 5 \n\t" - - : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), - [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), - [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8) - : [a]"r"(a), [b]"r"(b), [w]"r"(w), [tmp]"r"(tmp) - : "memory", "hi", "lo" - ); - - return temp0; -} - -#undef VERTICAL_PASS -#undef HORIZONTAL_PASS - -static int Disto16x16_MIPS32(const uint8_t* const a, const uint8_t* const b, - const uint16_t* const w) { - int D = 0; - int x, y; - for (y = 0; y < 16 * BPS; y += 4 * BPS) { - for (x = 0; x < 16; x += 4) { - D += Disto4x4_MIPS32(a + x + y, b + x + y, w); - } - } - return D; -} - -// macro for one horizontal pass in FTransform -// temp0..temp15 holds tmp[0]..tmp[15] -// A - offset in bytes to load from src and ref buffers -// TEMP0..TEMP3 - registers for corresponding tmp elements -#define HORIZONTAL_PASS(A, TEMP0, TEMP1, TEMP2, TEMP3) \ - "lw %[" #TEMP1 "], 0(%[args]) \n\t" \ - "lw %[" #TEMP2 "], 4(%[args]) \n\t" \ - "lbu %[temp16], 0+" XSTR(BPS) "*" #A "(%[" #TEMP1 "]) \n\t" \ - "lbu %[temp17], 0+" XSTR(BPS) "*" #A "(%[" #TEMP2 "]) \n\t" \ - "lbu %[temp18], 1+" XSTR(BPS) "*" #A "(%[" #TEMP1 "]) \n\t" \ - "lbu %[temp19], 1+" XSTR(BPS) "*" #A "(%[" #TEMP2 "]) \n\t" \ - "subu %[temp20], %[temp16], %[temp17] \n\t" \ - "lbu %[temp16], 2+" XSTR(BPS) "*" #A "(%[" #TEMP1 "]) \n\t" \ - "lbu %[temp17], 2+" XSTR(BPS) "*" #A "(%[" #TEMP2 "]) \n\t" \ - "subu %[" #TEMP0 "], %[temp18], %[temp19] \n\t" \ - "lbu %[temp18], 3+" XSTR(BPS) "*" #A "(%[" #TEMP1 "]) \n\t" \ - "lbu %[temp19], 3+" XSTR(BPS) "*" #A "(%[" #TEMP2 "]) \n\t" \ - "subu %[" #TEMP1 "], %[temp16], %[temp17] \n\t" \ - "subu %[" #TEMP2 "], %[temp18], %[temp19] \n\t" \ - "addu %[" #TEMP3 "], %[temp20], %[" #TEMP2 "] \n\t" \ - "subu %[" #TEMP2 "], %[temp20], %[" #TEMP2 "] \n\t" \ - "addu %[temp20], %[" #TEMP0 "], %[" #TEMP1 "] \n\t" \ - "subu %[" #TEMP0 "], %[" #TEMP0 "], %[" #TEMP1 "] \n\t" \ - "mul %[temp16], %[" #TEMP2 "], %[c5352] \n\t" \ - "mul %[temp17], %[" #TEMP2 "], %[c2217] \n\t" \ - "mul %[temp18], %[" #TEMP0 "], %[c5352] \n\t" \ - "mul %[temp19], %[" #TEMP0 "], %[c2217] \n\t" \ - "addu %[" #TEMP1 "], %[" #TEMP3 "], %[temp20] \n\t" \ - "subu %[temp20], %[" #TEMP3 "], %[temp20] \n\t" \ - "sll %[" #TEMP0 "], %[" #TEMP1 "], 3 \n\t" \ - "sll %[" #TEMP2 "], %[temp20], 3 \n\t" \ - "addiu %[temp16], %[temp16], 1812 \n\t" \ - "addiu %[temp17], %[temp17], 937 \n\t" \ - "addu %[temp16], %[temp16], %[temp19] \n\t" \ - "subu %[temp17], %[temp17], %[temp18] \n\t" \ - "sra %[" #TEMP1 "], %[temp16], 9 \n\t" \ - "sra %[" #TEMP3 "], %[temp17], 9 \n\t" - -// macro for one vertical pass in FTransform -// temp0..temp15 holds tmp[0]..tmp[15] -// A..D - offsets in bytes to store to out buffer -// TEMP0, TEMP4, TEMP8 and TEMP12 - registers for corresponding tmp elements -#define VERTICAL_PASS(A, B, C, D, TEMP0, TEMP4, TEMP8, TEMP12) \ - "addu %[temp16], %[" #TEMP0 "], %[" #TEMP12 "] \n\t" \ - "subu %[temp19], %[" #TEMP0 "], %[" #TEMP12 "] \n\t" \ - "addu %[temp17], %[" #TEMP4 "], %[" #TEMP8 "] \n\t" \ - "subu %[temp18], %[" #TEMP4 "], %[" #TEMP8 "] \n\t" \ - "mul %[" #TEMP8 "], %[temp19], %[c2217] \n\t" \ - "mul %[" #TEMP12 "], %[temp18], %[c2217] \n\t" \ - "mul %[" #TEMP4 "], %[temp19], %[c5352] \n\t" \ - "mul %[temp18], %[temp18], %[c5352] \n\t" \ - "addiu %[temp16], %[temp16], 7 \n\t" \ - "addu %[" #TEMP0 "], %[temp16], %[temp17] \n\t" \ - "sra %[" #TEMP0 "], %[" #TEMP0 "], 4 \n\t" \ - "addu %[" #TEMP12 "], %[" #TEMP12 "], %[" #TEMP4 "] \n\t" \ - "subu %[" #TEMP4 "], %[temp16], %[temp17] \n\t" \ - "sra %[" #TEMP4 "], %[" #TEMP4 "], 4 \n\t" \ - "addiu %[" #TEMP8 "], %[" #TEMP8 "], 30000 \n\t" \ - "addiu %[" #TEMP12 "], %[" #TEMP12 "], 12000 \n\t" \ - "addiu %[" #TEMP8 "], %[" #TEMP8 "], 21000 \n\t" \ - "subu %[" #TEMP8 "], %[" #TEMP8 "], %[temp18] \n\t" \ - "sra %[" #TEMP12 "], %[" #TEMP12 "], 16 \n\t" \ - "sra %[" #TEMP8 "], %[" #TEMP8 "], 16 \n\t" \ - "addiu %[temp16], %[" #TEMP12 "], 1 \n\t" \ - "movn %[" #TEMP12 "], %[temp16], %[temp19] \n\t" \ - "sh %[" #TEMP0 "], " #A "(%[temp20]) \n\t" \ - "sh %[" #TEMP4 "], " #C "(%[temp20]) \n\t" \ - "sh %[" #TEMP8 "], " #D "(%[temp20]) \n\t" \ - "sh %[" #TEMP12 "], " #B "(%[temp20]) \n\t" - -static void FTransform_MIPS32(const uint8_t* src, const uint8_t* ref, - int16_t* out) { - int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8; - int temp9, temp10, temp11, temp12, temp13, temp14, temp15, temp16; - int temp17, temp18, temp19, temp20; - const int c2217 = 2217; - const int c5352 = 5352; - const int* const args[3] = - { (const int*)src, (const int*)ref, (const int*)out }; - - __asm__ volatile( - HORIZONTAL_PASS(0, temp0, temp1, temp2, temp3) - HORIZONTAL_PASS(1, temp4, temp5, temp6, temp7) - HORIZONTAL_PASS(2, temp8, temp9, temp10, temp11) - HORIZONTAL_PASS(3, temp12, temp13, temp14, temp15) - "lw %[temp20], 8(%[args]) \n\t" - VERTICAL_PASS(0, 8, 16, 24, temp0, temp4, temp8, temp12) - VERTICAL_PASS(2, 10, 18, 26, temp1, temp5, temp9, temp13) - VERTICAL_PASS(4, 12, 20, 28, temp2, temp6, temp10, temp14) - VERTICAL_PASS(6, 14, 22, 30, temp3, temp7, temp11, temp15) - - : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), - [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), - [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8), - [temp9]"=&r"(temp9), [temp10]"=&r"(temp10), [temp11]"=&r"(temp11), - [temp12]"=&r"(temp12), [temp13]"=&r"(temp13), [temp14]"=&r"(temp14), - [temp15]"=&r"(temp15), [temp16]"=&r"(temp16), [temp17]"=&r"(temp17), - [temp18]"=&r"(temp18), [temp19]"=&r"(temp19), [temp20]"=&r"(temp20) - : [args]"r"(args), [c2217]"r"(c2217), [c5352]"r"(c5352) - : "memory", "hi", "lo" - ); -} - -#undef VERTICAL_PASS -#undef HORIZONTAL_PASS - -#if !defined(WORK_AROUND_GCC) - -#define GET_SSE_INNER(A, B, C, D) \ - "lbu %[temp0], " #A "(%[a]) \n\t" \ - "lbu %[temp1], " #A "(%[b]) \n\t" \ - "lbu %[temp2], " #B "(%[a]) \n\t" \ - "lbu %[temp3], " #B "(%[b]) \n\t" \ - "lbu %[temp4], " #C "(%[a]) \n\t" \ - "lbu %[temp5], " #C "(%[b]) \n\t" \ - "lbu %[temp6], " #D "(%[a]) \n\t" \ - "lbu %[temp7], " #D "(%[b]) \n\t" \ - "subu %[temp0], %[temp0], %[temp1] \n\t" \ - "subu %[temp2], %[temp2], %[temp3] \n\t" \ - "subu %[temp4], %[temp4], %[temp5] \n\t" \ - "subu %[temp6], %[temp6], %[temp7] \n\t" \ - "madd %[temp0], %[temp0] \n\t" \ - "madd %[temp2], %[temp2] \n\t" \ - "madd %[temp4], %[temp4] \n\t" \ - "madd %[temp6], %[temp6] \n\t" - -#define GET_SSE(A, B, C, D) \ - GET_SSE_INNER(A, A + 1, A + 2, A + 3) \ - GET_SSE_INNER(B, B + 1, B + 2, B + 3) \ - GET_SSE_INNER(C, C + 1, C + 2, C + 3) \ - GET_SSE_INNER(D, D + 1, D + 2, D + 3) - -static int SSE16x16_MIPS32(const uint8_t* a, const uint8_t* b) { - int count; - int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7; - - __asm__ volatile( - "mult $zero, $zero \n\t" - - GET_SSE( 0 * BPS, 4 + 0 * BPS, 8 + 0 * BPS, 12 + 0 * BPS) - GET_SSE( 1 * BPS, 4 + 1 * BPS, 8 + 1 * BPS, 12 + 1 * BPS) - GET_SSE( 2 * BPS, 4 + 2 * BPS, 8 + 2 * BPS, 12 + 2 * BPS) - GET_SSE( 3 * BPS, 4 + 3 * BPS, 8 + 3 * BPS, 12 + 3 * BPS) - GET_SSE( 4 * BPS, 4 + 4 * BPS, 8 + 4 * BPS, 12 + 4 * BPS) - GET_SSE( 5 * BPS, 4 + 5 * BPS, 8 + 5 * BPS, 12 + 5 * BPS) - GET_SSE( 6 * BPS, 4 + 6 * BPS, 8 + 6 * BPS, 12 + 6 * BPS) - GET_SSE( 7 * BPS, 4 + 7 * BPS, 8 + 7 * BPS, 12 + 7 * BPS) - GET_SSE( 8 * BPS, 4 + 8 * BPS, 8 + 8 * BPS, 12 + 8 * BPS) - GET_SSE( 9 * BPS, 4 + 9 * BPS, 8 + 9 * BPS, 12 + 9 * BPS) - GET_SSE(10 * BPS, 4 + 10 * BPS, 8 + 10 * BPS, 12 + 10 * BPS) - GET_SSE(11 * BPS, 4 + 11 * BPS, 8 + 11 * BPS, 12 + 11 * BPS) - GET_SSE(12 * BPS, 4 + 12 * BPS, 8 + 12 * BPS, 12 + 12 * BPS) - GET_SSE(13 * BPS, 4 + 13 * BPS, 8 + 13 * BPS, 12 + 13 * BPS) - GET_SSE(14 * BPS, 4 + 14 * BPS, 8 + 14 * BPS, 12 + 14 * BPS) - GET_SSE(15 * BPS, 4 + 15 * BPS, 8 + 15 * BPS, 12 + 15 * BPS) - - "mflo %[count] \n\t" - : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), - [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), - [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [count]"=&r"(count) - : [a]"r"(a), [b]"r"(b) - : "memory", "hi", "lo" - ); - return count; -} - -static int SSE16x8_MIPS32(const uint8_t* a, const uint8_t* b) { - int count; - int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7; - - __asm__ volatile( - "mult $zero, $zero \n\t" - - GET_SSE( 0 * BPS, 4 + 0 * BPS, 8 + 0 * BPS, 12 + 0 * BPS) - GET_SSE( 1 * BPS, 4 + 1 * BPS, 8 + 1 * BPS, 12 + 1 * BPS) - GET_SSE( 2 * BPS, 4 + 2 * BPS, 8 + 2 * BPS, 12 + 2 * BPS) - GET_SSE( 3 * BPS, 4 + 3 * BPS, 8 + 3 * BPS, 12 + 3 * BPS) - GET_SSE( 4 * BPS, 4 + 4 * BPS, 8 + 4 * BPS, 12 + 4 * BPS) - GET_SSE( 5 * BPS, 4 + 5 * BPS, 8 + 5 * BPS, 12 + 5 * BPS) - GET_SSE( 6 * BPS, 4 + 6 * BPS, 8 + 6 * BPS, 12 + 6 * BPS) - GET_SSE( 7 * BPS, 4 + 7 * BPS, 8 + 7 * BPS, 12 + 7 * BPS) - - "mflo %[count] \n\t" - : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), - [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), - [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [count]"=&r"(count) - : [a]"r"(a), [b]"r"(b) - : "memory", "hi", "lo" - ); - return count; -} - -static int SSE8x8_MIPS32(const uint8_t* a, const uint8_t* b) { - int count; - int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7; - - __asm__ volatile( - "mult $zero, $zero \n\t" - - GET_SSE(0 * BPS, 4 + 0 * BPS, 1 * BPS, 4 + 1 * BPS) - GET_SSE(2 * BPS, 4 + 2 * BPS, 3 * BPS, 4 + 3 * BPS) - GET_SSE(4 * BPS, 4 + 4 * BPS, 5 * BPS, 4 + 5 * BPS) - GET_SSE(6 * BPS, 4 + 6 * BPS, 7 * BPS, 4 + 7 * BPS) - - "mflo %[count] \n\t" - : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), - [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), - [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [count]"=&r"(count) - : [a]"r"(a), [b]"r"(b) - : "memory", "hi", "lo" - ); - return count; -} - -static int SSE4x4_MIPS32(const uint8_t* a, const uint8_t* b) { - int count; - int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7; - - __asm__ volatile( - "mult $zero, $zero \n\t" - - GET_SSE(0 * BPS, 1 * BPS, 2 * BPS, 3 * BPS) - - "mflo %[count] \n\t" - : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), - [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), - [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [count]"=&r"(count) - : [a]"r"(a), [b]"r"(b) - : "memory", "hi", "lo" - ); - return count; -} - -#undef GET_SSE -#undef GET_SSE_INNER - -#endif // !WORK_AROUND_GCC - -//------------------------------------------------------------------------------ -// Entry point - -extern void VP8EncDspInitMIPS32(void); - -WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspInitMIPS32(void) { - VP8ITransform = ITransform_MIPS32; - VP8FTransform = FTransform_MIPS32; - - VP8EncQuantizeBlock = QuantizeBlock_MIPS32; - VP8EncQuantize2Blocks = Quantize2Blocks_MIPS32; - - VP8TDisto4x4 = Disto4x4_MIPS32; - VP8TDisto16x16 = Disto16x16_MIPS32; - -#if !defined(WORK_AROUND_GCC) - VP8SSE16x16 = SSE16x16_MIPS32; - VP8SSE8x8 = SSE8x8_MIPS32; - VP8SSE16x8 = SSE16x8_MIPS32; - VP8SSE4x4 = SSE4x4_MIPS32; -#endif -} - -#else // !WEBP_USE_MIPS32 - -WEBP_DSP_INIT_STUB(VP8EncDspInitMIPS32) - -#endif // WEBP_USE_MIPS32 diff --git a/libwebp/src/dsp/enc_mips_dsp_r2.c b/libwebp/src/dsp/enc_mips_dsp_r2.c deleted file mode 100644 index e1431f3b..00000000 --- a/libwebp/src/dsp/enc_mips_dsp_r2.c +++ /dev/null @@ -1,1517 +0,0 @@ -// Copyright 2014 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// MIPS version of speed-critical encoding functions. -// -// Author(s): Darko Laus (darko.laus@imgtec.com) -// Mirko Raus (mirko.raus@imgtec.com) - -#include "src/dsp/dsp.h" - -#if defined(WEBP_USE_MIPS_DSP_R2) - -#include "src/dsp/mips_macro.h" -#include "src/enc/cost_enc.h" -#include "src/enc/vp8i_enc.h" - -static const int kC1 = WEBP_TRANSFORM_AC3_C1; -static const int kC2 = WEBP_TRANSFORM_AC3_C2; - -// O - output -// I - input (macro doesn't change it) -#define ADD_SUB_HALVES_X4(O0, O1, O2, O3, O4, O5, O6, O7, \ - I0, I1, I2, I3, I4, I5, I6, I7) \ - "addq.ph %[" #O0 "], %[" #I0 "], %[" #I1 "] \n\t" \ - "subq.ph %[" #O1 "], %[" #I0 "], %[" #I1 "] \n\t" \ - "addq.ph %[" #O2 "], %[" #I2 "], %[" #I3 "] \n\t" \ - "subq.ph %[" #O3 "], %[" #I2 "], %[" #I3 "] \n\t" \ - "addq.ph %[" #O4 "], %[" #I4 "], %[" #I5 "] \n\t" \ - "subq.ph %[" #O5 "], %[" #I4 "], %[" #I5 "] \n\t" \ - "addq.ph %[" #O6 "], %[" #I6 "], %[" #I7 "] \n\t" \ - "subq.ph %[" #O7 "], %[" #I6 "], %[" #I7 "] \n\t" - -// IO - input/output -#define ABS_X8(IO0, IO1, IO2, IO3, IO4, IO5, IO6, IO7) \ - "absq_s.ph %[" #IO0 "], %[" #IO0 "] \n\t" \ - "absq_s.ph %[" #IO1 "], %[" #IO1 "] \n\t" \ - "absq_s.ph %[" #IO2 "], %[" #IO2 "] \n\t" \ - "absq_s.ph %[" #IO3 "], %[" #IO3 "] \n\t" \ - "absq_s.ph %[" #IO4 "], %[" #IO4 "] \n\t" \ - "absq_s.ph %[" #IO5 "], %[" #IO5 "] \n\t" \ - "absq_s.ph %[" #IO6 "], %[" #IO6 "] \n\t" \ - "absq_s.ph %[" #IO7 "], %[" #IO7 "] \n\t" - -// dpa.w.ph $ac0 temp0 ,temp1 -// $ac += temp0[31..16] * temp1[31..16] + temp0[15..0] * temp1[15..0] -// dpax.w.ph $ac0 temp0 ,temp1 -// $ac += temp0[31..16] * temp1[15..0] + temp0[15..0] * temp1[31..16] -// O - output -// I - input (macro doesn't change it) -#define MUL_HALF(O0, I0, I1, I2, I3, I4, I5, I6, I7, \ - I8, I9, I10, I11, I12, I13, I14, I15) \ - "mult $ac0, $zero, $zero \n\t" \ - "dpa.w.ph $ac0, %[" #I2 "], %[" #I0 "] \n\t" \ - "dpax.w.ph $ac0, %[" #I5 "], %[" #I6 "] \n\t" \ - "dpa.w.ph $ac0, %[" #I8 "], %[" #I9 "] \n\t" \ - "dpax.w.ph $ac0, %[" #I11 "], %[" #I4 "] \n\t" \ - "dpa.w.ph $ac0, %[" #I12 "], %[" #I7 "] \n\t" \ - "dpax.w.ph $ac0, %[" #I13 "], %[" #I1 "] \n\t" \ - "dpa.w.ph $ac0, %[" #I14 "], %[" #I3 "] \n\t" \ - "dpax.w.ph $ac0, %[" #I15 "], %[" #I10 "] \n\t" \ - "mflo %[" #O0 "], $ac0 \n\t" - -#define OUTPUT_EARLY_CLOBBER_REGS_17() \ - OUTPUT_EARLY_CLOBBER_REGS_10(), \ - [temp11]"=&r"(temp11), [temp12]"=&r"(temp12), [temp13]"=&r"(temp13), \ - [temp14]"=&r"(temp14), [temp15]"=&r"(temp15), [temp16]"=&r"(temp16), \ - [temp17]"=&r"(temp17) - -// macro for one horizontal pass in FTransform -// temp0..temp15 holds tmp[0]..tmp[15] -// A - offset in bytes to load from src and ref buffers -// TEMP0..TEMP3 - registers for corresponding tmp elements -#define HORIZONTAL_PASS(A, TEMP0, TEMP1, TEMP2, TEMP3) \ - "lw %[" #TEMP0 "], 0(%[args]) \n\t" \ - "lw %[" #TEMP1 "], 4(%[args]) \n\t" \ - "lw %[" #TEMP2 "], " XSTR(BPS) "*" #A "(%[" #TEMP0 "]) \n\t" \ - "lw %[" #TEMP3 "], " XSTR(BPS) "*" #A "(%[" #TEMP1 "]) \n\t" \ - "preceu.ph.qbl %[" #TEMP0 "], %[" #TEMP2 "] \n\t" \ - "preceu.ph.qbl %[" #TEMP1 "], %[" #TEMP3 "] \n\t" \ - "preceu.ph.qbr %[" #TEMP2 "], %[" #TEMP2 "] \n\t" \ - "preceu.ph.qbr %[" #TEMP3 "], %[" #TEMP3 "] \n\t" \ - "subq.ph %[" #TEMP0 "], %[" #TEMP0 "], %[" #TEMP1 "] \n\t" \ - "subq.ph %[" #TEMP2 "], %[" #TEMP2 "], %[" #TEMP3 "] \n\t" \ - "rotr %[" #TEMP0 "], %[" #TEMP0 "], 16 \n\t" \ - "addq.ph %[" #TEMP1 "], %[" #TEMP2 "], %[" #TEMP0 "] \n\t" \ - "subq.ph %[" #TEMP3 "], %[" #TEMP2 "], %[" #TEMP0 "] \n\t" \ - "seh %[" #TEMP0 "], %[" #TEMP1 "] \n\t" \ - "sra %[temp16], %[" #TEMP1 "], 16 \n\t" \ - "seh %[temp19], %[" #TEMP3 "] \n\t" \ - "sra %[" #TEMP3 "], %[" #TEMP3 "], 16 \n\t" \ - "subu %[" #TEMP2 "], %[" #TEMP0 "], %[temp16] \n\t" \ - "addu %[" #TEMP0 "], %[" #TEMP0 "], %[temp16] \n\t" \ - "mul %[temp17], %[temp19], %[c2217] \n\t" \ - "mul %[temp18], %[" #TEMP3 "], %[c5352] \n\t" \ - "mul %[" #TEMP1 "], %[temp19], %[c5352] \n\t" \ - "mul %[temp16], %[" #TEMP3 "], %[c2217] \n\t" \ - "sll %[" #TEMP2 "], %[" #TEMP2 "], 3 \n\t" \ - "sll %[" #TEMP0 "], %[" #TEMP0 "], 3 \n\t" \ - "subu %[" #TEMP3 "], %[temp17], %[temp18] \n\t" \ - "addu %[" #TEMP1 "], %[temp16], %[" #TEMP1 "] \n\t" \ - "addiu %[" #TEMP3 "], %[" #TEMP3 "], 937 \n\t" \ - "addiu %[" #TEMP1 "], %[" #TEMP1 "], 1812 \n\t" \ - "sra %[" #TEMP3 "], %[" #TEMP3 "], 9 \n\t" \ - "sra %[" #TEMP1 "], %[" #TEMP1 "], 9 \n\t" - -// macro for one vertical pass in FTransform -// temp0..temp15 holds tmp[0]..tmp[15] -// A..D - offsets in bytes to store to out buffer -// TEMP0, TEMP4, TEMP8 and TEMP12 - registers for corresponding tmp elements -#define VERTICAL_PASS(A, B, C, D, TEMP0, TEMP4, TEMP8, TEMP12) \ - "addu %[temp16], %[" #TEMP0 "], %[" #TEMP12 "] \n\t" \ - "subu %[temp19], %[" #TEMP0 "], %[" #TEMP12 "] \n\t" \ - "addu %[temp17], %[" #TEMP4 "], %[" #TEMP8 "] \n\t" \ - "subu %[temp18], %[" #TEMP4 "], %[" #TEMP8 "] \n\t" \ - "mul %[" #TEMP8 "], %[temp19], %[c2217] \n\t" \ - "mul %[" #TEMP12 "], %[temp18], %[c2217] \n\t" \ - "mul %[" #TEMP4 "], %[temp19], %[c5352] \n\t" \ - "mul %[temp18], %[temp18], %[c5352] \n\t" \ - "addiu %[temp16], %[temp16], 7 \n\t" \ - "addu %[" #TEMP0 "], %[temp16], %[temp17] \n\t" \ - "sra %[" #TEMP0 "], %[" #TEMP0 "], 4 \n\t" \ - "addu %[" #TEMP12 "], %[" #TEMP12 "], %[" #TEMP4 "] \n\t" \ - "subu %[" #TEMP4 "], %[temp16], %[temp17] \n\t" \ - "sra %[" #TEMP4 "], %[" #TEMP4 "], 4 \n\t" \ - "addiu %[" #TEMP8 "], %[" #TEMP8 "], 30000 \n\t" \ - "addiu %[" #TEMP12 "], %[" #TEMP12 "], 12000 \n\t" \ - "addiu %[" #TEMP8 "], %[" #TEMP8 "], 21000 \n\t" \ - "subu %[" #TEMP8 "], %[" #TEMP8 "], %[temp18] \n\t" \ - "sra %[" #TEMP12 "], %[" #TEMP12 "], 16 \n\t" \ - "sra %[" #TEMP8 "], %[" #TEMP8 "], 16 \n\t" \ - "addiu %[temp16], %[" #TEMP12 "], 1 \n\t" \ - "movn %[" #TEMP12 "], %[temp16], %[temp19] \n\t" \ - "sh %[" #TEMP0 "], " #A "(%[temp20]) \n\t" \ - "sh %[" #TEMP4 "], " #C "(%[temp20]) \n\t" \ - "sh %[" #TEMP8 "], " #D "(%[temp20]) \n\t" \ - "sh %[" #TEMP12 "], " #B "(%[temp20]) \n\t" - -static void FTransform_MIPSdspR2(const uint8_t* src, const uint8_t* ref, - int16_t* out) { - const int c2217 = 2217; - const int c5352 = 5352; - int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8; - int temp9, temp10, temp11, temp12, temp13, temp14, temp15, temp16; - int temp17, temp18, temp19, temp20; - const int* const args[3] = - { (const int*)src, (const int*)ref, (const int*)out }; - - __asm__ volatile ( - HORIZONTAL_PASS(0, temp0, temp1, temp2, temp3) - HORIZONTAL_PASS(1, temp4, temp5, temp6, temp7) - HORIZONTAL_PASS(2, temp8, temp9, temp10, temp11) - HORIZONTAL_PASS(3, temp12, temp13, temp14, temp15) - "lw %[temp20], 8(%[args]) \n\t" - VERTICAL_PASS(0, 8, 16, 24, temp0, temp4, temp8, temp12) - VERTICAL_PASS(2, 10, 18, 26, temp1, temp5, temp9, temp13) - VERTICAL_PASS(4, 12, 20, 28, temp2, temp6, temp10, temp14) - VERTICAL_PASS(6, 14, 22, 30, temp3, temp7, temp11, temp15) - OUTPUT_EARLY_CLOBBER_REGS_18(), - [temp0]"=&r"(temp0), [temp19]"=&r"(temp19), [temp20]"=&r"(temp20) - : [args]"r"(args), [c2217]"r"(c2217), [c5352]"r"(c5352) - : "memory", "hi", "lo" - ); -} - -#undef VERTICAL_PASS -#undef HORIZONTAL_PASS - -static WEBP_INLINE void ITransformOne(const uint8_t* ref, const int16_t* in, - uint8_t* dst) { - int temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8, temp9; - int temp10, temp11, temp12, temp13, temp14, temp15, temp16, temp17, temp18; - - __asm__ volatile ( - "ulw %[temp1], 0(%[in]) \n\t" - "ulw %[temp2], 16(%[in]) \n\t" - LOAD_IN_X2(temp5, temp6, 24, 26) - ADD_SUB_HALVES(temp3, temp4, temp1, temp2) - LOAD_IN_X2(temp1, temp2, 8, 10) - MUL_SHIFT_SUM(temp7, temp8, temp9, temp10, temp11, temp12, temp13, temp14, - temp10, temp8, temp9, temp7, temp1, temp2, temp5, temp6, - temp13, temp11, temp14, temp12) - INSERT_HALF_X2(temp8, temp7, temp10, temp9) - "ulw %[temp17], 4(%[in]) \n\t" - "ulw %[temp18], 20(%[in]) \n\t" - ADD_SUB_HALVES(temp1, temp2, temp3, temp8) - ADD_SUB_HALVES(temp5, temp6, temp4, temp7) - ADD_SUB_HALVES(temp7, temp8, temp17, temp18) - LOAD_IN_X2(temp17, temp18, 12, 14) - LOAD_IN_X2(temp9, temp10, 28, 30) - MUL_SHIFT_SUM(temp11, temp12, temp13, temp14, temp15, temp16, temp4, temp17, - temp12, temp14, temp11, temp13, temp17, temp18, temp9, temp10, - temp15, temp4, temp16, temp17) - INSERT_HALF_X2(temp11, temp12, temp13, temp14) - ADD_SUB_HALVES(temp17, temp8, temp8, temp11) - ADD_SUB_HALVES(temp3, temp4, temp7, temp12) - - // horizontal - SRA_16(temp9, temp10, temp11, temp12, temp1, temp2, temp5, temp6) - INSERT_HALF_X2(temp1, temp6, temp5, temp2) - SRA_16(temp13, temp14, temp15, temp16, temp3, temp4, temp17, temp8) - "repl.ph %[temp2], 0x4 \n\t" - INSERT_HALF_X2(temp3, temp8, temp17, temp4) - "addq.ph %[temp1], %[temp1], %[temp2] \n\t" - "addq.ph %[temp6], %[temp6], %[temp2] \n\t" - ADD_SUB_HALVES(temp2, temp4, temp1, temp3) - ADD_SUB_HALVES(temp5, temp7, temp6, temp8) - MUL_SHIFT_SUM(temp1, temp3, temp6, temp8, temp9, temp13, temp17, temp18, - temp3, temp13, temp1, temp9, temp9, temp13, temp11, temp15, - temp6, temp17, temp8, temp18) - MUL_SHIFT_SUM(temp6, temp8, temp18, temp17, temp11, temp15, temp12, temp16, - temp8, temp15, temp6, temp11, temp12, temp16, temp10, temp14, - temp18, temp12, temp17, temp16) - INSERT_HALF_X2(temp1, temp3, temp9, temp13) - INSERT_HALF_X2(temp6, temp8, temp11, temp15) - SHIFT_R_SUM_X2(temp9, temp10, temp11, temp12, temp13, temp14, temp15, - temp16, temp2, temp4, temp5, temp7, temp3, temp1, temp8, - temp6) - PACK_2_HALVES_TO_WORD(temp1, temp2, temp3, temp4, temp9, temp12, temp13, - temp16, temp11, temp10, temp15, temp14) - LOAD_WITH_OFFSET_X4(temp10, temp11, temp14, temp15, ref, - 0, 0, 0, 0, - 0, 1, 2, 3, - BPS) - CONVERT_2_BYTES_TO_HALF(temp5, temp6, temp7, temp8, temp17, temp18, temp10, - temp11, temp10, temp11, temp14, temp15) - STORE_SAT_SUM_X2(temp5, temp6, temp7, temp8, temp17, temp18, temp10, temp11, - temp9, temp12, temp1, temp2, temp13, temp16, temp3, temp4, - dst, 0, 1, 2, 3, BPS) - - OUTPUT_EARLY_CLOBBER_REGS_18() - : [dst]"r"(dst), [in]"r"(in), [kC1]"r"(kC1), [kC2]"r"(kC2), [ref]"r"(ref) - : "memory", "hi", "lo" - ); -} - -static void ITransform_MIPSdspR2(const uint8_t* ref, const int16_t* in, - uint8_t* dst, int do_two) { - ITransformOne(ref, in, dst); - if (do_two) { - ITransformOne(ref + 4, in + 16, dst + 4); - } -} - -static int Disto4x4_MIPSdspR2(const uint8_t* const a, const uint8_t* const b, - const uint16_t* const w) { - int temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8, temp9; - int temp10, temp11, temp12, temp13, temp14, temp15, temp16, temp17; - - __asm__ volatile ( - LOAD_WITH_OFFSET_X4(temp1, temp2, temp3, temp4, a, - 0, 0, 0, 0, - 0, 1, 2, 3, - BPS) - CONVERT_2_BYTES_TO_HALF(temp5, temp6, temp7, temp8, temp9,temp10, temp11, - temp12, temp1, temp2, temp3, temp4) - ADD_SUB_HALVES_X4(temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8, - temp5, temp6, temp7, temp8, temp9, temp10, temp11, temp12) - PACK_2_HALVES_TO_WORD(temp9, temp10, temp11, temp12, temp1, temp3, temp5, - temp7, temp2, temp4, temp6, temp8) - ADD_SUB_HALVES_X4(temp2, temp4, temp6, temp8, temp9, temp1, temp3, temp10, - temp1, temp9, temp3, temp10, temp5, temp11, temp7, temp12) - ADD_SUB_HALVES_X4(temp5, temp11, temp7, temp2, temp9, temp3, temp6, temp12, - temp2, temp9, temp6, temp3, temp4, temp1, temp8, temp10) - ADD_SUB_HALVES_X4(temp1, temp4, temp10, temp8, temp7, temp11, temp5, temp2, - temp5, temp7, temp11, temp2, temp9, temp6, temp3, temp12) - ABS_X8(temp1, temp4, temp10, temp8, temp7, temp11, temp5, temp2) - LOAD_WITH_OFFSET_X4(temp3, temp6, temp9, temp12, w, - 0, 4, 8, 12, - 0, 0, 0, 0, - 0) - LOAD_WITH_OFFSET_X4(temp13, temp14, temp15, temp16, w, - 0, 4, 8, 12, - 1, 1, 1, 1, - 16) - MUL_HALF(temp17, temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8, - temp9, temp10, temp11, temp12, temp13, temp14, temp15, temp16) - LOAD_WITH_OFFSET_X4(temp1, temp2, temp3, temp4, b, - 0, 0, 0, 0, - 0, 1, 2, 3, - BPS) - CONVERT_2_BYTES_TO_HALF(temp5,temp6, temp7, temp8, temp9,temp10, temp11, - temp12, temp1, temp2, temp3, temp4) - ADD_SUB_HALVES_X4(temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8, - temp5, temp6, temp7, temp8, temp9, temp10, temp11, temp12) - PACK_2_HALVES_TO_WORD(temp9, temp10, temp11, temp12, temp1, temp3, temp5, - temp7, temp2, temp4, temp6, temp8) - ADD_SUB_HALVES_X4(temp2, temp4, temp6, temp8, temp9, temp1, temp3, temp10, - temp1, temp9, temp3, temp10, temp5, temp11, temp7, temp12) - ADD_SUB_HALVES_X4(temp5, temp11, temp7, temp2, temp9, temp3, temp6, temp12, - temp2, temp9, temp6, temp3, temp4, temp1, temp8, temp10) - ADD_SUB_HALVES_X4(temp1, temp4, temp10, temp8, temp7, temp11, temp5, temp2, - temp5, temp7, temp11, temp2, temp9, temp6, temp3, temp12) - ABS_X8(temp1, temp4, temp10, temp8, temp7, temp11, temp5, temp2) - LOAD_WITH_OFFSET_X4(temp3, temp6, temp9, temp12, w, - 0, 4, 8, 12, - 0, 0, 0, 0, - 0) - LOAD_WITH_OFFSET_X4(temp13, temp14, temp15, temp16, w, - 0, 4, 8, 12, - 1, 1, 1, 1, - 16) - MUL_HALF(temp3, temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8, - temp9, temp10, temp11, temp12, temp13, temp14, temp15, temp16) - OUTPUT_EARLY_CLOBBER_REGS_17() - : [a]"r"(a), [b]"r"(b), [w]"r"(w) - : "memory", "hi", "lo" - ); - return abs(temp3 - temp17) >> 5; -} - -static int Disto16x16_MIPSdspR2(const uint8_t* const a, - const uint8_t* const b, - const uint16_t* const w) { - int D = 0; - int x, y; - for (y = 0; y < 16 * BPS; y += 4 * BPS) { - for (x = 0; x < 16; x += 4) { - D += Disto4x4_MIPSdspR2(a + x + y, b + x + y, w); - } - } - return D; -} - -//------------------------------------------------------------------------------ -// Intra predictions - -#define FILL_PART(J, SIZE) \ - "usw %[value], 0+" #J "*" XSTR(BPS) "(%[dst]) \n\t" \ - "usw %[value], 4+" #J "*" XSTR(BPS) "(%[dst]) \n\t" \ - ".if " #SIZE " == 16 \n\t" \ - "usw %[value], 8+" #J "*" XSTR(BPS) "(%[dst]) \n\t" \ - "usw %[value], 12+" #J "*" XSTR(BPS) "(%[dst]) \n\t" \ - ".endif \n\t" - -#define FILL_8_OR_16(DST, VALUE, SIZE) do { \ - int value = (VALUE); \ - __asm__ volatile ( \ - "replv.qb %[value], %[value] \n\t" \ - FILL_PART( 0, SIZE) \ - FILL_PART( 1, SIZE) \ - FILL_PART( 2, SIZE) \ - FILL_PART( 3, SIZE) \ - FILL_PART( 4, SIZE) \ - FILL_PART( 5, SIZE) \ - FILL_PART( 6, SIZE) \ - FILL_PART( 7, SIZE) \ - ".if " #SIZE " == 16 \n\t" \ - FILL_PART( 8, 16) \ - FILL_PART( 9, 16) \ - FILL_PART(10, 16) \ - FILL_PART(11, 16) \ - FILL_PART(12, 16) \ - FILL_PART(13, 16) \ - FILL_PART(14, 16) \ - FILL_PART(15, 16) \ - ".endif \n\t" \ - : [value]"+&r"(value) \ - : [dst]"r"((DST)) \ - : "memory" \ - ); \ -} while (0) - -#define VERTICAL_PRED(DST, TOP, SIZE) \ -static WEBP_INLINE void VerticalPred##SIZE(uint8_t* (DST), \ - const uint8_t* (TOP)) { \ - int j; \ - if ((TOP)) { \ - for (j = 0; j < (SIZE); ++j) memcpy((DST) + j * BPS, (TOP), (SIZE)); \ - } else { \ - FILL_8_OR_16((DST), 127, (SIZE)); \ - } \ -} - -VERTICAL_PRED(dst, top, 8) -VERTICAL_PRED(dst, top, 16) - -#undef VERTICAL_PRED - -#define HORIZONTAL_PRED(DST, LEFT, SIZE) \ -static WEBP_INLINE void HorizontalPred##SIZE(uint8_t* (DST), \ - const uint8_t* (LEFT)) { \ - if (LEFT) { \ - int j; \ - for (j = 0; j < (SIZE); ++j) { \ - memset((DST) + j * BPS, (LEFT)[j], (SIZE)); \ - } \ - } else { \ - FILL_8_OR_16((DST), 129, (SIZE)); \ - } \ -} - -HORIZONTAL_PRED(dst, left, 8) -HORIZONTAL_PRED(dst, left, 16) - -#undef HORIZONTAL_PRED - -#define CLIPPING() \ - "preceu.ph.qbl %[temp2], %[temp0] \n\t" \ - "preceu.ph.qbr %[temp0], %[temp0] \n\t" \ - "preceu.ph.qbl %[temp3], %[temp1] \n\t" \ - "preceu.ph.qbr %[temp1], %[temp1] \n\t" \ - "addu.ph %[temp2], %[temp2], %[leftY_1] \n\t" \ - "addu.ph %[temp0], %[temp0], %[leftY_1] \n\t" \ - "addu.ph %[temp3], %[temp3], %[leftY_1] \n\t" \ - "addu.ph %[temp1], %[temp1], %[leftY_1] \n\t" \ - "shll_s.ph %[temp2], %[temp2], 7 \n\t" \ - "shll_s.ph %[temp0], %[temp0], 7 \n\t" \ - "shll_s.ph %[temp3], %[temp3], 7 \n\t" \ - "shll_s.ph %[temp1], %[temp1], 7 \n\t" \ - "precrqu_s.qb.ph %[temp0], %[temp2], %[temp0] \n\t" \ - "precrqu_s.qb.ph %[temp1], %[temp3], %[temp1] \n\t" - -#define CLIP_8B_TO_DST(DST, LEFT, TOP, SIZE) do { \ - int leftY_1 = ((int)(LEFT)[y] << 16) + (LEFT)[y]; \ - int temp0, temp1, temp2, temp3; \ - __asm__ volatile ( \ - "replv.ph %[leftY_1], %[leftY_1] \n\t" \ - "ulw %[temp0], 0(%[top]) \n\t" \ - "ulw %[temp1], 4(%[top]) \n\t" \ - "subu.ph %[leftY_1], %[leftY_1], %[left_1] \n\t" \ - CLIPPING() \ - "usw %[temp0], 0(%[dst]) \n\t" \ - "usw %[temp1], 4(%[dst]) \n\t" \ - ".if " #SIZE " == 16 \n\t" \ - "ulw %[temp0], 8(%[top]) \n\t" \ - "ulw %[temp1], 12(%[top]) \n\t" \ - CLIPPING() \ - "usw %[temp0], 8(%[dst]) \n\t" \ - "usw %[temp1], 12(%[dst]) \n\t" \ - ".endif \n\t" \ - : [leftY_1]"+&r"(leftY_1), [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), \ - [temp2]"=&r"(temp2), [temp3]"=&r"(temp3) \ - : [left_1]"r"(left_1), [top]"r"((TOP)), [dst]"r"((DST)) \ - : "memory" \ - ); \ -} while (0) - -#define CLIP_TO_DST(DST, LEFT, TOP, SIZE) do { \ - int y; \ - const int left_1 = ((int)(LEFT)[-1] << 16) + (LEFT)[-1]; \ - for (y = 0; y < (SIZE); ++y) { \ - CLIP_8B_TO_DST((DST), (LEFT), (TOP), (SIZE)); \ - (DST) += BPS; \ - } \ -} while (0) - -#define TRUE_MOTION(DST, LEFT, TOP, SIZE) \ -static WEBP_INLINE void TrueMotion##SIZE(uint8_t* (DST), const uint8_t* (LEFT),\ - const uint8_t* (TOP)) { \ - if ((LEFT) != NULL) { \ - if ((TOP) != NULL) { \ - CLIP_TO_DST((DST), (LEFT), (TOP), (SIZE)); \ - } else { \ - HorizontalPred##SIZE((DST), (LEFT)); \ - } \ - } else { \ - /* true motion without left samples (hence: with default 129 value) */ \ - /* is equivalent to VE prediction where you just copy the top samples. */ \ - /* Note that if top samples are not available, the default value is */ \ - /* then 129, and not 127 as in the VerticalPred case. */ \ - if ((TOP) != NULL) { \ - VerticalPred##SIZE((DST), (TOP)); \ - } else { \ - FILL_8_OR_16((DST), 129, (SIZE)); \ - } \ - } \ -} - -TRUE_MOTION(dst, left, top, 8) -TRUE_MOTION(dst, left, top, 16) - -#undef TRUE_MOTION -#undef CLIP_TO_DST -#undef CLIP_8B_TO_DST -#undef CLIPPING - -static WEBP_INLINE void DCMode16(uint8_t* dst, const uint8_t* left, - const uint8_t* top) { - int DC, DC1; - int temp0, temp1, temp2, temp3; - - __asm__ volatile( - "beqz %[top], 2f \n\t" - LOAD_WITH_OFFSET_X4(temp0, temp1, temp2, temp3, top, - 0, 4, 8, 12, - 0, 0, 0, 0, - 0) - "raddu.w.qb %[temp0], %[temp0] \n\t" - "raddu.w.qb %[temp1], %[temp1] \n\t" - "raddu.w.qb %[temp2], %[temp2] \n\t" - "raddu.w.qb %[temp3], %[temp3] \n\t" - "addu %[temp0], %[temp0], %[temp1] \n\t" - "addu %[temp2], %[temp2], %[temp3] \n\t" - "addu %[DC], %[temp0], %[temp2] \n\t" - "move %[DC1], %[DC] \n\t" - "beqz %[left], 1f \n\t" - LOAD_WITH_OFFSET_X4(temp0, temp1, temp2, temp3, left, - 0, 4, 8, 12, - 0, 0, 0, 0, - 0) - "raddu.w.qb %[temp0], %[temp0] \n\t" - "raddu.w.qb %[temp1], %[temp1] \n\t" - "raddu.w.qb %[temp2], %[temp2] \n\t" - "raddu.w.qb %[temp3], %[temp3] \n\t" - "addu %[temp0], %[temp0], %[temp1] \n\t" - "addu %[temp2], %[temp2], %[temp3] \n\t" - "addu %[DC1], %[temp0], %[temp2] \n\t" - "1: \n\t" - "addu %[DC], %[DC], %[DC1] \n\t" - "j 3f \n\t" - "2: \n\t" - "beqz %[left], 4f \n\t" - LOAD_WITH_OFFSET_X4(temp0, temp1, temp2, temp3, left, - 0, 4, 8, 12, - 0, 0, 0, 0, - 0) - "raddu.w.qb %[temp0], %[temp0] \n\t" - "raddu.w.qb %[temp1], %[temp1] \n\t" - "raddu.w.qb %[temp2], %[temp2] \n\t" - "raddu.w.qb %[temp3], %[temp3] \n\t" - "addu %[temp0], %[temp0], %[temp1] \n\t" - "addu %[temp2], %[temp2], %[temp3] \n\t" - "addu %[DC], %[temp0], %[temp2] \n\t" - "addu %[DC], %[DC], %[DC] \n\t" - "3: \n\t" - "shra_r.w %[DC], %[DC], 5 \n\t" - "j 5f \n\t" - "4: \n\t" - "li %[DC], 0x80 \n\t" - "5: \n\t" - : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [DC]"=&r"(DC), - [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), [DC1]"=&r"(DC1) - : [left]"r"(left), [top]"r"(top) - : "memory" - ); - - FILL_8_OR_16(dst, DC, 16); -} - -static WEBP_INLINE void DCMode8(uint8_t* dst, const uint8_t* left, - const uint8_t* top) { - int DC, DC1; - int temp0, temp1, temp2, temp3; - - __asm__ volatile( - "beqz %[top], 2f \n\t" - "ulw %[temp0], 0(%[top]) \n\t" - "ulw %[temp1], 4(%[top]) \n\t" - "raddu.w.qb %[temp0], %[temp0] \n\t" - "raddu.w.qb %[temp1], %[temp1] \n\t" - "addu %[DC], %[temp0], %[temp1] \n\t" - "move %[DC1], %[DC] \n\t" - "beqz %[left], 1f \n\t" - "ulw %[temp2], 0(%[left]) \n\t" - "ulw %[temp3], 4(%[left]) \n\t" - "raddu.w.qb %[temp2], %[temp2] \n\t" - "raddu.w.qb %[temp3], %[temp3] \n\t" - "addu %[DC1], %[temp2], %[temp3] \n\t" - "1: \n\t" - "addu %[DC], %[DC], %[DC1] \n\t" - "j 3f \n\t" - "2: \n\t" - "beqz %[left], 4f \n\t" - "ulw %[temp2], 0(%[left]) \n\t" - "ulw %[temp3], 4(%[left]) \n\t" - "raddu.w.qb %[temp2], %[temp2] \n\t" - "raddu.w.qb %[temp3], %[temp3] \n\t" - "addu %[DC], %[temp2], %[temp3] \n\t" - "addu %[DC], %[DC], %[DC] \n\t" - "3: \n\t" - "shra_r.w %[DC], %[DC], 4 \n\t" - "j 5f \n\t" - "4: \n\t" - "li %[DC], 0x80 \n\t" - "5: \n\t" - : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [DC]"=&r"(DC), - [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), [DC1]"=&r"(DC1) - : [left]"r"(left), [top]"r"(top) - : "memory" - ); - - FILL_8_OR_16(dst, DC, 8); -} - -static void DC4(uint8_t* dst, const uint8_t* top) { - int temp0, temp1; - __asm__ volatile( - "ulw %[temp0], 0(%[top]) \n\t" - "ulw %[temp1], -5(%[top]) \n\t" - "raddu.w.qb %[temp0], %[temp0] \n\t" - "raddu.w.qb %[temp1], %[temp1] \n\t" - "addu %[temp0], %[temp0], %[temp1] \n\t" - "addiu %[temp0], %[temp0], 4 \n\t" - "srl %[temp0], %[temp0], 3 \n\t" - "replv.qb %[temp0], %[temp0] \n\t" - "usw %[temp0], 0*" XSTR(BPS) "(%[dst]) \n\t" - "usw %[temp0], 1*" XSTR(BPS) "(%[dst]) \n\t" - "usw %[temp0], 2*" XSTR(BPS) "(%[dst]) \n\t" - "usw %[temp0], 3*" XSTR(BPS) "(%[dst]) \n\t" - : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1) - : [top]"r"(top), [dst]"r"(dst) - : "memory" - ); -} - -static void TM4(uint8_t* dst, const uint8_t* top) { - int a10, a32, temp0, temp1, temp2, temp3, temp4, temp5; - const int c35 = 0xff00ff; - __asm__ volatile ( - "lbu %[temp1], 0(%[top]) \n\t" - "lbu %[a10], 1(%[top]) \n\t" - "lbu %[temp2], 2(%[top]) \n\t" - "lbu %[a32], 3(%[top]) \n\t" - "ulw %[temp0], -5(%[top]) \n\t" - "lbu %[temp4], -1(%[top]) \n\t" - "append %[a10], %[temp1], 16 \n\t" - "append %[a32], %[temp2], 16 \n\t" - "replv.ph %[temp4], %[temp4] \n\t" - "shrl.ph %[temp1], %[temp0], 8 \n\t" - "and %[temp0], %[temp0], %[c35] \n\t" - "subu.ph %[temp1], %[temp1], %[temp4] \n\t" - "subu.ph %[temp0], %[temp0], %[temp4] \n\t" - "srl %[temp2], %[temp1], 16 \n\t" - "srl %[temp3], %[temp0], 16 \n\t" - "replv.ph %[temp2], %[temp2] \n\t" - "replv.ph %[temp3], %[temp3] \n\t" - "replv.ph %[temp4], %[temp1] \n\t" - "replv.ph %[temp5], %[temp0] \n\t" - "addu.ph %[temp0], %[temp3], %[a10] \n\t" - "addu.ph %[temp1], %[temp3], %[a32] \n\t" - "addu.ph %[temp3], %[temp2], %[a10] \n\t" - "addu.ph %[temp2], %[temp2], %[a32] \n\t" - "shll_s.ph %[temp0], %[temp0], 7 \n\t" - "shll_s.ph %[temp1], %[temp1], 7 \n\t" - "shll_s.ph %[temp3], %[temp3], 7 \n\t" - "shll_s.ph %[temp2], %[temp2], 7 \n\t" - "precrqu_s.qb.ph %[temp0], %[temp1], %[temp0] \n\t" - "precrqu_s.qb.ph %[temp1], %[temp2], %[temp3] \n\t" - "addu.ph %[temp2], %[temp5], %[a10] \n\t" - "addu.ph %[temp3], %[temp5], %[a32] \n\t" - "addu.ph %[temp5], %[temp4], %[a10] \n\t" - "addu.ph %[temp4], %[temp4], %[a32] \n\t" - "shll_s.ph %[temp2], %[temp2], 7 \n\t" - "shll_s.ph %[temp3], %[temp3], 7 \n\t" - "shll_s.ph %[temp4], %[temp4], 7 \n\t" - "shll_s.ph %[temp5], %[temp5], 7 \n\t" - "precrqu_s.qb.ph %[temp2], %[temp3], %[temp2] \n\t" - "precrqu_s.qb.ph %[temp3], %[temp4], %[temp5] \n\t" - "usw %[temp1], 0*" XSTR(BPS) "(%[dst]) \n\t" - "usw %[temp0], 1*" XSTR(BPS) "(%[dst]) \n\t" - "usw %[temp3], 2*" XSTR(BPS) "(%[dst]) \n\t" - "usw %[temp2], 3*" XSTR(BPS) "(%[dst]) \n\t" - : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), - [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), - [a10]"=&r"(a10), [a32]"=&r"(a32) - : [c35]"r"(c35), [top]"r"(top), [dst]"r"(dst) - : "memory" - ); -} - -static void VE4(uint8_t* dst, const uint8_t* top) { - int temp0, temp1, temp2, temp3, temp4, temp5, temp6; - __asm__ volatile( - "ulw %[temp0], -1(%[top]) \n\t" - "ulh %[temp1], 3(%[top]) \n\t" - "preceu.ph.qbr %[temp2], %[temp0] \n\t" - "preceu.ph.qbl %[temp3], %[temp0] \n\t" - "preceu.ph.qbr %[temp4], %[temp1] \n\t" - "packrl.ph %[temp5], %[temp3], %[temp2] \n\t" - "packrl.ph %[temp6], %[temp4], %[temp3] \n\t" - "shll.ph %[temp5], %[temp5], 1 \n\t" - "shll.ph %[temp6], %[temp6], 1 \n\t" - "addq.ph %[temp2], %[temp5], %[temp2] \n\t" - "addq.ph %[temp6], %[temp6], %[temp4] \n\t" - "addq.ph %[temp2], %[temp2], %[temp3] \n\t" - "addq.ph %[temp6], %[temp6], %[temp3] \n\t" - "shra_r.ph %[temp2], %[temp2], 2 \n\t" - "shra_r.ph %[temp6], %[temp6], 2 \n\t" - "precr.qb.ph %[temp4], %[temp6], %[temp2] \n\t" - "usw %[temp4], 0*" XSTR(BPS) "(%[dst]) \n\t" - "usw %[temp4], 1*" XSTR(BPS) "(%[dst]) \n\t" - "usw %[temp4], 2*" XSTR(BPS) "(%[dst]) \n\t" - "usw %[temp4], 3*" XSTR(BPS) "(%[dst]) \n\t" - : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), - [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), - [temp6]"=&r"(temp6) - : [top]"r"(top), [dst]"r"(dst) - : "memory" - ); -} - -static void HE4(uint8_t* dst, const uint8_t* top) { - int temp0, temp1, temp2, temp3, temp4, temp5, temp6; - __asm__ volatile( - "ulw %[temp0], -4(%[top]) \n\t" - "lbu %[temp1], -5(%[top]) \n\t" - "preceu.ph.qbr %[temp2], %[temp0] \n\t" - "preceu.ph.qbl %[temp3], %[temp0] \n\t" - "replv.ph %[temp4], %[temp1] \n\t" - "packrl.ph %[temp5], %[temp3], %[temp2] \n\t" - "packrl.ph %[temp6], %[temp2], %[temp4] \n\t" - "shll.ph %[temp5], %[temp5], 1 \n\t" - "shll.ph %[temp6], %[temp6], 1 \n\t" - "addq.ph %[temp3], %[temp3], %[temp5] \n\t" - "addq.ph %[temp3], %[temp3], %[temp2] \n\t" - "addq.ph %[temp2], %[temp2], %[temp6] \n\t" - "addq.ph %[temp2], %[temp2], %[temp4] \n\t" - "shra_r.ph %[temp3], %[temp3], 2 \n\t" - "shra_r.ph %[temp2], %[temp2], 2 \n\t" - "replv.qb %[temp0], %[temp3] \n\t" - "replv.qb %[temp1], %[temp2] \n\t" - "srl %[temp3], %[temp3], 16 \n\t" - "srl %[temp2], %[temp2], 16 \n\t" - "replv.qb %[temp3], %[temp3] \n\t" - "replv.qb %[temp2], %[temp2] \n\t" - "usw %[temp3], 0*" XSTR(BPS) "(%[dst]) \n\t" - "usw %[temp0], 1*" XSTR(BPS) "(%[dst]) \n\t" - "usw %[temp2], 2*" XSTR(BPS) "(%[dst]) \n\t" - "usw %[temp1], 3*" XSTR(BPS) "(%[dst]) \n\t" - : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), - [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), - [temp6]"=&r"(temp6) - : [top]"r"(top), [dst]"r"(dst) - : "memory" - ); -} - -static void RD4(uint8_t* dst, const uint8_t* top) { - int temp0, temp1, temp2, temp3, temp4, temp5; - int temp6, temp7, temp8, temp9, temp10, temp11; - __asm__ volatile( - "ulw %[temp0], -5(%[top]) \n\t" - "ulw %[temp1], -1(%[top]) \n\t" - "preceu.ph.qbl %[temp2], %[temp0] \n\t" - "preceu.ph.qbr %[temp3], %[temp0] \n\t" - "preceu.ph.qbr %[temp4], %[temp1] \n\t" - "preceu.ph.qbl %[temp5], %[temp1] \n\t" - "packrl.ph %[temp6], %[temp2], %[temp3] \n\t" - "packrl.ph %[temp7], %[temp4], %[temp2] \n\t" - "packrl.ph %[temp8], %[temp5], %[temp4] \n\t" - "shll.ph %[temp6], %[temp6], 1 \n\t" - "addq.ph %[temp9], %[temp2], %[temp6] \n\t" - "shll.ph %[temp7], %[temp7], 1 \n\t" - "addq.ph %[temp9], %[temp9], %[temp3] \n\t" - "shll.ph %[temp8], %[temp8], 1 \n\t" - "shra_r.ph %[temp9], %[temp9], 2 \n\t" - "addq.ph %[temp10], %[temp4], %[temp7] \n\t" - "addq.ph %[temp11], %[temp5], %[temp8] \n\t" - "addq.ph %[temp10], %[temp10], %[temp2] \n\t" - "addq.ph %[temp11], %[temp11], %[temp4] \n\t" - "shra_r.ph %[temp10], %[temp10], 2 \n\t" - "shra_r.ph %[temp11], %[temp11], 2 \n\t" - "lbu %[temp0], 3(%[top]) \n\t" - "lbu %[temp1], 2(%[top]) \n\t" - "lbu %[temp2], 1(%[top]) \n\t" - "sll %[temp1], %[temp1], 1 \n\t" - "addu %[temp0], %[temp0], %[temp1] \n\t" - "addu %[temp0], %[temp0], %[temp2] \n\t" - "precr.qb.ph %[temp9], %[temp10], %[temp9] \n\t" - "shra_r.w %[temp0], %[temp0], 2 \n\t" - "precr.qb.ph %[temp10], %[temp11], %[temp10] \n\t" - "usw %[temp9], 3*" XSTR(BPS) "(%[dst]) \n\t" - "usw %[temp10], 1*" XSTR(BPS) "(%[dst]) \n\t" - "prepend %[temp9], %[temp11], 8 \n\t" - "prepend %[temp10], %[temp0], 8 \n\t" - "usw %[temp9], 2*" XSTR(BPS) "(%[dst]) \n\t" - "usw %[temp10], 0*" XSTR(BPS) "(%[dst]) \n\t" - : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), - [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), - [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8), - [temp9]"=&r"(temp9), [temp10]"=&r"(temp10), [temp11]"=&r"(temp11) - : [top]"r"(top), [dst]"r"(dst) - : "memory" - ); -} - -static void VR4(uint8_t* dst, const uint8_t* top) { - int temp0, temp1, temp2, temp3, temp4; - int temp5, temp6, temp7, temp8, temp9; - __asm__ volatile ( - "ulw %[temp0], -4(%[top]) \n\t" - "ulw %[temp1], 0(%[top]) \n\t" - "preceu.ph.qbl %[temp2], %[temp0] \n\t" - "preceu.ph.qbr %[temp0], %[temp0] \n\t" - "preceu.ph.qbla %[temp3], %[temp1] \n\t" - "preceu.ph.qbra %[temp1], %[temp1] \n\t" - "packrl.ph %[temp7], %[temp3], %[temp2] \n\t" - "addqh_r.ph %[temp4], %[temp1], %[temp3] \n\t" - "move %[temp6], %[temp1] \n\t" - "append %[temp1], %[temp2], 16 \n\t" - "shll.ph %[temp9], %[temp6], 1 \n\t" - "addqh_r.ph %[temp5], %[temp7], %[temp6] \n\t" - "shll.ph %[temp8], %[temp7], 1 \n\t" - "addu.ph %[temp3], %[temp7], %[temp3] \n\t" - "addu.ph %[temp1], %[temp1], %[temp6] \n\t" - "packrl.ph %[temp7], %[temp2], %[temp0] \n\t" - "addu.ph %[temp6], %[temp0], %[temp2] \n\t" - "addu.ph %[temp3], %[temp3], %[temp9] \n\t" - "addu.ph %[temp1], %[temp1], %[temp8] \n\t" - "shll.ph %[temp7], %[temp7], 1 \n\t" - "shra_r.ph %[temp3], %[temp3], 2 \n\t" - "shra_r.ph %[temp1], %[temp1], 2 \n\t" - "addu.ph %[temp6], %[temp6], %[temp7] \n\t" - "shra_r.ph %[temp6], %[temp6], 2 \n\t" - "precrq.ph.w %[temp8], %[temp4], %[temp5] \n\t" - "append %[temp4], %[temp5], 16 \n\t" - "precrq.ph.w %[temp2], %[temp3], %[temp1] \n\t" - "append %[temp3], %[temp1], 16 \n\t" - "precr.qb.ph %[temp8], %[temp8], %[temp4] \n\t" - "precr.qb.ph %[temp3], %[temp2], %[temp3] \n\t" - "usw %[temp8], 0*" XSTR(BPS) "(%[dst]) \n\t" - "usw %[temp3], 1*" XSTR(BPS) "(%[dst]) \n\t" - "append %[temp3], %[temp6], 8 \n\t" - "srl %[temp6], %[temp6], 16 \n\t" - "append %[temp8], %[temp6], 8 \n\t" - "usw %[temp3], 3*" XSTR(BPS) "(%[dst]) \n\t" - "usw %[temp8], 2*" XSTR(BPS) "(%[dst]) \n\t" - : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), - [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), - [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8), - [temp9]"=&r"(temp9) - : [top]"r"(top), [dst]"r"(dst) - : "memory" - ); -} - -static void LD4(uint8_t* dst, const uint8_t* top) { - int temp0, temp1, temp2, temp3, temp4, temp5; - int temp6, temp7, temp8, temp9, temp10, temp11; - __asm__ volatile( - "ulw %[temp0], 0(%[top]) \n\t" - "ulw %[temp1], 4(%[top]) \n\t" - "preceu.ph.qbl %[temp2], %[temp0] \n\t" - "preceu.ph.qbr %[temp3], %[temp0] \n\t" - "preceu.ph.qbr %[temp4], %[temp1] \n\t" - "preceu.ph.qbl %[temp5], %[temp1] \n\t" - "packrl.ph %[temp6], %[temp2], %[temp3] \n\t" - "packrl.ph %[temp7], %[temp4], %[temp2] \n\t" - "packrl.ph %[temp8], %[temp5], %[temp4] \n\t" - "shll.ph %[temp6], %[temp6], 1 \n\t" - "addq.ph %[temp9], %[temp2], %[temp6] \n\t" - "shll.ph %[temp7], %[temp7], 1 \n\t" - "addq.ph %[temp9], %[temp9], %[temp3] \n\t" - "shll.ph %[temp8], %[temp8], 1 \n\t" - "shra_r.ph %[temp9], %[temp9], 2 \n\t" - "addq.ph %[temp10], %[temp4], %[temp7] \n\t" - "addq.ph %[temp11], %[temp5], %[temp8] \n\t" - "addq.ph %[temp10], %[temp10], %[temp2] \n\t" - "addq.ph %[temp11], %[temp11], %[temp4] \n\t" - "shra_r.ph %[temp10], %[temp10], 2 \n\t" - "shra_r.ph %[temp11], %[temp11], 2 \n\t" - "srl %[temp1], %[temp1], 24 \n\t" - "sll %[temp1], %[temp1], 1 \n\t" - "raddu.w.qb %[temp5], %[temp5] \n\t" - "precr.qb.ph %[temp9], %[temp10], %[temp9] \n\t" - "precr.qb.ph %[temp10], %[temp11], %[temp10] \n\t" - "addu %[temp1], %[temp1], %[temp5] \n\t" - "shra_r.w %[temp1], %[temp1], 2 \n\t" - "usw %[temp9], 0*" XSTR(BPS) "(%[dst]) \n\t" - "usw %[temp10], 2*" XSTR(BPS) "(%[dst]) \n\t" - "prepend %[temp9], %[temp11], 8 \n\t" - "prepend %[temp10], %[temp1], 8 \n\t" - "usw %[temp9], 1*" XSTR(BPS) "(%[dst]) \n\t" - "usw %[temp10], 3*" XSTR(BPS) "(%[dst]) \n\t" - : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), - [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), - [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8), - [temp9]"=&r"(temp9), [temp10]"=&r"(temp10), [temp11]"=&r"(temp11) - : [top]"r"(top), [dst]"r"(dst) - : "memory" - ); -} - -static void VL4(uint8_t* dst, const uint8_t* top) { - int temp0, temp1, temp2, temp3, temp4; - int temp5, temp6, temp7, temp8, temp9; - __asm__ volatile ( - "ulw %[temp0], 0(%[top]) \n\t" - "ulw %[temp1], 4(%[top]) \n\t" - "preceu.ph.qbla %[temp2], %[temp0] \n\t" - "preceu.ph.qbra %[temp0], %[temp0] \n\t" - "preceu.ph.qbl %[temp3], %[temp1] \n\t" - "preceu.ph.qbr %[temp1], %[temp1] \n\t" - "addqh_r.ph %[temp4], %[temp0], %[temp2] \n\t" - "packrl.ph %[temp7], %[temp1], %[temp0] \n\t" - "precrq.ph.w %[temp6], %[temp1], %[temp2] \n\t" - "shll.ph %[temp9], %[temp2], 1 \n\t" - "addqh_r.ph %[temp5], %[temp7], %[temp2] \n\t" - "shll.ph %[temp8], %[temp7], 1 \n\t" - "addu.ph %[temp2], %[temp2], %[temp6] \n\t" - "addu.ph %[temp0], %[temp0], %[temp7] \n\t" - "packrl.ph %[temp7], %[temp3], %[temp1] \n\t" - "addu.ph %[temp6], %[temp1], %[temp3] \n\t" - "addu.ph %[temp2], %[temp2], %[temp8] \n\t" - "addu.ph %[temp0], %[temp0], %[temp9] \n\t" - "shll.ph %[temp7], %[temp7], 1 \n\t" - "shra_r.ph %[temp2], %[temp2], 2 \n\t" - "shra_r.ph %[temp0], %[temp0], 2 \n\t" - "addu.ph %[temp6], %[temp6], %[temp7] \n\t" - "shra_r.ph %[temp6], %[temp6], 2 \n\t" - "precrq.ph.w %[temp8], %[temp5], %[temp4] \n\t" - "append %[temp5], %[temp4], 16 \n\t" - "precrq.ph.w %[temp3], %[temp2], %[temp0] \n\t" - "append %[temp2], %[temp0], 16 \n\t" - "precr.qb.ph %[temp8], %[temp8], %[temp5] \n\t" - "precr.qb.ph %[temp3], %[temp3], %[temp2] \n\t" - "usw %[temp8], 0*" XSTR(BPS) "(%[dst]) \n\t" - "prepend %[temp8], %[temp6], 8 \n\t" - "usw %[temp3], 1*" XSTR(BPS) "(%[dst]) \n\t" - "srl %[temp6], %[temp6], 16 \n\t" - "prepend %[temp3], %[temp6], 8 \n\t" - "usw %[temp8], 2*" XSTR(BPS) "(%[dst]) \n\t" - "usw %[temp3], 3*" XSTR(BPS) "(%[dst]) \n\t" - : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), - [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), - [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8), - [temp9]"=&r"(temp9) - : [top]"r"(top), [dst]"r"(dst) - : "memory" - ); -} - -static void HD4(uint8_t* dst, const uint8_t* top) { - int temp0, temp1, temp2, temp3, temp4; - int temp5, temp6, temp7, temp8, temp9; - __asm__ volatile ( - "ulw %[temp0], -5(%[top]) \n\t" - "ulw %[temp1], -1(%[top]) \n\t" - "preceu.ph.qbla %[temp2], %[temp0] \n\t" - "preceu.ph.qbra %[temp0], %[temp0] \n\t" - "preceu.ph.qbl %[temp3], %[temp1] \n\t" - "preceu.ph.qbr %[temp1], %[temp1] \n\t" - "addqh_r.ph %[temp4], %[temp0], %[temp2] \n\t" - "packrl.ph %[temp7], %[temp1], %[temp0] \n\t" - "precrq.ph.w %[temp6], %[temp1], %[temp2] \n\t" - "shll.ph %[temp9], %[temp2], 1 \n\t" - "addqh_r.ph %[temp5], %[temp7], %[temp2] \n\t" - "shll.ph %[temp8], %[temp7], 1 \n\t" - "addu.ph %[temp2], %[temp2], %[temp6] \n\t" - "addu.ph %[temp0], %[temp0], %[temp7] \n\t" - "packrl.ph %[temp7], %[temp3], %[temp1] \n\t" - "addu.ph %[temp6], %[temp1], %[temp3] \n\t" - "addu.ph %[temp2], %[temp2], %[temp8] \n\t" - "addu.ph %[temp0], %[temp0], %[temp9] \n\t" - "shll.ph %[temp7], %[temp7], 1 \n\t" - "shra_r.ph %[temp2], %[temp2], 2 \n\t" - "shra_r.ph %[temp0], %[temp0], 2 \n\t" - "addu.ph %[temp6], %[temp6], %[temp7] \n\t" - "shra_r.ph %[temp6], %[temp6], 2 \n\t" - "precrq.ph.w %[temp1], %[temp2], %[temp5] \n\t" - "precrq.ph.w %[temp3], %[temp0], %[temp4] \n\t" - "precr.qb.ph %[temp7], %[temp6], %[temp1] \n\t" - "precr.qb.ph %[temp6], %[temp1], %[temp3] \n\t" - "usw %[temp7], 0*" XSTR(BPS) "(%[dst]) \n\t" - "usw %[temp6], 1*" XSTR(BPS) "(%[dst]) \n\t" - "append %[temp2], %[temp5], 16 \n\t" - "append %[temp0], %[temp4], 16 \n\t" - "precr.qb.ph %[temp5], %[temp3], %[temp2] \n\t" - "precr.qb.ph %[temp4], %[temp2], %[temp0] \n\t" - "usw %[temp5], 2*" XSTR(BPS) "(%[dst]) \n\t" - "usw %[temp4], 3*" XSTR(BPS) "(%[dst]) \n\t" - : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), - [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), - [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8), - [temp9]"=&r"(temp9) - : [top]"r"(top), [dst]"r"(dst) - : "memory" - ); -} - -static void HU4(uint8_t* dst, const uint8_t* top) { - int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7; - __asm__ volatile ( - "ulw %[temp0], -5(%[top]) \n\t" - "preceu.ph.qbl %[temp1], %[temp0] \n\t" - "preceu.ph.qbr %[temp2], %[temp0] \n\t" - "packrl.ph %[temp3], %[temp1], %[temp2] \n\t" - "replv.qb %[temp7], %[temp2] \n\t" - "addqh_r.ph %[temp4], %[temp1], %[temp3] \n\t" - "addqh_r.ph %[temp5], %[temp3], %[temp2] \n\t" - "shll.ph %[temp6], %[temp3], 1 \n\t" - "addu.ph %[temp3], %[temp2], %[temp3] \n\t" - "addu.ph %[temp6], %[temp1], %[temp6] \n\t" - "shll.ph %[temp0], %[temp2], 1 \n\t" - "addu.ph %[temp6], %[temp6], %[temp2] \n\t" - "addu.ph %[temp0], %[temp3], %[temp0] \n\t" - "shra_r.ph %[temp6], %[temp6], 2 \n\t" - "shra_r.ph %[temp0], %[temp0], 2 \n\t" - "packrl.ph %[temp3], %[temp6], %[temp5] \n\t" - "precrq.ph.w %[temp2], %[temp6], %[temp4] \n\t" - "append %[temp0], %[temp5], 16 \n\t" - "precr.qb.ph %[temp3], %[temp3], %[temp2] \n\t" - "usw %[temp3], 0*" XSTR(BPS) "(%[dst]) \n\t" - "precr.qb.ph %[temp1], %[temp7], %[temp0] \n\t" - "usw %[temp7], 3*" XSTR(BPS) "(%[dst]) \n\t" - "packrl.ph %[temp2], %[temp1], %[temp3] \n\t" - "usw %[temp1], 2*" XSTR(BPS) "(%[dst]) \n\t" - "usw %[temp2], 1*" XSTR(BPS) "(%[dst]) \n\t" - : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), - [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), - [temp6]"=&r"(temp6), [temp7]"=&r"(temp7) - : [top]"r"(top), [dst]"r"(dst) - : "memory" - ); -} - -//------------------------------------------------------------------------------ -// Chroma 8x8 prediction (paragraph 12.2) - -static void IntraChromaPreds_MIPSdspR2(uint8_t* dst, const uint8_t* left, - const uint8_t* top) { - // U block - DCMode8(C8DC8 + dst, left, top); - VerticalPred8(C8VE8 + dst, top); - HorizontalPred8(C8HE8 + dst, left); - TrueMotion8(C8TM8 + dst, left, top); - // V block - dst += 8; - if (top) top += 8; - if (left) left += 16; - DCMode8(C8DC8 + dst, left, top); - VerticalPred8(C8VE8 + dst, top); - HorizontalPred8(C8HE8 + dst, left); - TrueMotion8(C8TM8 + dst, left, top); -} - -//------------------------------------------------------------------------------ -// luma 16x16 prediction (paragraph 12.3) - -static void Intra16Preds_MIPSdspR2(uint8_t* dst, - const uint8_t* left, const uint8_t* top) { - DCMode16(I16DC16 + dst, left, top); - VerticalPred16(I16VE16 + dst, top); - HorizontalPred16(I16HE16 + dst, left); - TrueMotion16(I16TM16 + dst, left, top); -} - -// Left samples are top[-5 .. -2], top_left is top[-1], top are -// located at top[0..3], and top right is top[4..7] -static void Intra4Preds_MIPSdspR2(uint8_t* dst, const uint8_t* top) { - DC4(I4DC4 + dst, top); - TM4(I4TM4 + dst, top); - VE4(I4VE4 + dst, top); - HE4(I4HE4 + dst, top); - RD4(I4RD4 + dst, top); - VR4(I4VR4 + dst, top); - LD4(I4LD4 + dst, top); - VL4(I4VL4 + dst, top); - HD4(I4HD4 + dst, top); - HU4(I4HU4 + dst, top); -} - -//------------------------------------------------------------------------------ -// Metric - -#if !defined(WORK_AROUND_GCC) - -#define GET_SSE_INNER(A) \ - "lw %[temp0], " #A "(%[a]) \n\t" \ - "lw %[temp1], " #A "(%[b]) \n\t" \ - "preceu.ph.qbr %[temp2], %[temp0] \n\t" \ - "preceu.ph.qbl %[temp0], %[temp0] \n\t" \ - "preceu.ph.qbr %[temp3], %[temp1] \n\t" \ - "preceu.ph.qbl %[temp1], %[temp1] \n\t" \ - "subq.ph %[temp2], %[temp2], %[temp3] \n\t" \ - "subq.ph %[temp0], %[temp0], %[temp1] \n\t" \ - "dpa.w.ph $ac0, %[temp2], %[temp2] \n\t" \ - "dpa.w.ph $ac0, %[temp0], %[temp0] \n\t" - -#define GET_SSE(A, B, C, D) \ - GET_SSE_INNER(A) \ - GET_SSE_INNER(B) \ - GET_SSE_INNER(C) \ - GET_SSE_INNER(D) - -static int SSE16x16_MIPSdspR2(const uint8_t* a, const uint8_t* b) { - int count; - int temp0, temp1, temp2, temp3; - __asm__ volatile ( - "mult $zero, $zero \n\t" - GET_SSE( 0 * BPS, 4 + 0 * BPS, 8 + 0 * BPS, 12 + 0 * BPS) - GET_SSE( 1 * BPS, 4 + 1 * BPS, 8 + 1 * BPS, 12 + 1 * BPS) - GET_SSE( 2 * BPS, 4 + 2 * BPS, 8 + 2 * BPS, 12 + 2 * BPS) - GET_SSE( 3 * BPS, 4 + 3 * BPS, 8 + 3 * BPS, 12 + 3 * BPS) - GET_SSE( 4 * BPS, 4 + 4 * BPS, 8 + 4 * BPS, 12 + 4 * BPS) - GET_SSE( 5 * BPS, 4 + 5 * BPS, 8 + 5 * BPS, 12 + 5 * BPS) - GET_SSE( 6 * BPS, 4 + 6 * BPS, 8 + 6 * BPS, 12 + 6 * BPS) - GET_SSE( 7 * BPS, 4 + 7 * BPS, 8 + 7 * BPS, 12 + 7 * BPS) - GET_SSE( 8 * BPS, 4 + 8 * BPS, 8 + 8 * BPS, 12 + 8 * BPS) - GET_SSE( 9 * BPS, 4 + 9 * BPS, 8 + 9 * BPS, 12 + 9 * BPS) - GET_SSE(10 * BPS, 4 + 10 * BPS, 8 + 10 * BPS, 12 + 10 * BPS) - GET_SSE(11 * BPS, 4 + 11 * BPS, 8 + 11 * BPS, 12 + 11 * BPS) - GET_SSE(12 * BPS, 4 + 12 * BPS, 8 + 12 * BPS, 12 + 12 * BPS) - GET_SSE(13 * BPS, 4 + 13 * BPS, 8 + 13 * BPS, 12 + 13 * BPS) - GET_SSE(14 * BPS, 4 + 14 * BPS, 8 + 14 * BPS, 12 + 14 * BPS) - GET_SSE(15 * BPS, 4 + 15 * BPS, 8 + 15 * BPS, 12 + 15 * BPS) - "mflo %[count] \n\t" - : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), - [temp3]"=&r"(temp3), [count]"=&r"(count) - : [a]"r"(a), [b]"r"(b) - : "memory", "hi", "lo" - ); - return count; -} - -static int SSE16x8_MIPSdspR2(const uint8_t* a, const uint8_t* b) { - int count; - int temp0, temp1, temp2, temp3; - __asm__ volatile ( - "mult $zero, $zero \n\t" - GET_SSE( 0 * BPS, 4 + 0 * BPS, 8 + 0 * BPS, 12 + 0 * BPS) - GET_SSE( 1 * BPS, 4 + 1 * BPS, 8 + 1 * BPS, 12 + 1 * BPS) - GET_SSE( 2 * BPS, 4 + 2 * BPS, 8 + 2 * BPS, 12 + 2 * BPS) - GET_SSE( 3 * BPS, 4 + 3 * BPS, 8 + 3 * BPS, 12 + 3 * BPS) - GET_SSE( 4 * BPS, 4 + 4 * BPS, 8 + 4 * BPS, 12 + 4 * BPS) - GET_SSE( 5 * BPS, 4 + 5 * BPS, 8 + 5 * BPS, 12 + 5 * BPS) - GET_SSE( 6 * BPS, 4 + 6 * BPS, 8 + 6 * BPS, 12 + 6 * BPS) - GET_SSE( 7 * BPS, 4 + 7 * BPS, 8 + 7 * BPS, 12 + 7 * BPS) - "mflo %[count] \n\t" - : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), - [temp3]"=&r"(temp3), [count]"=&r"(count) - : [a]"r"(a), [b]"r"(b) - : "memory", "hi", "lo" - ); - return count; -} - -static int SSE8x8_MIPSdspR2(const uint8_t* a, const uint8_t* b) { - int count; - int temp0, temp1, temp2, temp3; - __asm__ volatile ( - "mult $zero, $zero \n\t" - GET_SSE(0 * BPS, 4 + 0 * BPS, 1 * BPS, 4 + 1 * BPS) - GET_SSE(2 * BPS, 4 + 2 * BPS, 3 * BPS, 4 + 3 * BPS) - GET_SSE(4 * BPS, 4 + 4 * BPS, 5 * BPS, 4 + 5 * BPS) - GET_SSE(6 * BPS, 4 + 6 * BPS, 7 * BPS, 4 + 7 * BPS) - "mflo %[count] \n\t" - : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), - [temp3]"=&r"(temp3), [count]"=&r"(count) - : [a]"r"(a), [b]"r"(b) - : "memory", "hi", "lo" - ); - return count; -} - -static int SSE4x4_MIPSdspR2(const uint8_t* a, const uint8_t* b) { - int count; - int temp0, temp1, temp2, temp3; - __asm__ volatile ( - "mult $zero, $zero \n\t" - GET_SSE(0 * BPS, 1 * BPS, 2 * BPS, 3 * BPS) - "mflo %[count] \n\t" - : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), - [temp3]"=&r"(temp3), [count]"=&r"(count) - : [a]"r"(a), [b]"r"(b) - : "memory", "hi", "lo" - ); - return count; -} - -#undef GET_SSE -#undef GET_SSE_INNER - -#endif // !WORK_AROUND_GCC - -#undef FILL_8_OR_16 -#undef FILL_PART -#undef OUTPUT_EARLY_CLOBBER_REGS_17 -#undef MUL_HALF -#undef ABS_X8 -#undef ADD_SUB_HALVES_X4 - -//------------------------------------------------------------------------------ -// Quantization -// - -// macro for one pass through for loop in QuantizeBlock reading 2 values at time -// QUANTDIV macro inlined -// J - offset in bytes (kZigzag[n] * 2) -// K - offset in bytes (kZigzag[n] * 4) -// N - offset in bytes (n * 2) -// N1 - offset in bytes ((n + 1) * 2) -#define QUANTIZE_ONE(J, K, N, N1) \ - "ulw %[temp1], " #J "(%[ppin]) \n\t" \ - "ulw %[temp2], " #J "(%[ppsharpen]) \n\t" \ - "lhu %[temp3], " #K "(%[ppzthresh]) \n\t" \ - "lhu %[temp6], " #K "+4(%[ppzthresh]) \n\t" \ - "absq_s.ph %[temp4], %[temp1] \n\t" \ - "ins %[temp3], %[temp6], 16, 16 \n\t" \ - "addu.ph %[coeff], %[temp4], %[temp2] \n\t" \ - "shra.ph %[sign], %[temp1], 15 \n\t" \ - "li %[level], 0x10001 \n\t" \ - "cmp.lt.ph %[temp3], %[coeff] \n\t" \ - "lhu %[temp1], " #J "(%[ppiq]) \n\t" \ - "pick.ph %[temp5], %[level], $0 \n\t" \ - "lw %[temp2], " #K "(%[ppbias]) \n\t" \ - "beqz %[temp5], 0f \n\t" \ - "lhu %[temp3], " #J "(%[ppq]) \n\t" \ - "beq %[temp5], %[level], 1f \n\t" \ - "andi %[temp5], %[temp5], 0x1 \n\t" \ - "andi %[temp4], %[coeff], 0xffff \n\t" \ - "beqz %[temp5], 2f \n\t" \ - "mul %[level], %[temp4], %[temp1] \n\t" \ - "sh $0, " #J "+2(%[ppin]) \n\t" \ - "sh $0, " #N1 "(%[pout]) \n\t" \ - "addu %[level], %[level], %[temp2] \n\t" \ - "sra %[level], %[level], 17 \n\t" \ - "slt %[temp4], %[max_level], %[level] \n\t" \ - "movn %[level], %[max_level], %[temp4] \n\t" \ - "andi %[temp6], %[sign], 0xffff \n\t" \ - "xor %[level], %[level], %[temp6] \n\t" \ - "subu %[level], %[level], %[temp6] \n\t" \ - "mul %[temp5], %[level], %[temp3] \n\t" \ - "or %[ret], %[ret], %[level] \n\t" \ - "sh %[level], " #N "(%[pout]) \n\t" \ - "sh %[temp5], " #J "(%[ppin]) \n\t" \ - "j 3f \n\t" \ -"2: \n\t" \ - "lhu %[temp1], " #J "+2(%[ppiq]) \n\t" \ - "srl %[temp5], %[coeff], 16 \n\t" \ - "mul %[level], %[temp5], %[temp1] \n\t" \ - "lw %[temp2], " #K "+4(%[ppbias]) \n\t" \ - "lhu %[temp3], " #J "+2(%[ppq]) \n\t" \ - "addu %[level], %[level], %[temp2] \n\t" \ - "sra %[level], %[level], 17 \n\t" \ - "srl %[temp6], %[sign], 16 \n\t" \ - "slt %[temp4], %[max_level], %[level] \n\t" \ - "movn %[level], %[max_level], %[temp4] \n\t" \ - "xor %[level], %[level], %[temp6] \n\t" \ - "subu %[level], %[level], %[temp6] \n\t" \ - "mul %[temp5], %[level], %[temp3] \n\t" \ - "sh $0, " #J "(%[ppin]) \n\t" \ - "sh $0, " #N "(%[pout]) \n\t" \ - "or %[ret], %[ret], %[level] \n\t" \ - "sh %[temp5], " #J "+2(%[ppin]) \n\t" \ - "sh %[level], " #N1 "(%[pout]) \n\t" \ - "j 3f \n\t" \ -"1: \n\t" \ - "lhu %[temp1], " #J "(%[ppiq]) \n\t" \ - "lw %[temp2], " #K "(%[ppbias]) \n\t" \ - "ulw %[temp3], " #J "(%[ppq]) \n\t" \ - "andi %[temp5], %[coeff], 0xffff \n\t" \ - "srl %[temp0], %[coeff], 16 \n\t" \ - "lhu %[temp6], " #J "+2(%[ppiq]) \n\t" \ - "lw %[coeff], " #K "+4(%[ppbias]) \n\t" \ - "mul %[level], %[temp5], %[temp1] \n\t" \ - "mul %[temp4], %[temp0], %[temp6] \n\t" \ - "addu %[level], %[level], %[temp2] \n\t" \ - "addu %[temp4], %[temp4], %[coeff] \n\t" \ - "precrq.ph.w %[level], %[temp4], %[level] \n\t" \ - "shra.ph %[level], %[level], 1 \n\t" \ - "cmp.lt.ph %[max_level1],%[level] \n\t" \ - "pick.ph %[level], %[max_level], %[level] \n\t" \ - "xor %[level], %[level], %[sign] \n\t" \ - "subu.ph %[level], %[level], %[sign] \n\t" \ - "mul.ph %[temp3], %[level], %[temp3] \n\t" \ - "or %[ret], %[ret], %[level] \n\t" \ - "sh %[level], " #N "(%[pout]) \n\t" \ - "srl %[level], %[level], 16 \n\t" \ - "sh %[level], " #N1 "(%[pout]) \n\t" \ - "usw %[temp3], " #J "(%[ppin]) \n\t" \ - "j 3f \n\t" \ -"0: \n\t" \ - "sh $0, " #N "(%[pout]) \n\t" \ - "sh $0, " #N1 "(%[pout]) \n\t" \ - "usw $0, " #J "(%[ppin]) \n\t" \ -"3: \n\t" - -static int QuantizeBlock_MIPSdspR2(int16_t in[16], int16_t out[16], - const VP8Matrix* const mtx) { - int temp0, temp1, temp2, temp3, temp4, temp5,temp6; - int sign, coeff, level; - int max_level = MAX_LEVEL; - int max_level1 = max_level << 16 | max_level; - int ret = 0; - - int16_t* ppin = &in[0]; - int16_t* pout = &out[0]; - const uint16_t* ppsharpen = &mtx->sharpen_[0]; - const uint32_t* ppzthresh = &mtx->zthresh_[0]; - const uint16_t* ppq = &mtx->q_[0]; - const uint16_t* ppiq = &mtx->iq_[0]; - const uint32_t* ppbias = &mtx->bias_[0]; - - __asm__ volatile ( - QUANTIZE_ONE( 0, 0, 0, 2) - QUANTIZE_ONE( 4, 8, 10, 12) - QUANTIZE_ONE( 8, 16, 4, 8) - QUANTIZE_ONE(12, 24, 14, 24) - QUANTIZE_ONE(16, 32, 6, 16) - QUANTIZE_ONE(20, 40, 22, 26) - QUANTIZE_ONE(24, 48, 18, 20) - QUANTIZE_ONE(28, 56, 28, 30) - - : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), - [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), - [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), - [sign]"=&r"(sign), [coeff]"=&r"(coeff), - [level]"=&r"(level), [temp6]"=&r"(temp6), [ret]"+&r"(ret) - : [ppin]"r"(ppin), [pout]"r"(pout), [max_level1]"r"(max_level1), - [ppiq]"r"(ppiq), [max_level]"r"(max_level), - [ppbias]"r"(ppbias), [ppzthresh]"r"(ppzthresh), - [ppsharpen]"r"(ppsharpen), [ppq]"r"(ppq) - : "memory", "hi", "lo" - ); - - return (ret != 0); -} - -static int Quantize2Blocks_MIPSdspR2(int16_t in[32], int16_t out[32], - const VP8Matrix* const mtx) { - int nz; - nz = QuantizeBlock_MIPSdspR2(in + 0 * 16, out + 0 * 16, mtx) << 0; - nz |= QuantizeBlock_MIPSdspR2(in + 1 * 16, out + 1 * 16, mtx) << 1; - return nz; -} - -#undef QUANTIZE_ONE - -// macro for one horizontal pass in FTransformWHT -// temp0..temp7 holds tmp[0]..tmp[15] -// A, B, C, D - offset in bytes to load from in buffer -// TEMP0, TEMP1 - registers for corresponding tmp elements -#define HORIZONTAL_PASS_WHT(A, B, C, D, TEMP0, TEMP1) \ - "lh %[" #TEMP0 "], " #A "(%[in]) \n\t" \ - "lh %[" #TEMP1 "], " #B "(%[in]) \n\t" \ - "lh %[temp8], " #C "(%[in]) \n\t" \ - "lh %[temp9], " #D "(%[in]) \n\t" \ - "ins %[" #TEMP1 "], %[" #TEMP0 "], 16, 16 \n\t" \ - "ins %[temp9], %[temp8], 16, 16 \n\t" \ - "subq.ph %[temp8], %[" #TEMP1 "], %[temp9] \n\t" \ - "addq.ph %[temp9], %[" #TEMP1 "], %[temp9] \n\t" \ - "precrq.ph.w %[" #TEMP0 "], %[temp8], %[temp9] \n\t" \ - "append %[temp8], %[temp9], 16 \n\t" \ - "subq.ph %[" #TEMP1 "], %[" #TEMP0 "], %[temp8] \n\t" \ - "addq.ph %[" #TEMP0 "], %[" #TEMP0 "], %[temp8] \n\t" \ - "rotr %[" #TEMP1 "], %[" #TEMP1 "], 16 \n\t" - -// macro for one vertical pass in FTransformWHT -// temp0..temp7 holds tmp[0]..tmp[15] -// A, B, C, D - offsets in bytes to store to out buffer -// TEMP0, TEMP2, TEMP4 and TEMP6 - registers for corresponding tmp elements -#define VERTICAL_PASS_WHT(A, B, C, D, TEMP0, TEMP2, TEMP4, TEMP6) \ - "addq.ph %[temp8], %[" #TEMP0 "], %[" #TEMP4 "] \n\t" \ - "addq.ph %[temp9], %[" #TEMP2 "], %[" #TEMP6 "] \n\t" \ - "subq.ph %[" #TEMP2 "], %[" #TEMP2 "], %[" #TEMP6 "] \n\t" \ - "subq.ph %[" #TEMP6 "], %[" #TEMP0 "], %[" #TEMP4 "] \n\t" \ - "addqh.ph %[" #TEMP0 "], %[temp8], %[temp9] \n\t" \ - "subqh.ph %[" #TEMP4 "], %[" #TEMP6 "], %[" #TEMP2 "] \n\t" \ - "addqh.ph %[" #TEMP2 "], %[" #TEMP2 "], %[" #TEMP6 "] \n\t" \ - "subqh.ph %[" #TEMP6 "], %[temp8], %[temp9] \n\t" \ - "usw %[" #TEMP0 "], " #A "(%[out]) \n\t" \ - "usw %[" #TEMP2 "], " #B "(%[out]) \n\t" \ - "usw %[" #TEMP4 "], " #C "(%[out]) \n\t" \ - "usw %[" #TEMP6 "], " #D "(%[out]) \n\t" - -static void FTransformWHT_MIPSdspR2(const int16_t* in, int16_t* out) { - int temp0, temp1, temp2, temp3, temp4; - int temp5, temp6, temp7, temp8, temp9; - - __asm__ volatile ( - HORIZONTAL_PASS_WHT( 0, 32, 64, 96, temp0, temp1) - HORIZONTAL_PASS_WHT(128, 160, 192, 224, temp2, temp3) - HORIZONTAL_PASS_WHT(256, 288, 320, 352, temp4, temp5) - HORIZONTAL_PASS_WHT(384, 416, 448, 480, temp6, temp7) - VERTICAL_PASS_WHT(0, 8, 16, 24, temp0, temp2, temp4, temp6) - VERTICAL_PASS_WHT(4, 12, 20, 28, temp1, temp3, temp5, temp7) - : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), - [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), - [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8), - [temp9]"=&r"(temp9) - : [in]"r"(in), [out]"r"(out) - : "memory" - ); -} - -#undef VERTICAL_PASS_WHT -#undef HORIZONTAL_PASS_WHT - -// macro for converting coefficients to bin -// convert 8 coeffs at time -// A, B, C, D - offsets in bytes to load from out buffer -#define CONVERT_COEFFS_TO_BIN(A, B, C, D) \ - "ulw %[temp0], " #A "(%[out]) \n\t" \ - "ulw %[temp1], " #B "(%[out]) \n\t" \ - "ulw %[temp2], " #C "(%[out]) \n\t" \ - "ulw %[temp3], " #D "(%[out]) \n\t" \ - "absq_s.ph %[temp0], %[temp0] \n\t" \ - "absq_s.ph %[temp1], %[temp1] \n\t" \ - "absq_s.ph %[temp2], %[temp2] \n\t" \ - "absq_s.ph %[temp3], %[temp3] \n\t" \ - "shra.ph %[temp0], %[temp0], 3 \n\t" \ - "shra.ph %[temp1], %[temp1], 3 \n\t" \ - "shra.ph %[temp2], %[temp2], 3 \n\t" \ - "shra.ph %[temp3], %[temp3], 3 \n\t" \ - "shll_s.ph %[temp0], %[temp0], 10 \n\t" \ - "shll_s.ph %[temp1], %[temp1], 10 \n\t" \ - "shll_s.ph %[temp2], %[temp2], 10 \n\t" \ - "shll_s.ph %[temp3], %[temp3], 10 \n\t" \ - "shrl.ph %[temp0], %[temp0], 10 \n\t" \ - "shrl.ph %[temp1], %[temp1], 10 \n\t" \ - "shrl.ph %[temp2], %[temp2], 10 \n\t" \ - "shrl.ph %[temp3], %[temp3], 10 \n\t" \ - "shll.ph %[temp0], %[temp0], 2 \n\t" \ - "shll.ph %[temp1], %[temp1], 2 \n\t" \ - "shll.ph %[temp2], %[temp2], 2 \n\t" \ - "shll.ph %[temp3], %[temp3], 2 \n\t" \ - "ext %[temp4], %[temp0], 0, 16 \n\t" \ - "ext %[temp0], %[temp0], 16, 16 \n\t" \ - "addu %[temp4], %[temp4], %[dist] \n\t" \ - "addu %[temp0], %[temp0], %[dist] \n\t" \ - "ext %[temp5], %[temp1], 0, 16 \n\t" \ - "lw %[temp8], 0(%[temp4]) \n\t" \ - "ext %[temp1], %[temp1], 16, 16 \n\t" \ - "addu %[temp5], %[temp5], %[dist] \n\t" \ - "addiu %[temp8], %[temp8], 1 \n\t" \ - "sw %[temp8], 0(%[temp4]) \n\t" \ - "lw %[temp8], 0(%[temp0]) \n\t" \ - "addu %[temp1], %[temp1], %[dist] \n\t" \ - "ext %[temp6], %[temp2], 0, 16 \n\t" \ - "addiu %[temp8], %[temp8], 1 \n\t" \ - "sw %[temp8], 0(%[temp0]) \n\t" \ - "lw %[temp8], 0(%[temp5]) \n\t" \ - "ext %[temp2], %[temp2], 16, 16 \n\t" \ - "addu %[temp6], %[temp6], %[dist] \n\t" \ - "addiu %[temp8], %[temp8], 1 \n\t" \ - "sw %[temp8], 0(%[temp5]) \n\t" \ - "lw %[temp8], 0(%[temp1]) \n\t" \ - "addu %[temp2], %[temp2], %[dist] \n\t" \ - "ext %[temp7], %[temp3], 0, 16 \n\t" \ - "addiu %[temp8], %[temp8], 1 \n\t" \ - "sw %[temp8], 0(%[temp1]) \n\t" \ - "lw %[temp8], 0(%[temp6]) \n\t" \ - "ext %[temp3], %[temp3], 16, 16 \n\t" \ - "addu %[temp7], %[temp7], %[dist] \n\t" \ - "addiu %[temp8], %[temp8], 1 \n\t" \ - "sw %[temp8], 0(%[temp6]) \n\t" \ - "lw %[temp8], 0(%[temp2]) \n\t" \ - "addu %[temp3], %[temp3], %[dist] \n\t" \ - "addiu %[temp8], %[temp8], 1 \n\t" \ - "sw %[temp8], 0(%[temp2]) \n\t" \ - "lw %[temp8], 0(%[temp7]) \n\t" \ - "addiu %[temp8], %[temp8], 1 \n\t" \ - "sw %[temp8], 0(%[temp7]) \n\t" \ - "lw %[temp8], 0(%[temp3]) \n\t" \ - "addiu %[temp8], %[temp8], 1 \n\t" \ - "sw %[temp8], 0(%[temp3]) \n\t" - -static void CollectHistogram_MIPSdspR2(const uint8_t* ref, const uint8_t* pred, - int start_block, int end_block, - VP8Histogram* const histo) { - int j; - int distribution[MAX_COEFF_THRESH + 1] = { 0 }; - const int max_coeff = (MAX_COEFF_THRESH << 16) + MAX_COEFF_THRESH; - for (j = start_block; j < end_block; ++j) { - int16_t out[16]; - int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8; - - VP8FTransform(ref + VP8DspScan[j], pred + VP8DspScan[j], out); - - // Convert coefficients to bin. - __asm__ volatile ( - CONVERT_COEFFS_TO_BIN( 0, 4, 8, 12) - CONVERT_COEFFS_TO_BIN(16, 20, 24, 28) - : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), - [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), - [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8) - : [dist]"r"(distribution), [out]"r"(out), [max_coeff]"r"(max_coeff) - : "memory" - ); - } - VP8SetHistogramData(distribution, histo); -} - -#undef CONVERT_COEFFS_TO_BIN - -//------------------------------------------------------------------------------ -// Entry point - -extern void VP8EncDspInitMIPSdspR2(void); - -WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspInitMIPSdspR2(void) { - VP8FTransform = FTransform_MIPSdspR2; - VP8FTransformWHT = FTransformWHT_MIPSdspR2; - VP8ITransform = ITransform_MIPSdspR2; - - VP8TDisto4x4 = Disto4x4_MIPSdspR2; - VP8TDisto16x16 = Disto16x16_MIPSdspR2; - - VP8EncPredLuma16 = Intra16Preds_MIPSdspR2; - VP8EncPredChroma8 = IntraChromaPreds_MIPSdspR2; - VP8EncPredLuma4 = Intra4Preds_MIPSdspR2; - -#if !defined(WORK_AROUND_GCC) - VP8SSE16x16 = SSE16x16_MIPSdspR2; - VP8SSE8x8 = SSE8x8_MIPSdspR2; - VP8SSE16x8 = SSE16x8_MIPSdspR2; - VP8SSE4x4 = SSE4x4_MIPSdspR2; -#endif - - VP8EncQuantizeBlock = QuantizeBlock_MIPSdspR2; - VP8EncQuantize2Blocks = Quantize2Blocks_MIPSdspR2; - - VP8CollectHistogram = CollectHistogram_MIPSdspR2; -} - -#else // !WEBP_USE_MIPS_DSP_R2 - -WEBP_DSP_INIT_STUB(VP8EncDspInitMIPSdspR2) - -#endif // WEBP_USE_MIPS_DSP_R2 diff --git a/libwebp/src/dsp/enc_msa.c b/libwebp/src/dsp/enc_msa.c deleted file mode 100644 index 6f85add4..00000000 --- a/libwebp/src/dsp/enc_msa.c +++ /dev/null @@ -1,896 +0,0 @@ -// Copyright 2016 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// MSA version of encoder dsp functions. -// -// Author: Prashant Patil (prashant.patil@imgtec.com) - -#include "src/dsp/dsp.h" - -#if defined(WEBP_USE_MSA) - -#include -#include "src/dsp/msa_macro.h" -#include "src/enc/vp8i_enc.h" - -//------------------------------------------------------------------------------ -// Transforms - -#define IDCT_1D_W(in0, in1, in2, in3, out0, out1, out2, out3) do { \ - v4i32 a1_m, b1_m, c1_m, d1_m; \ - const v4i32 cospi8sqrt2minus1 = __msa_fill_w(20091); \ - const v4i32 sinpi8sqrt2 = __msa_fill_w(35468); \ - v4i32 c_tmp1_m = in1 * sinpi8sqrt2; \ - v4i32 c_tmp2_m = in3 * cospi8sqrt2minus1; \ - v4i32 d_tmp1_m = in1 * cospi8sqrt2minus1; \ - v4i32 d_tmp2_m = in3 * sinpi8sqrt2; \ - \ - ADDSUB2(in0, in2, a1_m, b1_m); \ - SRAI_W2_SW(c_tmp1_m, c_tmp2_m, 16); \ - c_tmp2_m = c_tmp2_m + in3; \ - c1_m = c_tmp1_m - c_tmp2_m; \ - SRAI_W2_SW(d_tmp1_m, d_tmp2_m, 16); \ - d_tmp1_m = d_tmp1_m + in1; \ - d1_m = d_tmp1_m + d_tmp2_m; \ - BUTTERFLY_4(a1_m, b1_m, c1_m, d1_m, out0, out1, out2, out3); \ -} while (0) - -static WEBP_INLINE void ITransformOne(const uint8_t* ref, const int16_t* in, - uint8_t* dst) { - v8i16 input0, input1; - v4i32 in0, in1, in2, in3, hz0, hz1, hz2, hz3, vt0, vt1, vt2, vt3; - v4i32 res0, res1, res2, res3; - v16i8 dest0, dest1, dest2, dest3; - const v16i8 zero = { 0 }; - - LD_SH2(in, 8, input0, input1); - UNPCK_SH_SW(input0, in0, in1); - UNPCK_SH_SW(input1, in2, in3); - IDCT_1D_W(in0, in1, in2, in3, hz0, hz1, hz2, hz3); - TRANSPOSE4x4_SW_SW(hz0, hz1, hz2, hz3, hz0, hz1, hz2, hz3); - IDCT_1D_W(hz0, hz1, hz2, hz3, vt0, vt1, vt2, vt3); - SRARI_W4_SW(vt0, vt1, vt2, vt3, 3); - TRANSPOSE4x4_SW_SW(vt0, vt1, vt2, vt3, vt0, vt1, vt2, vt3); - LD_SB4(ref, BPS, dest0, dest1, dest2, dest3); - ILVR_B4_SW(zero, dest0, zero, dest1, zero, dest2, zero, dest3, - res0, res1, res2, res3); - ILVR_H4_SW(zero, res0, zero, res1, zero, res2, zero, res3, - res0, res1, res2, res3); - ADD4(res0, vt0, res1, vt1, res2, vt2, res3, vt3, res0, res1, res2, res3); - CLIP_SW4_0_255(res0, res1, res2, res3); - PCKEV_B2_SW(res0, res1, res2, res3, vt0, vt1); - res0 = (v4i32)__msa_pckev_b((v16i8)vt0, (v16i8)vt1); - ST4x4_UB(res0, res0, 3, 2, 1, 0, dst, BPS); -} - -static void ITransform_MSA(const uint8_t* ref, const int16_t* in, uint8_t* dst, - int do_two) { - ITransformOne(ref, in, dst); - if (do_two) { - ITransformOne(ref + 4, in + 16, dst + 4); - } -} - -static void FTransform_MSA(const uint8_t* src, const uint8_t* ref, - int16_t* out) { - uint64_t out0, out1, out2, out3; - uint32_t in0, in1, in2, in3; - v4i32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; - v8i16 t0, t1, t2, t3; - v16u8 srcl0, srcl1, src0 = { 0 }, src1 = { 0 }; - const v8i16 mask0 = { 0, 4, 8, 12, 1, 5, 9, 13 }; - const v8i16 mask1 = { 3, 7, 11, 15, 2, 6, 10, 14 }; - const v8i16 mask2 = { 4, 0, 5, 1, 6, 2, 7, 3 }; - const v8i16 mask3 = { 0, 4, 1, 5, 2, 6, 3, 7 }; - const v8i16 cnst0 = { 2217, -5352, 2217, -5352, 2217, -5352, 2217, -5352 }; - const v8i16 cnst1 = { 5352, 2217, 5352, 2217, 5352, 2217, 5352, 2217 }; - - LW4(src, BPS, in0, in1, in2, in3); - INSERT_W4_UB(in0, in1, in2, in3, src0); - LW4(ref, BPS, in0, in1, in2, in3); - INSERT_W4_UB(in0, in1, in2, in3, src1); - ILVRL_B2_UB(src0, src1, srcl0, srcl1); - HSUB_UB2_SH(srcl0, srcl1, t0, t1); - VSHF_H2_SH(t0, t1, t0, t1, mask0, mask1, t2, t3); - ADDSUB2(t2, t3, t0, t1); - t0 = SRLI_H(t0, 3); - VSHF_H2_SH(t0, t0, t1, t1, mask2, mask3, t3, t2); - tmp0 = __msa_hadd_s_w(t3, t3); - tmp2 = __msa_hsub_s_w(t3, t3); - FILL_W2_SW(1812, 937, tmp1, tmp3); - DPADD_SH2_SW(t2, t2, cnst0, cnst1, tmp3, tmp1); - SRAI_W2_SW(tmp1, tmp3, 9); - PCKEV_H2_SH(tmp1, tmp0, tmp3, tmp2, t0, t1); - VSHF_H2_SH(t0, t1, t0, t1, mask0, mask1, t2, t3); - ADDSUB2(t2, t3, t0, t1); - VSHF_H2_SH(t0, t0, t1, t1, mask2, mask3, t3, t2); - tmp0 = __msa_hadd_s_w(t3, t3); - tmp2 = __msa_hsub_s_w(t3, t3); - ADDVI_W2_SW(tmp0, 7, tmp2, 7, tmp0, tmp2); - SRAI_W2_SW(tmp0, tmp2, 4); - FILL_W2_SW(12000, 51000, tmp1, tmp3); - DPADD_SH2_SW(t2, t2, cnst0, cnst1, tmp3, tmp1); - SRAI_W2_SW(tmp1, tmp3, 16); - UNPCK_R_SH_SW(t1, tmp4); - tmp5 = __msa_ceqi_w(tmp4, 0); - tmp4 = (v4i32)__msa_nor_v((v16u8)tmp5, (v16u8)tmp5); - tmp5 = __msa_fill_w(1); - tmp5 = (v4i32)__msa_and_v((v16u8)tmp5, (v16u8)tmp4); - tmp1 += tmp5; - PCKEV_H2_SH(tmp1, tmp0, tmp3, tmp2, t0, t1); - out0 = __msa_copy_s_d((v2i64)t0, 0); - out1 = __msa_copy_s_d((v2i64)t0, 1); - out2 = __msa_copy_s_d((v2i64)t1, 0); - out3 = __msa_copy_s_d((v2i64)t1, 1); - SD4(out0, out1, out2, out3, out, 8); -} - -static void FTransformWHT_MSA(const int16_t* in, int16_t* out) { - v8i16 in0 = { 0 }; - v8i16 in1 = { 0 }; - v8i16 tmp0, tmp1, tmp2, tmp3; - v8i16 out0, out1; - const v8i16 mask0 = { 0, 1, 2, 3, 8, 9, 10, 11 }; - const v8i16 mask1 = { 4, 5, 6, 7, 12, 13, 14, 15 }; - const v8i16 mask2 = { 0, 4, 8, 12, 1, 5, 9, 13 }; - const v8i16 mask3 = { 3, 7, 11, 15, 2, 6, 10, 14 }; - - in0 = __msa_insert_h(in0, 0, in[ 0]); - in0 = __msa_insert_h(in0, 1, in[ 64]); - in0 = __msa_insert_h(in0, 2, in[128]); - in0 = __msa_insert_h(in0, 3, in[192]); - in0 = __msa_insert_h(in0, 4, in[ 16]); - in0 = __msa_insert_h(in0, 5, in[ 80]); - in0 = __msa_insert_h(in0, 6, in[144]); - in0 = __msa_insert_h(in0, 7, in[208]); - in1 = __msa_insert_h(in1, 0, in[ 48]); - in1 = __msa_insert_h(in1, 1, in[112]); - in1 = __msa_insert_h(in1, 2, in[176]); - in1 = __msa_insert_h(in1, 3, in[240]); - in1 = __msa_insert_h(in1, 4, in[ 32]); - in1 = __msa_insert_h(in1, 5, in[ 96]); - in1 = __msa_insert_h(in1, 6, in[160]); - in1 = __msa_insert_h(in1, 7, in[224]); - ADDSUB2(in0, in1, tmp0, tmp1); - VSHF_H2_SH(tmp0, tmp1, tmp0, tmp1, mask0, mask1, tmp2, tmp3); - ADDSUB2(tmp2, tmp3, tmp0, tmp1); - VSHF_H2_SH(tmp0, tmp1, tmp0, tmp1, mask2, mask3, in0, in1); - ADDSUB2(in0, in1, tmp0, tmp1); - VSHF_H2_SH(tmp0, tmp1, tmp0, tmp1, mask0, mask1, tmp2, tmp3); - ADDSUB2(tmp2, tmp3, out0, out1); - SRAI_H2_SH(out0, out1, 1); - ST_SH2(out0, out1, out, 8); -} - -static int TTransform_MSA(const uint8_t* in, const uint16_t* w) { - int sum; - uint32_t in0_m, in1_m, in2_m, in3_m; - v16i8 src0 = { 0 }; - v8i16 in0, in1, tmp0, tmp1, tmp2, tmp3; - v4i32 dst0, dst1; - const v16i8 zero = { 0 }; - const v8i16 mask0 = { 0, 1, 2, 3, 8, 9, 10, 11 }; - const v8i16 mask1 = { 4, 5, 6, 7, 12, 13, 14, 15 }; - const v8i16 mask2 = { 0, 4, 8, 12, 1, 5, 9, 13 }; - const v8i16 mask3 = { 3, 7, 11, 15, 2, 6, 10, 14 }; - - LW4(in, BPS, in0_m, in1_m, in2_m, in3_m); - INSERT_W4_SB(in0_m, in1_m, in2_m, in3_m, src0); - ILVRL_B2_SH(zero, src0, tmp0, tmp1); - VSHF_H2_SH(tmp0, tmp1, tmp0, tmp1, mask2, mask3, in0, in1); - ADDSUB2(in0, in1, tmp0, tmp1); - VSHF_H2_SH(tmp0, tmp1, tmp0, tmp1, mask0, mask1, tmp2, tmp3); - ADDSUB2(tmp2, tmp3, tmp0, tmp1); - VSHF_H2_SH(tmp0, tmp1, tmp0, tmp1, mask2, mask3, in0, in1); - ADDSUB2(in0, in1, tmp0, tmp1); - VSHF_H2_SH(tmp0, tmp1, tmp0, tmp1, mask0, mask1, tmp2, tmp3); - ADDSUB2(tmp2, tmp3, tmp0, tmp1); - tmp0 = __msa_add_a_h(tmp0, (v8i16)zero); - tmp1 = __msa_add_a_h(tmp1, (v8i16)zero); - LD_SH2(w, 8, tmp2, tmp3); - DOTP_SH2_SW(tmp0, tmp1, tmp2, tmp3, dst0, dst1); - dst0 = dst0 + dst1; - sum = HADD_SW_S32(dst0); - return sum; -} - -static int Disto4x4_MSA(const uint8_t* const a, const uint8_t* const b, - const uint16_t* const w) { - const int sum1 = TTransform_MSA(a, w); - const int sum2 = TTransform_MSA(b, w); - return abs(sum2 - sum1) >> 5; -} - -static int Disto16x16_MSA(const uint8_t* const a, const uint8_t* const b, - const uint16_t* const w) { - int D = 0; - int x, y; - for (y = 0; y < 16 * BPS; y += 4 * BPS) { - for (x = 0; x < 16; x += 4) { - D += Disto4x4_MSA(a + x + y, b + x + y, w); - } - } - return D; -} - -//------------------------------------------------------------------------------ -// Histogram - -static void CollectHistogram_MSA(const uint8_t* ref, const uint8_t* pred, - int start_block, int end_block, - VP8Histogram* const histo) { - int j; - int distribution[MAX_COEFF_THRESH + 1] = { 0 }; - for (j = start_block; j < end_block; ++j) { - int16_t out[16]; - VP8FTransform(ref + VP8DspScan[j], pred + VP8DspScan[j], out); - { - int k; - v8i16 coeff0, coeff1; - const v8i16 zero = { 0 }; - const v8i16 max_coeff_thr = __msa_ldi_h(MAX_COEFF_THRESH); - LD_SH2(&out[0], 8, coeff0, coeff1); - coeff0 = __msa_add_a_h(coeff0, zero); - coeff1 = __msa_add_a_h(coeff1, zero); - SRAI_H2_SH(coeff0, coeff1, 3); - coeff0 = __msa_min_s_h(coeff0, max_coeff_thr); - coeff1 = __msa_min_s_h(coeff1, max_coeff_thr); - ST_SH2(coeff0, coeff1, &out[0], 8); - for (k = 0; k < 16; ++k) { - ++distribution[out[k]]; - } - } - } - VP8SetHistogramData(distribution, histo); -} - -//------------------------------------------------------------------------------ -// Intra predictions - -// luma 4x4 prediction - -#define DST(x, y) dst[(x) + (y) * BPS] -#define AVG3(a, b, c) (((a) + 2 * (b) + (c) + 2) >> 2) -#define AVG2(a, b) (((a) + (b) + 1) >> 1) - -static WEBP_INLINE void VE4(uint8_t* dst, const uint8_t* top) { // vertical - const v16u8 A1 = { 0 }; - const uint64_t val_m = LD(top - 1); - const v16u8 A = (v16u8)__msa_insert_d((v2i64)A1, 0, val_m); - const v16u8 B = SLDI_UB(A, A, 1); - const v16u8 C = SLDI_UB(A, A, 2); - const v16u8 AC = __msa_ave_u_b(A, C); - const v16u8 B2 = __msa_ave_u_b(B, B); - const v16u8 R = __msa_aver_u_b(AC, B2); - const uint32_t out = __msa_copy_s_w((v4i32)R, 0); - SW4(out, out, out, out, dst, BPS); -} - -static WEBP_INLINE void HE4(uint8_t* dst, const uint8_t* top) { // horizontal - const int X = top[-1]; - const int I = top[-2]; - const int J = top[-3]; - const int K = top[-4]; - const int L = top[-5]; - WebPUint32ToMem(dst + 0 * BPS, 0x01010101U * AVG3(X, I, J)); - WebPUint32ToMem(dst + 1 * BPS, 0x01010101U * AVG3(I, J, K)); - WebPUint32ToMem(dst + 2 * BPS, 0x01010101U * AVG3(J, K, L)); - WebPUint32ToMem(dst + 3 * BPS, 0x01010101U * AVG3(K, L, L)); -} - -static WEBP_INLINE void DC4(uint8_t* dst, const uint8_t* top) { - uint32_t dc = 4; - int i; - for (i = 0; i < 4; ++i) dc += top[i] + top[-5 + i]; - dc >>= 3; - dc = dc | (dc << 8) | (dc << 16) | (dc << 24); - SW4(dc, dc, dc, dc, dst, BPS); -} - -static WEBP_INLINE void RD4(uint8_t* dst, const uint8_t* top) { - const v16u8 A2 = { 0 }; - const uint64_t val_m = LD(top - 5); - const v16u8 A1 = (v16u8)__msa_insert_d((v2i64)A2, 0, val_m); - const v16u8 A = (v16u8)__msa_insert_b((v16i8)A1, 8, top[3]); - const v16u8 B = SLDI_UB(A, A, 1); - const v16u8 C = SLDI_UB(A, A, 2); - const v16u8 AC = __msa_ave_u_b(A, C); - const v16u8 B2 = __msa_ave_u_b(B, B); - const v16u8 R0 = __msa_aver_u_b(AC, B2); - const v16u8 R1 = SLDI_UB(R0, R0, 1); - const v16u8 R2 = SLDI_UB(R1, R1, 1); - const v16u8 R3 = SLDI_UB(R2, R2, 1); - const uint32_t val0 = __msa_copy_s_w((v4i32)R0, 0); - const uint32_t val1 = __msa_copy_s_w((v4i32)R1, 0); - const uint32_t val2 = __msa_copy_s_w((v4i32)R2, 0); - const uint32_t val3 = __msa_copy_s_w((v4i32)R3, 0); - SW4(val3, val2, val1, val0, dst, BPS); -} - -static WEBP_INLINE void LD4(uint8_t* dst, const uint8_t* top) { - const v16u8 A1 = { 0 }; - const uint64_t val_m = LD(top); - const v16u8 A = (v16u8)__msa_insert_d((v2i64)A1, 0, val_m); - const v16u8 B = SLDI_UB(A, A, 1); - const v16u8 C1 = SLDI_UB(A, A, 2); - const v16u8 C = (v16u8)__msa_insert_b((v16i8)C1, 6, top[7]); - const v16u8 AC = __msa_ave_u_b(A, C); - const v16u8 B2 = __msa_ave_u_b(B, B); - const v16u8 R0 = __msa_aver_u_b(AC, B2); - const v16u8 R1 = SLDI_UB(R0, R0, 1); - const v16u8 R2 = SLDI_UB(R1, R1, 1); - const v16u8 R3 = SLDI_UB(R2, R2, 1); - const uint32_t val0 = __msa_copy_s_w((v4i32)R0, 0); - const uint32_t val1 = __msa_copy_s_w((v4i32)R1, 0); - const uint32_t val2 = __msa_copy_s_w((v4i32)R2, 0); - const uint32_t val3 = __msa_copy_s_w((v4i32)R3, 0); - SW4(val0, val1, val2, val3, dst, BPS); -} - -static WEBP_INLINE void VR4(uint8_t* dst, const uint8_t* top) { - const int X = top[-1]; - const int I = top[-2]; - const int J = top[-3]; - const int K = top[-4]; - const int A = top[0]; - const int B = top[1]; - const int C = top[2]; - const int D = top[3]; - DST(0, 0) = DST(1, 2) = AVG2(X, A); - DST(1, 0) = DST(2, 2) = AVG2(A, B); - DST(2, 0) = DST(3, 2) = AVG2(B, C); - DST(3, 0) = AVG2(C, D); - DST(0, 3) = AVG3(K, J, I); - DST(0, 2) = AVG3(J, I, X); - DST(0, 1) = DST(1, 3) = AVG3(I, X, A); - DST(1, 1) = DST(2, 3) = AVG3(X, A, B); - DST(2, 1) = DST(3, 3) = AVG3(A, B, C); - DST(3, 1) = AVG3(B, C, D); -} - -static WEBP_INLINE void VL4(uint8_t* dst, const uint8_t* top) { - const int A = top[0]; - const int B = top[1]; - const int C = top[2]; - const int D = top[3]; - const int E = top[4]; - const int F = top[5]; - const int G = top[6]; - const int H = top[7]; - DST(0, 0) = AVG2(A, B); - DST(1, 0) = DST(0, 2) = AVG2(B, C); - DST(2, 0) = DST(1, 2) = AVG2(C, D); - DST(3, 0) = DST(2, 2) = AVG2(D, E); - DST(0, 1) = AVG3(A, B, C); - DST(1, 1) = DST(0, 3) = AVG3(B, C, D); - DST(2, 1) = DST(1, 3) = AVG3(C, D, E); - DST(3, 1) = DST(2, 3) = AVG3(D, E, F); - DST(3, 2) = AVG3(E, F, G); - DST(3, 3) = AVG3(F, G, H); -} - -static WEBP_INLINE void HU4(uint8_t* dst, const uint8_t* top) { - const int I = top[-2]; - const int J = top[-3]; - const int K = top[-4]; - const int L = top[-5]; - DST(0, 0) = AVG2(I, J); - DST(2, 0) = DST(0, 1) = AVG2(J, K); - DST(2, 1) = DST(0, 2) = AVG2(K, L); - DST(1, 0) = AVG3(I, J, K); - DST(3, 0) = DST(1, 1) = AVG3(J, K, L); - DST(3, 1) = DST(1, 2) = AVG3(K, L, L); - DST(3, 2) = DST(2, 2) = - DST(0, 3) = DST(1, 3) = DST(2, 3) = DST(3, 3) = L; -} - -static WEBP_INLINE void HD4(uint8_t* dst, const uint8_t* top) { - const int X = top[-1]; - const int I = top[-2]; - const int J = top[-3]; - const int K = top[-4]; - const int L = top[-5]; - const int A = top[0]; - const int B = top[1]; - const int C = top[2]; - DST(0, 0) = DST(2, 1) = AVG2(I, X); - DST(0, 1) = DST(2, 2) = AVG2(J, I); - DST(0, 2) = DST(2, 3) = AVG2(K, J); - DST(0, 3) = AVG2(L, K); - DST(3, 0) = AVG3(A, B, C); - DST(2, 0) = AVG3(X, A, B); - DST(1, 0) = DST(3, 1) = AVG3(I, X, A); - DST(1, 1) = DST(3, 2) = AVG3(J, I, X); - DST(1, 2) = DST(3, 3) = AVG3(K, J, I); - DST(1, 3) = AVG3(L, K, J); -} - -static WEBP_INLINE void TM4(uint8_t* dst, const uint8_t* top) { - const v16i8 zero = { 0 }; - const v8i16 TL = (v8i16)__msa_fill_h(top[-1]); - const v8i16 L0 = (v8i16)__msa_fill_h(top[-2]); - const v8i16 L1 = (v8i16)__msa_fill_h(top[-3]); - const v8i16 L2 = (v8i16)__msa_fill_h(top[-4]); - const v8i16 L3 = (v8i16)__msa_fill_h(top[-5]); - const v16u8 T1 = LD_UB(top); - const v8i16 T = (v8i16)__msa_ilvr_b(zero, (v16i8)T1); - const v8i16 d = T - TL; - v8i16 r0, r1, r2, r3; - ADD4(d, L0, d, L1, d, L2, d, L3, r0, r1, r2, r3); - CLIP_SH4_0_255(r0, r1, r2, r3); - PCKEV_ST4x4_UB(r0, r1, r2, r3, dst, BPS); -} - -#undef DST -#undef AVG3 -#undef AVG2 - -static void Intra4Preds_MSA(uint8_t* dst, const uint8_t* top) { - DC4(I4DC4 + dst, top); - TM4(I4TM4 + dst, top); - VE4(I4VE4 + dst, top); - HE4(I4HE4 + dst, top); - RD4(I4RD4 + dst, top); - VR4(I4VR4 + dst, top); - LD4(I4LD4 + dst, top); - VL4(I4VL4 + dst, top); - HD4(I4HD4 + dst, top); - HU4(I4HU4 + dst, top); -} - -// luma 16x16 prediction - -#define STORE16x16(out, dst) do { \ - ST_UB8(out, out, out, out, out, out, out, out, dst + 0 * BPS, BPS); \ - ST_UB8(out, out, out, out, out, out, out, out, dst + 8 * BPS, BPS); \ -} while (0) - -static WEBP_INLINE void VerticalPred16x16(uint8_t* dst, const uint8_t* top) { - if (top != NULL) { - const v16u8 out = LD_UB(top); - STORE16x16(out, dst); - } else { - const v16u8 out = (v16u8)__msa_fill_b(0x7f); - STORE16x16(out, dst); - } -} - -static WEBP_INLINE void HorizontalPred16x16(uint8_t* dst, - const uint8_t* left) { - if (left != NULL) { - int j; - for (j = 0; j < 16; j += 4) { - const v16u8 L0 = (v16u8)__msa_fill_b(left[0]); - const v16u8 L1 = (v16u8)__msa_fill_b(left[1]); - const v16u8 L2 = (v16u8)__msa_fill_b(left[2]); - const v16u8 L3 = (v16u8)__msa_fill_b(left[3]); - ST_UB4(L0, L1, L2, L3, dst, BPS); - dst += 4 * BPS; - left += 4; - } - } else { - const v16u8 out = (v16u8)__msa_fill_b(0x81); - STORE16x16(out, dst); - } -} - -static WEBP_INLINE void TrueMotion16x16(uint8_t* dst, const uint8_t* left, - const uint8_t* top) { - if (left != NULL) { - if (top != NULL) { - int j; - v8i16 d1, d2; - const v16i8 zero = { 0 }; - const v8i16 TL = (v8i16)__msa_fill_h(left[-1]); - const v16u8 T = LD_UB(top); - ILVRL_B2_SH(zero, T, d1, d2); - SUB2(d1, TL, d2, TL, d1, d2); - for (j = 0; j < 16; j += 4) { - v16i8 t0, t1, t2, t3; - v8i16 r0, r1, r2, r3, r4, r5, r6, r7; - const v8i16 L0 = (v8i16)__msa_fill_h(left[j + 0]); - const v8i16 L1 = (v8i16)__msa_fill_h(left[j + 1]); - const v8i16 L2 = (v8i16)__msa_fill_h(left[j + 2]); - const v8i16 L3 = (v8i16)__msa_fill_h(left[j + 3]); - ADD4(d1, L0, d1, L1, d1, L2, d1, L3, r0, r1, r2, r3); - ADD4(d2, L0, d2, L1, d2, L2, d2, L3, r4, r5, r6, r7); - CLIP_SH4_0_255(r0, r1, r2, r3); - CLIP_SH4_0_255(r4, r5, r6, r7); - PCKEV_B4_SB(r4, r0, r5, r1, r6, r2, r7, r3, t0, t1, t2, t3); - ST_SB4(t0, t1, t2, t3, dst, BPS); - dst += 4 * BPS; - } - } else { - HorizontalPred16x16(dst, left); - } - } else { - if (top != NULL) { - VerticalPred16x16(dst, top); - } else { - const v16u8 out = (v16u8)__msa_fill_b(0x81); - STORE16x16(out, dst); - } - } -} - -static WEBP_INLINE void DCMode16x16(uint8_t* dst, const uint8_t* left, - const uint8_t* top) { - int DC; - v16u8 out; - if (top != NULL && left != NULL) { - const v16u8 rtop = LD_UB(top); - const v8u16 dctop = __msa_hadd_u_h(rtop, rtop); - const v16u8 rleft = LD_UB(left); - const v8u16 dcleft = __msa_hadd_u_h(rleft, rleft); - const v8u16 dctemp = dctop + dcleft; - DC = HADD_UH_U32(dctemp); - DC = (DC + 16) >> 5; - } else if (left != NULL) { // left but no top - const v16u8 rleft = LD_UB(left); - const v8u16 dcleft = __msa_hadd_u_h(rleft, rleft); - DC = HADD_UH_U32(dcleft); - DC = (DC + DC + 16) >> 5; - } else if (top != NULL) { // top but no left - const v16u8 rtop = LD_UB(top); - const v8u16 dctop = __msa_hadd_u_h(rtop, rtop); - DC = HADD_UH_U32(dctop); - DC = (DC + DC + 16) >> 5; - } else { // no top, no left, nothing. - DC = 0x80; - } - out = (v16u8)__msa_fill_b(DC); - STORE16x16(out, dst); -} - -static void Intra16Preds_MSA(uint8_t* dst, - const uint8_t* left, const uint8_t* top) { - DCMode16x16(I16DC16 + dst, left, top); - VerticalPred16x16(I16VE16 + dst, top); - HorizontalPred16x16(I16HE16 + dst, left); - TrueMotion16x16(I16TM16 + dst, left, top); -} - -// Chroma 8x8 prediction - -#define CALC_DC8(in, out) do { \ - const v8u16 temp0 = __msa_hadd_u_h(in, in); \ - const v4u32 temp1 = __msa_hadd_u_w(temp0, temp0); \ - const v2i64 temp2 = (v2i64)__msa_hadd_u_d(temp1, temp1); \ - const v2i64 temp3 = __msa_splati_d(temp2, 1); \ - const v2i64 temp4 = temp3 + temp2; \ - const v16i8 temp5 = (v16i8)__msa_srari_d(temp4, 4); \ - const v2i64 temp6 = (v2i64)__msa_splati_b(temp5, 0); \ - out = __msa_copy_s_d(temp6, 0); \ -} while (0) - -#define STORE8x8(out, dst) do { \ - SD4(out, out, out, out, dst + 0 * BPS, BPS); \ - SD4(out, out, out, out, dst + 4 * BPS, BPS); \ -} while (0) - -static WEBP_INLINE void VerticalPred8x8(uint8_t* dst, const uint8_t* top) { - if (top != NULL) { - const uint64_t out = LD(top); - STORE8x8(out, dst); - } else { - const uint64_t out = 0x7f7f7f7f7f7f7f7fULL; - STORE8x8(out, dst); - } -} - -static WEBP_INLINE void HorizontalPred8x8(uint8_t* dst, const uint8_t* left) { - if (left != NULL) { - int j; - for (j = 0; j < 8; j += 4) { - const v16u8 L0 = (v16u8)__msa_fill_b(left[0]); - const v16u8 L1 = (v16u8)__msa_fill_b(left[1]); - const v16u8 L2 = (v16u8)__msa_fill_b(left[2]); - const v16u8 L3 = (v16u8)__msa_fill_b(left[3]); - const uint64_t out0 = __msa_copy_s_d((v2i64)L0, 0); - const uint64_t out1 = __msa_copy_s_d((v2i64)L1, 0); - const uint64_t out2 = __msa_copy_s_d((v2i64)L2, 0); - const uint64_t out3 = __msa_copy_s_d((v2i64)L3, 0); - SD4(out0, out1, out2, out3, dst, BPS); - dst += 4 * BPS; - left += 4; - } - } else { - const uint64_t out = 0x8181818181818181ULL; - STORE8x8(out, dst); - } -} - -static WEBP_INLINE void TrueMotion8x8(uint8_t* dst, const uint8_t* left, - const uint8_t* top) { - if (left != NULL) { - if (top != NULL) { - int j; - const v8i16 TL = (v8i16)__msa_fill_h(left[-1]); - const v16u8 T1 = LD_UB(top); - const v16i8 zero = { 0 }; - const v8i16 T = (v8i16)__msa_ilvr_b(zero, (v16i8)T1); - const v8i16 d = T - TL; - for (j = 0; j < 8; j += 4) { - uint64_t out0, out1, out2, out3; - v16i8 t0, t1; - v8i16 r0 = (v8i16)__msa_fill_h(left[j + 0]); - v8i16 r1 = (v8i16)__msa_fill_h(left[j + 1]); - v8i16 r2 = (v8i16)__msa_fill_h(left[j + 2]); - v8i16 r3 = (v8i16)__msa_fill_h(left[j + 3]); - ADD4(d, r0, d, r1, d, r2, d, r3, r0, r1, r2, r3); - CLIP_SH4_0_255(r0, r1, r2, r3); - PCKEV_B2_SB(r1, r0, r3, r2, t0, t1); - out0 = __msa_copy_s_d((v2i64)t0, 0); - out1 = __msa_copy_s_d((v2i64)t0, 1); - out2 = __msa_copy_s_d((v2i64)t1, 0); - out3 = __msa_copy_s_d((v2i64)t1, 1); - SD4(out0, out1, out2, out3, dst, BPS); - dst += 4 * BPS; - } - } else { - HorizontalPred8x8(dst, left); - } - } else { - if (top != NULL) { - VerticalPred8x8(dst, top); - } else { - const uint64_t out = 0x8181818181818181ULL; - STORE8x8(out, dst); - } - } -} - -static WEBP_INLINE void DCMode8x8(uint8_t* dst, const uint8_t* left, - const uint8_t* top) { - uint64_t out; - v16u8 src = { 0 }; - if (top != NULL && left != NULL) { - const uint64_t left_m = LD(left); - const uint64_t top_m = LD(top); - INSERT_D2_UB(left_m, top_m, src); - CALC_DC8(src, out); - } else if (left != NULL) { // left but no top - const uint64_t left_m = LD(left); - INSERT_D2_UB(left_m, left_m, src); - CALC_DC8(src, out); - } else if (top != NULL) { // top but no left - const uint64_t top_m = LD(top); - INSERT_D2_UB(top_m, top_m, src); - CALC_DC8(src, out); - } else { // no top, no left, nothing. - src = (v16u8)__msa_fill_b(0x80); - out = __msa_copy_s_d((v2i64)src, 0); - } - STORE8x8(out, dst); -} - -static void IntraChromaPreds_MSA(uint8_t* dst, const uint8_t* left, - const uint8_t* top) { - // U block - DCMode8x8(C8DC8 + dst, left, top); - VerticalPred8x8(C8VE8 + dst, top); - HorizontalPred8x8(C8HE8 + dst, left); - TrueMotion8x8(C8TM8 + dst, left, top); - // V block - dst += 8; - if (top != NULL) top += 8; - if (left != NULL) left += 16; - DCMode8x8(C8DC8 + dst, left, top); - VerticalPred8x8(C8VE8 + dst, top); - HorizontalPred8x8(C8HE8 + dst, left); - TrueMotion8x8(C8TM8 + dst, left, top); -} - -//------------------------------------------------------------------------------ -// Metric - -#define PACK_DOTP_UB4_SW(in0, in1, in2, in3, out0, out1, out2, out3) do { \ - v16u8 tmp0, tmp1; \ - v8i16 tmp2, tmp3; \ - ILVRL_B2_UB(in0, in1, tmp0, tmp1); \ - HSUB_UB2_SH(tmp0, tmp1, tmp2, tmp3); \ - DOTP_SH2_SW(tmp2, tmp3, tmp2, tmp3, out0, out1); \ - ILVRL_B2_UB(in2, in3, tmp0, tmp1); \ - HSUB_UB2_SH(tmp0, tmp1, tmp2, tmp3); \ - DOTP_SH2_SW(tmp2, tmp3, tmp2, tmp3, out2, out3); \ -} while (0) - -#define PACK_DPADD_UB4_SW(in0, in1, in2, in3, out0, out1, out2, out3) do { \ - v16u8 tmp0, tmp1; \ - v8i16 tmp2, tmp3; \ - ILVRL_B2_UB(in0, in1, tmp0, tmp1); \ - HSUB_UB2_SH(tmp0, tmp1, tmp2, tmp3); \ - DPADD_SH2_SW(tmp2, tmp3, tmp2, tmp3, out0, out1); \ - ILVRL_B2_UB(in2, in3, tmp0, tmp1); \ - HSUB_UB2_SH(tmp0, tmp1, tmp2, tmp3); \ - DPADD_SH2_SW(tmp2, tmp3, tmp2, tmp3, out2, out3); \ -} while (0) - -static int SSE16x16_MSA(const uint8_t* a, const uint8_t* b) { - uint32_t sum; - v16u8 src0, src1, src2, src3, src4, src5, src6, src7; - v16u8 ref0, ref1, ref2, ref3, ref4, ref5, ref6, ref7; - v4i32 out0, out1, out2, out3; - - LD_UB8(a, BPS, src0, src1, src2, src3, src4, src5, src6, src7); - LD_UB8(b, BPS, ref0, ref1, ref2, ref3, ref4, ref5, ref6, ref7); - PACK_DOTP_UB4_SW(src0, ref0, src1, ref1, out0, out1, out2, out3); - PACK_DPADD_UB4_SW(src2, ref2, src3, ref3, out0, out1, out2, out3); - PACK_DPADD_UB4_SW(src4, ref4, src5, ref5, out0, out1, out2, out3); - PACK_DPADD_UB4_SW(src6, ref6, src7, ref7, out0, out1, out2, out3); - a += 8 * BPS; - b += 8 * BPS; - LD_UB8(a, BPS, src0, src1, src2, src3, src4, src5, src6, src7); - LD_UB8(b, BPS, ref0, ref1, ref2, ref3, ref4, ref5, ref6, ref7); - PACK_DPADD_UB4_SW(src0, ref0, src1, ref1, out0, out1, out2, out3); - PACK_DPADD_UB4_SW(src2, ref2, src3, ref3, out0, out1, out2, out3); - PACK_DPADD_UB4_SW(src4, ref4, src5, ref5, out0, out1, out2, out3); - PACK_DPADD_UB4_SW(src6, ref6, src7, ref7, out0, out1, out2, out3); - out0 += out1; - out2 += out3; - out0 += out2; - sum = HADD_SW_S32(out0); - return sum; -} - -static int SSE16x8_MSA(const uint8_t* a, const uint8_t* b) { - uint32_t sum; - v16u8 src0, src1, src2, src3, src4, src5, src6, src7; - v16u8 ref0, ref1, ref2, ref3, ref4, ref5, ref6, ref7; - v4i32 out0, out1, out2, out3; - - LD_UB8(a, BPS, src0, src1, src2, src3, src4, src5, src6, src7); - LD_UB8(b, BPS, ref0, ref1, ref2, ref3, ref4, ref5, ref6, ref7); - PACK_DOTP_UB4_SW(src0, ref0, src1, ref1, out0, out1, out2, out3); - PACK_DPADD_UB4_SW(src2, ref2, src3, ref3, out0, out1, out2, out3); - PACK_DPADD_UB4_SW(src4, ref4, src5, ref5, out0, out1, out2, out3); - PACK_DPADD_UB4_SW(src6, ref6, src7, ref7, out0, out1, out2, out3); - out0 += out1; - out2 += out3; - out0 += out2; - sum = HADD_SW_S32(out0); - return sum; -} - -static int SSE8x8_MSA(const uint8_t* a, const uint8_t* b) { - uint32_t sum; - v16u8 src0, src1, src2, src3, src4, src5, src6, src7; - v16u8 ref0, ref1, ref2, ref3, ref4, ref5, ref6, ref7; - v16u8 t0, t1, t2, t3; - v4i32 out0, out1, out2, out3; - - LD_UB8(a, BPS, src0, src1, src2, src3, src4, src5, src6, src7); - LD_UB8(b, BPS, ref0, ref1, ref2, ref3, ref4, ref5, ref6, ref7); - ILVR_B4_UB(src0, src1, src2, src3, ref0, ref1, ref2, ref3, t0, t1, t2, t3); - PACK_DOTP_UB4_SW(t0, t2, t1, t3, out0, out1, out2, out3); - ILVR_B4_UB(src4, src5, src6, src7, ref4, ref5, ref6, ref7, t0, t1, t2, t3); - PACK_DPADD_UB4_SW(t0, t2, t1, t3, out0, out1, out2, out3); - out0 += out1; - out2 += out3; - out0 += out2; - sum = HADD_SW_S32(out0); - return sum; -} - -static int SSE4x4_MSA(const uint8_t* a, const uint8_t* b) { - uint32_t sum = 0; - uint32_t src0, src1, src2, src3, ref0, ref1, ref2, ref3; - v16u8 src = { 0 }, ref = { 0 }, tmp0, tmp1; - v8i16 diff0, diff1; - v4i32 out0, out1; - - LW4(a, BPS, src0, src1, src2, src3); - LW4(b, BPS, ref0, ref1, ref2, ref3); - INSERT_W4_UB(src0, src1, src2, src3, src); - INSERT_W4_UB(ref0, ref1, ref2, ref3, ref); - ILVRL_B2_UB(src, ref, tmp0, tmp1); - HSUB_UB2_SH(tmp0, tmp1, diff0, diff1); - DOTP_SH2_SW(diff0, diff1, diff0, diff1, out0, out1); - out0 += out1; - sum = HADD_SW_S32(out0); - return sum; -} - -//------------------------------------------------------------------------------ -// Quantization - -static int QuantizeBlock_MSA(int16_t in[16], int16_t out[16], - const VP8Matrix* const mtx) { - int sum; - v8i16 in0, in1, sh0, sh1, out0, out1; - v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, sign0, sign1; - v4i32 s0, s1, s2, s3, b0, b1, b2, b3, t0, t1, t2, t3; - const v8i16 zero = { 0 }; - const v8i16 zigzag0 = { 0, 1, 4, 8, 5, 2, 3, 6 }; - const v8i16 zigzag1 = { 9, 12, 13, 10, 7, 11, 14, 15 }; - const v8i16 maxlevel = __msa_fill_h(MAX_LEVEL); - - LD_SH2(&in[0], 8, in0, in1); - LD_SH2(&mtx->sharpen_[0], 8, sh0, sh1); - tmp4 = __msa_add_a_h(in0, zero); - tmp5 = __msa_add_a_h(in1, zero); - ILVRL_H2_SH(sh0, tmp4, tmp0, tmp1); - ILVRL_H2_SH(sh1, tmp5, tmp2, tmp3); - HADD_SH4_SW(tmp0, tmp1, tmp2, tmp3, s0, s1, s2, s3); - sign0 = (in0 < zero); - sign1 = (in1 < zero); // sign - LD_SH2(&mtx->iq_[0], 8, tmp0, tmp1); // iq - ILVRL_H2_SW(zero, tmp0, t0, t1); - ILVRL_H2_SW(zero, tmp1, t2, t3); - LD_SW4(&mtx->bias_[0], 4, b0, b1, b2, b3); // bias - MUL4(t0, s0, t1, s1, t2, s2, t3, s3, t0, t1, t2, t3); - ADD4(b0, t0, b1, t1, b2, t2, b3, t3, b0, b1, b2, b3); - SRAI_W4_SW(b0, b1, b2, b3, 17); - PCKEV_H2_SH(b1, b0, b3, b2, tmp2, tmp3); - tmp0 = (tmp2 > maxlevel); - tmp1 = (tmp3 > maxlevel); - tmp2 = (v8i16)__msa_bmnz_v((v16u8)tmp2, (v16u8)maxlevel, (v16u8)tmp0); - tmp3 = (v8i16)__msa_bmnz_v((v16u8)tmp3, (v16u8)maxlevel, (v16u8)tmp1); - SUB2(zero, tmp2, zero, tmp3, tmp0, tmp1); - tmp2 = (v8i16)__msa_bmnz_v((v16u8)tmp2, (v16u8)tmp0, (v16u8)sign0); - tmp3 = (v8i16)__msa_bmnz_v((v16u8)tmp3, (v16u8)tmp1, (v16u8)sign1); - LD_SW4(&mtx->zthresh_[0], 4, t0, t1, t2, t3); // zthresh - t0 = (s0 > t0); - t1 = (s1 > t1); - t2 = (s2 > t2); - t3 = (s3 > t3); - PCKEV_H2_SH(t1, t0, t3, t2, tmp0, tmp1); - tmp4 = (v8i16)__msa_bmnz_v((v16u8)zero, (v16u8)tmp2, (v16u8)tmp0); - tmp5 = (v8i16)__msa_bmnz_v((v16u8)zero, (v16u8)tmp3, (v16u8)tmp1); - LD_SH2(&mtx->q_[0], 8, tmp0, tmp1); - MUL2(tmp4, tmp0, tmp5, tmp1, in0, in1); - VSHF_H2_SH(tmp4, tmp5, tmp4, tmp5, zigzag0, zigzag1, out0, out1); - ST_SH2(in0, in1, &in[0], 8); - ST_SH2(out0, out1, &out[0], 8); - out0 = __msa_add_a_h(out0, out1); - sum = HADD_SH_S32(out0); - return (sum > 0); -} - -static int Quantize2Blocks_MSA(int16_t in[32], int16_t out[32], - const VP8Matrix* const mtx) { - int nz; - nz = VP8EncQuantizeBlock(in + 0 * 16, out + 0 * 16, mtx) << 0; - nz |= VP8EncQuantizeBlock(in + 1 * 16, out + 1 * 16, mtx) << 1; - return nz; -} - -//------------------------------------------------------------------------------ -// Entry point - -extern void VP8EncDspInitMSA(void); - -WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspInitMSA(void) { - VP8ITransform = ITransform_MSA; - VP8FTransform = FTransform_MSA; - VP8FTransformWHT = FTransformWHT_MSA; - - VP8TDisto4x4 = Disto4x4_MSA; - VP8TDisto16x16 = Disto16x16_MSA; - VP8CollectHistogram = CollectHistogram_MSA; - - VP8EncPredLuma4 = Intra4Preds_MSA; - VP8EncPredLuma16 = Intra16Preds_MSA; - VP8EncPredChroma8 = IntraChromaPreds_MSA; - - VP8SSE16x16 = SSE16x16_MSA; - VP8SSE16x8 = SSE16x8_MSA; - VP8SSE8x8 = SSE8x8_MSA; - VP8SSE4x4 = SSE4x4_MSA; - - VP8EncQuantizeBlock = QuantizeBlock_MSA; - VP8EncQuantize2Blocks = Quantize2Blocks_MSA; - VP8EncQuantizeBlockWHT = QuantizeBlock_MSA; -} - -#else // !WEBP_USE_MSA - -WEBP_DSP_INIT_STUB(VP8EncDspInitMSA) - -#endif // WEBP_USE_MSA diff --git a/libwebp/src/dsp/enc_neon.c b/libwebp/src/dsp/enc_neon.c deleted file mode 100644 index 6f641c9a..00000000 --- a/libwebp/src/dsp/enc_neon.c +++ /dev/null @@ -1,944 +0,0 @@ -// Copyright 2012 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// ARM NEON version of speed-critical encoding functions. -// -// adapted from libvpx (https://www.webmproject.org/code/) - -#include "src/dsp/dsp.h" - -#if defined(WEBP_USE_NEON) - -#include - -#include "src/dsp/neon.h" -#include "src/enc/vp8i_enc.h" - -//------------------------------------------------------------------------------ -// Transforms (Paragraph 14.4) - -// Inverse transform. -// This code is pretty much the same as TransformOne in the dec_neon.c, except -// for subtraction to *ref. See the comments there for algorithmic explanations. - -static const int16_t kC1 = WEBP_TRANSFORM_AC3_C1; -static const int16_t kC2 = - WEBP_TRANSFORM_AC3_C2 / 2; // half of kC2, actually. See comment above. - -// This code works but is *slower* than the inlined-asm version below -// (with gcc-4.6). So we disable it for now. Later, it'll be conditional to -// WEBP_USE_INTRINSICS define. -// With gcc-4.8, it's a little faster speed than inlined-assembly. -#if defined(WEBP_USE_INTRINSICS) - -// Treats 'v' as an uint8x8_t and zero extends to an int16x8_t. -static WEBP_INLINE int16x8_t ConvertU8ToS16_NEON(uint32x2_t v) { - return vreinterpretq_s16_u16(vmovl_u8(vreinterpret_u8_u32(v))); -} - -// Performs unsigned 8b saturation on 'dst01' and 'dst23' storing the result -// to the corresponding rows of 'dst'. -static WEBP_INLINE void SaturateAndStore4x4_NEON(uint8_t* const dst, - const int16x8_t dst01, - const int16x8_t dst23) { - // Unsigned saturate to 8b. - const uint8x8_t dst01_u8 = vqmovun_s16(dst01); - const uint8x8_t dst23_u8 = vqmovun_s16(dst23); - - // Store the results. - vst1_lane_u32((uint32_t*)(dst + 0 * BPS), vreinterpret_u32_u8(dst01_u8), 0); - vst1_lane_u32((uint32_t*)(dst + 1 * BPS), vreinterpret_u32_u8(dst01_u8), 1); - vst1_lane_u32((uint32_t*)(dst + 2 * BPS), vreinterpret_u32_u8(dst23_u8), 0); - vst1_lane_u32((uint32_t*)(dst + 3 * BPS), vreinterpret_u32_u8(dst23_u8), 1); -} - -static WEBP_INLINE void Add4x4_NEON(const int16x8_t row01, - const int16x8_t row23, - const uint8_t* const ref, - uint8_t* const dst) { - uint32x2_t dst01 = vdup_n_u32(0); - uint32x2_t dst23 = vdup_n_u32(0); - - // Load the source pixels. - dst01 = vld1_lane_u32((uint32_t*)(ref + 0 * BPS), dst01, 0); - dst23 = vld1_lane_u32((uint32_t*)(ref + 2 * BPS), dst23, 0); - dst01 = vld1_lane_u32((uint32_t*)(ref + 1 * BPS), dst01, 1); - dst23 = vld1_lane_u32((uint32_t*)(ref + 3 * BPS), dst23, 1); - - { - // Convert to 16b. - const int16x8_t dst01_s16 = ConvertU8ToS16_NEON(dst01); - const int16x8_t dst23_s16 = ConvertU8ToS16_NEON(dst23); - - // Descale with rounding. - const int16x8_t out01 = vrsraq_n_s16(dst01_s16, row01, 3); - const int16x8_t out23 = vrsraq_n_s16(dst23_s16, row23, 3); - // Add the inverse transform. - SaturateAndStore4x4_NEON(dst, out01, out23); - } -} - -static WEBP_INLINE void Transpose8x2_NEON(const int16x8_t in0, - const int16x8_t in1, - int16x8x2_t* const out) { - // a0 a1 a2 a3 | b0 b1 b2 b3 => a0 b0 c0 d0 | a1 b1 c1 d1 - // c0 c1 c2 c3 | d0 d1 d2 d3 a2 b2 c2 d2 | a3 b3 c3 d3 - const int16x8x2_t tmp0 = vzipq_s16(in0, in1); // a0 c0 a1 c1 a2 c2 ... - // b0 d0 b1 d1 b2 d2 ... - *out = vzipq_s16(tmp0.val[0], tmp0.val[1]); -} - -static WEBP_INLINE void TransformPass_NEON(int16x8x2_t* const rows) { - // {rows} = in0 | in4 - // in8 | in12 - // B1 = in4 | in12 - const int16x8_t B1 = - vcombine_s16(vget_high_s16(rows->val[0]), vget_high_s16(rows->val[1])); - // C0 = kC1 * in4 | kC1 * in12 - // C1 = kC2 * in4 | kC2 * in12 - const int16x8_t C0 = vsraq_n_s16(B1, vqdmulhq_n_s16(B1, kC1), 1); - const int16x8_t C1 = vqdmulhq_n_s16(B1, kC2); - const int16x4_t a = vqadd_s16(vget_low_s16(rows->val[0]), - vget_low_s16(rows->val[1])); // in0 + in8 - const int16x4_t b = vqsub_s16(vget_low_s16(rows->val[0]), - vget_low_s16(rows->val[1])); // in0 - in8 - // c = kC2 * in4 - kC1 * in12 - // d = kC1 * in4 + kC2 * in12 - const int16x4_t c = vqsub_s16(vget_low_s16(C1), vget_high_s16(C0)); - const int16x4_t d = vqadd_s16(vget_low_s16(C0), vget_high_s16(C1)); - const int16x8_t D0 = vcombine_s16(a, b); // D0 = a | b - const int16x8_t D1 = vcombine_s16(d, c); // D1 = d | c - const int16x8_t E0 = vqaddq_s16(D0, D1); // a+d | b+c - const int16x8_t E_tmp = vqsubq_s16(D0, D1); // a-d | b-c - const int16x8_t E1 = vcombine_s16(vget_high_s16(E_tmp), vget_low_s16(E_tmp)); - Transpose8x2_NEON(E0, E1, rows); -} - -static void ITransformOne_NEON(const uint8_t* ref, - const int16_t* in, uint8_t* dst) { - int16x8x2_t rows; - INIT_VECTOR2(rows, vld1q_s16(in + 0), vld1q_s16(in + 8)); - TransformPass_NEON(&rows); - TransformPass_NEON(&rows); - Add4x4_NEON(rows.val[0], rows.val[1], ref, dst); -} - -#else - -static void ITransformOne_NEON(const uint8_t* ref, - const int16_t* in, uint8_t* dst) { - const int kBPS = BPS; - const int16_t kC1C2[] = { kC1, kC2, 0, 0 }; - - __asm__ volatile ( - "vld1.16 {q1, q2}, [%[in]] \n" - "vld1.16 {d0}, [%[kC1C2]] \n" - - // d2: in[0] - // d3: in[8] - // d4: in[4] - // d5: in[12] - "vswp d3, d4 \n" - - // q8 = {in[4], in[12]} * kC1 * 2 >> 16 - // q9 = {in[4], in[12]} * kC2 >> 16 - "vqdmulh.s16 q8, q2, d0[0] \n" - "vqdmulh.s16 q9, q2, d0[1] \n" - - // d22 = a = in[0] + in[8] - // d23 = b = in[0] - in[8] - "vqadd.s16 d22, d2, d3 \n" - "vqsub.s16 d23, d2, d3 \n" - - // q8 = in[4]/[12] * kC1 >> 16 - "vshr.s16 q8, q8, #1 \n" - - // Add {in[4], in[12]} back after the multiplication. - "vqadd.s16 q8, q2, q8 \n" - - // d20 = c = in[4]*kC2 - in[12]*kC1 - // d21 = d = in[4]*kC1 + in[12]*kC2 - "vqsub.s16 d20, d18, d17 \n" - "vqadd.s16 d21, d19, d16 \n" - - // d2 = tmp[0] = a + d - // d3 = tmp[1] = b + c - // d4 = tmp[2] = b - c - // d5 = tmp[3] = a - d - "vqadd.s16 d2, d22, d21 \n" - "vqadd.s16 d3, d23, d20 \n" - "vqsub.s16 d4, d23, d20 \n" - "vqsub.s16 d5, d22, d21 \n" - - "vzip.16 q1, q2 \n" - "vzip.16 q1, q2 \n" - - "vswp d3, d4 \n" - - // q8 = {tmp[4], tmp[12]} * kC1 * 2 >> 16 - // q9 = {tmp[4], tmp[12]} * kC2 >> 16 - "vqdmulh.s16 q8, q2, d0[0] \n" - "vqdmulh.s16 q9, q2, d0[1] \n" - - // d22 = a = tmp[0] + tmp[8] - // d23 = b = tmp[0] - tmp[8] - "vqadd.s16 d22, d2, d3 \n" - "vqsub.s16 d23, d2, d3 \n" - - "vshr.s16 q8, q8, #1 \n" - "vqadd.s16 q8, q2, q8 \n" - - // d20 = c = in[4]*kC2 - in[12]*kC1 - // d21 = d = in[4]*kC1 + in[12]*kC2 - "vqsub.s16 d20, d18, d17 \n" - "vqadd.s16 d21, d19, d16 \n" - - // d2 = tmp[0] = a + d - // d3 = tmp[1] = b + c - // d4 = tmp[2] = b - c - // d5 = tmp[3] = a - d - "vqadd.s16 d2, d22, d21 \n" - "vqadd.s16 d3, d23, d20 \n" - "vqsub.s16 d4, d23, d20 \n" - "vqsub.s16 d5, d22, d21 \n" - - "vld1.32 d6[0], [%[ref]], %[kBPS] \n" - "vld1.32 d6[1], [%[ref]], %[kBPS] \n" - "vld1.32 d7[0], [%[ref]], %[kBPS] \n" - "vld1.32 d7[1], [%[ref]], %[kBPS] \n" - - "sub %[ref], %[ref], %[kBPS], lsl #2 \n" - - // (val) + 4 >> 3 - "vrshr.s16 d2, d2, #3 \n" - "vrshr.s16 d3, d3, #3 \n" - "vrshr.s16 d4, d4, #3 \n" - "vrshr.s16 d5, d5, #3 \n" - - "vzip.16 q1, q2 \n" - "vzip.16 q1, q2 \n" - - // Must accumulate before saturating - "vmovl.u8 q8, d6 \n" - "vmovl.u8 q9, d7 \n" - - "vqadd.s16 q1, q1, q8 \n" - "vqadd.s16 q2, q2, q9 \n" - - "vqmovun.s16 d0, q1 \n" - "vqmovun.s16 d1, q2 \n" - - "vst1.32 d0[0], [%[dst]], %[kBPS] \n" - "vst1.32 d0[1], [%[dst]], %[kBPS] \n" - "vst1.32 d1[0], [%[dst]], %[kBPS] \n" - "vst1.32 d1[1], [%[dst]] \n" - - : [in] "+r"(in), [dst] "+r"(dst) // modified registers - : [kBPS] "r"(kBPS), [kC1C2] "r"(kC1C2), [ref] "r"(ref) // constants - : "memory", "q0", "q1", "q2", "q8", "q9", "q10", "q11" // clobbered - ); -} - -#endif // WEBP_USE_INTRINSICS - -static void ITransform_NEON(const uint8_t* ref, - const int16_t* in, uint8_t* dst, int do_two) { - ITransformOne_NEON(ref, in, dst); - if (do_two) { - ITransformOne_NEON(ref + 4, in + 16, dst + 4); - } -} - -// Load all 4x4 pixels into a single uint8x16_t variable. -static uint8x16_t Load4x4_NEON(const uint8_t* src) { - uint32x4_t out = vdupq_n_u32(0); - out = vld1q_lane_u32((const uint32_t*)(src + 0 * BPS), out, 0); - out = vld1q_lane_u32((const uint32_t*)(src + 1 * BPS), out, 1); - out = vld1q_lane_u32((const uint32_t*)(src + 2 * BPS), out, 2); - out = vld1q_lane_u32((const uint32_t*)(src + 3 * BPS), out, 3); - return vreinterpretq_u8_u32(out); -} - -// Forward transform. - -#if defined(WEBP_USE_INTRINSICS) - -static WEBP_INLINE void Transpose4x4_S16_NEON(const int16x4_t A, - const int16x4_t B, - const int16x4_t C, - const int16x4_t D, - int16x8_t* const out01, - int16x8_t* const out32) { - const int16x4x2_t AB = vtrn_s16(A, B); - const int16x4x2_t CD = vtrn_s16(C, D); - const int32x2x2_t tmp02 = vtrn_s32(vreinterpret_s32_s16(AB.val[0]), - vreinterpret_s32_s16(CD.val[0])); - const int32x2x2_t tmp13 = vtrn_s32(vreinterpret_s32_s16(AB.val[1]), - vreinterpret_s32_s16(CD.val[1])); - *out01 = vreinterpretq_s16_s64( - vcombine_s64(vreinterpret_s64_s32(tmp02.val[0]), - vreinterpret_s64_s32(tmp13.val[0]))); - *out32 = vreinterpretq_s16_s64( - vcombine_s64(vreinterpret_s64_s32(tmp13.val[1]), - vreinterpret_s64_s32(tmp02.val[1]))); -} - -static WEBP_INLINE int16x8_t DiffU8ToS16_NEON(const uint8x8_t a, - const uint8x8_t b) { - return vreinterpretq_s16_u16(vsubl_u8(a, b)); -} - -static void FTransform_NEON(const uint8_t* src, const uint8_t* ref, - int16_t* out) { - int16x8_t d0d1, d3d2; // working 4x4 int16 variables - { - const uint8x16_t S0 = Load4x4_NEON(src); - const uint8x16_t R0 = Load4x4_NEON(ref); - const int16x8_t D0D1 = DiffU8ToS16_NEON(vget_low_u8(S0), vget_low_u8(R0)); - const int16x8_t D2D3 = DiffU8ToS16_NEON(vget_high_u8(S0), vget_high_u8(R0)); - const int16x4_t D0 = vget_low_s16(D0D1); - const int16x4_t D1 = vget_high_s16(D0D1); - const int16x4_t D2 = vget_low_s16(D2D3); - const int16x4_t D3 = vget_high_s16(D2D3); - Transpose4x4_S16_NEON(D0, D1, D2, D3, &d0d1, &d3d2); - } - { // 1rst pass - const int32x4_t kCst937 = vdupq_n_s32(937); - const int32x4_t kCst1812 = vdupq_n_s32(1812); - const int16x8_t a0a1 = vaddq_s16(d0d1, d3d2); // d0+d3 | d1+d2 (=a0|a1) - const int16x8_t a3a2 = vsubq_s16(d0d1, d3d2); // d0-d3 | d1-d2 (=a3|a2) - const int16x8_t a0a1_2 = vshlq_n_s16(a0a1, 3); - const int16x4_t tmp0 = vadd_s16(vget_low_s16(a0a1_2), - vget_high_s16(a0a1_2)); - const int16x4_t tmp2 = vsub_s16(vget_low_s16(a0a1_2), - vget_high_s16(a0a1_2)); - const int32x4_t a3_2217 = vmull_n_s16(vget_low_s16(a3a2), 2217); - const int32x4_t a2_2217 = vmull_n_s16(vget_high_s16(a3a2), 2217); - const int32x4_t a2_p_a3 = vmlal_n_s16(a2_2217, vget_low_s16(a3a2), 5352); - const int32x4_t a3_m_a2 = vmlsl_n_s16(a3_2217, vget_high_s16(a3a2), 5352); - const int16x4_t tmp1 = vshrn_n_s32(vaddq_s32(a2_p_a3, kCst1812), 9); - const int16x4_t tmp3 = vshrn_n_s32(vaddq_s32(a3_m_a2, kCst937), 9); - Transpose4x4_S16_NEON(tmp0, tmp1, tmp2, tmp3, &d0d1, &d3d2); - } - { // 2nd pass - // the (1<<16) addition is for the replacement: a3!=0 <-> 1-(a3==0) - const int32x4_t kCst12000 = vdupq_n_s32(12000 + (1 << 16)); - const int32x4_t kCst51000 = vdupq_n_s32(51000); - const int16x8_t a0a1 = vaddq_s16(d0d1, d3d2); // d0+d3 | d1+d2 (=a0|a1) - const int16x8_t a3a2 = vsubq_s16(d0d1, d3d2); // d0-d3 | d1-d2 (=a3|a2) - const int16x4_t a0_k7 = vadd_s16(vget_low_s16(a0a1), vdup_n_s16(7)); - const int16x4_t out0 = vshr_n_s16(vadd_s16(a0_k7, vget_high_s16(a0a1)), 4); - const int16x4_t out2 = vshr_n_s16(vsub_s16(a0_k7, vget_high_s16(a0a1)), 4); - const int32x4_t a3_2217 = vmull_n_s16(vget_low_s16(a3a2), 2217); - const int32x4_t a2_2217 = vmull_n_s16(vget_high_s16(a3a2), 2217); - const int32x4_t a2_p_a3 = vmlal_n_s16(a2_2217, vget_low_s16(a3a2), 5352); - const int32x4_t a3_m_a2 = vmlsl_n_s16(a3_2217, vget_high_s16(a3a2), 5352); - const int16x4_t tmp1 = vaddhn_s32(a2_p_a3, kCst12000); - const int16x4_t out3 = vaddhn_s32(a3_m_a2, kCst51000); - const int16x4_t a3_eq_0 = - vreinterpret_s16_u16(vceq_s16(vget_low_s16(a3a2), vdup_n_s16(0))); - const int16x4_t out1 = vadd_s16(tmp1, a3_eq_0); - vst1_s16(out + 0, out0); - vst1_s16(out + 4, out1); - vst1_s16(out + 8, out2); - vst1_s16(out + 12, out3); - } -} - -#else - -// adapted from vp8/encoder/arm/neon/shortfdct_neon.asm -static const int16_t kCoeff16[] = { - 5352, 5352, 5352, 5352, 2217, 2217, 2217, 2217 -}; -static const int32_t kCoeff32[] = { - 1812, 1812, 1812, 1812, - 937, 937, 937, 937, - 12000, 12000, 12000, 12000, - 51000, 51000, 51000, 51000 -}; - -static void FTransform_NEON(const uint8_t* src, const uint8_t* ref, - int16_t* out) { - const int kBPS = BPS; - const uint8_t* src_ptr = src; - const uint8_t* ref_ptr = ref; - const int16_t* coeff16 = kCoeff16; - const int32_t* coeff32 = kCoeff32; - - __asm__ volatile ( - // load src into q4, q5 in high half - "vld1.8 {d8}, [%[src_ptr]], %[kBPS] \n" - "vld1.8 {d10}, [%[src_ptr]], %[kBPS] \n" - "vld1.8 {d9}, [%[src_ptr]], %[kBPS] \n" - "vld1.8 {d11}, [%[src_ptr]] \n" - - // load ref into q6, q7 in high half - "vld1.8 {d12}, [%[ref_ptr]], %[kBPS] \n" - "vld1.8 {d14}, [%[ref_ptr]], %[kBPS] \n" - "vld1.8 {d13}, [%[ref_ptr]], %[kBPS] \n" - "vld1.8 {d15}, [%[ref_ptr]] \n" - - // Pack the high values in to q4 and q6 - "vtrn.32 q4, q5 \n" - "vtrn.32 q6, q7 \n" - - // d[0-3] = src - ref - "vsubl.u8 q0, d8, d12 \n" - "vsubl.u8 q1, d9, d13 \n" - - // load coeff16 into q8(d16=5352, d17=2217) - "vld1.16 {q8}, [%[coeff16]] \n" - - // load coeff32 high half into q9 = 1812, q10 = 937 - "vld1.32 {q9, q10}, [%[coeff32]]! \n" - - // load coeff32 low half into q11=12000, q12=51000 - "vld1.32 {q11,q12}, [%[coeff32]] \n" - - // part 1 - // Transpose. Register dN is the same as dN in C - "vtrn.32 d0, d2 \n" - "vtrn.32 d1, d3 \n" - "vtrn.16 d0, d1 \n" - "vtrn.16 d2, d3 \n" - - "vadd.s16 d4, d0, d3 \n" // a0 = d0 + d3 - "vadd.s16 d5, d1, d2 \n" // a1 = d1 + d2 - "vsub.s16 d6, d1, d2 \n" // a2 = d1 - d2 - "vsub.s16 d7, d0, d3 \n" // a3 = d0 - d3 - - "vadd.s16 d0, d4, d5 \n" // a0 + a1 - "vshl.s16 d0, d0, #3 \n" // temp[0+i*4] = (a0+a1) << 3 - "vsub.s16 d2, d4, d5 \n" // a0 - a1 - "vshl.s16 d2, d2, #3 \n" // (temp[2+i*4] = (a0-a1) << 3 - - "vmlal.s16 q9, d7, d16 \n" // a3*5352 + 1812 - "vmlal.s16 q10, d7, d17 \n" // a3*2217 + 937 - "vmlal.s16 q9, d6, d17 \n" // a2*2217 + a3*5352 + 1812 - "vmlsl.s16 q10, d6, d16 \n" // a3*2217 + 937 - a2*5352 - - // temp[1+i*4] = (d2*2217 + d3*5352 + 1812) >> 9 - // temp[3+i*4] = (d3*2217 + 937 - d2*5352) >> 9 - "vshrn.s32 d1, q9, #9 \n" - "vshrn.s32 d3, q10, #9 \n" - - // part 2 - // transpose d0=ip[0], d1=ip[4], d2=ip[8], d3=ip[12] - "vtrn.32 d0, d2 \n" - "vtrn.32 d1, d3 \n" - "vtrn.16 d0, d1 \n" - "vtrn.16 d2, d3 \n" - - "vmov.s16 d26, #7 \n" - - "vadd.s16 d4, d0, d3 \n" // a1 = ip[0] + ip[12] - "vadd.s16 d5, d1, d2 \n" // b1 = ip[4] + ip[8] - "vsub.s16 d6, d1, d2 \n" // c1 = ip[4] - ip[8] - "vadd.s16 d4, d4, d26 \n" // a1 + 7 - "vsub.s16 d7, d0, d3 \n" // d1 = ip[0] - ip[12] - - "vadd.s16 d0, d4, d5 \n" // op[0] = a1 + b1 + 7 - "vsub.s16 d2, d4, d5 \n" // op[8] = a1 - b1 + 7 - - "vmlal.s16 q11, d7, d16 \n" // d1*5352 + 12000 - "vmlal.s16 q12, d7, d17 \n" // d1*2217 + 51000 - - "vceq.s16 d4, d7, #0 \n" - - "vshr.s16 d0, d0, #4 \n" - "vshr.s16 d2, d2, #4 \n" - - "vmlal.s16 q11, d6, d17 \n" // c1*2217 + d1*5352 + 12000 - "vmlsl.s16 q12, d6, d16 \n" // d1*2217 - c1*5352 + 51000 - - "vmvn d4, d4 \n" // !(d1 == 0) - // op[4] = (c1*2217 + d1*5352 + 12000)>>16 - "vshrn.s32 d1, q11, #16 \n" - // op[4] += (d1!=0) - "vsub.s16 d1, d1, d4 \n" - // op[12]= (d1*2217 - c1*5352 + 51000)>>16 - "vshrn.s32 d3, q12, #16 \n" - - // set result to out array - "vst1.16 {q0, q1}, [%[out]] \n" - : [src_ptr] "+r"(src_ptr), [ref_ptr] "+r"(ref_ptr), - [coeff32] "+r"(coeff32) // modified registers - : [kBPS] "r"(kBPS), [coeff16] "r"(coeff16), - [out] "r"(out) // constants - : "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q8", "q9", - "q10", "q11", "q12", "q13" // clobbered - ); -} - -#endif - -#define LOAD_LANE_16b(VALUE, LANE) do { \ - (VALUE) = vld1_lane_s16(src, (VALUE), (LANE)); \ - src += stride; \ -} while (0) - -static void FTransformWHT_NEON(const int16_t* src, int16_t* out) { - const int stride = 16; - const int16x4_t zero = vdup_n_s16(0); - int32x4x4_t tmp0; - int16x4x4_t in; - INIT_VECTOR4(in, zero, zero, zero, zero); - LOAD_LANE_16b(in.val[0], 0); - LOAD_LANE_16b(in.val[1], 0); - LOAD_LANE_16b(in.val[2], 0); - LOAD_LANE_16b(in.val[3], 0); - LOAD_LANE_16b(in.val[0], 1); - LOAD_LANE_16b(in.val[1], 1); - LOAD_LANE_16b(in.val[2], 1); - LOAD_LANE_16b(in.val[3], 1); - LOAD_LANE_16b(in.val[0], 2); - LOAD_LANE_16b(in.val[1], 2); - LOAD_LANE_16b(in.val[2], 2); - LOAD_LANE_16b(in.val[3], 2); - LOAD_LANE_16b(in.val[0], 3); - LOAD_LANE_16b(in.val[1], 3); - LOAD_LANE_16b(in.val[2], 3); - LOAD_LANE_16b(in.val[3], 3); - - { - // a0 = in[0 * 16] + in[2 * 16] - // a1 = in[1 * 16] + in[3 * 16] - // a2 = in[1 * 16] - in[3 * 16] - // a3 = in[0 * 16] - in[2 * 16] - const int32x4_t a0 = vaddl_s16(in.val[0], in.val[2]); - const int32x4_t a1 = vaddl_s16(in.val[1], in.val[3]); - const int32x4_t a2 = vsubl_s16(in.val[1], in.val[3]); - const int32x4_t a3 = vsubl_s16(in.val[0], in.val[2]); - tmp0.val[0] = vaddq_s32(a0, a1); - tmp0.val[1] = vaddq_s32(a3, a2); - tmp0.val[2] = vsubq_s32(a3, a2); - tmp0.val[3] = vsubq_s32(a0, a1); - } - { - const int32x4x4_t tmp1 = Transpose4x4_NEON(tmp0); - // a0 = tmp[0 + i] + tmp[ 8 + i] - // a1 = tmp[4 + i] + tmp[12 + i] - // a2 = tmp[4 + i] - tmp[12 + i] - // a3 = tmp[0 + i] - tmp[ 8 + i] - const int32x4_t a0 = vaddq_s32(tmp1.val[0], tmp1.val[2]); - const int32x4_t a1 = vaddq_s32(tmp1.val[1], tmp1.val[3]); - const int32x4_t a2 = vsubq_s32(tmp1.val[1], tmp1.val[3]); - const int32x4_t a3 = vsubq_s32(tmp1.val[0], tmp1.val[2]); - const int32x4_t b0 = vhaddq_s32(a0, a1); // (a0 + a1) >> 1 - const int32x4_t b1 = vhaddq_s32(a3, a2); // (a3 + a2) >> 1 - const int32x4_t b2 = vhsubq_s32(a3, a2); // (a3 - a2) >> 1 - const int32x4_t b3 = vhsubq_s32(a0, a1); // (a0 - a1) >> 1 - const int16x4_t out0 = vmovn_s32(b0); - const int16x4_t out1 = vmovn_s32(b1); - const int16x4_t out2 = vmovn_s32(b2); - const int16x4_t out3 = vmovn_s32(b3); - - vst1_s16(out + 0, out0); - vst1_s16(out + 4, out1); - vst1_s16(out + 8, out2); - vst1_s16(out + 12, out3); - } -} -#undef LOAD_LANE_16b - -//------------------------------------------------------------------------------ -// Texture distortion -// -// We try to match the spectral content (weighted) between source and -// reconstructed samples. - -// a 0123, b 0123 -// a 4567, b 4567 -// a 89ab, b 89ab -// a cdef, b cdef -// -// transpose -// -// a 048c, b 048c -// a 159d, b 159d -// a 26ae, b 26ae -// a 37bf, b 37bf -// -static WEBP_INLINE int16x8x4_t DistoTranspose4x4S16_NEON(int16x8x4_t q4_in) { - const int16x8x2_t q2_tmp0 = vtrnq_s16(q4_in.val[0], q4_in.val[1]); - const int16x8x2_t q2_tmp1 = vtrnq_s16(q4_in.val[2], q4_in.val[3]); - const int32x4x2_t q2_tmp2 = vtrnq_s32(vreinterpretq_s32_s16(q2_tmp0.val[0]), - vreinterpretq_s32_s16(q2_tmp1.val[0])); - const int32x4x2_t q2_tmp3 = vtrnq_s32(vreinterpretq_s32_s16(q2_tmp0.val[1]), - vreinterpretq_s32_s16(q2_tmp1.val[1])); - q4_in.val[0] = vreinterpretq_s16_s32(q2_tmp2.val[0]); - q4_in.val[2] = vreinterpretq_s16_s32(q2_tmp2.val[1]); - q4_in.val[1] = vreinterpretq_s16_s32(q2_tmp3.val[0]); - q4_in.val[3] = vreinterpretq_s16_s32(q2_tmp3.val[1]); - return q4_in; -} - -static WEBP_INLINE int16x8x4_t DistoHorizontalPass_NEON( - const int16x8x4_t q4_in) { - // {a0, a1} = {in[0] + in[2], in[1] + in[3]} - // {a3, a2} = {in[0] - in[2], in[1] - in[3]} - const int16x8_t q_a0 = vaddq_s16(q4_in.val[0], q4_in.val[2]); - const int16x8_t q_a1 = vaddq_s16(q4_in.val[1], q4_in.val[3]); - const int16x8_t q_a3 = vsubq_s16(q4_in.val[0], q4_in.val[2]); - const int16x8_t q_a2 = vsubq_s16(q4_in.val[1], q4_in.val[3]); - int16x8x4_t q4_out; - // tmp[0] = a0 + a1 - // tmp[1] = a3 + a2 - // tmp[2] = a3 - a2 - // tmp[3] = a0 - a1 - INIT_VECTOR4(q4_out, - vabsq_s16(vaddq_s16(q_a0, q_a1)), - vabsq_s16(vaddq_s16(q_a3, q_a2)), - vabdq_s16(q_a3, q_a2), vabdq_s16(q_a0, q_a1)); - return q4_out; -} - -static WEBP_INLINE int16x8x4_t DistoVerticalPass_NEON(const uint8x8x4_t q4_in) { - const int16x8_t q_a0 = vreinterpretq_s16_u16(vaddl_u8(q4_in.val[0], - q4_in.val[2])); - const int16x8_t q_a1 = vreinterpretq_s16_u16(vaddl_u8(q4_in.val[1], - q4_in.val[3])); - const int16x8_t q_a2 = vreinterpretq_s16_u16(vsubl_u8(q4_in.val[1], - q4_in.val[3])); - const int16x8_t q_a3 = vreinterpretq_s16_u16(vsubl_u8(q4_in.val[0], - q4_in.val[2])); - int16x8x4_t q4_out; - - INIT_VECTOR4(q4_out, - vaddq_s16(q_a0, q_a1), vaddq_s16(q_a3, q_a2), - vsubq_s16(q_a3, q_a2), vsubq_s16(q_a0, q_a1)); - return q4_out; -} - -static WEBP_INLINE int16x4x4_t DistoLoadW_NEON(const uint16_t* w) { - const uint16x8_t q_w07 = vld1q_u16(&w[0]); - const uint16x8_t q_w8f = vld1q_u16(&w[8]); - int16x4x4_t d4_w; - INIT_VECTOR4(d4_w, - vget_low_s16(vreinterpretq_s16_u16(q_w07)), - vget_high_s16(vreinterpretq_s16_u16(q_w07)), - vget_low_s16(vreinterpretq_s16_u16(q_w8f)), - vget_high_s16(vreinterpretq_s16_u16(q_w8f))); - return d4_w; -} - -static WEBP_INLINE int32x2_t DistoSum_NEON(const int16x8x4_t q4_in, - const int16x4x4_t d4_w) { - int32x2_t d_sum; - // sum += w[ 0] * abs(b0); - // sum += w[ 4] * abs(b1); - // sum += w[ 8] * abs(b2); - // sum += w[12] * abs(b3); - int32x4_t q_sum0 = vmull_s16(d4_w.val[0], vget_low_s16(q4_in.val[0])); - int32x4_t q_sum1 = vmull_s16(d4_w.val[1], vget_low_s16(q4_in.val[1])); - int32x4_t q_sum2 = vmull_s16(d4_w.val[2], vget_low_s16(q4_in.val[2])); - int32x4_t q_sum3 = vmull_s16(d4_w.val[3], vget_low_s16(q4_in.val[3])); - q_sum0 = vmlsl_s16(q_sum0, d4_w.val[0], vget_high_s16(q4_in.val[0])); - q_sum1 = vmlsl_s16(q_sum1, d4_w.val[1], vget_high_s16(q4_in.val[1])); - q_sum2 = vmlsl_s16(q_sum2, d4_w.val[2], vget_high_s16(q4_in.val[2])); - q_sum3 = vmlsl_s16(q_sum3, d4_w.val[3], vget_high_s16(q4_in.val[3])); - - q_sum0 = vaddq_s32(q_sum0, q_sum1); - q_sum2 = vaddq_s32(q_sum2, q_sum3); - q_sum2 = vaddq_s32(q_sum0, q_sum2); - d_sum = vpadd_s32(vget_low_s32(q_sum2), vget_high_s32(q_sum2)); - d_sum = vpadd_s32(d_sum, d_sum); - return d_sum; -} - -#define LOAD_LANE_32b(src, VALUE, LANE) \ - (VALUE) = vld1_lane_u32((const uint32_t*)(src), (VALUE), (LANE)) - -// Hadamard transform -// Returns the weighted sum of the absolute value of transformed coefficients. -// w[] contains a row-major 4 by 4 symmetric matrix. -static int Disto4x4_NEON(const uint8_t* const a, const uint8_t* const b, - const uint16_t* const w) { - uint32x2_t d_in_ab_0123 = vdup_n_u32(0); - uint32x2_t d_in_ab_4567 = vdup_n_u32(0); - uint32x2_t d_in_ab_89ab = vdup_n_u32(0); - uint32x2_t d_in_ab_cdef = vdup_n_u32(0); - uint8x8x4_t d4_in; - - // load data a, b - LOAD_LANE_32b(a + 0 * BPS, d_in_ab_0123, 0); - LOAD_LANE_32b(a + 1 * BPS, d_in_ab_4567, 0); - LOAD_LANE_32b(a + 2 * BPS, d_in_ab_89ab, 0); - LOAD_LANE_32b(a + 3 * BPS, d_in_ab_cdef, 0); - LOAD_LANE_32b(b + 0 * BPS, d_in_ab_0123, 1); - LOAD_LANE_32b(b + 1 * BPS, d_in_ab_4567, 1); - LOAD_LANE_32b(b + 2 * BPS, d_in_ab_89ab, 1); - LOAD_LANE_32b(b + 3 * BPS, d_in_ab_cdef, 1); - INIT_VECTOR4(d4_in, - vreinterpret_u8_u32(d_in_ab_0123), - vreinterpret_u8_u32(d_in_ab_4567), - vreinterpret_u8_u32(d_in_ab_89ab), - vreinterpret_u8_u32(d_in_ab_cdef)); - - { - // Vertical pass first to avoid a transpose (vertical and horizontal passes - // are commutative because w/kWeightY is symmetric) and subsequent - // transpose. - const int16x8x4_t q4_v = DistoVerticalPass_NEON(d4_in); - const int16x4x4_t d4_w = DistoLoadW_NEON(w); - // horizontal pass - const int16x8x4_t q4_t = DistoTranspose4x4S16_NEON(q4_v); - const int16x8x4_t q4_h = DistoHorizontalPass_NEON(q4_t); - int32x2_t d_sum = DistoSum_NEON(q4_h, d4_w); - - // abs(sum2 - sum1) >> 5 - d_sum = vabs_s32(d_sum); - d_sum = vshr_n_s32(d_sum, 5); - return vget_lane_s32(d_sum, 0); - } -} -#undef LOAD_LANE_32b - -static int Disto16x16_NEON(const uint8_t* const a, const uint8_t* const b, - const uint16_t* const w) { - int D = 0; - int x, y; - for (y = 0; y < 16 * BPS; y += 4 * BPS) { - for (x = 0; x < 16; x += 4) { - D += Disto4x4_NEON(a + x + y, b + x + y, w); - } - } - return D; -} - -//------------------------------------------------------------------------------ - -static void CollectHistogram_NEON(const uint8_t* ref, const uint8_t* pred, - int start_block, int end_block, - VP8Histogram* const histo) { - const uint16x8_t max_coeff_thresh = vdupq_n_u16(MAX_COEFF_THRESH); - int j; - int distribution[MAX_COEFF_THRESH + 1] = { 0 }; - for (j = start_block; j < end_block; ++j) { - int16_t out[16]; - FTransform_NEON(ref + VP8DspScan[j], pred + VP8DspScan[j], out); - { - int k; - const int16x8_t a0 = vld1q_s16(out + 0); - const int16x8_t b0 = vld1q_s16(out + 8); - const uint16x8_t a1 = vreinterpretq_u16_s16(vabsq_s16(a0)); - const uint16x8_t b1 = vreinterpretq_u16_s16(vabsq_s16(b0)); - const uint16x8_t a2 = vshrq_n_u16(a1, 3); - const uint16x8_t b2 = vshrq_n_u16(b1, 3); - const uint16x8_t a3 = vminq_u16(a2, max_coeff_thresh); - const uint16x8_t b3 = vminq_u16(b2, max_coeff_thresh); - vst1q_s16(out + 0, vreinterpretq_s16_u16(a3)); - vst1q_s16(out + 8, vreinterpretq_s16_u16(b3)); - // Convert coefficients to bin. - for (k = 0; k < 16; ++k) { - ++distribution[out[k]]; - } - } - } - VP8SetHistogramData(distribution, histo); -} - -//------------------------------------------------------------------------------ - -static WEBP_INLINE void AccumulateSSE16_NEON(const uint8_t* const a, - const uint8_t* const b, - uint32x4_t* const sum) { - const uint8x16_t a0 = vld1q_u8(a); - const uint8x16_t b0 = vld1q_u8(b); - const uint8x16_t abs_diff = vabdq_u8(a0, b0); - const uint16x8_t prod1 = vmull_u8(vget_low_u8(abs_diff), - vget_low_u8(abs_diff)); - const uint16x8_t prod2 = vmull_u8(vget_high_u8(abs_diff), - vget_high_u8(abs_diff)); - /* pair-wise adds and widen */ - const uint32x4_t sum1 = vpaddlq_u16(prod1); - const uint32x4_t sum2 = vpaddlq_u16(prod2); - *sum = vaddq_u32(*sum, vaddq_u32(sum1, sum2)); -} - -// Horizontal sum of all four uint32_t values in 'sum'. -static int SumToInt_NEON(uint32x4_t sum) { -#if WEBP_AARCH64 - return (int)vaddvq_u32(sum); -#else - const uint64x2_t sum2 = vpaddlq_u32(sum); - const uint32x2_t sum3 = vadd_u32(vreinterpret_u32_u64(vget_low_u64(sum2)), - vreinterpret_u32_u64(vget_high_u64(sum2))); - return (int)vget_lane_u32(sum3, 0); -#endif -} - -static int SSE16x16_NEON(const uint8_t* a, const uint8_t* b) { - uint32x4_t sum = vdupq_n_u32(0); - int y; - for (y = 0; y < 16; ++y) { - AccumulateSSE16_NEON(a + y * BPS, b + y * BPS, &sum); - } - return SumToInt_NEON(sum); -} - -static int SSE16x8_NEON(const uint8_t* a, const uint8_t* b) { - uint32x4_t sum = vdupq_n_u32(0); - int y; - for (y = 0; y < 8; ++y) { - AccumulateSSE16_NEON(a + y * BPS, b + y * BPS, &sum); - } - return SumToInt_NEON(sum); -} - -static int SSE8x8_NEON(const uint8_t* a, const uint8_t* b) { - uint32x4_t sum = vdupq_n_u32(0); - int y; - for (y = 0; y < 8; ++y) { - const uint8x8_t a0 = vld1_u8(a + y * BPS); - const uint8x8_t b0 = vld1_u8(b + y * BPS); - const uint8x8_t abs_diff = vabd_u8(a0, b0); - const uint16x8_t prod = vmull_u8(abs_diff, abs_diff); - sum = vpadalq_u16(sum, prod); - } - return SumToInt_NEON(sum); -} - -static int SSE4x4_NEON(const uint8_t* a, const uint8_t* b) { - const uint8x16_t a0 = Load4x4_NEON(a); - const uint8x16_t b0 = Load4x4_NEON(b); - const uint8x16_t abs_diff = vabdq_u8(a0, b0); - const uint16x8_t prod1 = vmull_u8(vget_low_u8(abs_diff), - vget_low_u8(abs_diff)); - const uint16x8_t prod2 = vmull_u8(vget_high_u8(abs_diff), - vget_high_u8(abs_diff)); - /* pair-wise adds and widen */ - const uint32x4_t sum1 = vpaddlq_u16(prod1); - const uint32x4_t sum2 = vpaddlq_u16(prod2); - return SumToInt_NEON(vaddq_u32(sum1, sum2)); -} - -//------------------------------------------------------------------------------ - -// Compilation with gcc-4.6.x is problematic for now. -#if !defined(WORK_AROUND_GCC) - -static int16x8_t Quantize_NEON(int16_t* const in, - const VP8Matrix* const mtx, int offset) { - const uint16x8_t sharp = vld1q_u16(&mtx->sharpen_[offset]); - const uint16x8_t q = vld1q_u16(&mtx->q_[offset]); - const uint16x8_t iq = vld1q_u16(&mtx->iq_[offset]); - const uint32x4_t bias0 = vld1q_u32(&mtx->bias_[offset + 0]); - const uint32x4_t bias1 = vld1q_u32(&mtx->bias_[offset + 4]); - - const int16x8_t a = vld1q_s16(in + offset); // in - const uint16x8_t b = vreinterpretq_u16_s16(vabsq_s16(a)); // coeff = abs(in) - const int16x8_t sign = vshrq_n_s16(a, 15); // sign - const uint16x8_t c = vaddq_u16(b, sharp); // + sharpen - const uint32x4_t m0 = vmull_u16(vget_low_u16(c), vget_low_u16(iq)); - const uint32x4_t m1 = vmull_u16(vget_high_u16(c), vget_high_u16(iq)); - const uint32x4_t m2 = vhaddq_u32(m0, bias0); - const uint32x4_t m3 = vhaddq_u32(m1, bias1); // (coeff * iQ + bias) >> 1 - const uint16x8_t c0 = vcombine_u16(vshrn_n_u32(m2, 16), - vshrn_n_u32(m3, 16)); // QFIX=17 = 16+1 - const uint16x8_t c1 = vminq_u16(c0, vdupq_n_u16(MAX_LEVEL)); - const int16x8_t c2 = veorq_s16(vreinterpretq_s16_u16(c1), sign); - const int16x8_t c3 = vsubq_s16(c2, sign); // restore sign - const int16x8_t c4 = vmulq_s16(c3, vreinterpretq_s16_u16(q)); - vst1q_s16(in + offset, c4); - assert(QFIX == 17); // this function can't work as is if QFIX != 16+1 - return c3; -} - -static const uint8_t kShuffles[4][8] = { - { 0, 1, 2, 3, 8, 9, 16, 17 }, - { 10, 11, 4, 5, 6, 7, 12, 13 }, - { 18, 19, 24, 25, 26, 27, 20, 21 }, - { 14, 15, 22, 23, 28, 29, 30, 31 } -}; - -static int QuantizeBlock_NEON(int16_t in[16], int16_t out[16], - const VP8Matrix* const mtx) { - const int16x8_t out0 = Quantize_NEON(in, mtx, 0); - const int16x8_t out1 = Quantize_NEON(in, mtx, 8); - uint8x8x4_t shuffles; - // vtbl?_u8 are marked unavailable for iOS arm64 with Xcode < 6.3, use - // non-standard versions there. -#if defined(__APPLE__) && WEBP_AARCH64 && \ - defined(__apple_build_version__) && (__apple_build_version__< 6020037) - uint8x16x2_t all_out; - INIT_VECTOR2(all_out, vreinterpretq_u8_s16(out0), vreinterpretq_u8_s16(out1)); - INIT_VECTOR4(shuffles, - vtbl2q_u8(all_out, vld1_u8(kShuffles[0])), - vtbl2q_u8(all_out, vld1_u8(kShuffles[1])), - vtbl2q_u8(all_out, vld1_u8(kShuffles[2])), - vtbl2q_u8(all_out, vld1_u8(kShuffles[3]))); -#else - uint8x8x4_t all_out; - INIT_VECTOR4(all_out, - vreinterpret_u8_s16(vget_low_s16(out0)), - vreinterpret_u8_s16(vget_high_s16(out0)), - vreinterpret_u8_s16(vget_low_s16(out1)), - vreinterpret_u8_s16(vget_high_s16(out1))); - INIT_VECTOR4(shuffles, - vtbl4_u8(all_out, vld1_u8(kShuffles[0])), - vtbl4_u8(all_out, vld1_u8(kShuffles[1])), - vtbl4_u8(all_out, vld1_u8(kShuffles[2])), - vtbl4_u8(all_out, vld1_u8(kShuffles[3]))); -#endif - // Zigzag reordering - vst1_u8((uint8_t*)(out + 0), shuffles.val[0]); - vst1_u8((uint8_t*)(out + 4), shuffles.val[1]); - vst1_u8((uint8_t*)(out + 8), shuffles.val[2]); - vst1_u8((uint8_t*)(out + 12), shuffles.val[3]); - // test zeros - if (*(uint64_t*)(out + 0) != 0) return 1; - if (*(uint64_t*)(out + 4) != 0) return 1; - if (*(uint64_t*)(out + 8) != 0) return 1; - if (*(uint64_t*)(out + 12) != 0) return 1; - return 0; -} - -static int Quantize2Blocks_NEON(int16_t in[32], int16_t out[32], - const VP8Matrix* const mtx) { - int nz; - nz = QuantizeBlock_NEON(in + 0 * 16, out + 0 * 16, mtx) << 0; - nz |= QuantizeBlock_NEON(in + 1 * 16, out + 1 * 16, mtx) << 1; - return nz; -} - -#endif // !WORK_AROUND_GCC - -//------------------------------------------------------------------------------ -// Entry point - -extern void VP8EncDspInitNEON(void); - -WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspInitNEON(void) { - VP8ITransform = ITransform_NEON; - VP8FTransform = FTransform_NEON; - - VP8FTransformWHT = FTransformWHT_NEON; - - VP8TDisto4x4 = Disto4x4_NEON; - VP8TDisto16x16 = Disto16x16_NEON; - VP8CollectHistogram = CollectHistogram_NEON; - - VP8SSE16x16 = SSE16x16_NEON; - VP8SSE16x8 = SSE16x8_NEON; - VP8SSE8x8 = SSE8x8_NEON; - VP8SSE4x4 = SSE4x4_NEON; - -#if !defined(WORK_AROUND_GCC) - VP8EncQuantizeBlock = QuantizeBlock_NEON; - VP8EncQuantize2Blocks = Quantize2Blocks_NEON; -#endif -} - -#else // !WEBP_USE_NEON - -WEBP_DSP_INIT_STUB(VP8EncDspInitNEON) - -#endif // WEBP_USE_NEON diff --git a/libwebp/src/dsp/enc_sse2.c b/libwebp/src/dsp/enc_sse2.c deleted file mode 100644 index 010624a2..00000000 --- a/libwebp/src/dsp/enc_sse2.c +++ /dev/null @@ -1,1514 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// SSE2 version of speed-critical encoding functions. -// -// Author: Christian Duvivier (cduvivier@google.com) - -#include "src/dsp/dsp.h" - -#if defined(WEBP_USE_SSE2) -#include -#include // for abs() -#include - -#include "src/dsp/common_sse2.h" -#include "src/enc/cost_enc.h" -#include "src/enc/vp8i_enc.h" - -//------------------------------------------------------------------------------ -// Transforms (Paragraph 14.4) - -// Does one inverse transform. -static void ITransform_One_SSE2(const uint8_t* ref, const int16_t* in, - uint8_t* dst) { - // This implementation makes use of 16-bit fixed point versions of two - // multiply constants: - // K1 = sqrt(2) * cos (pi/8) ~= 85627 / 2^16 - // K2 = sqrt(2) * sin (pi/8) ~= 35468 / 2^16 - // - // To be able to use signed 16-bit integers, we use the following trick to - // have constants within range: - // - Associated constants are obtained by subtracting the 16-bit fixed point - // version of one: - // k = K - (1 << 16) => K = k + (1 << 16) - // K1 = 85267 => k1 = 20091 - // K2 = 35468 => k2 = -30068 - // - The multiplication of a variable by a constant become the sum of the - // variable and the multiplication of that variable by the associated - // constant: - // (x * K) >> 16 = (x * (k + (1 << 16))) >> 16 = ((x * k ) >> 16) + x - const __m128i k1k2 = _mm_set_epi16(-30068, -30068, -30068, -30068, - 20091, 20091, 20091, 20091); - const __m128i k2k1 = _mm_set_epi16(20091, 20091, 20091, 20091, - -30068, -30068, -30068, -30068); - const __m128i zero = _mm_setzero_si128(); - const __m128i zero_four = _mm_set_epi16(0, 0, 0, 0, 4, 4, 4, 4); - __m128i T01, T23; - - // Load and concatenate the transform coefficients. - const __m128i in01 = _mm_loadu_si128((const __m128i*)&in[0]); - const __m128i in23 = _mm_loadu_si128((const __m128i*)&in[8]); - // a00 a10 a20 a30 a01 a11 a21 a31 - // a02 a12 a22 a32 a03 a13 a23 a33 - - // Vertical pass and subsequent transpose. - { - const __m128i in1 = _mm_unpackhi_epi64(in01, in01); - const __m128i in3 = _mm_unpackhi_epi64(in23, in23); - - // First pass, c and d calculations are longer because of the "trick" - // multiplications. - // c = MUL(in1, K2) - MUL(in3, K1) = MUL(in1, k2) - MUL(in3, k1) + in1 - in3 - // d = MUL(in1, K1) + MUL(in3, K2) = MUL(in1, k1) + MUL(in3, k2) + in1 + in3 - const __m128i a_d3 = _mm_add_epi16(in01, in23); - const __m128i b_c3 = _mm_sub_epi16(in01, in23); - const __m128i c1d1 = _mm_mulhi_epi16(in1, k2k1); - const __m128i c2d2 = _mm_mulhi_epi16(in3, k1k2); - const __m128i c3 = _mm_unpackhi_epi64(b_c3, b_c3); - const __m128i c4 = _mm_sub_epi16(c1d1, c2d2); - const __m128i c = _mm_add_epi16(c3, c4); - const __m128i d4u = _mm_add_epi16(c1d1, c2d2); - const __m128i du = _mm_add_epi16(a_d3, d4u); - const __m128i d = _mm_unpackhi_epi64(du, du); - - // Second pass. - const __m128i comb_ab = _mm_unpacklo_epi64(a_d3, b_c3); - const __m128i comb_dc = _mm_unpacklo_epi64(d, c); - - const __m128i tmp01 = _mm_add_epi16(comb_ab, comb_dc); - const __m128i tmp32 = _mm_sub_epi16(comb_ab, comb_dc); - const __m128i tmp23 = _mm_shuffle_epi32(tmp32, _MM_SHUFFLE(1, 0, 3, 2)); - - const __m128i transpose_0 = _mm_unpacklo_epi16(tmp01, tmp23); - const __m128i transpose_1 = _mm_unpackhi_epi16(tmp01, tmp23); - // a00 a20 a01 a21 a02 a22 a03 a23 - // a10 a30 a11 a31 a12 a32 a13 a33 - - T01 = _mm_unpacklo_epi16(transpose_0, transpose_1); - T23 = _mm_unpackhi_epi16(transpose_0, transpose_1); - // a00 a10 a20 a30 a01 a11 a21 a31 - // a02 a12 a22 a32 a03 a13 a23 a33 - } - - // Horizontal pass and subsequent transpose. - { - const __m128i T1 = _mm_unpackhi_epi64(T01, T01); - const __m128i T3 = _mm_unpackhi_epi64(T23, T23); - - // First pass, c and d calculations are longer because of the "trick" - // multiplications. - const __m128i dc = _mm_add_epi16(T01, zero_four); - - // c = MUL(T1, K2) - MUL(T3, K1) = MUL(T1, k2) - MUL(T3, k1) + T1 - T3 - // d = MUL(T1, K1) + MUL(T3, K2) = MUL(T1, k1) + MUL(T3, k2) + T1 + T3 - const __m128i a_d3 = _mm_add_epi16(dc, T23); - const __m128i b_c3 = _mm_sub_epi16(dc, T23); - const __m128i c1d1 = _mm_mulhi_epi16(T1, k2k1); - const __m128i c2d2 = _mm_mulhi_epi16(T3, k1k2); - const __m128i c3 = _mm_unpackhi_epi64(b_c3, b_c3); - const __m128i c4 = _mm_sub_epi16(c1d1, c2d2); - const __m128i c = _mm_add_epi16(c3, c4); - const __m128i d4u = _mm_add_epi16(c1d1, c2d2); - const __m128i du = _mm_add_epi16(a_d3, d4u); - const __m128i d = _mm_unpackhi_epi64(du, du); - - // Second pass. - const __m128i comb_ab = _mm_unpacklo_epi64(a_d3, b_c3); - const __m128i comb_dc = _mm_unpacklo_epi64(d, c); - - const __m128i tmp01 = _mm_add_epi16(comb_ab, comb_dc); - const __m128i tmp32 = _mm_sub_epi16(comb_ab, comb_dc); - const __m128i tmp23 = _mm_shuffle_epi32(tmp32, _MM_SHUFFLE(1, 0, 3, 2)); - - const __m128i shifted01 = _mm_srai_epi16(tmp01, 3); - const __m128i shifted23 = _mm_srai_epi16(tmp23, 3); - // a00 a01 a02 a03 a10 a11 a12 a13 - // a20 a21 a22 a23 a30 a31 a32 a33 - - const __m128i transpose_0 = _mm_unpacklo_epi16(shifted01, shifted23); - const __m128i transpose_1 = _mm_unpackhi_epi16(shifted01, shifted23); - // a00 a20 a01 a21 a02 a22 a03 a23 - // a10 a30 a11 a31 a12 a32 a13 a33 - - T01 = _mm_unpacklo_epi16(transpose_0, transpose_1); - T23 = _mm_unpackhi_epi16(transpose_0, transpose_1); - // a00 a10 a20 a30 a01 a11 a21 a31 - // a02 a12 a22 a32 a03 a13 a23 a33 - } - - // Add inverse transform to 'ref' and store. - { - // Load the reference(s). - __m128i ref01, ref23, ref0123; - int32_t buf[4]; - - // Load four bytes/pixels per line. - const __m128i ref0 = _mm_cvtsi32_si128(WebPMemToInt32(&ref[0 * BPS])); - const __m128i ref1 = _mm_cvtsi32_si128(WebPMemToInt32(&ref[1 * BPS])); - const __m128i ref2 = _mm_cvtsi32_si128(WebPMemToInt32(&ref[2 * BPS])); - const __m128i ref3 = _mm_cvtsi32_si128(WebPMemToInt32(&ref[3 * BPS])); - ref01 = _mm_unpacklo_epi32(ref0, ref1); - ref23 = _mm_unpacklo_epi32(ref2, ref3); - - // Convert to 16b. - ref01 = _mm_unpacklo_epi8(ref01, zero); - ref23 = _mm_unpacklo_epi8(ref23, zero); - // Add the inverse transform(s). - ref01 = _mm_add_epi16(ref01, T01); - ref23 = _mm_add_epi16(ref23, T23); - // Unsigned saturate to 8b. - ref0123 = _mm_packus_epi16(ref01, ref23); - - _mm_storeu_si128((__m128i *)buf, ref0123); - - // Store four bytes/pixels per line. - WebPInt32ToMem(&dst[0 * BPS], buf[0]); - WebPInt32ToMem(&dst[1 * BPS], buf[1]); - WebPInt32ToMem(&dst[2 * BPS], buf[2]); - WebPInt32ToMem(&dst[3 * BPS], buf[3]); - } -} - -// Does two inverse transforms. -static void ITransform_Two_SSE2(const uint8_t* ref, const int16_t* in, - uint8_t* dst) { - // This implementation makes use of 16-bit fixed point versions of two - // multiply constants: - // K1 = sqrt(2) * cos (pi/8) ~= 85627 / 2^16 - // K2 = sqrt(2) * sin (pi/8) ~= 35468 / 2^16 - // - // To be able to use signed 16-bit integers, we use the following trick to - // have constants within range: - // - Associated constants are obtained by subtracting the 16-bit fixed point - // version of one: - // k = K - (1 << 16) => K = k + (1 << 16) - // K1 = 85267 => k1 = 20091 - // K2 = 35468 => k2 = -30068 - // - The multiplication of a variable by a constant become the sum of the - // variable and the multiplication of that variable by the associated - // constant: - // (x * K) >> 16 = (x * (k + (1 << 16))) >> 16 = ((x * k ) >> 16) + x - const __m128i k1 = _mm_set1_epi16(20091); - const __m128i k2 = _mm_set1_epi16(-30068); - __m128i T0, T1, T2, T3; - - // Load and concatenate the transform coefficients (we'll do two inverse - // transforms in parallel). - __m128i in0, in1, in2, in3; - { - const __m128i tmp0 = _mm_loadu_si128((const __m128i*)&in[0]); - const __m128i tmp1 = _mm_loadu_si128((const __m128i*)&in[8]); - const __m128i tmp2 = _mm_loadu_si128((const __m128i*)&in[16]); - const __m128i tmp3 = _mm_loadu_si128((const __m128i*)&in[24]); - in0 = _mm_unpacklo_epi64(tmp0, tmp2); - in1 = _mm_unpackhi_epi64(tmp0, tmp2); - in2 = _mm_unpacklo_epi64(tmp1, tmp3); - in3 = _mm_unpackhi_epi64(tmp1, tmp3); - // a00 a10 a20 a30 b00 b10 b20 b30 - // a01 a11 a21 a31 b01 b11 b21 b31 - // a02 a12 a22 a32 b02 b12 b22 b32 - // a03 a13 a23 a33 b03 b13 b23 b33 - } - - // Vertical pass and subsequent transpose. - { - // First pass, c and d calculations are longer because of the "trick" - // multiplications. - const __m128i a = _mm_add_epi16(in0, in2); - const __m128i b = _mm_sub_epi16(in0, in2); - // c = MUL(in1, K2) - MUL(in3, K1) = MUL(in1, k2) - MUL(in3, k1) + in1 - in3 - const __m128i c1 = _mm_mulhi_epi16(in1, k2); - const __m128i c2 = _mm_mulhi_epi16(in3, k1); - const __m128i c3 = _mm_sub_epi16(in1, in3); - const __m128i c4 = _mm_sub_epi16(c1, c2); - const __m128i c = _mm_add_epi16(c3, c4); - // d = MUL(in1, K1) + MUL(in3, K2) = MUL(in1, k1) + MUL(in3, k2) + in1 + in3 - const __m128i d1 = _mm_mulhi_epi16(in1, k1); - const __m128i d2 = _mm_mulhi_epi16(in3, k2); - const __m128i d3 = _mm_add_epi16(in1, in3); - const __m128i d4 = _mm_add_epi16(d1, d2); - const __m128i d = _mm_add_epi16(d3, d4); - - // Second pass. - const __m128i tmp0 = _mm_add_epi16(a, d); - const __m128i tmp1 = _mm_add_epi16(b, c); - const __m128i tmp2 = _mm_sub_epi16(b, c); - const __m128i tmp3 = _mm_sub_epi16(a, d); - - // Transpose the two 4x4. - VP8Transpose_2_4x4_16b(&tmp0, &tmp1, &tmp2, &tmp3, &T0, &T1, &T2, &T3); - } - - // Horizontal pass and subsequent transpose. - { - // First pass, c and d calculations are longer because of the "trick" - // multiplications. - const __m128i four = _mm_set1_epi16(4); - const __m128i dc = _mm_add_epi16(T0, four); - const __m128i a = _mm_add_epi16(dc, T2); - const __m128i b = _mm_sub_epi16(dc, T2); - // c = MUL(T1, K2) - MUL(T3, K1) = MUL(T1, k2) - MUL(T3, k1) + T1 - T3 - const __m128i c1 = _mm_mulhi_epi16(T1, k2); - const __m128i c2 = _mm_mulhi_epi16(T3, k1); - const __m128i c3 = _mm_sub_epi16(T1, T3); - const __m128i c4 = _mm_sub_epi16(c1, c2); - const __m128i c = _mm_add_epi16(c3, c4); - // d = MUL(T1, K1) + MUL(T3, K2) = MUL(T1, k1) + MUL(T3, k2) + T1 + T3 - const __m128i d1 = _mm_mulhi_epi16(T1, k1); - const __m128i d2 = _mm_mulhi_epi16(T3, k2); - const __m128i d3 = _mm_add_epi16(T1, T3); - const __m128i d4 = _mm_add_epi16(d1, d2); - const __m128i d = _mm_add_epi16(d3, d4); - - // Second pass. - const __m128i tmp0 = _mm_add_epi16(a, d); - const __m128i tmp1 = _mm_add_epi16(b, c); - const __m128i tmp2 = _mm_sub_epi16(b, c); - const __m128i tmp3 = _mm_sub_epi16(a, d); - const __m128i shifted0 = _mm_srai_epi16(tmp0, 3); - const __m128i shifted1 = _mm_srai_epi16(tmp1, 3); - const __m128i shifted2 = _mm_srai_epi16(tmp2, 3); - const __m128i shifted3 = _mm_srai_epi16(tmp3, 3); - - // Transpose the two 4x4. - VP8Transpose_2_4x4_16b(&shifted0, &shifted1, &shifted2, &shifted3, &T0, &T1, - &T2, &T3); - } - - // Add inverse transform to 'ref' and store. - { - const __m128i zero = _mm_setzero_si128(); - // Load the reference(s). - __m128i ref0, ref1, ref2, ref3; - // Load eight bytes/pixels per line. - ref0 = _mm_loadl_epi64((const __m128i*)&ref[0 * BPS]); - ref1 = _mm_loadl_epi64((const __m128i*)&ref[1 * BPS]); - ref2 = _mm_loadl_epi64((const __m128i*)&ref[2 * BPS]); - ref3 = _mm_loadl_epi64((const __m128i*)&ref[3 * BPS]); - // Convert to 16b. - ref0 = _mm_unpacklo_epi8(ref0, zero); - ref1 = _mm_unpacklo_epi8(ref1, zero); - ref2 = _mm_unpacklo_epi8(ref2, zero); - ref3 = _mm_unpacklo_epi8(ref3, zero); - // Add the inverse transform(s). - ref0 = _mm_add_epi16(ref0, T0); - ref1 = _mm_add_epi16(ref1, T1); - ref2 = _mm_add_epi16(ref2, T2); - ref3 = _mm_add_epi16(ref3, T3); - // Unsigned saturate to 8b. - ref0 = _mm_packus_epi16(ref0, ref0); - ref1 = _mm_packus_epi16(ref1, ref1); - ref2 = _mm_packus_epi16(ref2, ref2); - ref3 = _mm_packus_epi16(ref3, ref3); - // Store eight bytes/pixels per line. - _mm_storel_epi64((__m128i*)&dst[0 * BPS], ref0); - _mm_storel_epi64((__m128i*)&dst[1 * BPS], ref1); - _mm_storel_epi64((__m128i*)&dst[2 * BPS], ref2); - _mm_storel_epi64((__m128i*)&dst[3 * BPS], ref3); - } -} - -// Does one or two inverse transforms. -static void ITransform_SSE2(const uint8_t* ref, const int16_t* in, uint8_t* dst, - int do_two) { - if (do_two) { - ITransform_Two_SSE2(ref, in, dst); - } else { - ITransform_One_SSE2(ref, in, dst); - } -} - -static void FTransformPass1_SSE2(const __m128i* const in01, - const __m128i* const in23, - __m128i* const out01, - __m128i* const out32) { - const __m128i k937 = _mm_set1_epi32(937); - const __m128i k1812 = _mm_set1_epi32(1812); - - const __m128i k88p = _mm_set_epi16(8, 8, 8, 8, 8, 8, 8, 8); - const __m128i k88m = _mm_set_epi16(-8, 8, -8, 8, -8, 8, -8, 8); - const __m128i k5352_2217p = _mm_set_epi16(2217, 5352, 2217, 5352, - 2217, 5352, 2217, 5352); - const __m128i k5352_2217m = _mm_set_epi16(-5352, 2217, -5352, 2217, - -5352, 2217, -5352, 2217); - - // *in01 = 00 01 10 11 02 03 12 13 - // *in23 = 20 21 30 31 22 23 32 33 - const __m128i shuf01_p = _mm_shufflehi_epi16(*in01, _MM_SHUFFLE(2, 3, 0, 1)); - const __m128i shuf23_p = _mm_shufflehi_epi16(*in23, _MM_SHUFFLE(2, 3, 0, 1)); - // 00 01 10 11 03 02 13 12 - // 20 21 30 31 23 22 33 32 - const __m128i s01 = _mm_unpacklo_epi64(shuf01_p, shuf23_p); - const __m128i s32 = _mm_unpackhi_epi64(shuf01_p, shuf23_p); - // 00 01 10 11 20 21 30 31 - // 03 02 13 12 23 22 33 32 - const __m128i a01 = _mm_add_epi16(s01, s32); - const __m128i a32 = _mm_sub_epi16(s01, s32); - // [d0 + d3 | d1 + d2 | ...] = [a0 a1 | a0' a1' | ... ] - // [d0 - d3 | d1 - d2 | ...] = [a3 a2 | a3' a2' | ... ] - - const __m128i tmp0 = _mm_madd_epi16(a01, k88p); // [ (a0 + a1) << 3, ... ] - const __m128i tmp2 = _mm_madd_epi16(a01, k88m); // [ (a0 - a1) << 3, ... ] - const __m128i tmp1_1 = _mm_madd_epi16(a32, k5352_2217p); - const __m128i tmp3_1 = _mm_madd_epi16(a32, k5352_2217m); - const __m128i tmp1_2 = _mm_add_epi32(tmp1_1, k1812); - const __m128i tmp3_2 = _mm_add_epi32(tmp3_1, k937); - const __m128i tmp1 = _mm_srai_epi32(tmp1_2, 9); - const __m128i tmp3 = _mm_srai_epi32(tmp3_2, 9); - const __m128i s03 = _mm_packs_epi32(tmp0, tmp2); - const __m128i s12 = _mm_packs_epi32(tmp1, tmp3); - const __m128i s_lo = _mm_unpacklo_epi16(s03, s12); // 0 1 0 1 0 1... - const __m128i s_hi = _mm_unpackhi_epi16(s03, s12); // 2 3 2 3 2 3 - const __m128i v23 = _mm_unpackhi_epi32(s_lo, s_hi); - *out01 = _mm_unpacklo_epi32(s_lo, s_hi); - *out32 = _mm_shuffle_epi32(v23, _MM_SHUFFLE(1, 0, 3, 2)); // 3 2 3 2 3 2.. -} - -static void FTransformPass2_SSE2(const __m128i* const v01, - const __m128i* const v32, - int16_t* out) { - const __m128i zero = _mm_setzero_si128(); - const __m128i seven = _mm_set1_epi16(7); - const __m128i k5352_2217 = _mm_set_epi16(5352, 2217, 5352, 2217, - 5352, 2217, 5352, 2217); - const __m128i k2217_5352 = _mm_set_epi16(2217, -5352, 2217, -5352, - 2217, -5352, 2217, -5352); - const __m128i k12000_plus_one = _mm_set1_epi32(12000 + (1 << 16)); - const __m128i k51000 = _mm_set1_epi32(51000); - - // Same operations are done on the (0,3) and (1,2) pairs. - // a3 = v0 - v3 - // a2 = v1 - v2 - const __m128i a32 = _mm_sub_epi16(*v01, *v32); - const __m128i a22 = _mm_unpackhi_epi64(a32, a32); - - const __m128i b23 = _mm_unpacklo_epi16(a22, a32); - const __m128i c1 = _mm_madd_epi16(b23, k5352_2217); - const __m128i c3 = _mm_madd_epi16(b23, k2217_5352); - const __m128i d1 = _mm_add_epi32(c1, k12000_plus_one); - const __m128i d3 = _mm_add_epi32(c3, k51000); - const __m128i e1 = _mm_srai_epi32(d1, 16); - const __m128i e3 = _mm_srai_epi32(d3, 16); - // f1 = ((b3 * 5352 + b2 * 2217 + 12000) >> 16) - // f3 = ((b3 * 2217 - b2 * 5352 + 51000) >> 16) - const __m128i f1 = _mm_packs_epi32(e1, e1); - const __m128i f3 = _mm_packs_epi32(e3, e3); - // g1 = f1 + (a3 != 0); - // The compare will return (0xffff, 0) for (==0, !=0). To turn that into the - // desired (0, 1), we add one earlier through k12000_plus_one. - // -> g1 = f1 + 1 - (a3 == 0) - const __m128i g1 = _mm_add_epi16(f1, _mm_cmpeq_epi16(a32, zero)); - - // a0 = v0 + v3 - // a1 = v1 + v2 - const __m128i a01 = _mm_add_epi16(*v01, *v32); - const __m128i a01_plus_7 = _mm_add_epi16(a01, seven); - const __m128i a11 = _mm_unpackhi_epi64(a01, a01); - const __m128i c0 = _mm_add_epi16(a01_plus_7, a11); - const __m128i c2 = _mm_sub_epi16(a01_plus_7, a11); - // d0 = (a0 + a1 + 7) >> 4; - // d2 = (a0 - a1 + 7) >> 4; - const __m128i d0 = _mm_srai_epi16(c0, 4); - const __m128i d2 = _mm_srai_epi16(c2, 4); - - const __m128i d0_g1 = _mm_unpacklo_epi64(d0, g1); - const __m128i d2_f3 = _mm_unpacklo_epi64(d2, f3); - _mm_storeu_si128((__m128i*)&out[0], d0_g1); - _mm_storeu_si128((__m128i*)&out[8], d2_f3); -} - -static void FTransform_SSE2(const uint8_t* src, const uint8_t* ref, - int16_t* out) { - const __m128i zero = _mm_setzero_si128(); - // Load src. - const __m128i src0 = _mm_loadl_epi64((const __m128i*)&src[0 * BPS]); - const __m128i src1 = _mm_loadl_epi64((const __m128i*)&src[1 * BPS]); - const __m128i src2 = _mm_loadl_epi64((const __m128i*)&src[2 * BPS]); - const __m128i src3 = _mm_loadl_epi64((const __m128i*)&src[3 * BPS]); - // 00 01 02 03 * - // 10 11 12 13 * - // 20 21 22 23 * - // 30 31 32 33 * - // Shuffle. - const __m128i src_0 = _mm_unpacklo_epi16(src0, src1); - const __m128i src_1 = _mm_unpacklo_epi16(src2, src3); - // 00 01 10 11 02 03 12 13 * * ... - // 20 21 30 31 22 22 32 33 * * ... - - // Load ref. - const __m128i ref0 = _mm_loadl_epi64((const __m128i*)&ref[0 * BPS]); - const __m128i ref1 = _mm_loadl_epi64((const __m128i*)&ref[1 * BPS]); - const __m128i ref2 = _mm_loadl_epi64((const __m128i*)&ref[2 * BPS]); - const __m128i ref3 = _mm_loadl_epi64((const __m128i*)&ref[3 * BPS]); - const __m128i ref_0 = _mm_unpacklo_epi16(ref0, ref1); - const __m128i ref_1 = _mm_unpacklo_epi16(ref2, ref3); - - // Convert both to 16 bit. - const __m128i src_0_16b = _mm_unpacklo_epi8(src_0, zero); - const __m128i src_1_16b = _mm_unpacklo_epi8(src_1, zero); - const __m128i ref_0_16b = _mm_unpacklo_epi8(ref_0, zero); - const __m128i ref_1_16b = _mm_unpacklo_epi8(ref_1, zero); - - // Compute the difference. - const __m128i row01 = _mm_sub_epi16(src_0_16b, ref_0_16b); - const __m128i row23 = _mm_sub_epi16(src_1_16b, ref_1_16b); - __m128i v01, v32; - - // First pass - FTransformPass1_SSE2(&row01, &row23, &v01, &v32); - - // Second pass - FTransformPass2_SSE2(&v01, &v32, out); -} - -static void FTransform2_SSE2(const uint8_t* src, const uint8_t* ref, - int16_t* out) { - const __m128i zero = _mm_setzero_si128(); - - // Load src and convert to 16b. - const __m128i src0 = _mm_loadl_epi64((const __m128i*)&src[0 * BPS]); - const __m128i src1 = _mm_loadl_epi64((const __m128i*)&src[1 * BPS]); - const __m128i src2 = _mm_loadl_epi64((const __m128i*)&src[2 * BPS]); - const __m128i src3 = _mm_loadl_epi64((const __m128i*)&src[3 * BPS]); - const __m128i src_0 = _mm_unpacklo_epi8(src0, zero); - const __m128i src_1 = _mm_unpacklo_epi8(src1, zero); - const __m128i src_2 = _mm_unpacklo_epi8(src2, zero); - const __m128i src_3 = _mm_unpacklo_epi8(src3, zero); - // Load ref and convert to 16b. - const __m128i ref0 = _mm_loadl_epi64((const __m128i*)&ref[0 * BPS]); - const __m128i ref1 = _mm_loadl_epi64((const __m128i*)&ref[1 * BPS]); - const __m128i ref2 = _mm_loadl_epi64((const __m128i*)&ref[2 * BPS]); - const __m128i ref3 = _mm_loadl_epi64((const __m128i*)&ref[3 * BPS]); - const __m128i ref_0 = _mm_unpacklo_epi8(ref0, zero); - const __m128i ref_1 = _mm_unpacklo_epi8(ref1, zero); - const __m128i ref_2 = _mm_unpacklo_epi8(ref2, zero); - const __m128i ref_3 = _mm_unpacklo_epi8(ref3, zero); - // Compute difference. -> 00 01 02 03 00' 01' 02' 03' - const __m128i diff0 = _mm_sub_epi16(src_0, ref_0); - const __m128i diff1 = _mm_sub_epi16(src_1, ref_1); - const __m128i diff2 = _mm_sub_epi16(src_2, ref_2); - const __m128i diff3 = _mm_sub_epi16(src_3, ref_3); - - // Unpack and shuffle - // 00 01 02 03 0 0 0 0 - // 10 11 12 13 0 0 0 0 - // 20 21 22 23 0 0 0 0 - // 30 31 32 33 0 0 0 0 - const __m128i shuf01l = _mm_unpacklo_epi32(diff0, diff1); - const __m128i shuf23l = _mm_unpacklo_epi32(diff2, diff3); - const __m128i shuf01h = _mm_unpackhi_epi32(diff0, diff1); - const __m128i shuf23h = _mm_unpackhi_epi32(diff2, diff3); - __m128i v01l, v32l; - __m128i v01h, v32h; - - // First pass - FTransformPass1_SSE2(&shuf01l, &shuf23l, &v01l, &v32l); - FTransformPass1_SSE2(&shuf01h, &shuf23h, &v01h, &v32h); - - // Second pass - FTransformPass2_SSE2(&v01l, &v32l, out + 0); - FTransformPass2_SSE2(&v01h, &v32h, out + 16); -} - -static void FTransformWHTRow_SSE2(const int16_t* const in, __m128i* const out) { - const __m128i kMult = _mm_set_epi16(-1, 1, -1, 1, 1, 1, 1, 1); - const __m128i src0 = _mm_loadl_epi64((__m128i*)&in[0 * 16]); - const __m128i src1 = _mm_loadl_epi64((__m128i*)&in[1 * 16]); - const __m128i src2 = _mm_loadl_epi64((__m128i*)&in[2 * 16]); - const __m128i src3 = _mm_loadl_epi64((__m128i*)&in[3 * 16]); - const __m128i A01 = _mm_unpacklo_epi16(src0, src1); // A0 A1 | ... - const __m128i A23 = _mm_unpacklo_epi16(src2, src3); // A2 A3 | ... - const __m128i B0 = _mm_adds_epi16(A01, A23); // a0 | a1 | ... - const __m128i B1 = _mm_subs_epi16(A01, A23); // a3 | a2 | ... - const __m128i C0 = _mm_unpacklo_epi32(B0, B1); // a0 | a1 | a3 | a2 | ... - const __m128i C1 = _mm_unpacklo_epi32(B1, B0); // a3 | a2 | a0 | a1 | ... - const __m128i D = _mm_unpacklo_epi64(C0, C1); // a0 a1 a3 a2 a3 a2 a0 a1 - *out = _mm_madd_epi16(D, kMult); -} - -static void FTransformWHT_SSE2(const int16_t* in, int16_t* out) { - // Input is 12b signed. - __m128i row0, row1, row2, row3; - // Rows are 14b signed. - FTransformWHTRow_SSE2(in + 0 * 64, &row0); - FTransformWHTRow_SSE2(in + 1 * 64, &row1); - FTransformWHTRow_SSE2(in + 2 * 64, &row2); - FTransformWHTRow_SSE2(in + 3 * 64, &row3); - - { - // The a* are 15b signed. - const __m128i a0 = _mm_add_epi32(row0, row2); - const __m128i a1 = _mm_add_epi32(row1, row3); - const __m128i a2 = _mm_sub_epi32(row1, row3); - const __m128i a3 = _mm_sub_epi32(row0, row2); - const __m128i a0a3 = _mm_packs_epi32(a0, a3); - const __m128i a1a2 = _mm_packs_epi32(a1, a2); - - // The b* are 16b signed. - const __m128i b0b1 = _mm_add_epi16(a0a3, a1a2); - const __m128i b3b2 = _mm_sub_epi16(a0a3, a1a2); - const __m128i tmp_b2b3 = _mm_unpackhi_epi64(b3b2, b3b2); - const __m128i b2b3 = _mm_unpacklo_epi64(tmp_b2b3, b3b2); - - _mm_storeu_si128((__m128i*)&out[0], _mm_srai_epi16(b0b1, 1)); - _mm_storeu_si128((__m128i*)&out[8], _mm_srai_epi16(b2b3, 1)); - } -} - -//------------------------------------------------------------------------------ -// Compute susceptibility based on DCT-coeff histograms: -// the higher, the "easier" the macroblock is to compress. - -static void CollectHistogram_SSE2(const uint8_t* ref, const uint8_t* pred, - int start_block, int end_block, - VP8Histogram* const histo) { - const __m128i zero = _mm_setzero_si128(); - const __m128i max_coeff_thresh = _mm_set1_epi16(MAX_COEFF_THRESH); - int j; - int distribution[MAX_COEFF_THRESH + 1] = { 0 }; - for (j = start_block; j < end_block; ++j) { - int16_t out[16]; - int k; - - FTransform_SSE2(ref + VP8DspScan[j], pred + VP8DspScan[j], out); - - // Convert coefficients to bin (within out[]). - { - // Load. - const __m128i out0 = _mm_loadu_si128((__m128i*)&out[0]); - const __m128i out1 = _mm_loadu_si128((__m128i*)&out[8]); - const __m128i d0 = _mm_sub_epi16(zero, out0); - const __m128i d1 = _mm_sub_epi16(zero, out1); - const __m128i abs0 = _mm_max_epi16(out0, d0); // abs(v), 16b - const __m128i abs1 = _mm_max_epi16(out1, d1); - // v = abs(out) >> 3 - const __m128i v0 = _mm_srai_epi16(abs0, 3); - const __m128i v1 = _mm_srai_epi16(abs1, 3); - // bin = min(v, MAX_COEFF_THRESH) - const __m128i bin0 = _mm_min_epi16(v0, max_coeff_thresh); - const __m128i bin1 = _mm_min_epi16(v1, max_coeff_thresh); - // Store. - _mm_storeu_si128((__m128i*)&out[0], bin0); - _mm_storeu_si128((__m128i*)&out[8], bin1); - } - - // Convert coefficients to bin. - for (k = 0; k < 16; ++k) { - ++distribution[out[k]]; - } - } - VP8SetHistogramData(distribution, histo); -} - -//------------------------------------------------------------------------------ -// Intra predictions - -// helper for chroma-DC predictions -static WEBP_INLINE void Put8x8uv_SSE2(uint8_t v, uint8_t* dst) { - int j; - const __m128i values = _mm_set1_epi8((char)v); - for (j = 0; j < 8; ++j) { - _mm_storel_epi64((__m128i*)(dst + j * BPS), values); - } -} - -static WEBP_INLINE void Put16_SSE2(uint8_t v, uint8_t* dst) { - int j; - const __m128i values = _mm_set1_epi8((char)v); - for (j = 0; j < 16; ++j) { - _mm_store_si128((__m128i*)(dst + j * BPS), values); - } -} - -static WEBP_INLINE void Fill_SSE2(uint8_t* dst, int value, int size) { - if (size == 4) { - int j; - for (j = 0; j < 4; ++j) { - memset(dst + j * BPS, value, 4); - } - } else if (size == 8) { - Put8x8uv_SSE2(value, dst); - } else { - Put16_SSE2(value, dst); - } -} - -static WEBP_INLINE void VE8uv_SSE2(uint8_t* dst, const uint8_t* top) { - int j; - const __m128i top_values = _mm_loadl_epi64((const __m128i*)top); - for (j = 0; j < 8; ++j) { - _mm_storel_epi64((__m128i*)(dst + j * BPS), top_values); - } -} - -static WEBP_INLINE void VE16_SSE2(uint8_t* dst, const uint8_t* top) { - const __m128i top_values = _mm_load_si128((const __m128i*)top); - int j; - for (j = 0; j < 16; ++j) { - _mm_store_si128((__m128i*)(dst + j * BPS), top_values); - } -} - -static WEBP_INLINE void VerticalPred_SSE2(uint8_t* dst, - const uint8_t* top, int size) { - if (top != NULL) { - if (size == 8) { - VE8uv_SSE2(dst, top); - } else { - VE16_SSE2(dst, top); - } - } else { - Fill_SSE2(dst, 127, size); - } -} - -static WEBP_INLINE void HE8uv_SSE2(uint8_t* dst, const uint8_t* left) { - int j; - for (j = 0; j < 8; ++j) { - const __m128i values = _mm_set1_epi8((char)left[j]); - _mm_storel_epi64((__m128i*)dst, values); - dst += BPS; - } -} - -static WEBP_INLINE void HE16_SSE2(uint8_t* dst, const uint8_t* left) { - int j; - for (j = 0; j < 16; ++j) { - const __m128i values = _mm_set1_epi8((char)left[j]); - _mm_store_si128((__m128i*)dst, values); - dst += BPS; - } -} - -static WEBP_INLINE void HorizontalPred_SSE2(uint8_t* dst, - const uint8_t* left, int size) { - if (left != NULL) { - if (size == 8) { - HE8uv_SSE2(dst, left); - } else { - HE16_SSE2(dst, left); - } - } else { - Fill_SSE2(dst, 129, size); - } -} - -static WEBP_INLINE void TM_SSE2(uint8_t* dst, const uint8_t* left, - const uint8_t* top, int size) { - const __m128i zero = _mm_setzero_si128(); - int y; - if (size == 8) { - const __m128i top_values = _mm_loadl_epi64((const __m128i*)top); - const __m128i top_base = _mm_unpacklo_epi8(top_values, zero); - for (y = 0; y < 8; ++y, dst += BPS) { - const int val = left[y] - left[-1]; - const __m128i base = _mm_set1_epi16(val); - const __m128i out = _mm_packus_epi16(_mm_add_epi16(base, top_base), zero); - _mm_storel_epi64((__m128i*)dst, out); - } - } else { - const __m128i top_values = _mm_load_si128((const __m128i*)top); - const __m128i top_base_0 = _mm_unpacklo_epi8(top_values, zero); - const __m128i top_base_1 = _mm_unpackhi_epi8(top_values, zero); - for (y = 0; y < 16; ++y, dst += BPS) { - const int val = left[y] - left[-1]; - const __m128i base = _mm_set1_epi16(val); - const __m128i out_0 = _mm_add_epi16(base, top_base_0); - const __m128i out_1 = _mm_add_epi16(base, top_base_1); - const __m128i out = _mm_packus_epi16(out_0, out_1); - _mm_store_si128((__m128i*)dst, out); - } - } -} - -static WEBP_INLINE void TrueMotion_SSE2(uint8_t* dst, const uint8_t* left, - const uint8_t* top, int size) { - if (left != NULL) { - if (top != NULL) { - TM_SSE2(dst, left, top, size); - } else { - HorizontalPred_SSE2(dst, left, size); - } - } else { - // true motion without left samples (hence: with default 129 value) - // is equivalent to VE prediction where you just copy the top samples. - // Note that if top samples are not available, the default value is - // then 129, and not 127 as in the VerticalPred case. - if (top != NULL) { - VerticalPred_SSE2(dst, top, size); - } else { - Fill_SSE2(dst, 129, size); - } - } -} - -static WEBP_INLINE void DC8uv_SSE2(uint8_t* dst, const uint8_t* left, - const uint8_t* top) { - const __m128i top_values = _mm_loadl_epi64((const __m128i*)top); - const __m128i left_values = _mm_loadl_epi64((const __m128i*)left); - const __m128i combined = _mm_unpacklo_epi64(top_values, left_values); - const int DC = VP8HorizontalAdd8b(&combined) + 8; - Put8x8uv_SSE2(DC >> 4, dst); -} - -static WEBP_INLINE void DC8uvNoLeft_SSE2(uint8_t* dst, const uint8_t* top) { - const __m128i zero = _mm_setzero_si128(); - const __m128i top_values = _mm_loadl_epi64((const __m128i*)top); - const __m128i sum = _mm_sad_epu8(top_values, zero); - const int DC = _mm_cvtsi128_si32(sum) + 4; - Put8x8uv_SSE2(DC >> 3, dst); -} - -static WEBP_INLINE void DC8uvNoTop_SSE2(uint8_t* dst, const uint8_t* left) { - // 'left' is contiguous so we can reuse the top summation. - DC8uvNoLeft_SSE2(dst, left); -} - -static WEBP_INLINE void DC8uvNoTopLeft_SSE2(uint8_t* dst) { - Put8x8uv_SSE2(0x80, dst); -} - -static WEBP_INLINE void DC8uvMode_SSE2(uint8_t* dst, const uint8_t* left, - const uint8_t* top) { - if (top != NULL) { - if (left != NULL) { // top and left present - DC8uv_SSE2(dst, left, top); - } else { // top, but no left - DC8uvNoLeft_SSE2(dst, top); - } - } else if (left != NULL) { // left but no top - DC8uvNoTop_SSE2(dst, left); - } else { // no top, no left, nothing. - DC8uvNoTopLeft_SSE2(dst); - } -} - -static WEBP_INLINE void DC16_SSE2(uint8_t* dst, const uint8_t* left, - const uint8_t* top) { - const __m128i top_row = _mm_load_si128((const __m128i*)top); - const __m128i left_row = _mm_load_si128((const __m128i*)left); - const int DC = - VP8HorizontalAdd8b(&top_row) + VP8HorizontalAdd8b(&left_row) + 16; - Put16_SSE2(DC >> 5, dst); -} - -static WEBP_INLINE void DC16NoLeft_SSE2(uint8_t* dst, const uint8_t* top) { - const __m128i top_row = _mm_load_si128((const __m128i*)top); - const int DC = VP8HorizontalAdd8b(&top_row) + 8; - Put16_SSE2(DC >> 4, dst); -} - -static WEBP_INLINE void DC16NoTop_SSE2(uint8_t* dst, const uint8_t* left) { - // 'left' is contiguous so we can reuse the top summation. - DC16NoLeft_SSE2(dst, left); -} - -static WEBP_INLINE void DC16NoTopLeft_SSE2(uint8_t* dst) { - Put16_SSE2(0x80, dst); -} - -static WEBP_INLINE void DC16Mode_SSE2(uint8_t* dst, const uint8_t* left, - const uint8_t* top) { - if (top != NULL) { - if (left != NULL) { // top and left present - DC16_SSE2(dst, left, top); - } else { // top, but no left - DC16NoLeft_SSE2(dst, top); - } - } else if (left != NULL) { // left but no top - DC16NoTop_SSE2(dst, left); - } else { // no top, no left, nothing. - DC16NoTopLeft_SSE2(dst); - } -} - -//------------------------------------------------------------------------------ -// 4x4 predictions - -#define DST(x, y) dst[(x) + (y) * BPS] -#define AVG3(a, b, c) (((a) + 2 * (b) + (c) + 2) >> 2) -#define AVG2(a, b) (((a) + (b) + 1) >> 1) - -// We use the following 8b-arithmetic tricks: -// (a + 2 * b + c + 2) >> 2 = (AC + b + 1) >> 1 -// where: AC = (a + c) >> 1 = [(a + c + 1) >> 1] - [(a^c) & 1] -// and: -// (a + 2 * b + c + 2) >> 2 = (AB + BC + 1) >> 1 - (ab|bc)&lsb -// where: AC = (a + b + 1) >> 1, BC = (b + c + 1) >> 1 -// and ab = a ^ b, bc = b ^ c, lsb = (AC^BC)&1 - -static WEBP_INLINE void VE4_SSE2(uint8_t* dst, - const uint8_t* top) { // vertical - const __m128i one = _mm_set1_epi8(1); - const __m128i ABCDEFGH = _mm_loadl_epi64((__m128i*)(top - 1)); - const __m128i BCDEFGH0 = _mm_srli_si128(ABCDEFGH, 1); - const __m128i CDEFGH00 = _mm_srli_si128(ABCDEFGH, 2); - const __m128i a = _mm_avg_epu8(ABCDEFGH, CDEFGH00); - const __m128i lsb = _mm_and_si128(_mm_xor_si128(ABCDEFGH, CDEFGH00), one); - const __m128i b = _mm_subs_epu8(a, lsb); - const __m128i avg = _mm_avg_epu8(b, BCDEFGH0); - const int vals = _mm_cvtsi128_si32(avg); - int i; - for (i = 0; i < 4; ++i) { - WebPInt32ToMem(dst + i * BPS, vals); - } -} - -static WEBP_INLINE void HE4_SSE2(uint8_t* dst, - const uint8_t* top) { // horizontal - const int X = top[-1]; - const int I = top[-2]; - const int J = top[-3]; - const int K = top[-4]; - const int L = top[-5]; - WebPUint32ToMem(dst + 0 * BPS, 0x01010101U * AVG3(X, I, J)); - WebPUint32ToMem(dst + 1 * BPS, 0x01010101U * AVG3(I, J, K)); - WebPUint32ToMem(dst + 2 * BPS, 0x01010101U * AVG3(J, K, L)); - WebPUint32ToMem(dst + 3 * BPS, 0x01010101U * AVG3(K, L, L)); -} - -static WEBP_INLINE void DC4_SSE2(uint8_t* dst, const uint8_t* top) { - uint32_t dc = 4; - int i; - for (i = 0; i < 4; ++i) dc += top[i] + top[-5 + i]; - Fill_SSE2(dst, dc >> 3, 4); -} - -static WEBP_INLINE void LD4_SSE2(uint8_t* dst, - const uint8_t* top) { // Down-Left - const __m128i one = _mm_set1_epi8(1); - const __m128i ABCDEFGH = _mm_loadl_epi64((const __m128i*)top); - const __m128i BCDEFGH0 = _mm_srli_si128(ABCDEFGH, 1); - const __m128i CDEFGH00 = _mm_srli_si128(ABCDEFGH, 2); - const __m128i CDEFGHH0 = _mm_insert_epi16(CDEFGH00, top[7], 3); - const __m128i avg1 = _mm_avg_epu8(ABCDEFGH, CDEFGHH0); - const __m128i lsb = _mm_and_si128(_mm_xor_si128(ABCDEFGH, CDEFGHH0), one); - const __m128i avg2 = _mm_subs_epu8(avg1, lsb); - const __m128i abcdefg = _mm_avg_epu8(avg2, BCDEFGH0); - WebPInt32ToMem(dst + 0 * BPS, _mm_cvtsi128_si32( abcdefg )); - WebPInt32ToMem(dst + 1 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 1))); - WebPInt32ToMem(dst + 2 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 2))); - WebPInt32ToMem(dst + 3 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 3))); -} - -static WEBP_INLINE void VR4_SSE2(uint8_t* dst, - const uint8_t* top) { // Vertical-Right - const __m128i one = _mm_set1_epi8(1); - const int I = top[-2]; - const int J = top[-3]; - const int K = top[-4]; - const int X = top[-1]; - const __m128i XABCD = _mm_loadl_epi64((const __m128i*)(top - 1)); - const __m128i ABCD0 = _mm_srli_si128(XABCD, 1); - const __m128i abcd = _mm_avg_epu8(XABCD, ABCD0); - const __m128i _XABCD = _mm_slli_si128(XABCD, 1); - const __m128i IXABCD = _mm_insert_epi16(_XABCD, (short)(I | (X << 8)), 0); - const __m128i avg1 = _mm_avg_epu8(IXABCD, ABCD0); - const __m128i lsb = _mm_and_si128(_mm_xor_si128(IXABCD, ABCD0), one); - const __m128i avg2 = _mm_subs_epu8(avg1, lsb); - const __m128i efgh = _mm_avg_epu8(avg2, XABCD); - WebPInt32ToMem(dst + 0 * BPS, _mm_cvtsi128_si32( abcd )); - WebPInt32ToMem(dst + 1 * BPS, _mm_cvtsi128_si32( efgh )); - WebPInt32ToMem(dst + 2 * BPS, _mm_cvtsi128_si32(_mm_slli_si128(abcd, 1))); - WebPInt32ToMem(dst + 3 * BPS, _mm_cvtsi128_si32(_mm_slli_si128(efgh, 1))); - - // these two are hard to implement in SSE2, so we keep the C-version: - DST(0, 2) = AVG3(J, I, X); - DST(0, 3) = AVG3(K, J, I); -} - -static WEBP_INLINE void VL4_SSE2(uint8_t* dst, - const uint8_t* top) { // Vertical-Left - const __m128i one = _mm_set1_epi8(1); - const __m128i ABCDEFGH = _mm_loadl_epi64((const __m128i*)top); - const __m128i BCDEFGH_ = _mm_srli_si128(ABCDEFGH, 1); - const __m128i CDEFGH__ = _mm_srli_si128(ABCDEFGH, 2); - const __m128i avg1 = _mm_avg_epu8(ABCDEFGH, BCDEFGH_); - const __m128i avg2 = _mm_avg_epu8(CDEFGH__, BCDEFGH_); - const __m128i avg3 = _mm_avg_epu8(avg1, avg2); - const __m128i lsb1 = _mm_and_si128(_mm_xor_si128(avg1, avg2), one); - const __m128i ab = _mm_xor_si128(ABCDEFGH, BCDEFGH_); - const __m128i bc = _mm_xor_si128(CDEFGH__, BCDEFGH_); - const __m128i abbc = _mm_or_si128(ab, bc); - const __m128i lsb2 = _mm_and_si128(abbc, lsb1); - const __m128i avg4 = _mm_subs_epu8(avg3, lsb2); - const uint32_t extra_out = - (uint32_t)_mm_cvtsi128_si32(_mm_srli_si128(avg4, 4)); - WebPInt32ToMem(dst + 0 * BPS, _mm_cvtsi128_si32( avg1 )); - WebPInt32ToMem(dst + 1 * BPS, _mm_cvtsi128_si32( avg4 )); - WebPInt32ToMem(dst + 2 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(avg1, 1))); - WebPInt32ToMem(dst + 3 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(avg4, 1))); - - // these two are hard to get and irregular - DST(3, 2) = (extra_out >> 0) & 0xff; - DST(3, 3) = (extra_out >> 8) & 0xff; -} - -static WEBP_INLINE void RD4_SSE2(uint8_t* dst, - const uint8_t* top) { // Down-right - const __m128i one = _mm_set1_epi8(1); - const __m128i LKJIXABC = _mm_loadl_epi64((const __m128i*)(top - 5)); - const __m128i LKJIXABCD = _mm_insert_epi16(LKJIXABC, top[3], 4); - const __m128i KJIXABCD_ = _mm_srli_si128(LKJIXABCD, 1); - const __m128i JIXABCD__ = _mm_srli_si128(LKJIXABCD, 2); - const __m128i avg1 = _mm_avg_epu8(JIXABCD__, LKJIXABCD); - const __m128i lsb = _mm_and_si128(_mm_xor_si128(JIXABCD__, LKJIXABCD), one); - const __m128i avg2 = _mm_subs_epu8(avg1, lsb); - const __m128i abcdefg = _mm_avg_epu8(avg2, KJIXABCD_); - WebPInt32ToMem(dst + 3 * BPS, _mm_cvtsi128_si32( abcdefg )); - WebPInt32ToMem(dst + 2 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 1))); - WebPInt32ToMem(dst + 1 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 2))); - WebPInt32ToMem(dst + 0 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 3))); -} - -static WEBP_INLINE void HU4_SSE2(uint8_t* dst, const uint8_t* top) { - const int I = top[-2]; - const int J = top[-3]; - const int K = top[-4]; - const int L = top[-5]; - DST(0, 0) = AVG2(I, J); - DST(2, 0) = DST(0, 1) = AVG2(J, K); - DST(2, 1) = DST(0, 2) = AVG2(K, L); - DST(1, 0) = AVG3(I, J, K); - DST(3, 0) = DST(1, 1) = AVG3(J, K, L); - DST(3, 1) = DST(1, 2) = AVG3(K, L, L); - DST(3, 2) = DST(2, 2) = - DST(0, 3) = DST(1, 3) = DST(2, 3) = DST(3, 3) = L; -} - -static WEBP_INLINE void HD4_SSE2(uint8_t* dst, const uint8_t* top) { - const int X = top[-1]; - const int I = top[-2]; - const int J = top[-3]; - const int K = top[-4]; - const int L = top[-5]; - const int A = top[0]; - const int B = top[1]; - const int C = top[2]; - - DST(0, 0) = DST(2, 1) = AVG2(I, X); - DST(0, 1) = DST(2, 2) = AVG2(J, I); - DST(0, 2) = DST(2, 3) = AVG2(K, J); - DST(0, 3) = AVG2(L, K); - - DST(3, 0) = AVG3(A, B, C); - DST(2, 0) = AVG3(X, A, B); - DST(1, 0) = DST(3, 1) = AVG3(I, X, A); - DST(1, 1) = DST(3, 2) = AVG3(J, I, X); - DST(1, 2) = DST(3, 3) = AVG3(K, J, I); - DST(1, 3) = AVG3(L, K, J); -} - -static WEBP_INLINE void TM4_SSE2(uint8_t* dst, const uint8_t* top) { - const __m128i zero = _mm_setzero_si128(); - const __m128i top_values = _mm_cvtsi32_si128(WebPMemToInt32(top)); - const __m128i top_base = _mm_unpacklo_epi8(top_values, zero); - int y; - for (y = 0; y < 4; ++y, dst += BPS) { - const int val = top[-2 - y] - top[-1]; - const __m128i base = _mm_set1_epi16(val); - const __m128i out = _mm_packus_epi16(_mm_add_epi16(base, top_base), zero); - WebPInt32ToMem(dst, _mm_cvtsi128_si32(out)); - } -} - -#undef DST -#undef AVG3 -#undef AVG2 - -//------------------------------------------------------------------------------ -// luma 4x4 prediction - -// Left samples are top[-5 .. -2], top_left is top[-1], top are -// located at top[0..3], and top right is top[4..7] -static void Intra4Preds_SSE2(uint8_t* dst, const uint8_t* top) { - DC4_SSE2(I4DC4 + dst, top); - TM4_SSE2(I4TM4 + dst, top); - VE4_SSE2(I4VE4 + dst, top); - HE4_SSE2(I4HE4 + dst, top); - RD4_SSE2(I4RD4 + dst, top); - VR4_SSE2(I4VR4 + dst, top); - LD4_SSE2(I4LD4 + dst, top); - VL4_SSE2(I4VL4 + dst, top); - HD4_SSE2(I4HD4 + dst, top); - HU4_SSE2(I4HU4 + dst, top); -} - -//------------------------------------------------------------------------------ -// Chroma 8x8 prediction (paragraph 12.2) - -static void IntraChromaPreds_SSE2(uint8_t* dst, const uint8_t* left, - const uint8_t* top) { - // U block - DC8uvMode_SSE2(C8DC8 + dst, left, top); - VerticalPred_SSE2(C8VE8 + dst, top, 8); - HorizontalPred_SSE2(C8HE8 + dst, left, 8); - TrueMotion_SSE2(C8TM8 + dst, left, top, 8); - // V block - dst += 8; - if (top != NULL) top += 8; - if (left != NULL) left += 16; - DC8uvMode_SSE2(C8DC8 + dst, left, top); - VerticalPred_SSE2(C8VE8 + dst, top, 8); - HorizontalPred_SSE2(C8HE8 + dst, left, 8); - TrueMotion_SSE2(C8TM8 + dst, left, top, 8); -} - -//------------------------------------------------------------------------------ -// luma 16x16 prediction (paragraph 12.3) - -static void Intra16Preds_SSE2(uint8_t* dst, - const uint8_t* left, const uint8_t* top) { - DC16Mode_SSE2(I16DC16 + dst, left, top); - VerticalPred_SSE2(I16VE16 + dst, top, 16); - HorizontalPred_SSE2(I16HE16 + dst, left, 16); - TrueMotion_SSE2(I16TM16 + dst, left, top, 16); -} - -//------------------------------------------------------------------------------ -// Metric - -static WEBP_INLINE void SubtractAndAccumulate_SSE2(const __m128i a, - const __m128i b, - __m128i* const sum) { - // take abs(a-b) in 8b - const __m128i a_b = _mm_subs_epu8(a, b); - const __m128i b_a = _mm_subs_epu8(b, a); - const __m128i abs_a_b = _mm_or_si128(a_b, b_a); - // zero-extend to 16b - const __m128i zero = _mm_setzero_si128(); - const __m128i C0 = _mm_unpacklo_epi8(abs_a_b, zero); - const __m128i C1 = _mm_unpackhi_epi8(abs_a_b, zero); - // multiply with self - const __m128i sum1 = _mm_madd_epi16(C0, C0); - const __m128i sum2 = _mm_madd_epi16(C1, C1); - *sum = _mm_add_epi32(sum1, sum2); -} - -static WEBP_INLINE int SSE_16xN_SSE2(const uint8_t* a, const uint8_t* b, - int num_pairs) { - __m128i sum = _mm_setzero_si128(); - int32_t tmp[4]; - int i; - - for (i = 0; i < num_pairs; ++i) { - const __m128i a0 = _mm_loadu_si128((const __m128i*)&a[BPS * 0]); - const __m128i b0 = _mm_loadu_si128((const __m128i*)&b[BPS * 0]); - const __m128i a1 = _mm_loadu_si128((const __m128i*)&a[BPS * 1]); - const __m128i b1 = _mm_loadu_si128((const __m128i*)&b[BPS * 1]); - __m128i sum1, sum2; - SubtractAndAccumulate_SSE2(a0, b0, &sum1); - SubtractAndAccumulate_SSE2(a1, b1, &sum2); - sum = _mm_add_epi32(sum, _mm_add_epi32(sum1, sum2)); - a += 2 * BPS; - b += 2 * BPS; - } - _mm_storeu_si128((__m128i*)tmp, sum); - return (tmp[3] + tmp[2] + tmp[1] + tmp[0]); -} - -static int SSE16x16_SSE2(const uint8_t* a, const uint8_t* b) { - return SSE_16xN_SSE2(a, b, 8); -} - -static int SSE16x8_SSE2(const uint8_t* a, const uint8_t* b) { - return SSE_16xN_SSE2(a, b, 4); -} - -#define LOAD_8x16b(ptr) \ - _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i*)(ptr)), zero) - -static int SSE8x8_SSE2(const uint8_t* a, const uint8_t* b) { - const __m128i zero = _mm_setzero_si128(); - int num_pairs = 4; - __m128i sum = zero; - int32_t tmp[4]; - while (num_pairs-- > 0) { - const __m128i a0 = LOAD_8x16b(&a[BPS * 0]); - const __m128i a1 = LOAD_8x16b(&a[BPS * 1]); - const __m128i b0 = LOAD_8x16b(&b[BPS * 0]); - const __m128i b1 = LOAD_8x16b(&b[BPS * 1]); - // subtract - const __m128i c0 = _mm_subs_epi16(a0, b0); - const __m128i c1 = _mm_subs_epi16(a1, b1); - // multiply/accumulate with self - const __m128i d0 = _mm_madd_epi16(c0, c0); - const __m128i d1 = _mm_madd_epi16(c1, c1); - // collect - const __m128i sum01 = _mm_add_epi32(d0, d1); - sum = _mm_add_epi32(sum, sum01); - a += 2 * BPS; - b += 2 * BPS; - } - _mm_storeu_si128((__m128i*)tmp, sum); - return (tmp[3] + tmp[2] + tmp[1] + tmp[0]); -} -#undef LOAD_8x16b - -static int SSE4x4_SSE2(const uint8_t* a, const uint8_t* b) { - const __m128i zero = _mm_setzero_si128(); - - // Load values. Note that we read 8 pixels instead of 4, - // but the a/b buffers are over-allocated to that effect. - const __m128i a0 = _mm_loadl_epi64((const __m128i*)&a[BPS * 0]); - const __m128i a1 = _mm_loadl_epi64((const __m128i*)&a[BPS * 1]); - const __m128i a2 = _mm_loadl_epi64((const __m128i*)&a[BPS * 2]); - const __m128i a3 = _mm_loadl_epi64((const __m128i*)&a[BPS * 3]); - const __m128i b0 = _mm_loadl_epi64((const __m128i*)&b[BPS * 0]); - const __m128i b1 = _mm_loadl_epi64((const __m128i*)&b[BPS * 1]); - const __m128i b2 = _mm_loadl_epi64((const __m128i*)&b[BPS * 2]); - const __m128i b3 = _mm_loadl_epi64((const __m128i*)&b[BPS * 3]); - // Combine pair of lines. - const __m128i a01 = _mm_unpacklo_epi32(a0, a1); - const __m128i a23 = _mm_unpacklo_epi32(a2, a3); - const __m128i b01 = _mm_unpacklo_epi32(b0, b1); - const __m128i b23 = _mm_unpacklo_epi32(b2, b3); - // Convert to 16b. - const __m128i a01s = _mm_unpacklo_epi8(a01, zero); - const __m128i a23s = _mm_unpacklo_epi8(a23, zero); - const __m128i b01s = _mm_unpacklo_epi8(b01, zero); - const __m128i b23s = _mm_unpacklo_epi8(b23, zero); - // subtract, square and accumulate - const __m128i d0 = _mm_subs_epi16(a01s, b01s); - const __m128i d1 = _mm_subs_epi16(a23s, b23s); - const __m128i e0 = _mm_madd_epi16(d0, d0); - const __m128i e1 = _mm_madd_epi16(d1, d1); - const __m128i sum = _mm_add_epi32(e0, e1); - - int32_t tmp[4]; - _mm_storeu_si128((__m128i*)tmp, sum); - return (tmp[3] + tmp[2] + tmp[1] + tmp[0]); -} - -//------------------------------------------------------------------------------ - -static void Mean16x4_SSE2(const uint8_t* ref, uint32_t dc[4]) { - const __m128i mask = _mm_set1_epi16(0x00ff); - const __m128i a0 = _mm_loadu_si128((const __m128i*)&ref[BPS * 0]); - const __m128i a1 = _mm_loadu_si128((const __m128i*)&ref[BPS * 1]); - const __m128i a2 = _mm_loadu_si128((const __m128i*)&ref[BPS * 2]); - const __m128i a3 = _mm_loadu_si128((const __m128i*)&ref[BPS * 3]); - const __m128i b0 = _mm_srli_epi16(a0, 8); // hi byte - const __m128i b1 = _mm_srli_epi16(a1, 8); - const __m128i b2 = _mm_srli_epi16(a2, 8); - const __m128i b3 = _mm_srli_epi16(a3, 8); - const __m128i c0 = _mm_and_si128(a0, mask); // lo byte - const __m128i c1 = _mm_and_si128(a1, mask); - const __m128i c2 = _mm_and_si128(a2, mask); - const __m128i c3 = _mm_and_si128(a3, mask); - const __m128i d0 = _mm_add_epi32(b0, c0); - const __m128i d1 = _mm_add_epi32(b1, c1); - const __m128i d2 = _mm_add_epi32(b2, c2); - const __m128i d3 = _mm_add_epi32(b3, c3); - const __m128i e0 = _mm_add_epi32(d0, d1); - const __m128i e1 = _mm_add_epi32(d2, d3); - const __m128i f0 = _mm_add_epi32(e0, e1); - uint16_t tmp[8]; - _mm_storeu_si128((__m128i*)tmp, f0); - dc[0] = tmp[0] + tmp[1]; - dc[1] = tmp[2] + tmp[3]; - dc[2] = tmp[4] + tmp[5]; - dc[3] = tmp[6] + tmp[7]; -} - -//------------------------------------------------------------------------------ -// Texture distortion -// -// We try to match the spectral content (weighted) between source and -// reconstructed samples. - -// Hadamard transform -// Returns the weighted sum of the absolute value of transformed coefficients. -// w[] contains a row-major 4 by 4 symmetric matrix. -static int TTransform_SSE2(const uint8_t* inA, const uint8_t* inB, - const uint16_t* const w) { - int32_t sum[4]; - __m128i tmp_0, tmp_1, tmp_2, tmp_3; - const __m128i zero = _mm_setzero_si128(); - - // Load and combine inputs. - { - const __m128i inA_0 = _mm_loadl_epi64((const __m128i*)&inA[BPS * 0]); - const __m128i inA_1 = _mm_loadl_epi64((const __m128i*)&inA[BPS * 1]); - const __m128i inA_2 = _mm_loadl_epi64((const __m128i*)&inA[BPS * 2]); - const __m128i inA_3 = _mm_loadl_epi64((const __m128i*)&inA[BPS * 3]); - const __m128i inB_0 = _mm_loadl_epi64((const __m128i*)&inB[BPS * 0]); - const __m128i inB_1 = _mm_loadl_epi64((const __m128i*)&inB[BPS * 1]); - const __m128i inB_2 = _mm_loadl_epi64((const __m128i*)&inB[BPS * 2]); - const __m128i inB_3 = _mm_loadl_epi64((const __m128i*)&inB[BPS * 3]); - - // Combine inA and inB (we'll do two transforms in parallel). - const __m128i inAB_0 = _mm_unpacklo_epi32(inA_0, inB_0); - const __m128i inAB_1 = _mm_unpacklo_epi32(inA_1, inB_1); - const __m128i inAB_2 = _mm_unpacklo_epi32(inA_2, inB_2); - const __m128i inAB_3 = _mm_unpacklo_epi32(inA_3, inB_3); - tmp_0 = _mm_unpacklo_epi8(inAB_0, zero); - tmp_1 = _mm_unpacklo_epi8(inAB_1, zero); - tmp_2 = _mm_unpacklo_epi8(inAB_2, zero); - tmp_3 = _mm_unpacklo_epi8(inAB_3, zero); - // a00 a01 a02 a03 b00 b01 b02 b03 - // a10 a11 a12 a13 b10 b11 b12 b13 - // a20 a21 a22 a23 b20 b21 b22 b23 - // a30 a31 a32 a33 b30 b31 b32 b33 - } - - // Vertical pass first to avoid a transpose (vertical and horizontal passes - // are commutative because w/kWeightY is symmetric) and subsequent transpose. - { - // Calculate a and b (two 4x4 at once). - const __m128i a0 = _mm_add_epi16(tmp_0, tmp_2); - const __m128i a1 = _mm_add_epi16(tmp_1, tmp_3); - const __m128i a2 = _mm_sub_epi16(tmp_1, tmp_3); - const __m128i a3 = _mm_sub_epi16(tmp_0, tmp_2); - const __m128i b0 = _mm_add_epi16(a0, a1); - const __m128i b1 = _mm_add_epi16(a3, a2); - const __m128i b2 = _mm_sub_epi16(a3, a2); - const __m128i b3 = _mm_sub_epi16(a0, a1); - // a00 a01 a02 a03 b00 b01 b02 b03 - // a10 a11 a12 a13 b10 b11 b12 b13 - // a20 a21 a22 a23 b20 b21 b22 b23 - // a30 a31 a32 a33 b30 b31 b32 b33 - - // Transpose the two 4x4. - VP8Transpose_2_4x4_16b(&b0, &b1, &b2, &b3, &tmp_0, &tmp_1, &tmp_2, &tmp_3); - } - - // Horizontal pass and difference of weighted sums. - { - // Load all inputs. - const __m128i w_0 = _mm_loadu_si128((const __m128i*)&w[0]); - const __m128i w_8 = _mm_loadu_si128((const __m128i*)&w[8]); - - // Calculate a and b (two 4x4 at once). - const __m128i a0 = _mm_add_epi16(tmp_0, tmp_2); - const __m128i a1 = _mm_add_epi16(tmp_1, tmp_3); - const __m128i a2 = _mm_sub_epi16(tmp_1, tmp_3); - const __m128i a3 = _mm_sub_epi16(tmp_0, tmp_2); - const __m128i b0 = _mm_add_epi16(a0, a1); - const __m128i b1 = _mm_add_epi16(a3, a2); - const __m128i b2 = _mm_sub_epi16(a3, a2); - const __m128i b3 = _mm_sub_epi16(a0, a1); - - // Separate the transforms of inA and inB. - __m128i A_b0 = _mm_unpacklo_epi64(b0, b1); - __m128i A_b2 = _mm_unpacklo_epi64(b2, b3); - __m128i B_b0 = _mm_unpackhi_epi64(b0, b1); - __m128i B_b2 = _mm_unpackhi_epi64(b2, b3); - - { - const __m128i d0 = _mm_sub_epi16(zero, A_b0); - const __m128i d1 = _mm_sub_epi16(zero, A_b2); - const __m128i d2 = _mm_sub_epi16(zero, B_b0); - const __m128i d3 = _mm_sub_epi16(zero, B_b2); - A_b0 = _mm_max_epi16(A_b0, d0); // abs(v), 16b - A_b2 = _mm_max_epi16(A_b2, d1); - B_b0 = _mm_max_epi16(B_b0, d2); - B_b2 = _mm_max_epi16(B_b2, d3); - } - - // weighted sums - A_b0 = _mm_madd_epi16(A_b0, w_0); - A_b2 = _mm_madd_epi16(A_b2, w_8); - B_b0 = _mm_madd_epi16(B_b0, w_0); - B_b2 = _mm_madd_epi16(B_b2, w_8); - A_b0 = _mm_add_epi32(A_b0, A_b2); - B_b0 = _mm_add_epi32(B_b0, B_b2); - - // difference of weighted sums - A_b0 = _mm_sub_epi32(A_b0, B_b0); - _mm_storeu_si128((__m128i*)&sum[0], A_b0); - } - return sum[0] + sum[1] + sum[2] + sum[3]; -} - -static int Disto4x4_SSE2(const uint8_t* const a, const uint8_t* const b, - const uint16_t* const w) { - const int diff_sum = TTransform_SSE2(a, b, w); - return abs(diff_sum) >> 5; -} - -static int Disto16x16_SSE2(const uint8_t* const a, const uint8_t* const b, - const uint16_t* const w) { - int D = 0; - int x, y; - for (y = 0; y < 16 * BPS; y += 4 * BPS) { - for (x = 0; x < 16; x += 4) { - D += Disto4x4_SSE2(a + x + y, b + x + y, w); - } - } - return D; -} - -//------------------------------------------------------------------------------ -// Quantization -// - -static WEBP_INLINE int DoQuantizeBlock_SSE2(int16_t in[16], int16_t out[16], - const uint16_t* const sharpen, - const VP8Matrix* const mtx) { - const __m128i max_coeff_2047 = _mm_set1_epi16(MAX_LEVEL); - const __m128i zero = _mm_setzero_si128(); - __m128i coeff0, coeff8; - __m128i out0, out8; - __m128i packed_out; - - // Load all inputs. - __m128i in0 = _mm_loadu_si128((__m128i*)&in[0]); - __m128i in8 = _mm_loadu_si128((__m128i*)&in[8]); - const __m128i iq0 = _mm_loadu_si128((const __m128i*)&mtx->iq_[0]); - const __m128i iq8 = _mm_loadu_si128((const __m128i*)&mtx->iq_[8]); - const __m128i q0 = _mm_loadu_si128((const __m128i*)&mtx->q_[0]); - const __m128i q8 = _mm_loadu_si128((const __m128i*)&mtx->q_[8]); - - // extract sign(in) (0x0000 if positive, 0xffff if negative) - const __m128i sign0 = _mm_cmpgt_epi16(zero, in0); - const __m128i sign8 = _mm_cmpgt_epi16(zero, in8); - - // coeff = abs(in) = (in ^ sign) - sign - coeff0 = _mm_xor_si128(in0, sign0); - coeff8 = _mm_xor_si128(in8, sign8); - coeff0 = _mm_sub_epi16(coeff0, sign0); - coeff8 = _mm_sub_epi16(coeff8, sign8); - - // coeff = abs(in) + sharpen - if (sharpen != NULL) { - const __m128i sharpen0 = _mm_loadu_si128((const __m128i*)&sharpen[0]); - const __m128i sharpen8 = _mm_loadu_si128((const __m128i*)&sharpen[8]); - coeff0 = _mm_add_epi16(coeff0, sharpen0); - coeff8 = _mm_add_epi16(coeff8, sharpen8); - } - - // out = (coeff * iQ + B) >> QFIX - { - // doing calculations with 32b precision (QFIX=17) - // out = (coeff * iQ) - const __m128i coeff_iQ0H = _mm_mulhi_epu16(coeff0, iq0); - const __m128i coeff_iQ0L = _mm_mullo_epi16(coeff0, iq0); - const __m128i coeff_iQ8H = _mm_mulhi_epu16(coeff8, iq8); - const __m128i coeff_iQ8L = _mm_mullo_epi16(coeff8, iq8); - __m128i out_00 = _mm_unpacklo_epi16(coeff_iQ0L, coeff_iQ0H); - __m128i out_04 = _mm_unpackhi_epi16(coeff_iQ0L, coeff_iQ0H); - __m128i out_08 = _mm_unpacklo_epi16(coeff_iQ8L, coeff_iQ8H); - __m128i out_12 = _mm_unpackhi_epi16(coeff_iQ8L, coeff_iQ8H); - // out = (coeff * iQ + B) - const __m128i bias_00 = _mm_loadu_si128((const __m128i*)&mtx->bias_[0]); - const __m128i bias_04 = _mm_loadu_si128((const __m128i*)&mtx->bias_[4]); - const __m128i bias_08 = _mm_loadu_si128((const __m128i*)&mtx->bias_[8]); - const __m128i bias_12 = _mm_loadu_si128((const __m128i*)&mtx->bias_[12]); - out_00 = _mm_add_epi32(out_00, bias_00); - out_04 = _mm_add_epi32(out_04, bias_04); - out_08 = _mm_add_epi32(out_08, bias_08); - out_12 = _mm_add_epi32(out_12, bias_12); - // out = QUANTDIV(coeff, iQ, B, QFIX) - out_00 = _mm_srai_epi32(out_00, QFIX); - out_04 = _mm_srai_epi32(out_04, QFIX); - out_08 = _mm_srai_epi32(out_08, QFIX); - out_12 = _mm_srai_epi32(out_12, QFIX); - - // pack result as 16b - out0 = _mm_packs_epi32(out_00, out_04); - out8 = _mm_packs_epi32(out_08, out_12); - - // if (coeff > 2047) coeff = 2047 - out0 = _mm_min_epi16(out0, max_coeff_2047); - out8 = _mm_min_epi16(out8, max_coeff_2047); - } - - // get sign back (if (sign[j]) out_n = -out_n) - out0 = _mm_xor_si128(out0, sign0); - out8 = _mm_xor_si128(out8, sign8); - out0 = _mm_sub_epi16(out0, sign0); - out8 = _mm_sub_epi16(out8, sign8); - - // in = out * Q - in0 = _mm_mullo_epi16(out0, q0); - in8 = _mm_mullo_epi16(out8, q8); - - _mm_storeu_si128((__m128i*)&in[0], in0); - _mm_storeu_si128((__m128i*)&in[8], in8); - - // zigzag the output before storing it. - // - // The zigzag pattern can almost be reproduced with a small sequence of - // shuffles. After it, we only need to swap the 7th (ending up in third - // position instead of twelfth) and 8th values. - { - __m128i outZ0, outZ8; - outZ0 = _mm_shufflehi_epi16(out0, _MM_SHUFFLE(2, 1, 3, 0)); - outZ0 = _mm_shuffle_epi32 (outZ0, _MM_SHUFFLE(3, 1, 2, 0)); - outZ0 = _mm_shufflehi_epi16(outZ0, _MM_SHUFFLE(3, 1, 0, 2)); - outZ8 = _mm_shufflelo_epi16(out8, _MM_SHUFFLE(3, 0, 2, 1)); - outZ8 = _mm_shuffle_epi32 (outZ8, _MM_SHUFFLE(3, 1, 2, 0)); - outZ8 = _mm_shufflelo_epi16(outZ8, _MM_SHUFFLE(1, 3, 2, 0)); - _mm_storeu_si128((__m128i*)&out[0], outZ0); - _mm_storeu_si128((__m128i*)&out[8], outZ8); - packed_out = _mm_packs_epi16(outZ0, outZ8); - } - { - const int16_t outZ_12 = out[12]; - const int16_t outZ_3 = out[3]; - out[3] = outZ_12; - out[12] = outZ_3; - } - - // detect if all 'out' values are zeroes or not - return (_mm_movemask_epi8(_mm_cmpeq_epi8(packed_out, zero)) != 0xffff); -} - -static int QuantizeBlock_SSE2(int16_t in[16], int16_t out[16], - const VP8Matrix* const mtx) { - return DoQuantizeBlock_SSE2(in, out, &mtx->sharpen_[0], mtx); -} - -static int QuantizeBlockWHT_SSE2(int16_t in[16], int16_t out[16], - const VP8Matrix* const mtx) { - return DoQuantizeBlock_SSE2(in, out, NULL, mtx); -} - -static int Quantize2Blocks_SSE2(int16_t in[32], int16_t out[32], - const VP8Matrix* const mtx) { - int nz; - const uint16_t* const sharpen = &mtx->sharpen_[0]; - nz = DoQuantizeBlock_SSE2(in + 0 * 16, out + 0 * 16, sharpen, mtx) << 0; - nz |= DoQuantizeBlock_SSE2(in + 1 * 16, out + 1 * 16, sharpen, mtx) << 1; - return nz; -} - -//------------------------------------------------------------------------------ -// Entry point - -extern void VP8EncDspInitSSE2(void); - -WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspInitSSE2(void) { - VP8CollectHistogram = CollectHistogram_SSE2; - VP8EncPredLuma16 = Intra16Preds_SSE2; - VP8EncPredChroma8 = IntraChromaPreds_SSE2; - VP8EncPredLuma4 = Intra4Preds_SSE2; - VP8EncQuantizeBlock = QuantizeBlock_SSE2; - VP8EncQuantize2Blocks = Quantize2Blocks_SSE2; - VP8EncQuantizeBlockWHT = QuantizeBlockWHT_SSE2; - VP8ITransform = ITransform_SSE2; - VP8FTransform = FTransform_SSE2; - VP8FTransform2 = FTransform2_SSE2; - VP8FTransformWHT = FTransformWHT_SSE2; - VP8SSE16x16 = SSE16x16_SSE2; - VP8SSE16x8 = SSE16x8_SSE2; - VP8SSE8x8 = SSE8x8_SSE2; - VP8SSE4x4 = SSE4x4_SSE2; - VP8TDisto4x4 = Disto4x4_SSE2; - VP8TDisto16x16 = Disto16x16_SSE2; - VP8Mean16x4 = Mean16x4_SSE2; -} - -#else // !WEBP_USE_SSE2 - -WEBP_DSP_INIT_STUB(VP8EncDspInitSSE2) - -#endif // WEBP_USE_SSE2 diff --git a/libwebp/src/dsp/enc_sse41.c b/libwebp/src/dsp/enc_sse41.c deleted file mode 100644 index 924035a6..00000000 --- a/libwebp/src/dsp/enc_sse41.c +++ /dev/null @@ -1,339 +0,0 @@ -// Copyright 2015 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// SSE4 version of some encoding functions. -// -// Author: Skal (pascal.massimino@gmail.com) - -#include "src/dsp/dsp.h" - -#if defined(WEBP_USE_SSE41) -#include -#include // for abs() - -#include "src/dsp/common_sse2.h" -#include "src/enc/vp8i_enc.h" - -//------------------------------------------------------------------------------ -// Compute susceptibility based on DCT-coeff histograms. - -static void CollectHistogram_SSE41(const uint8_t* ref, const uint8_t* pred, - int start_block, int end_block, - VP8Histogram* const histo) { - const __m128i max_coeff_thresh = _mm_set1_epi16(MAX_COEFF_THRESH); - int j; - int distribution[MAX_COEFF_THRESH + 1] = { 0 }; - for (j = start_block; j < end_block; ++j) { - int16_t out[16]; - int k; - - VP8FTransform(ref + VP8DspScan[j], pred + VP8DspScan[j], out); - - // Convert coefficients to bin (within out[]). - { - // Load. - const __m128i out0 = _mm_loadu_si128((__m128i*)&out[0]); - const __m128i out1 = _mm_loadu_si128((__m128i*)&out[8]); - // v = abs(out) >> 3 - const __m128i abs0 = _mm_abs_epi16(out0); - const __m128i abs1 = _mm_abs_epi16(out1); - const __m128i v0 = _mm_srai_epi16(abs0, 3); - const __m128i v1 = _mm_srai_epi16(abs1, 3); - // bin = min(v, MAX_COEFF_THRESH) - const __m128i bin0 = _mm_min_epi16(v0, max_coeff_thresh); - const __m128i bin1 = _mm_min_epi16(v1, max_coeff_thresh); - // Store. - _mm_storeu_si128((__m128i*)&out[0], bin0); - _mm_storeu_si128((__m128i*)&out[8], bin1); - } - - // Convert coefficients to bin. - for (k = 0; k < 16; ++k) { - ++distribution[out[k]]; - } - } - VP8SetHistogramData(distribution, histo); -} - -//------------------------------------------------------------------------------ -// Texture distortion -// -// We try to match the spectral content (weighted) between source and -// reconstructed samples. - -// Hadamard transform -// Returns the weighted sum of the absolute value of transformed coefficients. -// w[] contains a row-major 4 by 4 symmetric matrix. -static int TTransform_SSE41(const uint8_t* inA, const uint8_t* inB, - const uint16_t* const w) { - int32_t sum[4]; - __m128i tmp_0, tmp_1, tmp_2, tmp_3; - - // Load and combine inputs. - { - const __m128i inA_0 = _mm_loadu_si128((const __m128i*)&inA[BPS * 0]); - const __m128i inA_1 = _mm_loadu_si128((const __m128i*)&inA[BPS * 1]); - const __m128i inA_2 = _mm_loadu_si128((const __m128i*)&inA[BPS * 2]); - // In SSE4.1, with gcc 4.8 at least (maybe other versions), - // _mm_loadu_si128 is faster than _mm_loadl_epi64. But for the last lump - // of inA and inB, _mm_loadl_epi64 is still used not to have an out of - // bound read. - const __m128i inA_3 = _mm_loadl_epi64((const __m128i*)&inA[BPS * 3]); - const __m128i inB_0 = _mm_loadu_si128((const __m128i*)&inB[BPS * 0]); - const __m128i inB_1 = _mm_loadu_si128((const __m128i*)&inB[BPS * 1]); - const __m128i inB_2 = _mm_loadu_si128((const __m128i*)&inB[BPS * 2]); - const __m128i inB_3 = _mm_loadl_epi64((const __m128i*)&inB[BPS * 3]); - - // Combine inA and inB (we'll do two transforms in parallel). - const __m128i inAB_0 = _mm_unpacklo_epi32(inA_0, inB_0); - const __m128i inAB_1 = _mm_unpacklo_epi32(inA_1, inB_1); - const __m128i inAB_2 = _mm_unpacklo_epi32(inA_2, inB_2); - const __m128i inAB_3 = _mm_unpacklo_epi32(inA_3, inB_3); - tmp_0 = _mm_cvtepu8_epi16(inAB_0); - tmp_1 = _mm_cvtepu8_epi16(inAB_1); - tmp_2 = _mm_cvtepu8_epi16(inAB_2); - tmp_3 = _mm_cvtepu8_epi16(inAB_3); - // a00 a01 a02 a03 b00 b01 b02 b03 - // a10 a11 a12 a13 b10 b11 b12 b13 - // a20 a21 a22 a23 b20 b21 b22 b23 - // a30 a31 a32 a33 b30 b31 b32 b33 - } - - // Vertical pass first to avoid a transpose (vertical and horizontal passes - // are commutative because w/kWeightY is symmetric) and subsequent transpose. - { - // Calculate a and b (two 4x4 at once). - const __m128i a0 = _mm_add_epi16(tmp_0, tmp_2); - const __m128i a1 = _mm_add_epi16(tmp_1, tmp_3); - const __m128i a2 = _mm_sub_epi16(tmp_1, tmp_3); - const __m128i a3 = _mm_sub_epi16(tmp_0, tmp_2); - const __m128i b0 = _mm_add_epi16(a0, a1); - const __m128i b1 = _mm_add_epi16(a3, a2); - const __m128i b2 = _mm_sub_epi16(a3, a2); - const __m128i b3 = _mm_sub_epi16(a0, a1); - // a00 a01 a02 a03 b00 b01 b02 b03 - // a10 a11 a12 a13 b10 b11 b12 b13 - // a20 a21 a22 a23 b20 b21 b22 b23 - // a30 a31 a32 a33 b30 b31 b32 b33 - - // Transpose the two 4x4. - VP8Transpose_2_4x4_16b(&b0, &b1, &b2, &b3, &tmp_0, &tmp_1, &tmp_2, &tmp_3); - } - - // Horizontal pass and difference of weighted sums. - { - // Load all inputs. - const __m128i w_0 = _mm_loadu_si128((const __m128i*)&w[0]); - const __m128i w_8 = _mm_loadu_si128((const __m128i*)&w[8]); - - // Calculate a and b (two 4x4 at once). - const __m128i a0 = _mm_add_epi16(tmp_0, tmp_2); - const __m128i a1 = _mm_add_epi16(tmp_1, tmp_3); - const __m128i a2 = _mm_sub_epi16(tmp_1, tmp_3); - const __m128i a3 = _mm_sub_epi16(tmp_0, tmp_2); - const __m128i b0 = _mm_add_epi16(a0, a1); - const __m128i b1 = _mm_add_epi16(a3, a2); - const __m128i b2 = _mm_sub_epi16(a3, a2); - const __m128i b3 = _mm_sub_epi16(a0, a1); - - // Separate the transforms of inA and inB. - __m128i A_b0 = _mm_unpacklo_epi64(b0, b1); - __m128i A_b2 = _mm_unpacklo_epi64(b2, b3); - __m128i B_b0 = _mm_unpackhi_epi64(b0, b1); - __m128i B_b2 = _mm_unpackhi_epi64(b2, b3); - - A_b0 = _mm_abs_epi16(A_b0); - A_b2 = _mm_abs_epi16(A_b2); - B_b0 = _mm_abs_epi16(B_b0); - B_b2 = _mm_abs_epi16(B_b2); - - // weighted sums - A_b0 = _mm_madd_epi16(A_b0, w_0); - A_b2 = _mm_madd_epi16(A_b2, w_8); - B_b0 = _mm_madd_epi16(B_b0, w_0); - B_b2 = _mm_madd_epi16(B_b2, w_8); - A_b0 = _mm_add_epi32(A_b0, A_b2); - B_b0 = _mm_add_epi32(B_b0, B_b2); - - // difference of weighted sums - A_b2 = _mm_sub_epi32(A_b0, B_b0); - _mm_storeu_si128((__m128i*)&sum[0], A_b2); - } - return sum[0] + sum[1] + sum[2] + sum[3]; -} - -static int Disto4x4_SSE41(const uint8_t* const a, const uint8_t* const b, - const uint16_t* const w) { - const int diff_sum = TTransform_SSE41(a, b, w); - return abs(diff_sum) >> 5; -} - -static int Disto16x16_SSE41(const uint8_t* const a, const uint8_t* const b, - const uint16_t* const w) { - int D = 0; - int x, y; - for (y = 0; y < 16 * BPS; y += 4 * BPS) { - for (x = 0; x < 16; x += 4) { - D += Disto4x4_SSE41(a + x + y, b + x + y, w); - } - } - return D; -} - -//------------------------------------------------------------------------------ -// Quantization -// - -// Generates a pshufb constant for shuffling 16b words. -#define PSHUFB_CST(A,B,C,D,E,F,G,H) \ - _mm_set_epi8(2 * (H) + 1, 2 * (H) + 0, 2 * (G) + 1, 2 * (G) + 0, \ - 2 * (F) + 1, 2 * (F) + 0, 2 * (E) + 1, 2 * (E) + 0, \ - 2 * (D) + 1, 2 * (D) + 0, 2 * (C) + 1, 2 * (C) + 0, \ - 2 * (B) + 1, 2 * (B) + 0, 2 * (A) + 1, 2 * (A) + 0) - -static WEBP_INLINE int DoQuantizeBlock_SSE41(int16_t in[16], int16_t out[16], - const uint16_t* const sharpen, - const VP8Matrix* const mtx) { - const __m128i max_coeff_2047 = _mm_set1_epi16(MAX_LEVEL); - const __m128i zero = _mm_setzero_si128(); - __m128i out0, out8; - __m128i packed_out; - - // Load all inputs. - __m128i in0 = _mm_loadu_si128((__m128i*)&in[0]); - __m128i in8 = _mm_loadu_si128((__m128i*)&in[8]); - const __m128i iq0 = _mm_loadu_si128((const __m128i*)&mtx->iq_[0]); - const __m128i iq8 = _mm_loadu_si128((const __m128i*)&mtx->iq_[8]); - const __m128i q0 = _mm_loadu_si128((const __m128i*)&mtx->q_[0]); - const __m128i q8 = _mm_loadu_si128((const __m128i*)&mtx->q_[8]); - - // coeff = abs(in) - __m128i coeff0 = _mm_abs_epi16(in0); - __m128i coeff8 = _mm_abs_epi16(in8); - - // coeff = abs(in) + sharpen - if (sharpen != NULL) { - const __m128i sharpen0 = _mm_loadu_si128((const __m128i*)&sharpen[0]); - const __m128i sharpen8 = _mm_loadu_si128((const __m128i*)&sharpen[8]); - coeff0 = _mm_add_epi16(coeff0, sharpen0); - coeff8 = _mm_add_epi16(coeff8, sharpen8); - } - - // out = (coeff * iQ + B) >> QFIX - { - // doing calculations with 32b precision (QFIX=17) - // out = (coeff * iQ) - const __m128i coeff_iQ0H = _mm_mulhi_epu16(coeff0, iq0); - const __m128i coeff_iQ0L = _mm_mullo_epi16(coeff0, iq0); - const __m128i coeff_iQ8H = _mm_mulhi_epu16(coeff8, iq8); - const __m128i coeff_iQ8L = _mm_mullo_epi16(coeff8, iq8); - __m128i out_00 = _mm_unpacklo_epi16(coeff_iQ0L, coeff_iQ0H); - __m128i out_04 = _mm_unpackhi_epi16(coeff_iQ0L, coeff_iQ0H); - __m128i out_08 = _mm_unpacklo_epi16(coeff_iQ8L, coeff_iQ8H); - __m128i out_12 = _mm_unpackhi_epi16(coeff_iQ8L, coeff_iQ8H); - // out = (coeff * iQ + B) - const __m128i bias_00 = _mm_loadu_si128((const __m128i*)&mtx->bias_[0]); - const __m128i bias_04 = _mm_loadu_si128((const __m128i*)&mtx->bias_[4]); - const __m128i bias_08 = _mm_loadu_si128((const __m128i*)&mtx->bias_[8]); - const __m128i bias_12 = _mm_loadu_si128((const __m128i*)&mtx->bias_[12]); - out_00 = _mm_add_epi32(out_00, bias_00); - out_04 = _mm_add_epi32(out_04, bias_04); - out_08 = _mm_add_epi32(out_08, bias_08); - out_12 = _mm_add_epi32(out_12, bias_12); - // out = QUANTDIV(coeff, iQ, B, QFIX) - out_00 = _mm_srai_epi32(out_00, QFIX); - out_04 = _mm_srai_epi32(out_04, QFIX); - out_08 = _mm_srai_epi32(out_08, QFIX); - out_12 = _mm_srai_epi32(out_12, QFIX); - - // pack result as 16b - out0 = _mm_packs_epi32(out_00, out_04); - out8 = _mm_packs_epi32(out_08, out_12); - - // if (coeff > 2047) coeff = 2047 - out0 = _mm_min_epi16(out0, max_coeff_2047); - out8 = _mm_min_epi16(out8, max_coeff_2047); - } - - // put sign back - out0 = _mm_sign_epi16(out0, in0); - out8 = _mm_sign_epi16(out8, in8); - - // in = out * Q - in0 = _mm_mullo_epi16(out0, q0); - in8 = _mm_mullo_epi16(out8, q8); - - _mm_storeu_si128((__m128i*)&in[0], in0); - _mm_storeu_si128((__m128i*)&in[8], in8); - - // zigzag the output before storing it. The re-ordering is: - // 0 1 2 3 4 5 6 7 | 8 9 10 11 12 13 14 15 - // -> 0 1 4[8]5 2 3 6 | 9 12 13 10 [7]11 14 15 - // There's only two misplaced entries ([8] and [7]) that are crossing the - // reg's boundaries. - // We use pshufb instead of pshuflo/pshufhi. - { - const __m128i kCst_lo = PSHUFB_CST(0, 1, 4, -1, 5, 2, 3, 6); - const __m128i kCst_7 = PSHUFB_CST(-1, -1, -1, -1, 7, -1, -1, -1); - const __m128i tmp_lo = _mm_shuffle_epi8(out0, kCst_lo); - const __m128i tmp_7 = _mm_shuffle_epi8(out0, kCst_7); // extract #7 - const __m128i kCst_hi = PSHUFB_CST(1, 4, 5, 2, -1, 3, 6, 7); - const __m128i kCst_8 = PSHUFB_CST(-1, -1, -1, 0, -1, -1, -1, -1); - const __m128i tmp_hi = _mm_shuffle_epi8(out8, kCst_hi); - const __m128i tmp_8 = _mm_shuffle_epi8(out8, kCst_8); // extract #8 - const __m128i out_z0 = _mm_or_si128(tmp_lo, tmp_8); - const __m128i out_z8 = _mm_or_si128(tmp_hi, tmp_7); - _mm_storeu_si128((__m128i*)&out[0], out_z0); - _mm_storeu_si128((__m128i*)&out[8], out_z8); - packed_out = _mm_packs_epi16(out_z0, out_z8); - } - - // detect if all 'out' values are zeroes or not - return (_mm_movemask_epi8(_mm_cmpeq_epi8(packed_out, zero)) != 0xffff); -} - -#undef PSHUFB_CST - -static int QuantizeBlock_SSE41(int16_t in[16], int16_t out[16], - const VP8Matrix* const mtx) { - return DoQuantizeBlock_SSE41(in, out, &mtx->sharpen_[0], mtx); -} - -static int QuantizeBlockWHT_SSE41(int16_t in[16], int16_t out[16], - const VP8Matrix* const mtx) { - return DoQuantizeBlock_SSE41(in, out, NULL, mtx); -} - -static int Quantize2Blocks_SSE41(int16_t in[32], int16_t out[32], - const VP8Matrix* const mtx) { - int nz; - const uint16_t* const sharpen = &mtx->sharpen_[0]; - nz = DoQuantizeBlock_SSE41(in + 0 * 16, out + 0 * 16, sharpen, mtx) << 0; - nz |= DoQuantizeBlock_SSE41(in + 1 * 16, out + 1 * 16, sharpen, mtx) << 1; - return nz; -} - -//------------------------------------------------------------------------------ -// Entry point - -extern void VP8EncDspInitSSE41(void); -WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspInitSSE41(void) { - VP8CollectHistogram = CollectHistogram_SSE41; - VP8EncQuantizeBlock = QuantizeBlock_SSE41; - VP8EncQuantize2Blocks = Quantize2Blocks_SSE41; - VP8EncQuantizeBlockWHT = QuantizeBlockWHT_SSE41; - VP8TDisto4x4 = Disto4x4_SSE41; - VP8TDisto16x16 = Disto16x16_SSE41; -} - -#else // !WEBP_USE_SSE41 - -WEBP_DSP_INIT_STUB(VP8EncDspInitSSE41) - -#endif // WEBP_USE_SSE41 diff --git a/libwebp/src/dsp/filters.c b/libwebp/src/dsp/filters.c index c9232ff1..38da5252 100644 --- a/libwebp/src/dsp/filters.c +++ b/libwebp/src/dsp/filters.c @@ -11,11 +11,14 @@ // // Author: Urvang (urvang@google.com) -#include "src/dsp/dsp.h" #include #include #include +#include "src/dsp/cpu.h" +#include "src/dsp/dsp.h" +#include "src/webp/types.h" + //------------------------------------------------------------------------------ // Helpful macro. @@ -23,55 +26,42 @@ do { \ assert((in) != NULL); \ assert((out) != NULL); \ + assert((in) != (out)); \ assert(width > 0); \ assert(height > 0); \ assert(stride >= width); \ - assert(row >= 0 && num_rows > 0 && row + num_rows <= height); \ - (void)height; /* Silence unused warning. */ \ } while (0) #if !WEBP_NEON_OMIT_C_CODE -static WEBP_INLINE void PredictLine_C(const uint8_t* src, const uint8_t* pred, - uint8_t* dst, int length, int inverse) { +static WEBP_INLINE void PredictLine_C(const uint8_t* WEBP_RESTRICT src, + const uint8_t* WEBP_RESTRICT pred, + uint8_t* WEBP_RESTRICT dst, int length) { int i; - if (inverse) { - for (i = 0; i < length; ++i) dst[i] = (uint8_t)(src[i] + pred[i]); - } else { - for (i = 0; i < length; ++i) dst[i] = (uint8_t)(src[i] - pred[i]); - } + for (i = 0; i < length; ++i) dst[i] = (uint8_t)(src[i] - pred[i]); } //------------------------------------------------------------------------------ // Horizontal filter. -static WEBP_INLINE void DoHorizontalFilter_C(const uint8_t* in, +static WEBP_INLINE void DoHorizontalFilter_C(const uint8_t* WEBP_RESTRICT in, int width, int height, int stride, - int row, int num_rows, - int inverse, uint8_t* out) { - const uint8_t* preds; - const size_t start_offset = row * stride; - const int last_row = row + num_rows; + uint8_t* WEBP_RESTRICT out) { + const uint8_t* preds = in; + int row; DCHECK(in, out); - in += start_offset; - out += start_offset; - preds = inverse ? out : in; - - if (row == 0) { - // Leftmost pixel is the same as input for topmost scanline. - out[0] = in[0]; - PredictLine_C(in + 1, preds, out + 1, width - 1, inverse); - row = 1; - preds += stride; - in += stride; - out += stride; - } + + // Leftmost pixel is the same as input for topmost scanline. + out[0] = in[0]; + PredictLine_C(in + 1, preds, out + 1, width - 1); + preds += stride; + in += stride; + out += stride; // Filter line-by-line. - while (row < last_row) { + for (row = 1; row < height; ++row) { // Leftmost pixel is predicted from above. - PredictLine_C(in, preds - stride, out, 1, inverse); - PredictLine_C(in + 1, preds, out + 1, width - 1, inverse); - ++row; + PredictLine_C(in, preds - stride, out, 1); + PredictLine_C(in + 1, preds, out + 1, width - 1); preds += stride; in += stride; out += stride; @@ -81,35 +71,23 @@ static WEBP_INLINE void DoHorizontalFilter_C(const uint8_t* in, //------------------------------------------------------------------------------ // Vertical filter. -static WEBP_INLINE void DoVerticalFilter_C(const uint8_t* in, +static WEBP_INLINE void DoVerticalFilter_C(const uint8_t* WEBP_RESTRICT in, int width, int height, int stride, - int row, int num_rows, - int inverse, uint8_t* out) { - const uint8_t* preds; - const size_t start_offset = row * stride; - const int last_row = row + num_rows; + uint8_t* WEBP_RESTRICT out) { + const uint8_t* preds = in; + int row; DCHECK(in, out); - in += start_offset; - out += start_offset; - preds = inverse ? out : in; - - if (row == 0) { - // Very first top-left pixel is copied. - out[0] = in[0]; - // Rest of top scan-line is left-predicted. - PredictLine_C(in + 1, preds, out + 1, width - 1, inverse); - row = 1; - in += stride; - out += stride; - } else { - // We are starting from in-between. Make sure 'preds' points to prev row. - preds -= stride; - } + + // Very first top-left pixel is copied. + out[0] = in[0]; + // Rest of top scan-line is left-predicted. + PredictLine_C(in + 1, preds, out + 1, width - 1); + in += stride; + out += stride; // Filter line-by-line. - while (row < last_row) { - PredictLine_C(in, preds, out, width, inverse); - ++row; + for (row = 1; row < height; ++row) { + PredictLine_C(in, preds, out, width); preds += stride; in += stride; out += stride; @@ -126,40 +104,31 @@ static WEBP_INLINE int GradientPredictor_C(uint8_t a, uint8_t b, uint8_t c) { } #if !WEBP_NEON_OMIT_C_CODE -static WEBP_INLINE void DoGradientFilter_C(const uint8_t* in, +static WEBP_INLINE void DoGradientFilter_C(const uint8_t* WEBP_RESTRICT in, int width, int height, int stride, - int row, int num_rows, - int inverse, uint8_t* out) { - const uint8_t* preds; - const size_t start_offset = row * stride; - const int last_row = row + num_rows; + uint8_t* WEBP_RESTRICT out) { + const uint8_t* preds = in; + int row; DCHECK(in, out); - in += start_offset; - out += start_offset; - preds = inverse ? out : in; // left prediction for top scan-line - if (row == 0) { - out[0] = in[0]; - PredictLine_C(in + 1, preds, out + 1, width - 1, inverse); - row = 1; - preds += stride; - in += stride; - out += stride; - } + out[0] = in[0]; + PredictLine_C(in + 1, preds, out + 1, width - 1); + preds += stride; + in += stride; + out += stride; // Filter line-by-line. - while (row < last_row) { + for (row = 1; row < height; ++row) { int w; // leftmost pixel: predict from above. - PredictLine_C(in, preds - stride, out, 1, inverse); + PredictLine_C(in, preds - stride, out, 1); for (w = 1; w < width; ++w) { const int pred = GradientPredictor_C(preds[w - 1], preds[w - stride], preds[w - stride - 1]); - out[w] = (uint8_t)(in[w] + (inverse ? pred : -pred)); + out[w] = (uint8_t)(in[w] - pred); } - ++row; preds += stride; in += stride; out += stride; @@ -172,20 +141,22 @@ static WEBP_INLINE void DoGradientFilter_C(const uint8_t* in, //------------------------------------------------------------------------------ #if !WEBP_NEON_OMIT_C_CODE -static void HorizontalFilter_C(const uint8_t* data, int width, int height, - int stride, uint8_t* filtered_data) { - DoHorizontalFilter_C(data, width, height, stride, 0, height, 0, - filtered_data); +static void HorizontalFilter_C(const uint8_t* WEBP_RESTRICT data, + int width, int height, int stride, + uint8_t* WEBP_RESTRICT filtered_data) { + DoHorizontalFilter_C(data, width, height, stride, filtered_data); } -static void VerticalFilter_C(const uint8_t* data, int width, int height, - int stride, uint8_t* filtered_data) { - DoVerticalFilter_C(data, width, height, stride, 0, height, 0, filtered_data); +static void VerticalFilter_C(const uint8_t* WEBP_RESTRICT data, + int width, int height, int stride, + uint8_t* WEBP_RESTRICT filtered_data) { + DoVerticalFilter_C(data, width, height, stride, filtered_data); } -static void GradientFilter_C(const uint8_t* data, int width, int height, - int stride, uint8_t* filtered_data) { - DoGradientFilter_C(data, width, height, stride, 0, height, 0, filtered_data); +static void GradientFilter_C(const uint8_t* WEBP_RESTRICT data, + int width, int height, int stride, + uint8_t* WEBP_RESTRICT filtered_data) { + DoGradientFilter_C(data, width, height, stride, filtered_data); } #endif // !WEBP_NEON_OMIT_C_CODE diff --git a/libwebp/src/dsp/filters_mips_dsp_r2.c b/libwebp/src/dsp/filters_mips_dsp_r2.c index eca866f5..c62bb872 100644 --- a/libwebp/src/dsp/filters_mips_dsp_r2.c +++ b/libwebp/src/dsp/filters_mips_dsp_r2.c @@ -26,13 +26,12 @@ #define DCHECK(in, out) \ do { \ - assert(in != NULL); \ - assert(out != NULL); \ + assert((in) != NULL); \ + assert((out) != NULL); \ + assert((in) != (out)); \ assert(width > 0); \ assert(height > 0); \ assert(stride >= width); \ - assert(row >= 0 && num_rows > 0 && row + num_rows <= height); \ - (void)height; /* Silence unused warning. */ \ } while (0) #define DO_PREDICT_LINE(SRC, DST, LENGTH, INVERSE) do { \ @@ -103,7 +102,8 @@ ); \ } while (0) -static WEBP_INLINE void PredictLine_MIPSdspR2(const uint8_t* src, uint8_t* dst, +static WEBP_INLINE void PredictLine_MIPSdspR2(const uint8_t* WEBP_RESTRICT src, + uint8_t* WEBP_RESTRICT dst, int length) { DO_PREDICT_LINE(src, dst, length, 0); } @@ -184,99 +184,75 @@ static WEBP_INLINE void PredictLine_MIPSdspR2(const uint8_t* src, uint8_t* dst, // Horizontal filter. #define FILTER_LINE_BY_LINE do { \ - while (row < last_row) { \ + for (row = 1; row < height; ++row) { \ PREDICT_LINE_ONE_PASS(in, preds - stride, out); \ DO_PREDICT_LINE(in + 1, out + 1, width - 1, 0); \ - ++row; \ preds += stride; \ in += stride; \ out += stride; \ } \ } while (0) -static WEBP_INLINE void DoHorizontalFilter_MIPSdspR2(const uint8_t* in, - int width, int height, - int stride, - int row, int num_rows, - uint8_t* out) { - const uint8_t* preds; - const size_t start_offset = row * stride; - const int last_row = row + num_rows; +static WEBP_INLINE void DoHorizontalFilter_MIPSdspR2( + const uint8_t* WEBP_RESTRICT in, int width, int height, int stride, + uint8_t* WEBP_RESTRICT out) { + const uint8_t* preds = in; + int row; DCHECK(in, out); - in += start_offset; - out += start_offset; - preds = in; - - if (row == 0) { - // Leftmost pixel is the same as input for topmost scanline. - out[0] = in[0]; - PredictLine_MIPSdspR2(in + 1, out + 1, width - 1); - row = 1; - preds += stride; - in += stride; - out += stride; - } + + // Leftmost pixel is the same as input for topmost scanline. + out[0] = in[0]; + PredictLine_MIPSdspR2(in + 1, out + 1, width - 1); + preds += stride; + in += stride; + out += stride; // Filter line-by-line. FILTER_LINE_BY_LINE; } #undef FILTER_LINE_BY_LINE -static void HorizontalFilter_MIPSdspR2(const uint8_t* data, - int width, int height, - int stride, uint8_t* filtered_data) { - DoHorizontalFilter_MIPSdspR2(data, width, height, stride, 0, height, - filtered_data); +static void HorizontalFilter_MIPSdspR2(const uint8_t* WEBP_RESTRICT data, + int width, int height, int stride, + uint8_t* WEBP_RESTRICT filtered_data) { + DoHorizontalFilter_MIPSdspR2(data, width, height, stride, filtered_data); } //------------------------------------------------------------------------------ // Vertical filter. #define FILTER_LINE_BY_LINE do { \ - while (row < last_row) { \ + for (row = 1; row < height; ++row) { \ DO_PREDICT_LINE_VERTICAL(in, preds, out, width, 0); \ - ++row; \ preds += stride; \ in += stride; \ out += stride; \ } \ } while (0) -static WEBP_INLINE void DoVerticalFilter_MIPSdspR2(const uint8_t* in, - int width, int height, - int stride, - int row, int num_rows, - uint8_t* out) { - const uint8_t* preds; - const size_t start_offset = row * stride; - const int last_row = row + num_rows; +static WEBP_INLINE void DoVerticalFilter_MIPSdspR2( + const uint8_t* WEBP_RESTRICT in, int width, int height, int stride, + uint8_t* WEBP_RESTRICT out) { + const uint8_t* preds = in; + int row; DCHECK(in, out); - in += start_offset; - out += start_offset; - preds = in; - - if (row == 0) { - // Very first top-left pixel is copied. - out[0] = in[0]; - // Rest of top scan-line is left-predicted. - PredictLine_MIPSdspR2(in + 1, out + 1, width - 1); - row = 1; - in += stride; - out += stride; - } else { - // We are starting from in-between. Make sure 'preds' points to prev row. - preds -= stride; - } + + // Very first top-left pixel is copied. + out[0] = in[0]; + // Rest of top scan-line is left-predicted. + PredictLine_MIPSdspR2(in + 1, out + 1, width - 1); + in += stride; + out += stride; // Filter line-by-line. FILTER_LINE_BY_LINE; } #undef FILTER_LINE_BY_LINE -static void VerticalFilter_MIPSdspR2(const uint8_t* data, int width, int height, - int stride, uint8_t* filtered_data) { - DoVerticalFilter_MIPSdspR2(data, width, height, stride, 0, height, - filtered_data); +static void VerticalFilter_MIPSdspR2(const uint8_t* WEBP_RESTRICT data, + int width, int height, int stride, + uint8_t* WEBP_RESTRICT filtered_data) { + DoVerticalFilter_MIPSdspR2(data, width, height, stride, filtered_data); } //------------------------------------------------------------------------------ @@ -297,7 +273,7 @@ static int GradientPredictor_MIPSdspR2(uint8_t a, uint8_t b, uint8_t c) { } #define FILTER_LINE_BY_LINE(PREDS, OPERATION) do { \ - while (row < last_row) { \ + for (row = 1; row < height; ++row) { \ int w; \ PREDICT_LINE_ONE_PASS(in, PREDS - stride, out); \ for (w = 1; w < width; ++w) { \ @@ -306,42 +282,34 @@ static int GradientPredictor_MIPSdspR2(uint8_t a, uint8_t b, uint8_t c) { PREDS[w - stride - 1]); \ out[w] = in[w] OPERATION pred; \ } \ - ++row; \ in += stride; \ out += stride; \ } \ } while (0) -static void DoGradientFilter_MIPSdspR2(const uint8_t* in, +static void DoGradientFilter_MIPSdspR2(const uint8_t* WEBP_RESTRICT in, int width, int height, int stride, - int row, int num_rows, uint8_t* out) { - const uint8_t* preds; - const size_t start_offset = row * stride; - const int last_row = row + num_rows; + uint8_t* WEBP_RESTRICT out) { + const uint8_t* preds = in; + int row; DCHECK(in, out); - in += start_offset; - out += start_offset; - preds = in; // left prediction for top scan-line - if (row == 0) { - out[0] = in[0]; - PredictLine_MIPSdspR2(in + 1, out + 1, width - 1); - row = 1; - preds += stride; - in += stride; - out += stride; - } + out[0] = in[0]; + PredictLine_MIPSdspR2(in + 1, out + 1, width - 1); + preds += stride; + in += stride; + out += stride; // Filter line-by-line. FILTER_LINE_BY_LINE(in, -); } #undef FILTER_LINE_BY_LINE -static void GradientFilter_MIPSdspR2(const uint8_t* data, int width, int height, - int stride, uint8_t* filtered_data) { - DoGradientFilter_MIPSdspR2(data, width, height, stride, 0, height, - filtered_data); +static void GradientFilter_MIPSdspR2(const uint8_t* WEBP_RESTRICT data, + int width, int height, int stride, + uint8_t* WEBP_RESTRICT filtered_data) { + DoGradientFilter_MIPSdspR2(data, width, height, stride, filtered_data); } //------------------------------------------------------------------------------ diff --git a/libwebp/src/dsp/filters_msa.c b/libwebp/src/dsp/filters_msa.c index 33a1b20b..ae3d3699 100644 --- a/libwebp/src/dsp/filters_msa.c +++ b/libwebp/src/dsp/filters_msa.c @@ -21,7 +21,8 @@ static WEBP_INLINE void PredictLineInverse0(const uint8_t* src, const uint8_t* pred, - uint8_t* dst, int length) { + uint8_t* WEBP_RESTRICT dst, + int length) { v16u8 src0, pred0, dst0; assert(length >= 0); while (length >= 32) { @@ -58,8 +59,9 @@ static WEBP_INLINE void PredictLineInverse0(const uint8_t* src, #define DCHECK(in, out) \ do { \ - assert(in != NULL); \ - assert(out != NULL); \ + assert((in) != NULL); \ + assert((out) != NULL); \ + assert((in) != (out)); \ assert(width > 0); \ assert(height > 0); \ assert(stride >= width); \ @@ -68,8 +70,9 @@ static WEBP_INLINE void PredictLineInverse0(const uint8_t* src, //------------------------------------------------------------------------------ // Horrizontal filter -static void HorizontalFilter_MSA(const uint8_t* data, int width, int height, - int stride, uint8_t* filtered_data) { +static void HorizontalFilter_MSA(const uint8_t* WEBP_RESTRICT data, + int width, int height, int stride, + uint8_t* WEBP_RESTRICT filtered_data) { const uint8_t* preds = data; const uint8_t* in = data; uint8_t* out = filtered_data; @@ -99,8 +102,8 @@ static void HorizontalFilter_MSA(const uint8_t* data, int width, int height, static WEBP_INLINE void PredictLineGradient(const uint8_t* pinput, const uint8_t* ppred, - uint8_t* poutput, int stride, - int size) { + uint8_t* WEBP_RESTRICT poutput, + int stride, int size) { int w; const v16i8 zero = { 0 }; while (size >= 16) { @@ -131,8 +134,9 @@ static WEBP_INLINE void PredictLineGradient(const uint8_t* pinput, } -static void GradientFilter_MSA(const uint8_t* data, int width, int height, - int stride, uint8_t* filtered_data) { +static void GradientFilter_MSA(const uint8_t* WEBP_RESTRICT data, + int width, int height, int stride, + uint8_t* WEBP_RESTRICT filtered_data) { const uint8_t* in = data; const uint8_t* preds = data; uint8_t* out = filtered_data; @@ -159,8 +163,9 @@ static void GradientFilter_MSA(const uint8_t* data, int width, int height, //------------------------------------------------------------------------------ // Vertical filter -static void VerticalFilter_MSA(const uint8_t* data, int width, int height, - int stride, uint8_t* filtered_data) { +static void VerticalFilter_MSA(const uint8_t* WEBP_RESTRICT data, + int width, int height, int stride, + uint8_t* WEBP_RESTRICT filtered_data) { const uint8_t* in = data; const uint8_t* preds = data; uint8_t* out = filtered_data; diff --git a/libwebp/src/dsp/filters_neon.c b/libwebp/src/dsp/filters_neon.c index b49e515a..4df10172 100644 --- a/libwebp/src/dsp/filters_neon.c +++ b/libwebp/src/dsp/filters_neon.c @@ -23,13 +23,12 @@ #define DCHECK(in, out) \ do { \ - assert(in != NULL); \ - assert(out != NULL); \ + assert((in) != NULL); \ + assert((out) != NULL); \ + assert((in) != (out)); \ assert(width > 0); \ assert(height > 0); \ assert(stride >= width); \ - assert(row >= 0 && num_rows > 0 && row + num_rows <= height); \ - (void)height; /* Silence unused warning. */ \ } while (0) // load eight u8 and widen to s16 @@ -46,7 +45,7 @@ #define ROTATE_RIGHT_N(A, N) vext_u8((A), (A), (8 - (N)) % 8) static void PredictLine_NEON(const uint8_t* src, const uint8_t* pred, - uint8_t* dst, int length) { + uint8_t* WEBP_RESTRICT dst, int length) { int i; assert(length >= 0); for (i = 0; i + 16 <= length; i += 16) { @@ -59,86 +58,70 @@ static void PredictLine_NEON(const uint8_t* src, const uint8_t* pred, } // Special case for left-based prediction (when preds==dst-1 or preds==src-1). -static void PredictLineLeft_NEON(const uint8_t* src, uint8_t* dst, int length) { +static void PredictLineLeft_NEON(const uint8_t* WEBP_RESTRICT src, + uint8_t* WEBP_RESTRICT dst, int length) { PredictLine_NEON(src, src - 1, dst, length); } //------------------------------------------------------------------------------ // Horizontal filter. -static WEBP_INLINE void DoHorizontalFilter_NEON(const uint8_t* in, - int width, int height, - int stride, - int row, int num_rows, - uint8_t* out) { - const size_t start_offset = row * stride; - const int last_row = row + num_rows; +static WEBP_INLINE void DoHorizontalFilter_NEON( + const uint8_t* WEBP_RESTRICT in, int width, int height, int stride, + uint8_t* WEBP_RESTRICT out) { + int row; DCHECK(in, out); - in += start_offset; - out += start_offset; - if (row == 0) { - // Leftmost pixel is the same as input for topmost scanline. - out[0] = in[0]; - PredictLineLeft_NEON(in + 1, out + 1, width - 1); - row = 1; - in += stride; - out += stride; - } + // Leftmost pixel is the same as input for topmost scanline. + out[0] = in[0]; + PredictLineLeft_NEON(in + 1, out + 1, width - 1); + in += stride; + out += stride; // Filter line-by-line. - while (row < last_row) { + for (row = 1; row < height; ++row) { // Leftmost pixel is predicted from above. out[0] = in[0] - in[-stride]; PredictLineLeft_NEON(in + 1, out + 1, width - 1); - ++row; in += stride; out += stride; } } -static void HorizontalFilter_NEON(const uint8_t* data, int width, int height, - int stride, uint8_t* filtered_data) { - DoHorizontalFilter_NEON(data, width, height, stride, 0, height, - filtered_data); +static void HorizontalFilter_NEON(const uint8_t* WEBP_RESTRICT data, + int width, int height, int stride, + uint8_t* WEBP_RESTRICT filtered_data) { + DoHorizontalFilter_NEON(data, width, height, stride, filtered_data); } //------------------------------------------------------------------------------ // Vertical filter. -static WEBP_INLINE void DoVerticalFilter_NEON(const uint8_t* in, +static WEBP_INLINE void DoVerticalFilter_NEON(const uint8_t* WEBP_RESTRICT in, int width, int height, int stride, - int row, int num_rows, - uint8_t* out) { - const size_t start_offset = row * stride; - const int last_row = row + num_rows; + uint8_t* WEBP_RESTRICT out) { + int row; DCHECK(in, out); - in += start_offset; - out += start_offset; - if (row == 0) { - // Very first top-left pixel is copied. - out[0] = in[0]; - // Rest of top scan-line is left-predicted. - PredictLineLeft_NEON(in + 1, out + 1, width - 1); - row = 1; - in += stride; - out += stride; - } + // Very first top-left pixel is copied. + out[0] = in[0]; + // Rest of top scan-line is left-predicted. + PredictLineLeft_NEON(in + 1, out + 1, width - 1); + in += stride; + out += stride; // Filter line-by-line. - while (row < last_row) { + for (row = 1; row < height; ++row) { PredictLine_NEON(in, in - stride, out, width); - ++row; in += stride; out += stride; } } -static void VerticalFilter_NEON(const uint8_t* data, int width, int height, - int stride, uint8_t* filtered_data) { - DoVerticalFilter_NEON(data, width, height, stride, 0, height, - filtered_data); +static void VerticalFilter_NEON(const uint8_t* WEBP_RESTRICT data, + int width, int height, int stride, + uint8_t* WEBP_RESTRICT filtered_data) { + DoVerticalFilter_NEON(data, width, height, stride, filtered_data); } //------------------------------------------------------------------------------ @@ -151,7 +134,8 @@ static WEBP_INLINE int GradientPredictor_C(uint8_t a, uint8_t b, uint8_t c) { static void GradientPredictDirect_NEON(const uint8_t* const row, const uint8_t* const top, - uint8_t* const out, int length) { + uint8_t* WEBP_RESTRICT const out, + int length) { int i; for (i = 0; i + 8 <= length; i += 8) { const uint8x8_t A = vld1_u8(&row[i - 1]); @@ -167,40 +151,31 @@ static void GradientPredictDirect_NEON(const uint8_t* const row, } } -static WEBP_INLINE void DoGradientFilter_NEON(const uint8_t* in, - int width, int height, - int stride, - int row, int num_rows, - uint8_t* out) { - const size_t start_offset = row * stride; - const int last_row = row + num_rows; +static WEBP_INLINE void DoGradientFilter_NEON(const uint8_t* WEBP_RESTRICT in, + int width, int height, int stride, + uint8_t* WEBP_RESTRICT out) { + int row; DCHECK(in, out); - in += start_offset; - out += start_offset; // left prediction for top scan-line - if (row == 0) { - out[0] = in[0]; - PredictLineLeft_NEON(in + 1, out + 1, width - 1); - row = 1; - in += stride; - out += stride; - } + out[0] = in[0]; + PredictLineLeft_NEON(in + 1, out + 1, width - 1); + in += stride; + out += stride; // Filter line-by-line. - while (row < last_row) { + for (row = 1; row < height; ++row) { out[0] = in[0] - in[-stride]; GradientPredictDirect_NEON(in + 1, in + 1 - stride, out + 1, width - 1); - ++row; in += stride; out += stride; } } -static void GradientFilter_NEON(const uint8_t* data, int width, int height, - int stride, uint8_t* filtered_data) { - DoGradientFilter_NEON(data, width, height, stride, 0, height, - filtered_data); +static void GradientFilter_NEON(const uint8_t* WEBP_RESTRICT data, + int width, int height, int stride, + uint8_t* WEBP_RESTRICT filtered_data) { + DoGradientFilter_NEON(data, width, height, stride, filtered_data); } #undef DCHECK diff --git a/libwebp/src/dsp/filters_sse2.c b/libwebp/src/dsp/filters_sse2.c index bb4b5d58..b9a7aefd 100644 --- a/libwebp/src/dsp/filters_sse2.c +++ b/libwebp/src/dsp/filters_sse2.c @@ -20,6 +20,9 @@ #include #include +#include "src/dsp/cpu.h" +#include "src/webp/types.h" + //------------------------------------------------------------------------------ // Helpful macro. @@ -27,15 +30,15 @@ do { \ assert((in) != NULL); \ assert((out) != NULL); \ + assert((in) != (out)); \ assert(width > 0); \ assert(height > 0); \ assert(stride >= width); \ - assert(row >= 0 && num_rows > 0 && row + num_rows <= height); \ - (void)height; /* Silence unused warning. */ \ } while (0) -static void PredictLineTop_SSE2(const uint8_t* src, const uint8_t* pred, - uint8_t* dst, int length) { +static void PredictLineTop_SSE2(const uint8_t* WEBP_RESTRICT src, + const uint8_t* WEBP_RESTRICT pred, + uint8_t* WEBP_RESTRICT dst, int length) { int i; const int max_pos = length & ~31; assert(length >= 0); @@ -53,7 +56,8 @@ static void PredictLineTop_SSE2(const uint8_t* src, const uint8_t* pred, } // Special case for left-based prediction (when preds==dst-1 or preds==src-1). -static void PredictLineLeft_SSE2(const uint8_t* src, uint8_t* dst, int length) { +static void PredictLineLeft_SSE2(const uint8_t* WEBP_RESTRICT src, + uint8_t* WEBP_RESTRICT dst, int length) { int i; const int max_pos = length & ~31; assert(length >= 0); @@ -73,32 +77,23 @@ static void PredictLineLeft_SSE2(const uint8_t* src, uint8_t* dst, int length) { //------------------------------------------------------------------------------ // Horizontal filter. -static WEBP_INLINE void DoHorizontalFilter_SSE2(const uint8_t* in, - int width, int height, - int stride, - int row, int num_rows, - uint8_t* out) { - const size_t start_offset = row * stride; - const int last_row = row + num_rows; +static WEBP_INLINE void DoHorizontalFilter_SSE2( + const uint8_t* WEBP_RESTRICT in, int width, int height, int stride, + uint8_t* WEBP_RESTRICT out) { + int row; DCHECK(in, out); - in += start_offset; - out += start_offset; - if (row == 0) { - // Leftmost pixel is the same as input for topmost scanline. - out[0] = in[0]; - PredictLineLeft_SSE2(in + 1, out + 1, width - 1); - row = 1; - in += stride; - out += stride; - } + // Leftmost pixel is the same as input for topmost scanline. + out[0] = in[0]; + PredictLineLeft_SSE2(in + 1, out + 1, width - 1); + in += stride; + out += stride; // Filter line-by-line. - while (row < last_row) { + for (row = 1; row < height; ++row) { // Leftmost pixel is predicted from above. out[0] = in[0] - in[-stride]; PredictLineLeft_SSE2(in + 1, out + 1, width - 1); - ++row; in += stride; out += stride; } @@ -107,30 +102,22 @@ static WEBP_INLINE void DoHorizontalFilter_SSE2(const uint8_t* in, //------------------------------------------------------------------------------ // Vertical filter. -static WEBP_INLINE void DoVerticalFilter_SSE2(const uint8_t* in, +static WEBP_INLINE void DoVerticalFilter_SSE2(const uint8_t* WEBP_RESTRICT in, int width, int height, int stride, - int row, int num_rows, - uint8_t* out) { - const size_t start_offset = row * stride; - const int last_row = row + num_rows; + uint8_t* WEBP_RESTRICT out) { + int row; DCHECK(in, out); - in += start_offset; - out += start_offset; - if (row == 0) { - // Very first top-left pixel is copied. - out[0] = in[0]; - // Rest of top scan-line is left-predicted. - PredictLineLeft_SSE2(in + 1, out + 1, width - 1); - row = 1; - in += stride; - out += stride; - } + // Very first top-left pixel is copied. + out[0] = in[0]; + // Rest of top scan-line is left-predicted. + PredictLineLeft_SSE2(in + 1, out + 1, width - 1); + in += stride; + out += stride; // Filter line-by-line. - while (row < last_row) { + for (row = 1; row < height; ++row) { PredictLineTop_SSE2(in, in - stride, out, width); - ++row; in += stride; out += stride; } @@ -146,7 +133,8 @@ static WEBP_INLINE int GradientPredictor_SSE2(uint8_t a, uint8_t b, uint8_t c) { static void GradientPredictDirect_SSE2(const uint8_t* const row, const uint8_t* const top, - uint8_t* const out, int length) { + uint8_t* WEBP_RESTRICT const out, + int length) { const int max_pos = length & ~7; int i; const __m128i zero = _mm_setzero_si128(); @@ -170,30 +158,22 @@ static void GradientPredictDirect_SSE2(const uint8_t* const row, } } -static WEBP_INLINE void DoGradientFilter_SSE2(const uint8_t* in, +static WEBP_INLINE void DoGradientFilter_SSE2(const uint8_t* WEBP_RESTRICT in, int width, int height, int stride, - int row, int num_rows, - uint8_t* out) { - const size_t start_offset = row * stride; - const int last_row = row + num_rows; + uint8_t* WEBP_RESTRICT out) { + int row; DCHECK(in, out); - in += start_offset; - out += start_offset; // left prediction for top scan-line - if (row == 0) { - out[0] = in[0]; - PredictLineLeft_SSE2(in + 1, out + 1, width - 1); - row = 1; - in += stride; - out += stride; - } + out[0] = in[0]; + PredictLineLeft_SSE2(in + 1, out + 1, width - 1); + in += stride; + out += stride; // Filter line-by-line. - while (row < last_row) { + for (row = 1; row < height; ++row) { out[0] = (uint8_t)(in[0] - in[-stride]); GradientPredictDirect_SSE2(in + 1, in + 1 - stride, out + 1, width - 1); - ++row; in += stride; out += stride; } @@ -203,20 +183,22 @@ static WEBP_INLINE void DoGradientFilter_SSE2(const uint8_t* in, //------------------------------------------------------------------------------ -static void HorizontalFilter_SSE2(const uint8_t* data, int width, int height, - int stride, uint8_t* filtered_data) { - DoHorizontalFilter_SSE2(data, width, height, stride, 0, height, - filtered_data); +static void HorizontalFilter_SSE2(const uint8_t* WEBP_RESTRICT data, + int width, int height, int stride, + uint8_t* WEBP_RESTRICT filtered_data) { + DoHorizontalFilter_SSE2(data, width, height, stride, filtered_data); } -static void VerticalFilter_SSE2(const uint8_t* data, int width, int height, - int stride, uint8_t* filtered_data) { - DoVerticalFilter_SSE2(data, width, height, stride, 0, height, filtered_data); +static void VerticalFilter_SSE2(const uint8_t* WEBP_RESTRICT data, + int width, int height, int stride, + uint8_t* WEBP_RESTRICT filtered_data) { + DoVerticalFilter_SSE2(data, width, height, stride, filtered_data); } -static void GradientFilter_SSE2(const uint8_t* data, int width, int height, - int stride, uint8_t* filtered_data) { - DoGradientFilter_SSE2(data, width, height, stride, 0, height, filtered_data); +static void GradientFilter_SSE2(const uint8_t* WEBP_RESTRICT data, + int width, int height, int stride, + uint8_t* WEBP_RESTRICT filtered_data) { + DoGradientFilter_SSE2(data, width, height, stride, filtered_data); } //------------------------------------------------------------------------------ diff --git a/libwebp/src/dsp/lossless.c b/libwebp/src/dsp/lossless.c index 9f812094..1a3d800c 100644 --- a/libwebp/src/dsp/lossless.c +++ b/libwebp/src/dsp/lossless.c @@ -13,15 +13,21 @@ // Jyrki Alakuijala (jyrki@google.com) // Urvang Joshi (urvang@google.com) -#include "src/dsp/dsp.h" +#include "src/dsp/lossless.h" #include -#include #include +#include + #include "src/dec/vp8li_dec.h" -#include "src/utils/endian_inl_utils.h" -#include "src/dsp/lossless.h" +#include "src/dsp/cpu.h" +#include "src/dsp/dsp.h" #include "src/dsp/lossless_common.h" +#include "src/utils/endian_inl_utils.h" +#include "src/utils/utils.h" +#include "src/webp/decode.h" +#include "src/webp/format_constants.h" +#include "src/webp/types.h" //------------------------------------------------------------------------------ // Image transforms. @@ -107,14 +113,14 @@ static WEBP_INLINE uint32_t Select(uint32_t a, uint32_t b, uint32_t c) { //------------------------------------------------------------------------------ // Predictors -uint32_t VP8LPredictor0_C(const uint32_t* const left, - const uint32_t* const top) { +static uint32_t VP8LPredictor0_C(const uint32_t* const left, + const uint32_t* const top) { (void)top; (void)left; return ARGB_BLACK; } -uint32_t VP8LPredictor1_C(const uint32_t* const left, - const uint32_t* const top) { +static uint32_t VP8LPredictor1_C(const uint32_t* const left, + const uint32_t* const top) { (void)top; return *left; } @@ -182,13 +188,13 @@ uint32_t VP8LPredictor13_C(const uint32_t* const left, } static void PredictorAdd0_C(const uint32_t* in, const uint32_t* upper, - int num_pixels, uint32_t* out) { + int num_pixels, uint32_t* WEBP_RESTRICT out) { int x; (void)upper; for (x = 0; x < num_pixels; ++x) out[x] = VP8LAddPixels(in[x], ARGB_BLACK); } static void PredictorAdd1_C(const uint32_t* in, const uint32_t* upper, - int num_pixels, uint32_t* out) { + int num_pixels, uint32_t* WEBP_RESTRICT out) { int i; uint32_t left = out[-1]; (void)upper; @@ -215,7 +221,7 @@ GENERATE_PREDICTOR_ADD(VP8LPredictor13_C, PredictorAdd13_C) static void PredictorInverseTransform_C(const VP8LTransform* const transform, int y_start, int y_end, const uint32_t* in, uint32_t* out) { - const int width = transform->xsize_; + const int width = transform->xsize; if (y_start == 0) { // First Row follows the L (mode=1) mode. PredictorAdd0_C(in, NULL, 1, out); PredictorAdd1_C(in + 1, NULL, width - 1, out + 1); @@ -226,11 +232,11 @@ static void PredictorInverseTransform_C(const VP8LTransform* const transform, { int y = y_start; - const int tile_width = 1 << transform->bits_; + const int tile_width = 1 << transform->bits; const int mask = tile_width - 1; - const int tiles_per_row = VP8LSubSampleSize(width, transform->bits_); + const int tiles_per_row = VP8LSubSampleSize(width, transform->bits); const uint32_t* pred_mode_base = - transform->data_ + (y >> transform->bits_) * tiles_per_row; + transform->data + (y >> transform->bits) * tiles_per_row; while (y < y_end) { const uint32_t* pred_mode_src = pred_mode_base; @@ -278,9 +284,9 @@ static WEBP_INLINE int ColorTransformDelta(int8_t color_pred, static WEBP_INLINE void ColorCodeToMultipliers(uint32_t color_code, VP8LMultipliers* const m) { - m->green_to_red_ = (color_code >> 0) & 0xff; - m->green_to_blue_ = (color_code >> 8) & 0xff; - m->red_to_blue_ = (color_code >> 16) & 0xff; + m->green_to_red = (color_code >> 0) & 0xff; + m->green_to_blue = (color_code >> 8) & 0xff; + m->red_to_blue = (color_code >> 16) & 0xff; } void VP8LTransformColorInverse_C(const VP8LMultipliers* const m, @@ -293,10 +299,10 @@ void VP8LTransformColorInverse_C(const VP8LMultipliers* const m, const uint32_t red = argb >> 16; int new_red = red & 0xff; int new_blue = argb & 0xff; - new_red += ColorTransformDelta((int8_t)m->green_to_red_, green); + new_red += ColorTransformDelta((int8_t)m->green_to_red, green); new_red &= 0xff; - new_blue += ColorTransformDelta((int8_t)m->green_to_blue_, green); - new_blue += ColorTransformDelta((int8_t)m->red_to_blue_, (int8_t)new_red); + new_blue += ColorTransformDelta((int8_t)m->green_to_blue, green); + new_blue += ColorTransformDelta((int8_t)m->red_to_blue, (int8_t)new_red); new_blue &= 0xff; dst[i] = (argb & 0xff00ff00u) | (new_red << 16) | (new_blue); } @@ -306,15 +312,15 @@ void VP8LTransformColorInverse_C(const VP8LMultipliers* const m, static void ColorSpaceInverseTransform_C(const VP8LTransform* const transform, int y_start, int y_end, const uint32_t* src, uint32_t* dst) { - const int width = transform->xsize_; - const int tile_width = 1 << transform->bits_; + const int width = transform->xsize; + const int tile_width = 1 << transform->bits; const int mask = tile_width - 1; const int safe_width = width & ~mask; const int remaining_width = width - safe_width; - const int tiles_per_row = VP8LSubSampleSize(width, transform->bits_); + const int tiles_per_row = VP8LSubSampleSize(width, transform->bits); int y = y_start; const uint32_t* pred_row = - transform->data_ + (y >> transform->bits_) * tiles_per_row; + transform->data + (y >> transform->bits) * tiles_per_row; while (y < y_end) { const uint32_t* pred = pred_row; @@ -356,11 +362,11 @@ STATIC_DECL void FUNC_NAME(const VP8LTransform* const transform, \ int y_start, int y_end, const TYPE* src, \ TYPE* dst) { \ int y; \ - const int bits_per_pixel = 8 >> transform->bits_; \ - const int width = transform->xsize_; \ - const uint32_t* const color_map = transform->data_; \ + const int bits_per_pixel = 8 >> transform->bits; \ + const int width = transform->xsize; \ + const uint32_t* const color_map = transform->data; \ if (bits_per_pixel < 8) { \ - const int pixels_per_byte = 1 << transform->bits_; \ + const int pixels_per_byte = 1 << transform->bits; \ const int count_mask = pixels_per_byte - 1; \ const uint32_t bit_mask = (1 << bits_per_pixel) - 1; \ for (y = y_start; y < y_end; ++y) { \ @@ -391,16 +397,16 @@ COLOR_INDEX_INVERSE(VP8LColorIndexInverseTransformAlpha, MapAlpha_C, , void VP8LInverseTransform(const VP8LTransform* const transform, int row_start, int row_end, const uint32_t* const in, uint32_t* const out) { - const int width = transform->xsize_; + const int width = transform->xsize; assert(row_start < row_end); - assert(row_end <= transform->ysize_); - switch (transform->type_) { + assert(row_end <= transform->ysize); + switch (transform->type) { case SUBTRACT_GREEN_TRANSFORM: VP8LAddGreenToBlueAndRed(in, (row_end - row_start) * width, out); break; case PREDICTOR_TRANSFORM: PredictorInverseTransform_C(transform, row_start, row_end, in, out); - if (row_end != transform->ysize_) { + if (row_end != transform->ysize) { // The last predicted row in this iteration will be the top-pred row // for the first row in next iteration. memcpy(out - width, out + (row_end - row_start - 1) * width, @@ -411,15 +417,15 @@ void VP8LInverseTransform(const VP8LTransform* const transform, ColorSpaceInverseTransform_C(transform, row_start, row_end, in, out); break; case COLOR_INDEXING_TRANSFORM: - if (in == out && transform->bits_ > 0) { + if (in == out && transform->bits > 0) { // Move packed pixels to the end of unpacked region, so that unpacking // can occur seamlessly. // Also, note that this is the only transform that applies on - // the effective width of VP8LSubSampleSize(xsize_, bits_). All other - // transforms work on effective width of xsize_. + // the effective width of VP8LSubSampleSize(xsize, bits). All other + // transforms work on effective width of 'xsize'. const int out_stride = (row_end - row_start) * width; const int in_stride = (row_end - row_start) * - VP8LSubSampleSize(transform->xsize_, transform->bits_); + VP8LSubSampleSize(transform->xsize, transform->bits); uint32_t* const src = out + out_stride - in_stride; memmove(src, out, in_stride * sizeof(*src)); ColorIndexInverseTransform_C(transform, row_start, row_end, src, out); @@ -441,8 +447,8 @@ static int is_big_endian(void) { return (tmp.b[0] != 1); } -void VP8LConvertBGRAToRGB_C(const uint32_t* src, - int num_pixels, uint8_t* dst) { +void VP8LConvertBGRAToRGB_C(const uint32_t* WEBP_RESTRICT src, + int num_pixels, uint8_t* WEBP_RESTRICT dst) { const uint32_t* const src_end = src + num_pixels; while (src < src_end) { const uint32_t argb = *src++; @@ -452,8 +458,8 @@ void VP8LConvertBGRAToRGB_C(const uint32_t* src, } } -void VP8LConvertBGRAToRGBA_C(const uint32_t* src, - int num_pixels, uint8_t* dst) { +void VP8LConvertBGRAToRGBA_C(const uint32_t* WEBP_RESTRICT src, + int num_pixels, uint8_t* WEBP_RESTRICT dst) { const uint32_t* const src_end = src + num_pixels; while (src < src_end) { const uint32_t argb = *src++; @@ -464,8 +470,8 @@ void VP8LConvertBGRAToRGBA_C(const uint32_t* src, } } -void VP8LConvertBGRAToRGBA4444_C(const uint32_t* src, - int num_pixels, uint8_t* dst) { +void VP8LConvertBGRAToRGBA4444_C(const uint32_t* WEBP_RESTRICT src, + int num_pixels, uint8_t* WEBP_RESTRICT dst) { const uint32_t* const src_end = src + num_pixels; while (src < src_end) { const uint32_t argb = *src++; @@ -481,8 +487,8 @@ void VP8LConvertBGRAToRGBA4444_C(const uint32_t* src, } } -void VP8LConvertBGRAToRGB565_C(const uint32_t* src, - int num_pixels, uint8_t* dst) { +void VP8LConvertBGRAToRGB565_C(const uint32_t* WEBP_RESTRICT src, + int num_pixels, uint8_t* WEBP_RESTRICT dst) { const uint32_t* const src_end = src + num_pixels; while (src < src_end) { const uint32_t argb = *src++; @@ -498,8 +504,8 @@ void VP8LConvertBGRAToRGB565_C(const uint32_t* src, } } -void VP8LConvertBGRAToBGR_C(const uint32_t* src, - int num_pixels, uint8_t* dst) { +void VP8LConvertBGRAToBGR_C(const uint32_t* WEBP_RESTRICT src, + int num_pixels, uint8_t* WEBP_RESTRICT dst) { const uint32_t* const src_end = src + num_pixels; while (src < src_end) { const uint32_t argb = *src++; @@ -509,8 +515,8 @@ void VP8LConvertBGRAToBGR_C(const uint32_t* src, } } -static void CopyOrSwap(const uint32_t* src, int num_pixels, uint8_t* dst, - int swap_on_big_endian) { +static void CopyOrSwap(const uint32_t* WEBP_RESTRICT src, int num_pixels, + uint8_t* WEBP_RESTRICT dst, int swap_on_big_endian) { if (is_big_endian() == swap_on_big_endian) { const uint32_t* const src_end = src + num_pixels; while (src < src_end) { @@ -571,16 +577,21 @@ void VP8LConvertFromBGRA(const uint32_t* const in_data, int num_pixels, //------------------------------------------------------------------------------ VP8LProcessDecBlueAndRedFunc VP8LAddGreenToBlueAndRed; +VP8LProcessDecBlueAndRedFunc VP8LAddGreenToBlueAndRed_SSE; VP8LPredictorAddSubFunc VP8LPredictorsAdd[16]; +VP8LPredictorAddSubFunc VP8LPredictorsAdd_SSE[16]; VP8LPredictorFunc VP8LPredictors[16]; // exposed plain-C implementations VP8LPredictorAddSubFunc VP8LPredictorsAdd_C[16]; VP8LTransformColorInverseFunc VP8LTransformColorInverse; +VP8LTransformColorInverseFunc VP8LTransformColorInverse_SSE; VP8LConvertFunc VP8LConvertBGRAToRGB; +VP8LConvertFunc VP8LConvertBGRAToRGB_SSE; VP8LConvertFunc VP8LConvertBGRAToRGBA; +VP8LConvertFunc VP8LConvertBGRAToRGBA_SSE; VP8LConvertFunc VP8LConvertBGRAToRGBA4444; VP8LConvertFunc VP8LConvertBGRAToRGB565; VP8LConvertFunc VP8LConvertBGRAToBGR; @@ -591,6 +602,7 @@ VP8LMapAlphaFunc VP8LMapColor8b; extern VP8CPUInfo VP8GetCPUInfo; extern void VP8LDspInitSSE2(void); extern void VP8LDspInitSSE41(void); +extern void VP8LDspInitAVX2(void); extern void VP8LDspInitNEON(void); extern void VP8LDspInitMIPSdspR2(void); extern void VP8LDspInitMSA(void); @@ -643,6 +655,11 @@ WEBP_DSP_INIT_FUNC(VP8LDspInit) { #if defined(WEBP_HAVE_SSE41) if (VP8GetCPUInfo(kSSE4_1)) { VP8LDspInitSSE41(); +#if defined(WEBP_HAVE_AVX2) + if (VP8GetCPUInfo(kAVX2)) { + VP8LDspInitAVX2(); + } +#endif } #endif } diff --git a/libwebp/src/dsp/lossless.h b/libwebp/src/dsp/lossless.h index 0bf10a1a..c66ec5da 100644 --- a/libwebp/src/dsp/lossless.h +++ b/libwebp/src/dsp/lossless.h @@ -15,12 +15,10 @@ #ifndef WEBP_DSP_LOSSLESS_H_ #define WEBP_DSP_LOSSLESS_H_ +#include "src/dsp/dsp.h" #include "src/webp/types.h" #include "src/webp/decode.h" -#include "src/enc/histogram_enc.h" -#include "src/utils/utils.h" - #ifdef __cplusplus extern "C" { #endif @@ -32,10 +30,6 @@ typedef uint32_t (*VP8LPredictorFunc)(const uint32_t* const left, const uint32_t* const top); extern VP8LPredictorFunc VP8LPredictors[16]; -uint32_t VP8LPredictor0_C(const uint32_t* const left, - const uint32_t* const top); -uint32_t VP8LPredictor1_C(const uint32_t* const left, - const uint32_t* const top); uint32_t VP8LPredictor2_C(const uint32_t* const left, const uint32_t* const top); uint32_t VP8LPredictor3_C(const uint32_t* const left, @@ -64,25 +58,28 @@ uint32_t VP8LPredictor13_C(const uint32_t* const left, // These Add/Sub function expects upper[-1] and out[-1] to be readable. typedef void (*VP8LPredictorAddSubFunc)(const uint32_t* in, const uint32_t* upper, int num_pixels, - uint32_t* out); + uint32_t* WEBP_RESTRICT out); extern VP8LPredictorAddSubFunc VP8LPredictorsAdd[16]; extern VP8LPredictorAddSubFunc VP8LPredictorsAdd_C[16]; +extern VP8LPredictorAddSubFunc VP8LPredictorsAdd_SSE[16]; typedef void (*VP8LProcessDecBlueAndRedFunc)(const uint32_t* src, int num_pixels, uint32_t* dst); extern VP8LProcessDecBlueAndRedFunc VP8LAddGreenToBlueAndRed; +extern VP8LProcessDecBlueAndRedFunc VP8LAddGreenToBlueAndRed_SSE; typedef struct { // Note: the members are uint8_t, so that any negative values are // automatically converted to "mod 256" values. - uint8_t green_to_red_; - uint8_t green_to_blue_; - uint8_t red_to_blue_; + uint8_t green_to_red; + uint8_t green_to_blue; + uint8_t red_to_blue; } VP8LMultipliers; typedef void (*VP8LTransformColorInverseFunc)(const VP8LMultipliers* const m, const uint32_t* src, int num_pixels, uint32_t* dst); extern VP8LTransformColorInverseFunc VP8LTransformColorInverse; +extern VP8LTransformColorInverseFunc VP8LTransformColorInverse_SSE; struct VP8LTransform; // Defined in dec/vp8li.h. @@ -95,13 +92,15 @@ void VP8LInverseTransform(const struct VP8LTransform* const transform, const uint32_t* const in, uint32_t* const out); // Color space conversion. -typedef void (*VP8LConvertFunc)(const uint32_t* src, int num_pixels, - uint8_t* dst); +typedef void (*VP8LConvertFunc)(const uint32_t* WEBP_RESTRICT src, + int num_pixels, uint8_t* WEBP_RESTRICT dst); extern VP8LConvertFunc VP8LConvertBGRAToRGB; extern VP8LConvertFunc VP8LConvertBGRAToRGBA; extern VP8LConvertFunc VP8LConvertBGRAToRGBA4444; extern VP8LConvertFunc VP8LConvertBGRAToRGB565; extern VP8LConvertFunc VP8LConvertBGRAToBGR; +extern VP8LConvertFunc VP8LConvertBGRAToRGB_SSE; +extern VP8LConvertFunc VP8LConvertBGRAToRGBA_SSE; // Converts from BGRA to other color spaces. void VP8LConvertFromBGRA(const uint32_t* const in_data, int num_pixels, @@ -131,13 +130,16 @@ void VP8LTransformColorInverse_C(const VP8LMultipliers* const m, const uint32_t* src, int num_pixels, uint32_t* dst); -void VP8LConvertBGRAToRGB_C(const uint32_t* src, int num_pixels, uint8_t* dst); -void VP8LConvertBGRAToRGBA_C(const uint32_t* src, int num_pixels, uint8_t* dst); -void VP8LConvertBGRAToRGBA4444_C(const uint32_t* src, - int num_pixels, uint8_t* dst); -void VP8LConvertBGRAToRGB565_C(const uint32_t* src, - int num_pixels, uint8_t* dst); -void VP8LConvertBGRAToBGR_C(const uint32_t* src, int num_pixels, uint8_t* dst); +void VP8LConvertBGRAToRGB_C(const uint32_t* WEBP_RESTRICT src, int num_pixels, + uint8_t* WEBP_RESTRICT dst); +void VP8LConvertBGRAToRGBA_C(const uint32_t* WEBP_RESTRICT src, int num_pixels, + uint8_t* WEBP_RESTRICT dst); +void VP8LConvertBGRAToRGBA4444_C(const uint32_t* WEBP_RESTRICT src, + int num_pixels, uint8_t* WEBP_RESTRICT dst); +void VP8LConvertBGRAToRGB565_C(const uint32_t* WEBP_RESTRICT src, + int num_pixels, uint8_t* WEBP_RESTRICT dst); +void VP8LConvertBGRAToBGR_C(const uint32_t* WEBP_RESTRICT src, int num_pixels, + uint8_t* WEBP_RESTRICT dst); void VP8LAddGreenToBlueAndRed_C(const uint32_t* src, int num_pixels, uint32_t* dst); @@ -149,48 +151,55 @@ void VP8LDspInit(void); typedef void (*VP8LProcessEncBlueAndRedFunc)(uint32_t* dst, int num_pixels); extern VP8LProcessEncBlueAndRedFunc VP8LSubtractGreenFromBlueAndRed; -typedef void (*VP8LTransformColorFunc)(const VP8LMultipliers* const m, - uint32_t* dst, int num_pixels); +extern VP8LProcessEncBlueAndRedFunc VP8LSubtractGreenFromBlueAndRed_SSE; +typedef void (*VP8LTransformColorFunc)( + const VP8LMultipliers* WEBP_RESTRICT const m, uint32_t* WEBP_RESTRICT dst, + int num_pixels); extern VP8LTransformColorFunc VP8LTransformColor; +extern VP8LTransformColorFunc VP8LTransformColor_SSE; typedef void (*VP8LCollectColorBlueTransformsFunc)( - const uint32_t* argb, int stride, + const uint32_t* WEBP_RESTRICT argb, int stride, int tile_width, int tile_height, - int green_to_blue, int red_to_blue, int histo[]); + int green_to_blue, int red_to_blue, uint32_t histo[]); extern VP8LCollectColorBlueTransformsFunc VP8LCollectColorBlueTransforms; +extern VP8LCollectColorBlueTransformsFunc VP8LCollectColorBlueTransforms_SSE; typedef void (*VP8LCollectColorRedTransformsFunc)( - const uint32_t* argb, int stride, + const uint32_t* WEBP_RESTRICT argb, int stride, int tile_width, int tile_height, - int green_to_red, int histo[]); + int green_to_red, uint32_t histo[]); extern VP8LCollectColorRedTransformsFunc VP8LCollectColorRedTransforms; +extern VP8LCollectColorRedTransformsFunc VP8LCollectColorRedTransforms_SSE; // Expose some C-only fallback functions -void VP8LTransformColor_C(const VP8LMultipliers* const m, - uint32_t* data, int num_pixels); +void VP8LTransformColor_C(const VP8LMultipliers* WEBP_RESTRICT const m, + uint32_t* WEBP_RESTRICT data, int num_pixels); void VP8LSubtractGreenFromBlueAndRed_C(uint32_t* argb_data, int num_pixels); -void VP8LCollectColorRedTransforms_C(const uint32_t* argb, int stride, +void VP8LCollectColorRedTransforms_C(const uint32_t* WEBP_RESTRICT argb, + int stride, int tile_width, int tile_height, - int green_to_red, int histo[]); -void VP8LCollectColorBlueTransforms_C(const uint32_t* argb, int stride, + int green_to_red, uint32_t histo[]); +void VP8LCollectColorBlueTransforms_C(const uint32_t* WEBP_RESTRICT argb, + int stride, int tile_width, int tile_height, int green_to_blue, int red_to_blue, - int histo[]); + uint32_t histo[]); extern VP8LPredictorAddSubFunc VP8LPredictorsSub[16]; extern VP8LPredictorAddSubFunc VP8LPredictorsSub_C[16]; +extern VP8LPredictorAddSubFunc VP8LPredictorsSub_SSE[16]; // ----------------------------------------------------------------------------- // Huffman-cost related functions. typedef uint32_t (*VP8LCostFunc)(const uint32_t* population, int length); -typedef uint32_t (*VP8LCostCombinedFunc)(const uint32_t* X, const uint32_t* Y, - int length); -typedef float (*VP8LCombinedShannonEntropyFunc)(const int X[256], - const int Y[256]); +typedef uint64_t (*VP8LCombinedShannonEntropyFunc)(const uint32_t X[256], + const uint32_t Y[256]); +typedef uint64_t (*VP8LShannonEntropyFunc)(const uint32_t* X, int length); extern VP8LCostFunc VP8LExtraCost; -extern VP8LCostCombinedFunc VP8LExtraCostCombined; extern VP8LCombinedShannonEntropyFunc VP8LCombinedShannonEntropy; +extern VP8LShannonEntropyFunc VP8LShannonEntropy; typedef struct { // small struct to hold counters int counts[2]; // index: 0=zero streak, 1=non-zero streak @@ -198,7 +207,7 @@ typedef struct { // small struct to hold counters } VP8LStreaks; typedef struct { // small struct to hold bit entropy results - float entropy; // entropy + uint64_t entropy; // entropy uint32_t sum; // sum of the population int nonzeros; // number of non-zero elements in the population uint32_t max_val; // maximum value in the population @@ -212,26 +221,27 @@ void VP8LBitEntropyInit(VP8LBitEntropy* const entropy); // codec specific heuristics. typedef void (*VP8LGetCombinedEntropyUnrefinedFunc)( const uint32_t X[], const uint32_t Y[], int length, - VP8LBitEntropy* const bit_entropy, VP8LStreaks* const stats); + VP8LBitEntropy* WEBP_RESTRICT const bit_entropy, + VP8LStreaks* WEBP_RESTRICT const stats); extern VP8LGetCombinedEntropyUnrefinedFunc VP8LGetCombinedEntropyUnrefined; // Get the entropy for the distribution 'X'. -typedef void (*VP8LGetEntropyUnrefinedFunc)(const uint32_t X[], int length, - VP8LBitEntropy* const bit_entropy, - VP8LStreaks* const stats); +typedef void (*VP8LGetEntropyUnrefinedFunc)( + const uint32_t X[], int length, + VP8LBitEntropy* WEBP_RESTRICT const bit_entropy, + VP8LStreaks* WEBP_RESTRICT const stats); extern VP8LGetEntropyUnrefinedFunc VP8LGetEntropyUnrefined; -void VP8LBitsEntropyUnrefined(const uint32_t* const array, int n, - VP8LBitEntropy* const entropy); +void VP8LBitsEntropyUnrefined(const uint32_t* WEBP_RESTRICT const array, int n, + VP8LBitEntropy* WEBP_RESTRICT const entropy); -typedef void (*VP8LAddVectorFunc)(const uint32_t* a, const uint32_t* b, - uint32_t* out, int size); +typedef void (*VP8LAddVectorFunc)(const uint32_t* WEBP_RESTRICT a, + const uint32_t* WEBP_RESTRICT b, + uint32_t* WEBP_RESTRICT out, int size); extern VP8LAddVectorFunc VP8LAddVector; -typedef void (*VP8LAddVectorEqFunc)(const uint32_t* a, uint32_t* out, int size); +typedef void (*VP8LAddVectorEqFunc)(const uint32_t* WEBP_RESTRICT a, + uint32_t* WEBP_RESTRICT out, int size); extern VP8LAddVectorEqFunc VP8LAddVectorEq; -void VP8LHistogramAdd(const VP8LHistogram* const a, - const VP8LHistogram* const b, - VP8LHistogram* const out); // ----------------------------------------------------------------------------- // PrefixEncode() @@ -241,11 +251,13 @@ typedef int (*VP8LVectorMismatchFunc)(const uint32_t* const array1, // Returns the first index where array1 and array2 are different. extern VP8LVectorMismatchFunc VP8LVectorMismatch; -typedef void (*VP8LBundleColorMapFunc)(const uint8_t* const row, int width, - int xbits, uint32_t* dst); +typedef void (*VP8LBundleColorMapFunc)(const uint8_t* WEBP_RESTRICT const row, + int width, int xbits, + uint32_t* WEBP_RESTRICT dst); extern VP8LBundleColorMapFunc VP8LBundleColorMap; -void VP8LBundleColorMap_C(const uint8_t* const row, int width, int xbits, - uint32_t* dst); +extern VP8LBundleColorMapFunc VP8LBundleColorMap_SSE; +void VP8LBundleColorMap_C(const uint8_t* WEBP_RESTRICT const row, + int width, int xbits, uint32_t* WEBP_RESTRICT dst); // Must be called before calling any of the above methods. void VP8LEncDspInit(void); diff --git a/libwebp/src/dsp/lossless_avx2.c b/libwebp/src/dsp/lossless_avx2.c new file mode 100644 index 00000000..dc866049 --- /dev/null +++ b/libwebp/src/dsp/lossless_avx2.c @@ -0,0 +1,443 @@ +// Copyright 2025 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- +// +// AVX2 variant of methods for lossless decoder +// +// Author: Vincent Rabaud (vrabaud@google.com) + +#include "src/dsp/dsp.h" + +#if defined(WEBP_USE_AVX2) + +#include +#include + +#include "src/dsp/cpu.h" +#include "src/dsp/lossless.h" +#include "src/webp/format_constants.h" +#include "src/webp/types.h" + +//------------------------------------------------------------------------------ +// Predictor Transform + +static WEBP_INLINE void Average2_m256i(const __m256i* const a0, + const __m256i* const a1, + __m256i* const avg) { + // (a + b) >> 1 = ((a + b + 1) >> 1) - ((a ^ b) & 1) + const __m256i ones = _mm256_set1_epi8(1); + const __m256i avg1 = _mm256_avg_epu8(*a0, *a1); + const __m256i one = _mm256_and_si256(_mm256_xor_si256(*a0, *a1), ones); + *avg = _mm256_sub_epi8(avg1, one); +} + +// Batch versions of those functions. + +// Predictor0: ARGB_BLACK. +static void PredictorAdd0_AVX2(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* WEBP_RESTRICT out) { + int i; + const __m256i black = _mm256_set1_epi32((int)ARGB_BLACK); + for (i = 0; i + 8 <= num_pixels; i += 8) { + const __m256i src = _mm256_loadu_si256((const __m256i*)&in[i]); + const __m256i res = _mm256_add_epi8(src, black); + _mm256_storeu_si256((__m256i*)&out[i], res); + } + if (i != num_pixels) { + VP8LPredictorsAdd_SSE[0](in + i, NULL, num_pixels - i, out + i); + } + (void)upper; +} + +// Predictor1: left. +static void PredictorAdd1_AVX2(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* WEBP_RESTRICT out) { + int i; + __m256i prev = _mm256_set1_epi32((int)out[-1]); + for (i = 0; i + 8 <= num_pixels; i += 8) { + // h | g | f | e | d | c | b | a + const __m256i src = _mm256_loadu_si256((const __m256i*)&in[i]); + // g | f | e | 0 | c | b | a | 0 + const __m256i shift0 = _mm256_slli_si256(src, 4); + // g + h | f + g | e + f | e | c + d | b + c | a + b | a + const __m256i sum0 = _mm256_add_epi8(src, shift0); + // e + f | e | 0 | 0 | a + b | a | 0 | 0 + const __m256i shift1 = _mm256_slli_si256(sum0, 8); + // e + f + g + h | e + f + g | e + f | e | a + b + c + d | a + b + c | a + b + // | a + const __m256i sum1 = _mm256_add_epi8(sum0, shift1); + // Add a + b + c + d to the upper lane. + const int32_t sum_abcd = _mm256_extract_epi32(sum1, 3); + const __m256i sum2 = _mm256_add_epi8( + sum1, + _mm256_set_epi32(sum_abcd, sum_abcd, sum_abcd, sum_abcd, 0, 0, 0, 0)); + + const __m256i res = _mm256_add_epi8(sum2, prev); + _mm256_storeu_si256((__m256i*)&out[i], res); + // replicate last res output in prev. + prev = _mm256_permutevar8x32_epi32( + res, _mm256_set_epi32(7, 7, 7, 7, 7, 7, 7, 7)); + } + if (i != num_pixels) { + VP8LPredictorsAdd_SSE[1](in + i, upper + i, num_pixels - i, out + i); + } +} + +// Macro that adds 32-bit integers from IN using mod 256 arithmetic +// per 8 bit channel. +#define GENERATE_PREDICTOR_1(X, IN) \ + static void PredictorAdd##X##_AVX2(const uint32_t* in, \ + const uint32_t* upper, int num_pixels, \ + uint32_t* WEBP_RESTRICT out) { \ + int i; \ + for (i = 0; i + 8 <= num_pixels; i += 8) { \ + const __m256i src = _mm256_loadu_si256((const __m256i*)&in[i]); \ + const __m256i other = _mm256_loadu_si256((const __m256i*)&(IN)); \ + const __m256i res = _mm256_add_epi8(src, other); \ + _mm256_storeu_si256((__m256i*)&out[i], res); \ + } \ + if (i != num_pixels) { \ + VP8LPredictorsAdd_SSE[(X)](in + i, upper + i, num_pixels - i, out + i); \ + } \ + } + +// Predictor2: Top. +GENERATE_PREDICTOR_1(2, upper[i]) +// Predictor3: Top-right. +GENERATE_PREDICTOR_1(3, upper[i + 1]) +// Predictor4: Top-left. +GENERATE_PREDICTOR_1(4, upper[i - 1]) +#undef GENERATE_PREDICTOR_1 + +// Due to averages with integers, values cannot be accumulated in parallel for +// predictors 5 to 7. + +#define GENERATE_PREDICTOR_2(X, IN) \ + static void PredictorAdd##X##_AVX2(const uint32_t* in, \ + const uint32_t* upper, int num_pixels, \ + uint32_t* WEBP_RESTRICT out) { \ + int i; \ + for (i = 0; i + 8 <= num_pixels; i += 8) { \ + const __m256i Tother = _mm256_loadu_si256((const __m256i*)&(IN)); \ + const __m256i T = _mm256_loadu_si256((const __m256i*)&upper[i]); \ + const __m256i src = _mm256_loadu_si256((const __m256i*)&in[i]); \ + __m256i avg, res; \ + Average2_m256i(&T, &Tother, &avg); \ + res = _mm256_add_epi8(avg, src); \ + _mm256_storeu_si256((__m256i*)&out[i], res); \ + } \ + if (i != num_pixels) { \ + VP8LPredictorsAdd_SSE[(X)](in + i, upper + i, num_pixels - i, out + i); \ + } \ + } +// Predictor8: average TL T. +GENERATE_PREDICTOR_2(8, upper[i - 1]) +// Predictor9: average T TR. +GENERATE_PREDICTOR_2(9, upper[i + 1]) +#undef GENERATE_PREDICTOR_2 + +// Predictor10: average of (average of (L,TL), average of (T, TR)). +#define DO_PRED10(OUT) \ + do { \ + __m256i avgLTL, avg; \ + Average2_m256i(&L, &TL, &avgLTL); \ + Average2_m256i(&avgTTR, &avgLTL, &avg); \ + L = _mm256_add_epi8(avg, src); \ + out[i + (OUT)] = (uint32_t)_mm256_cvtsi256_si32(L); \ + } while (0) + +#define DO_PRED10_SHIFT \ + do { \ + /* Rotate the pre-computed values for the next iteration.*/ \ + avgTTR = _mm256_srli_si256(avgTTR, 4); \ + TL = _mm256_srli_si256(TL, 4); \ + src = _mm256_srli_si256(src, 4); \ + } while (0) + +static void PredictorAdd10_AVX2(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* WEBP_RESTRICT out) { + int i, j; + __m256i L = _mm256_setr_epi32((int)out[-1], 0, 0, 0, 0, 0, 0, 0); + for (i = 0; i + 8 <= num_pixels; i += 8) { + __m256i src = _mm256_loadu_si256((const __m256i*)&in[i]); + __m256i TL = _mm256_loadu_si256((const __m256i*)&upper[i - 1]); + const __m256i T = _mm256_loadu_si256((const __m256i*)&upper[i]); + const __m256i TR = _mm256_loadu_si256((const __m256i*)&upper[i + 1]); + __m256i avgTTR; + Average2_m256i(&T, &TR, &avgTTR); + { + const __m256i avgTTR_bak = avgTTR; + const __m256i TL_bak = TL; + const __m256i src_bak = src; + for (j = 0; j < 4; ++j) { + DO_PRED10(j); + DO_PRED10_SHIFT; + } + avgTTR = _mm256_permute2x128_si256(avgTTR_bak, avgTTR_bak, 1); + TL = _mm256_permute2x128_si256(TL_bak, TL_bak, 1); + src = _mm256_permute2x128_si256(src_bak, src_bak, 1); + for (; j < 8; ++j) { + DO_PRED10(j); + DO_PRED10_SHIFT; + } + } + } + if (i != num_pixels) { + VP8LPredictorsAdd_SSE[10](in + i, upper + i, num_pixels - i, out + i); + } +} +#undef DO_PRED10 +#undef DO_PRED10_SHIFT + +// Predictor11: select. +#define DO_PRED11(OUT) \ + do { \ + const __m256i L_lo = _mm256_unpacklo_epi32(L, T); \ + const __m256i TL_lo = _mm256_unpacklo_epi32(TL, T); \ + const __m256i pb = _mm256_sad_epu8(L_lo, TL_lo); /* pb = sum |L-TL|*/ \ + const __m256i mask = _mm256_cmpgt_epi32(pb, pa); \ + const __m256i A = _mm256_and_si256(mask, L); \ + const __m256i B = _mm256_andnot_si256(mask, T); \ + const __m256i pred = _mm256_or_si256(A, B); /* pred = (pa > b)? L : T*/ \ + L = _mm256_add_epi8(src, pred); \ + out[i + (OUT)] = (uint32_t)_mm256_cvtsi256_si32(L); \ + } while (0) + +#define DO_PRED11_SHIFT \ + do { \ + /* Shift the pre-computed value for the next iteration.*/ \ + T = _mm256_srli_si256(T, 4); \ + TL = _mm256_srli_si256(TL, 4); \ + src = _mm256_srli_si256(src, 4); \ + pa = _mm256_srli_si256(pa, 4); \ + } while (0) + +static void PredictorAdd11_AVX2(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* WEBP_RESTRICT out) { + int i, j; + __m256i pa; + __m256i L = _mm256_setr_epi32((int)out[-1], 0, 0, 0, 0, 0, 0, 0); + for (i = 0; i + 8 <= num_pixels; i += 8) { + __m256i T = _mm256_loadu_si256((const __m256i*)&upper[i]); + __m256i TL = _mm256_loadu_si256((const __m256i*)&upper[i - 1]); + __m256i src = _mm256_loadu_si256((const __m256i*)&in[i]); + { + // We can unpack with any value on the upper 32 bits, provided it's the + // same on both operands (so that their sum of abs diff is zero). Here we + // use T. + const __m256i T_lo = _mm256_unpacklo_epi32(T, T); + const __m256i TL_lo = _mm256_unpacklo_epi32(TL, T); + const __m256i T_hi = _mm256_unpackhi_epi32(T, T); + const __m256i TL_hi = _mm256_unpackhi_epi32(TL, T); + const __m256i s_lo = _mm256_sad_epu8(T_lo, TL_lo); + const __m256i s_hi = _mm256_sad_epu8(T_hi, TL_hi); + pa = _mm256_packs_epi32(s_lo, s_hi); // pa = sum |T-TL| + } + { + const __m256i T_bak = T; + const __m256i TL_bak = TL; + const __m256i src_bak = src; + const __m256i pa_bak = pa; + for (j = 0; j < 4; ++j) { + DO_PRED11(j); + DO_PRED11_SHIFT; + } + T = _mm256_permute2x128_si256(T_bak, T_bak, 1); + TL = _mm256_permute2x128_si256(TL_bak, TL_bak, 1); + src = _mm256_permute2x128_si256(src_bak, src_bak, 1); + pa = _mm256_permute2x128_si256(pa_bak, pa_bak, 1); + for (; j < 8; ++j) { + DO_PRED11(j); + DO_PRED11_SHIFT; + } + } + } + if (i != num_pixels) { + VP8LPredictorsAdd_SSE[11](in + i, upper + i, num_pixels - i, out + i); + } +} +#undef DO_PRED11 +#undef DO_PRED11_SHIFT + +// Predictor12: ClampedAddSubtractFull. +#define DO_PRED12(DIFF, OUT) \ + do { \ + const __m256i all = _mm256_add_epi16(L, (DIFF)); \ + const __m256i alls = _mm256_packus_epi16(all, all); \ + const __m256i res = _mm256_add_epi8(src, alls); \ + out[i + (OUT)] = (uint32_t)_mm256_cvtsi256_si32(res); \ + L = _mm256_unpacklo_epi8(res, zero); \ + } while (0) + +#define DO_PRED12_SHIFT(DIFF, LANE) \ + do { \ + /* Shift the pre-computed value for the next iteration.*/ \ + if ((LANE) == 0) (DIFF) = _mm256_srli_si256(DIFF, 8); \ + src = _mm256_srli_si256(src, 4); \ + } while (0) + +static void PredictorAdd12_AVX2(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* WEBP_RESTRICT out) { + int i; + const __m256i zero = _mm256_setzero_si256(); + const __m256i L8 = _mm256_setr_epi32((int)out[-1], 0, 0, 0, 0, 0, 0, 0); + __m256i L = _mm256_unpacklo_epi8(L8, zero); + for (i = 0; i + 8 <= num_pixels; i += 8) { + // Load 8 pixels at a time. + __m256i src = _mm256_loadu_si256((const __m256i*)&in[i]); + const __m256i T = _mm256_loadu_si256((const __m256i*)&upper[i]); + const __m256i T_lo = _mm256_unpacklo_epi8(T, zero); + const __m256i T_hi = _mm256_unpackhi_epi8(T, zero); + const __m256i TL = _mm256_loadu_si256((const __m256i*)&upper[i - 1]); + const __m256i TL_lo = _mm256_unpacklo_epi8(TL, zero); + const __m256i TL_hi = _mm256_unpackhi_epi8(TL, zero); + __m256i diff_lo = _mm256_sub_epi16(T_lo, TL_lo); + __m256i diff_hi = _mm256_sub_epi16(T_hi, TL_hi); + const __m256i diff_lo_bak = diff_lo; + const __m256i diff_hi_bak = diff_hi; + const __m256i src_bak = src; + DO_PRED12(diff_lo, 0); + DO_PRED12_SHIFT(diff_lo, 0); + DO_PRED12(diff_lo, 1); + DO_PRED12_SHIFT(diff_lo, 0); + DO_PRED12(diff_hi, 2); + DO_PRED12_SHIFT(diff_hi, 0); + DO_PRED12(diff_hi, 3); + DO_PRED12_SHIFT(diff_hi, 0); + + // Process the upper lane. + diff_lo = _mm256_permute2x128_si256(diff_lo_bak, diff_lo_bak, 1); + diff_hi = _mm256_permute2x128_si256(diff_hi_bak, diff_hi_bak, 1); + src = _mm256_permute2x128_si256(src_bak, src_bak, 1); + + DO_PRED12(diff_lo, 4); + DO_PRED12_SHIFT(diff_lo, 0); + DO_PRED12(diff_lo, 5); + DO_PRED12_SHIFT(diff_lo, 1); + DO_PRED12(diff_hi, 6); + DO_PRED12_SHIFT(diff_hi, 0); + DO_PRED12(diff_hi, 7); + } + if (i != num_pixels) { + VP8LPredictorsAdd_SSE[12](in + i, upper + i, num_pixels - i, out + i); + } +} +#undef DO_PRED12 +#undef DO_PRED12_SHIFT + +// Due to averages with integers, values cannot be accumulated in parallel for +// predictors 13. + +//------------------------------------------------------------------------------ +// Subtract-Green Transform + +static void AddGreenToBlueAndRed_AVX2(const uint32_t* const src, int num_pixels, + uint32_t* dst) { + int i; + const __m256i kCstShuffle = _mm256_set_epi8( + -1, 29, -1, 29, -1, 25, -1, 25, -1, 21, -1, 21, -1, 17, -1, 17, -1, 13, + -1, 13, -1, 9, -1, 9, -1, 5, -1, 5, -1, 1, -1, 1); + for (i = 0; i + 8 <= num_pixels; i += 8) { + const __m256i in = _mm256_loadu_si256((const __m256i*)&src[i]); // argb + const __m256i in_0g0g = _mm256_shuffle_epi8(in, kCstShuffle); // 0g0g + const __m256i out = _mm256_add_epi8(in, in_0g0g); + _mm256_storeu_si256((__m256i*)&dst[i], out); + } + // fallthrough and finish off with SSE. + if (i != num_pixels) { + VP8LAddGreenToBlueAndRed_SSE(src + i, num_pixels - i, dst + i); + } +} + +//------------------------------------------------------------------------------ +// Color Transform + +static void TransformColorInverse_AVX2(const VP8LMultipliers* const m, + const uint32_t* const src, + int num_pixels, uint32_t* dst) { +// sign-extended multiplying constants, pre-shifted by 5. +#define CST(X) (((int16_t)(m->X << 8)) >> 5) // sign-extend + const __m256i mults_rb = + _mm256_set1_epi32((int)((uint32_t)CST(green_to_red) << 16 | + (CST(green_to_blue) & 0xffff))); + const __m256i mults_b2 = _mm256_set1_epi32(CST(red_to_blue)); +#undef CST + const __m256i mask_ag = _mm256_set1_epi32((int)0xff00ff00); + const __m256i perm1 = _mm256_setr_epi8( + -1, 1, -1, 1, -1, 5, -1, 5, -1, 9, -1, 9, -1, 13, -1, 13, -1, 17, -1, 17, + -1, 21, -1, 21, -1, 25, -1, 25, -1, 29, -1, 29); + const __m256i perm2 = _mm256_setr_epi8( + -1, 2, -1, -1, -1, 6, -1, -1, -1, 10, -1, -1, -1, 14, -1, -1, -1, 18, -1, + -1, -1, 22, -1, -1, -1, 26, -1, -1, -1, 30, -1, -1); + int i; + for (i = 0; i + 8 <= num_pixels; i += 8) { + const __m256i A = _mm256_loadu_si256((const __m256i*)(src + i)); + const __m256i B = _mm256_shuffle_epi8(A, perm1); // argb -> g0g0 + const __m256i C = _mm256_mulhi_epi16(B, mults_rb); + const __m256i D = _mm256_add_epi8(A, C); + const __m256i E = _mm256_shuffle_epi8(D, perm2); + const __m256i F = _mm256_mulhi_epi16(E, mults_b2); + const __m256i G = _mm256_add_epi8(D, F); + const __m256i out = _mm256_blendv_epi8(G, A, mask_ag); + _mm256_storeu_si256((__m256i*)&dst[i], out); + } + // Fall-back to SSE-version for left-overs. + if (i != num_pixels) { + VP8LTransformColorInverse_SSE(m, src + i, num_pixels - i, dst + i); + } +} + +//------------------------------------------------------------------------------ +// Color-space conversion functions + +static void ConvertBGRAToRGBA_AVX2(const uint32_t* WEBP_RESTRICT src, + int num_pixels, uint8_t* WEBP_RESTRICT dst) { + const __m256i* in = (const __m256i*)src; + __m256i* out = (__m256i*)dst; + while (num_pixels >= 8) { + const __m256i A = _mm256_loadu_si256(in++); + const __m256i B = _mm256_shuffle_epi8( + A, + _mm256_set_epi8(15, 12, 13, 14, 11, 8, 9, 10, 7, 4, 5, 6, 3, 0, 1, 2, + 15, 12, 13, 14, 11, 8, 9, 10, 7, 4, 5, 6, 3, 0, 1, 2)); + _mm256_storeu_si256(out++, B); + num_pixels -= 8; + } + // left-overs + if (num_pixels > 0) { + VP8LConvertBGRAToRGBA_SSE((const uint32_t*)in, num_pixels, (uint8_t*)out); + } +} + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8LDspInitAVX2(void); + +WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInitAVX2(void) { + VP8LPredictorsAdd[0] = PredictorAdd0_AVX2; + VP8LPredictorsAdd[1] = PredictorAdd1_AVX2; + VP8LPredictorsAdd[2] = PredictorAdd2_AVX2; + VP8LPredictorsAdd[3] = PredictorAdd3_AVX2; + VP8LPredictorsAdd[4] = PredictorAdd4_AVX2; + VP8LPredictorsAdd[8] = PredictorAdd8_AVX2; + VP8LPredictorsAdd[9] = PredictorAdd9_AVX2; + VP8LPredictorsAdd[10] = PredictorAdd10_AVX2; + VP8LPredictorsAdd[11] = PredictorAdd11_AVX2; + VP8LPredictorsAdd[12] = PredictorAdd12_AVX2; + + VP8LAddGreenToBlueAndRed = AddGreenToBlueAndRed_AVX2; + VP8LTransformColorInverse = TransformColorInverse_AVX2; + VP8LConvertBGRAToRGBA = ConvertBGRAToRGBA_AVX2; +} + +#else // !WEBP_USE_AVX2 + +WEBP_DSP_INIT_STUB(VP8LDspInitAVX2) + +#endif // WEBP_USE_AVX2 diff --git a/libwebp/src/dsp/lossless_common.h b/libwebp/src/dsp/lossless_common.h index d6139b2b..c856679d 100644 --- a/libwebp/src/dsp/lossless_common.h +++ b/libwebp/src/dsp/lossless_common.h @@ -16,6 +16,9 @@ #ifndef WEBP_DSP_LOSSLESS_COMMON_H_ #define WEBP_DSP_LOSSLESS_COMMON_H_ +#include +#include + #include "src/dsp/cpu.h" #include "src/utils/utils.h" #include "src/webp/types.h" @@ -73,23 +76,44 @@ static WEBP_INLINE int VP8LNearLosslessBits(int near_lossless_quality) { // Keeping a high threshold for now. #define APPROX_LOG_WITH_CORRECTION_MAX 65536 #define APPROX_LOG_MAX 4096 +// VP8LFastLog2 and VP8LFastSLog2 are used on elements from image histograms. +// The histogram values cannot exceed the maximum number of pixels, which +// is (1 << 14) * (1 << 14). Therefore S * log(S) < (1 << 33). +// No more than 32 bits of precision should be chosen. +// To match the original float implementation, 23 bits of precision are used. +#define LOG_2_PRECISION_BITS 23 #define LOG_2_RECIPROCAL 1.44269504088896338700465094007086 +// LOG_2_RECIPROCAL * (1 << LOG_2_PRECISION_BITS) +#define LOG_2_RECIPROCAL_FIXED_DOUBLE 12102203.161561485379934310913085937500 +#define LOG_2_RECIPROCAL_FIXED ((uint64_t)12102203) #define LOG_LOOKUP_IDX_MAX 256 -extern const float kLog2Table[LOG_LOOKUP_IDX_MAX]; -extern const float kSLog2Table[LOG_LOOKUP_IDX_MAX]; -typedef float (*VP8LFastLog2SlowFunc)(uint32_t v); +extern const uint32_t kLog2Table[LOG_LOOKUP_IDX_MAX]; +extern const uint64_t kSLog2Table[LOG_LOOKUP_IDX_MAX]; +typedef uint32_t (*VP8LFastLog2SlowFunc)(uint32_t v); +typedef uint64_t (*VP8LFastSLog2SlowFunc)(uint32_t v); extern VP8LFastLog2SlowFunc VP8LFastLog2Slow; -extern VP8LFastLog2SlowFunc VP8LFastSLog2Slow; +extern VP8LFastSLog2SlowFunc VP8LFastSLog2Slow; -static WEBP_INLINE float VP8LFastLog2(uint32_t v) { +static WEBP_INLINE uint32_t VP8LFastLog2(uint32_t v) { return (v < LOG_LOOKUP_IDX_MAX) ? kLog2Table[v] : VP8LFastLog2Slow(v); } // Fast calculation of v * log2(v) for integer input. -static WEBP_INLINE float VP8LFastSLog2(uint32_t v) { +static WEBP_INLINE uint64_t VP8LFastSLog2(uint32_t v) { return (v < LOG_LOOKUP_IDX_MAX) ? kSLog2Table[v] : VP8LFastSLog2Slow(v); } +static WEBP_INLINE uint64_t RightShiftRound(uint64_t v, uint32_t shift) { + return (v + (1ull << shift >> 1)) >> shift; +} + +static WEBP_INLINE int64_t DivRound(int64_t a, int64_t b) { + return ((a < 0) == (b < 0)) ? ((a + b / 2) / b) : ((a - b / 2) / b); +} + +#define WEBP_INT64_MAX ((int64_t)((1ull << 63) - 1)) +#define WEBP_UINT64_MAX (~0ull) + // ----------------------------------------------------------------------------- // PrefixEncode() @@ -116,8 +140,8 @@ static WEBP_INLINE void VP8LPrefixEncodeNoLUT(int distance, int* const code, #define PREFIX_LOOKUP_IDX_MAX 512 typedef struct { - int8_t code_; - int8_t extra_bits_; + int8_t code; + int8_t extra_bits; } VP8LPrefixCode; // These tables are derived using VP8LPrefixEncodeNoLUT. @@ -127,8 +151,8 @@ static WEBP_INLINE void VP8LPrefixEncodeBits(int distance, int* const code, int* const extra_bits) { if (distance < PREFIX_LOOKUP_IDX_MAX) { const VP8LPrefixCode prefix_code = kPrefixEncodeCode[distance]; - *code = prefix_code.code_; - *extra_bits = prefix_code.extra_bits_; + *code = prefix_code.code; + *extra_bits = prefix_code.extra_bits; } else { VP8LPrefixEncodeBitsNoLUT(distance, code, extra_bits); } @@ -139,8 +163,8 @@ static WEBP_INLINE void VP8LPrefixEncode(int distance, int* const code, int* const extra_bits_value) { if (distance < PREFIX_LOOKUP_IDX_MAX) { const VP8LPrefixCode prefix_code = kPrefixEncodeCode[distance]; - *code = prefix_code.code_; - *extra_bits = prefix_code.extra_bits_; + *code = prefix_code.code; + *extra_bits = prefix_code.extra_bits; *extra_bits_value = kPrefixEncodeExtraBitsValue[distance]; } else { VP8LPrefixEncodeNoLUT(distance, code, extra_bits, extra_bits_value); @@ -173,15 +197,15 @@ uint32_t VP8LSubPixels(uint32_t a, uint32_t b) { // The predictor is added to the output pixel (which // is therefore considered as a residual) to get the final prediction. -#define GENERATE_PREDICTOR_ADD(PREDICTOR, PREDICTOR_ADD) \ -static void PREDICTOR_ADD(const uint32_t* in, const uint32_t* upper, \ - int num_pixels, uint32_t* out) { \ - int x; \ - assert(upper != NULL); \ - for (x = 0; x < num_pixels; ++x) { \ - const uint32_t pred = (PREDICTOR)(&out[x - 1], upper + x); \ - out[x] = VP8LAddPixels(in[x], pred); \ - } \ +#define GENERATE_PREDICTOR_ADD(PREDICTOR, PREDICTOR_ADD) \ +static void PREDICTOR_ADD(const uint32_t* in, const uint32_t* upper, \ + int num_pixels, uint32_t* WEBP_RESTRICT out) { \ + int x; \ + assert(upper != NULL); \ + for (x = 0; x < num_pixels; ++x) { \ + const uint32_t pred = (PREDICTOR)(&out[x - 1], upper + x); \ + out[x] = VP8LAddPixels(in[x], pred); \ + } \ } #ifdef __cplusplus diff --git a/libwebp/src/dsp/lossless_enc.c b/libwebp/src/dsp/lossless_enc.c deleted file mode 100644 index 997d56c2..00000000 --- a/libwebp/src/dsp/lossless_enc.c +++ /dev/null @@ -1,954 +0,0 @@ -// Copyright 2015 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Image transform methods for lossless encoder. -// -// Authors: Vikas Arora (vikaas.arora@gmail.com) -// Jyrki Alakuijala (jyrki@google.com) -// Urvang Joshi (urvang@google.com) - -#include "src/dsp/dsp.h" - -#include -#include -#include -#include "src/dec/vp8li_dec.h" -#include "src/utils/endian_inl_utils.h" -#include "src/dsp/lossless.h" -#include "src/dsp/lossless_common.h" -#include "src/dsp/yuv.h" - -// lookup table for small values of log2(int) -const float kLog2Table[LOG_LOOKUP_IDX_MAX] = { - 0.0000000000000000f, 0.0000000000000000f, - 1.0000000000000000f, 1.5849625007211560f, - 2.0000000000000000f, 2.3219280948873621f, - 2.5849625007211560f, 2.8073549220576041f, - 3.0000000000000000f, 3.1699250014423121f, - 3.3219280948873621f, 3.4594316186372973f, - 3.5849625007211560f, 3.7004397181410921f, - 3.8073549220576041f, 3.9068905956085187f, - 4.0000000000000000f, 4.0874628412503390f, - 4.1699250014423121f, 4.2479275134435852f, - 4.3219280948873626f, 4.3923174227787606f, - 4.4594316186372973f, 4.5235619560570130f, - 4.5849625007211560f, 4.6438561897747243f, - 4.7004397181410917f, 4.7548875021634682f, - 4.8073549220576037f, 4.8579809951275718f, - 4.9068905956085187f, 4.9541963103868749f, - 5.0000000000000000f, 5.0443941193584533f, - 5.0874628412503390f, 5.1292830169449663f, - 5.1699250014423121f, 5.2094533656289501f, - 5.2479275134435852f, 5.2854022188622487f, - 5.3219280948873626f, 5.3575520046180837f, - 5.3923174227787606f, 5.4262647547020979f, - 5.4594316186372973f, 5.4918530963296747f, - 5.5235619560570130f, 5.5545888516776376f, - 5.5849625007211560f, 5.6147098441152083f, - 5.6438561897747243f, 5.6724253419714951f, - 5.7004397181410917f, 5.7279204545631987f, - 5.7548875021634682f, 5.7813597135246599f, - 5.8073549220576037f, 5.8328900141647412f, - 5.8579809951275718f, 5.8826430493618415f, - 5.9068905956085187f, 5.9307373375628866f, - 5.9541963103868749f, 5.9772799234999167f, - 6.0000000000000000f, 6.0223678130284543f, - 6.0443941193584533f, 6.0660891904577720f, - 6.0874628412503390f, 6.1085244567781691f, - 6.1292830169449663f, 6.1497471195046822f, - 6.1699250014423121f, 6.1898245588800175f, - 6.2094533656289501f, 6.2288186904958804f, - 6.2479275134435852f, 6.2667865406949010f, - 6.2854022188622487f, 6.3037807481771030f, - 6.3219280948873626f, 6.3398500028846243f, - 6.3575520046180837f, 6.3750394313469245f, - 6.3923174227787606f, 6.4093909361377017f, - 6.4262647547020979f, 6.4429434958487279f, - 6.4594316186372973f, 6.4757334309663976f, - 6.4918530963296747f, 6.5077946401986963f, - 6.5235619560570130f, 6.5391588111080309f, - 6.5545888516776376f, 6.5698556083309478f, - 6.5849625007211560f, 6.5999128421871278f, - 6.6147098441152083f, 6.6293566200796094f, - 6.6438561897747243f, 6.6582114827517946f, - 6.6724253419714951f, 6.6865005271832185f, - 6.7004397181410917f, 6.7142455176661224f, - 6.7279204545631987f, 6.7414669864011464f, - 6.7548875021634682f, 6.7681843247769259f, - 6.7813597135246599f, 6.7944158663501061f, - 6.8073549220576037f, 6.8201789624151878f, - 6.8328900141647412f, 6.8454900509443747f, - 6.8579809951275718f, 6.8703647195834047f, - 6.8826430493618415f, 6.8948177633079437f, - 6.9068905956085187f, 6.9188632372745946f, - 6.9307373375628866f, 6.9425145053392398f, - 6.9541963103868749f, 6.9657842846620869f, - 6.9772799234999167f, 6.9886846867721654f, - 7.0000000000000000f, 7.0112272554232539f, - 7.0223678130284543f, 7.0334230015374501f, - 7.0443941193584533f, 7.0552824355011898f, - 7.0660891904577720f, 7.0768155970508308f, - 7.0874628412503390f, 7.0980320829605263f, - 7.1085244567781691f, 7.1189410727235076f, - 7.1292830169449663f, 7.1395513523987936f, - 7.1497471195046822f, 7.1598713367783890f, - 7.1699250014423121f, 7.1799090900149344f, - 7.1898245588800175f, 7.1996723448363644f, - 7.2094533656289501f, 7.2191685204621611f, - 7.2288186904958804f, 7.2384047393250785f, - 7.2479275134435852f, 7.2573878426926521f, - 7.2667865406949010f, 7.2761244052742375f, - 7.2854022188622487f, 7.2946207488916270f, - 7.3037807481771030f, 7.3128829552843557f, - 7.3219280948873626f, 7.3309168781146167f, - 7.3398500028846243f, 7.3487281542310771f, - 7.3575520046180837f, 7.3663222142458160f, - 7.3750394313469245f, 7.3837042924740519f, - 7.3923174227787606f, 7.4008794362821843f, - 7.4093909361377017f, 7.4178525148858982f, - 7.4262647547020979f, 7.4346282276367245f, - 7.4429434958487279f, 7.4512111118323289f, - 7.4594316186372973f, 7.4676055500829976f, - 7.4757334309663976f, 7.4838157772642563f, - 7.4918530963296747f, 7.4998458870832056f, - 7.5077946401986963f, 7.5156998382840427f, - 7.5235619560570130f, 7.5313814605163118f, - 7.5391588111080309f, 7.5468944598876364f, - 7.5545888516776376f, 7.5622424242210728f, - 7.5698556083309478f, 7.5774288280357486f, - 7.5849625007211560f, 7.5924570372680806f, - 7.5999128421871278f, 7.6073303137496104f, - 7.6147098441152083f, 7.6220518194563764f, - 7.6293566200796094f, 7.6366246205436487f, - 7.6438561897747243f, 7.6510516911789281f, - 7.6582114827517946f, 7.6653359171851764f, - 7.6724253419714951f, 7.6794800995054464f, - 7.6865005271832185f, 7.6934869574993252f, - 7.7004397181410917f, 7.7073591320808825f, - 7.7142455176661224f, 7.7210991887071855f, - 7.7279204545631987f, 7.7347096202258383f, - 7.7414669864011464f, 7.7481928495894605f, - 7.7548875021634682f, 7.7615512324444795f, - 7.7681843247769259f, 7.7747870596011736f, - 7.7813597135246599f, 7.7879025593914317f, - 7.7944158663501061f, 7.8008998999203047f, - 7.8073549220576037f, 7.8137811912170374f, - 7.8201789624151878f, 7.8265484872909150f, - 7.8328900141647412f, 7.8392037880969436f, - 7.8454900509443747f, 7.8517490414160571f, - 7.8579809951275718f, 7.8641861446542797f, - 7.8703647195834047f, 7.8765169465649993f, - 7.8826430493618415f, 7.8887432488982591f, - 7.8948177633079437f, 7.9008668079807486f, - 7.9068905956085187f, 7.9128893362299619f, - 7.9188632372745946f, 7.9248125036057812f, - 7.9307373375628866f, 7.9366379390025709f, - 7.9425145053392398f, 7.9483672315846778f, - 7.9541963103868749f, 7.9600019320680805f, - 7.9657842846620869f, 7.9715435539507719f, - 7.9772799234999167f, 7.9829935746943103f, - 7.9886846867721654f, 7.9943534368588577f -}; - -const float kSLog2Table[LOG_LOOKUP_IDX_MAX] = { - 0.00000000f, 0.00000000f, 2.00000000f, 4.75488750f, - 8.00000000f, 11.60964047f, 15.50977500f, 19.65148445f, - 24.00000000f, 28.52932501f, 33.21928095f, 38.05374781f, - 43.01955001f, 48.10571634f, 53.30296891f, 58.60335893f, - 64.00000000f, 69.48686830f, 75.05865003f, 80.71062276f, - 86.43856190f, 92.23866588f, 98.10749561f, 104.04192499f, - 110.03910002f, 116.09640474f, 122.21143267f, 128.38196256f, - 134.60593782f, 140.88144886f, 147.20671787f, 153.58008562f, - 160.00000000f, 166.46500594f, 172.97373660f, 179.52490559f, - 186.11730005f, 192.74977453f, 199.42124551f, 206.13068654f, - 212.87712380f, 219.65963219f, 226.47733176f, 233.32938445f, - 240.21499122f, 247.13338933f, 254.08384998f, 261.06567603f, - 268.07820003f, 275.12078236f, 282.19280949f, 289.29369244f, - 296.42286534f, 303.57978409f, 310.76392512f, 317.97478424f, - 325.21187564f, 332.47473081f, 339.76289772f, 347.07593991f, - 354.41343574f, 361.77497759f, 369.16017124f, 376.56863518f, - 384.00000000f, 391.45390785f, 398.93001188f, 406.42797576f, - 413.94747321f, 421.48818752f, 429.04981119f, 436.63204548f, - 444.23460010f, 451.85719280f, 459.49954906f, 467.16140179f, - 474.84249102f, 482.54256363f, 490.26137307f, 497.99867911f, - 505.75424759f, 513.52785023f, 521.31926438f, 529.12827280f, - 536.95466351f, 544.79822957f, 552.65876890f, 560.53608414f, - 568.42998244f, 576.34027536f, 584.26677867f, 592.20931226f, - 600.16769996f, 608.14176943f, 616.13135206f, 624.13628279f, - 632.15640007f, 640.19154569f, 648.24156472f, 656.30630539f, - 664.38561898f, 672.47935976f, 680.58738488f, 688.70955430f, - 696.84573069f, 704.99577935f, 713.15956818f, 721.33696754f, - 729.52785023f, 737.73209140f, 745.94956849f, 754.18016116f, - 762.42375127f, 770.68022275f, 778.94946161f, 787.23135586f, - 795.52579543f, 803.83267219f, 812.15187982f, 820.48331383f, - 828.82687147f, 837.18245171f, 845.54995518f, 853.92928416f, - 862.32034249f, 870.72303558f, 879.13727036f, 887.56295522f, - 896.00000000f, 904.44831595f, 912.90781569f, 921.37841320f, - 929.86002376f, 938.35256392f, 946.85595152f, 955.37010560f, - 963.89494641f, 972.43039537f, 980.97637504f, 989.53280911f, - 998.09962237f, 1006.67674069f, 1015.26409097f, 1023.86160116f, - 1032.46920021f, 1041.08681805f, 1049.71438560f, 1058.35183469f, - 1066.99909811f, 1075.65610955f, 1084.32280357f, 1092.99911564f, - 1101.68498204f, 1110.38033993f, 1119.08512727f, 1127.79928282f, - 1136.52274614f, 1145.25545758f, 1153.99735821f, 1162.74838989f, - 1171.50849518f, 1180.27761738f, 1189.05570047f, 1197.84268914f, - 1206.63852876f, 1215.44316535f, 1224.25654560f, 1233.07861684f, - 1241.90932703f, 1250.74862473f, 1259.59645914f, 1268.45278005f, - 1277.31753781f, 1286.19068338f, 1295.07216828f, 1303.96194457f, - 1312.85996488f, 1321.76618236f, 1330.68055071f, 1339.60302413f, - 1348.53355734f, 1357.47210556f, 1366.41862452f, 1375.37307041f, - 1384.33539991f, 1393.30557020f, 1402.28353887f, 1411.26926400f, - 1420.26270412f, 1429.26381818f, 1438.27256558f, 1447.28890615f, - 1456.31280014f, 1465.34420819f, 1474.38309138f, 1483.42941118f, - 1492.48312945f, 1501.54420843f, 1510.61261078f, 1519.68829949f, - 1528.77123795f, 1537.86138993f, 1546.95871952f, 1556.06319119f, - 1565.17476976f, 1574.29342040f, 1583.41910860f, 1592.55180020f, - 1601.69146137f, 1610.83805860f, 1619.99155871f, 1629.15192882f, - 1638.31913637f, 1647.49314911f, 1656.67393509f, 1665.86146266f, - 1675.05570047f, 1684.25661744f, 1693.46418280f, 1702.67836605f, - 1711.89913698f, 1721.12646563f, 1730.36032233f, 1739.60067768f, - 1748.84750254f, 1758.10076802f, 1767.36044551f, 1776.62650662f, - 1785.89892323f, 1795.17766747f, 1804.46271172f, 1813.75402857f, - 1823.05159087f, 1832.35537170f, 1841.66534438f, 1850.98148244f, - 1860.30375965f, 1869.63214999f, 1878.96662767f, 1888.30716711f, - 1897.65374295f, 1907.00633003f, 1916.36490342f, 1925.72943838f, - 1935.09991037f, 1944.47629506f, 1953.85856831f, 1963.24670620f, - 1972.64068498f, 1982.04048108f, 1991.44607117f, 2000.85743204f, - 2010.27454072f, 2019.69737440f, 2029.12591044f, 2038.56012640f -}; - -const VP8LPrefixCode kPrefixEncodeCode[PREFIX_LOOKUP_IDX_MAX] = { - { 0, 0}, { 0, 0}, { 1, 0}, { 2, 0}, { 3, 0}, { 4, 1}, { 4, 1}, { 5, 1}, - { 5, 1}, { 6, 2}, { 6, 2}, { 6, 2}, { 6, 2}, { 7, 2}, { 7, 2}, { 7, 2}, - { 7, 2}, { 8, 3}, { 8, 3}, { 8, 3}, { 8, 3}, { 8, 3}, { 8, 3}, { 8, 3}, - { 8, 3}, { 9, 3}, { 9, 3}, { 9, 3}, { 9, 3}, { 9, 3}, { 9, 3}, { 9, 3}, - { 9, 3}, {10, 4}, {10, 4}, {10, 4}, {10, 4}, {10, 4}, {10, 4}, {10, 4}, - {10, 4}, {10, 4}, {10, 4}, {10, 4}, {10, 4}, {10, 4}, {10, 4}, {10, 4}, - {10, 4}, {11, 4}, {11, 4}, {11, 4}, {11, 4}, {11, 4}, {11, 4}, {11, 4}, - {11, 4}, {11, 4}, {11, 4}, {11, 4}, {11, 4}, {11, 4}, {11, 4}, {11, 4}, - {11, 4}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, - {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, - {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, - {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, - {12, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, - {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, - {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, - {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, - {13, 5}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, - {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, - {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, - {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, - {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, - {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, - {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, - {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, - {14, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, - {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, - {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, - {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, - {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, - {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, - {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, - {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, - {15, 6}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, - {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, - {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, - {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, - {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, - {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, - {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, - {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, - {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, - {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, - {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, - {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, - {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, - {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, - {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, - {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, - {16, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, - {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, - {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, - {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, - {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, - {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, - {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, - {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, - {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, - {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, - {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, - {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, - {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, - {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, - {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, - {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, -}; - -const uint8_t kPrefixEncodeExtraBitsValue[PREFIX_LOOKUP_IDX_MAX] = { - 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 2, 3, 0, 1, 2, 3, - 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, - 127, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126 -}; - -static float FastSLog2Slow_C(uint32_t v) { - assert(v >= LOG_LOOKUP_IDX_MAX); - if (v < APPROX_LOG_WITH_CORRECTION_MAX) { -#if !defined(WEBP_HAVE_SLOW_CLZ_CTZ) - // use clz if available - const int log_cnt = BitsLog2Floor(v) - 7; - const uint32_t y = 1 << log_cnt; - int correction = 0; - const float v_f = (float)v; - const uint32_t orig_v = v; - v >>= log_cnt; -#else - int log_cnt = 0; - uint32_t y = 1; - int correction = 0; - const float v_f = (float)v; - const uint32_t orig_v = v; - do { - ++log_cnt; - v = v >> 1; - y = y << 1; - } while (v >= LOG_LOOKUP_IDX_MAX); -#endif - // vf = (2^log_cnt) * Xf; where y = 2^log_cnt and Xf < 256 - // Xf = floor(Xf) * (1 + (v % y) / v) - // log2(Xf) = log2(floor(Xf)) + log2(1 + (v % y) / v) - // The correction factor: log(1 + d) ~ d; for very small d values, so - // log2(1 + (v % y) / v) ~ LOG_2_RECIPROCAL * (v % y)/v - // LOG_2_RECIPROCAL ~ 23/16 - correction = (23 * (orig_v & (y - 1))) >> 4; - return v_f * (kLog2Table[v] + log_cnt) + correction; - } else { - return (float)(LOG_2_RECIPROCAL * v * log((double)v)); - } -} - -static float FastLog2Slow_C(uint32_t v) { - assert(v >= LOG_LOOKUP_IDX_MAX); - if (v < APPROX_LOG_WITH_CORRECTION_MAX) { -#if !defined(WEBP_HAVE_SLOW_CLZ_CTZ) - // use clz if available - const int log_cnt = BitsLog2Floor(v) - 7; - const uint32_t y = 1 << log_cnt; - const uint32_t orig_v = v; - double log_2; - v >>= log_cnt; -#else - int log_cnt = 0; - uint32_t y = 1; - const uint32_t orig_v = v; - double log_2; - do { - ++log_cnt; - v = v >> 1; - y = y << 1; - } while (v >= LOG_LOOKUP_IDX_MAX); -#endif - log_2 = kLog2Table[v] + log_cnt; - if (orig_v >= APPROX_LOG_MAX) { - // Since the division is still expensive, add this correction factor only - // for large values of 'v'. - const int correction = (23 * (orig_v & (y - 1))) >> 4; - log_2 += (double)correction / orig_v; - } - return (float)log_2; - } else { - return (float)(LOG_2_RECIPROCAL * log((double)v)); - } -} - -//------------------------------------------------------------------------------ -// Methods to calculate Entropy (Shannon). - -// Compute the combined Shanon's entropy for distribution {X} and {X+Y} -static float CombinedShannonEntropy_C(const int X[256], const int Y[256]) { - int i; - float retval = 0.f; - int sumX = 0, sumXY = 0; - for (i = 0; i < 256; ++i) { - const int x = X[i]; - if (x != 0) { - const int xy = x + Y[i]; - sumX += x; - retval -= VP8LFastSLog2(x); - sumXY += xy; - retval -= VP8LFastSLog2(xy); - } else if (Y[i] != 0) { - sumXY += Y[i]; - retval -= VP8LFastSLog2(Y[i]); - } - } - retval += VP8LFastSLog2(sumX) + VP8LFastSLog2(sumXY); - return retval; -} - -void VP8LBitEntropyInit(VP8LBitEntropy* const entropy) { - entropy->entropy = 0.; - entropy->sum = 0; - entropy->nonzeros = 0; - entropy->max_val = 0; - entropy->nonzero_code = VP8L_NON_TRIVIAL_SYM; -} - -void VP8LBitsEntropyUnrefined(const uint32_t* const array, int n, - VP8LBitEntropy* const entropy) { - int i; - - VP8LBitEntropyInit(entropy); - - for (i = 0; i < n; ++i) { - if (array[i] != 0) { - entropy->sum += array[i]; - entropy->nonzero_code = i; - ++entropy->nonzeros; - entropy->entropy -= VP8LFastSLog2(array[i]); - if (entropy->max_val < array[i]) { - entropy->max_val = array[i]; - } - } - } - entropy->entropy += VP8LFastSLog2(entropy->sum); -} - -static WEBP_INLINE void GetEntropyUnrefinedHelper( - uint32_t val, int i, uint32_t* const val_prev, int* const i_prev, - VP8LBitEntropy* const bit_entropy, VP8LStreaks* const stats) { - const int streak = i - *i_prev; - - // Gather info for the bit entropy. - if (*val_prev != 0) { - bit_entropy->sum += (*val_prev) * streak; - bit_entropy->nonzeros += streak; - bit_entropy->nonzero_code = *i_prev; - bit_entropy->entropy -= VP8LFastSLog2(*val_prev) * streak; - if (bit_entropy->max_val < *val_prev) { - bit_entropy->max_val = *val_prev; - } - } - - // Gather info for the Huffman cost. - stats->counts[*val_prev != 0] += (streak > 3); - stats->streaks[*val_prev != 0][(streak > 3)] += streak; - - *val_prev = val; - *i_prev = i; -} - -static void GetEntropyUnrefined_C(const uint32_t X[], int length, - VP8LBitEntropy* const bit_entropy, - VP8LStreaks* const stats) { - int i; - int i_prev = 0; - uint32_t x_prev = X[0]; - - memset(stats, 0, sizeof(*stats)); - VP8LBitEntropyInit(bit_entropy); - - for (i = 1; i < length; ++i) { - const uint32_t x = X[i]; - if (x != x_prev) { - GetEntropyUnrefinedHelper(x, i, &x_prev, &i_prev, bit_entropy, stats); - } - } - GetEntropyUnrefinedHelper(0, i, &x_prev, &i_prev, bit_entropy, stats); - - bit_entropy->entropy += VP8LFastSLog2(bit_entropy->sum); -} - -static void GetCombinedEntropyUnrefined_C(const uint32_t X[], - const uint32_t Y[], - int length, - VP8LBitEntropy* const bit_entropy, - VP8LStreaks* const stats) { - int i = 1; - int i_prev = 0; - uint32_t xy_prev = X[0] + Y[0]; - - memset(stats, 0, sizeof(*stats)); - VP8LBitEntropyInit(bit_entropy); - - for (i = 1; i < length; ++i) { - const uint32_t xy = X[i] + Y[i]; - if (xy != xy_prev) { - GetEntropyUnrefinedHelper(xy, i, &xy_prev, &i_prev, bit_entropy, stats); - } - } - GetEntropyUnrefinedHelper(0, i, &xy_prev, &i_prev, bit_entropy, stats); - - bit_entropy->entropy += VP8LFastSLog2(bit_entropy->sum); -} - -//------------------------------------------------------------------------------ - -void VP8LSubtractGreenFromBlueAndRed_C(uint32_t* argb_data, int num_pixels) { - int i; - for (i = 0; i < num_pixels; ++i) { - const int argb = (int)argb_data[i]; - const int green = (argb >> 8) & 0xff; - const uint32_t new_r = (((argb >> 16) & 0xff) - green) & 0xff; - const uint32_t new_b = (((argb >> 0) & 0xff) - green) & 0xff; - argb_data[i] = ((uint32_t)argb & 0xff00ff00u) | (new_r << 16) | new_b; - } -} - -static WEBP_INLINE int ColorTransformDelta(int8_t color_pred, int8_t color) { - return ((int)color_pred * color) >> 5; -} - -static WEBP_INLINE int8_t U32ToS8(uint32_t v) { - return (int8_t)(v & 0xff); -} - -void VP8LTransformColor_C(const VP8LMultipliers* const m, uint32_t* data, - int num_pixels) { - int i; - for (i = 0; i < num_pixels; ++i) { - const uint32_t argb = data[i]; - const int8_t green = U32ToS8(argb >> 8); - const int8_t red = U32ToS8(argb >> 16); - int new_red = red & 0xff; - int new_blue = argb & 0xff; - new_red -= ColorTransformDelta((int8_t)m->green_to_red_, green); - new_red &= 0xff; - new_blue -= ColorTransformDelta((int8_t)m->green_to_blue_, green); - new_blue -= ColorTransformDelta((int8_t)m->red_to_blue_, red); - new_blue &= 0xff; - data[i] = (argb & 0xff00ff00u) | (new_red << 16) | (new_blue); - } -} - -static WEBP_INLINE uint8_t TransformColorRed(uint8_t green_to_red, - uint32_t argb) { - const int8_t green = U32ToS8(argb >> 8); - int new_red = argb >> 16; - new_red -= ColorTransformDelta((int8_t)green_to_red, green); - return (new_red & 0xff); -} - -static WEBP_INLINE uint8_t TransformColorBlue(uint8_t green_to_blue, - uint8_t red_to_blue, - uint32_t argb) { - const int8_t green = U32ToS8(argb >> 8); - const int8_t red = U32ToS8(argb >> 16); - int new_blue = argb & 0xff; - new_blue -= ColorTransformDelta((int8_t)green_to_blue, green); - new_blue -= ColorTransformDelta((int8_t)red_to_blue, red); - return (new_blue & 0xff); -} - -void VP8LCollectColorRedTransforms_C(const uint32_t* argb, int stride, - int tile_width, int tile_height, - int green_to_red, int histo[]) { - while (tile_height-- > 0) { - int x; - for (x = 0; x < tile_width; ++x) { - ++histo[TransformColorRed((uint8_t)green_to_red, argb[x])]; - } - argb += stride; - } -} - -void VP8LCollectColorBlueTransforms_C(const uint32_t* argb, int stride, - int tile_width, int tile_height, - int green_to_blue, int red_to_blue, - int histo[]) { - while (tile_height-- > 0) { - int x; - for (x = 0; x < tile_width; ++x) { - ++histo[TransformColorBlue((uint8_t)green_to_blue, (uint8_t)red_to_blue, - argb[x])]; - } - argb += stride; - } -} - -//------------------------------------------------------------------------------ - -static int VectorMismatch_C(const uint32_t* const array1, - const uint32_t* const array2, int length) { - int match_len = 0; - - while (match_len < length && array1[match_len] == array2[match_len]) { - ++match_len; - } - return match_len; -} - -// Bundles multiple (1, 2, 4 or 8) pixels into a single pixel. -void VP8LBundleColorMap_C(const uint8_t* const row, int width, int xbits, - uint32_t* dst) { - int x; - if (xbits > 0) { - const int bit_depth = 1 << (3 - xbits); - const int mask = (1 << xbits) - 1; - uint32_t code = 0xff000000; - for (x = 0; x < width; ++x) { - const int xsub = x & mask; - if (xsub == 0) { - code = 0xff000000; - } - code |= row[x] << (8 + bit_depth * xsub); - dst[x >> xbits] = code; - } - } else { - for (x = 0; x < width; ++x) dst[x] = 0xff000000 | (row[x] << 8); - } -} - -//------------------------------------------------------------------------------ - -static uint32_t ExtraCost_C(const uint32_t* population, int length) { - int i; - uint32_t cost = population[4] + population[5]; - assert(length % 2 == 0); - for (i = 2; i < length / 2 - 1; ++i) { - cost += i * (population[2 * i + 2] + population[2 * i + 3]); - } - return cost; -} - -static uint32_t ExtraCostCombined_C(const uint32_t* X, const uint32_t* Y, - int length) { - int i; - uint32_t cost = X[4] + Y[4] + X[5] + Y[5]; - assert(length % 2 == 0); - for (i = 2; i < length / 2 - 1; ++i) { - const int xy0 = X[2 * i + 2] + Y[2 * i + 2]; - const int xy1 = X[2 * i + 3] + Y[2 * i + 3]; - cost += i * (xy0 + xy1); - } - return cost; -} - -//------------------------------------------------------------------------------ - -static void AddVector_C(const uint32_t* a, const uint32_t* b, uint32_t* out, - int size) { - int i; - for (i = 0; i < size; ++i) out[i] = a[i] + b[i]; -} - -static void AddVectorEq_C(const uint32_t* a, uint32_t* out, int size) { - int i; - for (i = 0; i < size; ++i) out[i] += a[i]; -} - -#define ADD(X, ARG, LEN) do { \ - if (a->is_used_[X]) { \ - if (b->is_used_[X]) { \ - VP8LAddVector(a->ARG, b->ARG, out->ARG, (LEN)); \ - } else { \ - memcpy(&out->ARG[0], &a->ARG[0], (LEN) * sizeof(out->ARG[0])); \ - } \ - } else if (b->is_used_[X]) { \ - memcpy(&out->ARG[0], &b->ARG[0], (LEN) * sizeof(out->ARG[0])); \ - } else { \ - memset(&out->ARG[0], 0, (LEN) * sizeof(out->ARG[0])); \ - } \ -} while (0) - -#define ADD_EQ(X, ARG, LEN) do { \ - if (a->is_used_[X]) { \ - if (out->is_used_[X]) { \ - VP8LAddVectorEq(a->ARG, out->ARG, (LEN)); \ - } else { \ - memcpy(&out->ARG[0], &a->ARG[0], (LEN) * sizeof(out->ARG[0])); \ - } \ - } \ -} while (0) - -void VP8LHistogramAdd(const VP8LHistogram* const a, - const VP8LHistogram* const b, VP8LHistogram* const out) { - int i; - const int literal_size = VP8LHistogramNumCodes(a->palette_code_bits_); - assert(a->palette_code_bits_ == b->palette_code_bits_); - - if (b != out) { - ADD(0, literal_, literal_size); - ADD(1, red_, NUM_LITERAL_CODES); - ADD(2, blue_, NUM_LITERAL_CODES); - ADD(3, alpha_, NUM_LITERAL_CODES); - ADD(4, distance_, NUM_DISTANCE_CODES); - for (i = 0; i < 5; ++i) { - out->is_used_[i] = (a->is_used_[i] | b->is_used_[i]); - } - } else { - ADD_EQ(0, literal_, literal_size); - ADD_EQ(1, red_, NUM_LITERAL_CODES); - ADD_EQ(2, blue_, NUM_LITERAL_CODES); - ADD_EQ(3, alpha_, NUM_LITERAL_CODES); - ADD_EQ(4, distance_, NUM_DISTANCE_CODES); - for (i = 0; i < 5; ++i) out->is_used_[i] |= a->is_used_[i]; - } -} -#undef ADD -#undef ADD_EQ - -//------------------------------------------------------------------------------ -// Image transforms. - -static void PredictorSub0_C(const uint32_t* in, const uint32_t* upper, - int num_pixels, uint32_t* out) { - int i; - for (i = 0; i < num_pixels; ++i) out[i] = VP8LSubPixels(in[i], ARGB_BLACK); - (void)upper; -} - -static void PredictorSub1_C(const uint32_t* in, const uint32_t* upper, - int num_pixels, uint32_t* out) { - int i; - for (i = 0; i < num_pixels; ++i) out[i] = VP8LSubPixels(in[i], in[i - 1]); - (void)upper; -} - -// It subtracts the prediction from the input pixel and stores the residual -// in the output pixel. -#define GENERATE_PREDICTOR_SUB(PREDICTOR_I) \ -static void PredictorSub##PREDICTOR_I##_C(const uint32_t* in, \ - const uint32_t* upper, \ - int num_pixels, uint32_t* out) { \ - int x; \ - assert(upper != NULL); \ - for (x = 0; x < num_pixels; ++x) { \ - const uint32_t pred = \ - VP8LPredictor##PREDICTOR_I##_C(&in[x - 1], upper + x); \ - out[x] = VP8LSubPixels(in[x], pred); \ - } \ -} - -GENERATE_PREDICTOR_SUB(2) -GENERATE_PREDICTOR_SUB(3) -GENERATE_PREDICTOR_SUB(4) -GENERATE_PREDICTOR_SUB(5) -GENERATE_PREDICTOR_SUB(6) -GENERATE_PREDICTOR_SUB(7) -GENERATE_PREDICTOR_SUB(8) -GENERATE_PREDICTOR_SUB(9) -GENERATE_PREDICTOR_SUB(10) -GENERATE_PREDICTOR_SUB(11) -GENERATE_PREDICTOR_SUB(12) -GENERATE_PREDICTOR_SUB(13) - -//------------------------------------------------------------------------------ - -VP8LProcessEncBlueAndRedFunc VP8LSubtractGreenFromBlueAndRed; - -VP8LTransformColorFunc VP8LTransformColor; - -VP8LCollectColorBlueTransformsFunc VP8LCollectColorBlueTransforms; -VP8LCollectColorRedTransformsFunc VP8LCollectColorRedTransforms; - -VP8LFastLog2SlowFunc VP8LFastLog2Slow; -VP8LFastLog2SlowFunc VP8LFastSLog2Slow; - -VP8LCostFunc VP8LExtraCost; -VP8LCostCombinedFunc VP8LExtraCostCombined; -VP8LCombinedShannonEntropyFunc VP8LCombinedShannonEntropy; - -VP8LGetEntropyUnrefinedFunc VP8LGetEntropyUnrefined; -VP8LGetCombinedEntropyUnrefinedFunc VP8LGetCombinedEntropyUnrefined; - -VP8LAddVectorFunc VP8LAddVector; -VP8LAddVectorEqFunc VP8LAddVectorEq; - -VP8LVectorMismatchFunc VP8LVectorMismatch; -VP8LBundleColorMapFunc VP8LBundleColorMap; - -VP8LPredictorAddSubFunc VP8LPredictorsSub[16]; -VP8LPredictorAddSubFunc VP8LPredictorsSub_C[16]; - -extern VP8CPUInfo VP8GetCPUInfo; -extern void VP8LEncDspInitSSE2(void); -extern void VP8LEncDspInitSSE41(void); -extern void VP8LEncDspInitNEON(void); -extern void VP8LEncDspInitMIPS32(void); -extern void VP8LEncDspInitMIPSdspR2(void); -extern void VP8LEncDspInitMSA(void); - -WEBP_DSP_INIT_FUNC(VP8LEncDspInit) { - VP8LDspInit(); - -#if !WEBP_NEON_OMIT_C_CODE - VP8LSubtractGreenFromBlueAndRed = VP8LSubtractGreenFromBlueAndRed_C; - - VP8LTransformColor = VP8LTransformColor_C; -#endif - - VP8LCollectColorBlueTransforms = VP8LCollectColorBlueTransforms_C; - VP8LCollectColorRedTransforms = VP8LCollectColorRedTransforms_C; - - VP8LFastLog2Slow = FastLog2Slow_C; - VP8LFastSLog2Slow = FastSLog2Slow_C; - - VP8LExtraCost = ExtraCost_C; - VP8LExtraCostCombined = ExtraCostCombined_C; - VP8LCombinedShannonEntropy = CombinedShannonEntropy_C; - - VP8LGetEntropyUnrefined = GetEntropyUnrefined_C; - VP8LGetCombinedEntropyUnrefined = GetCombinedEntropyUnrefined_C; - - VP8LAddVector = AddVector_C; - VP8LAddVectorEq = AddVectorEq_C; - - VP8LVectorMismatch = VectorMismatch_C; - VP8LBundleColorMap = VP8LBundleColorMap_C; - - VP8LPredictorsSub[0] = PredictorSub0_C; - VP8LPredictorsSub[1] = PredictorSub1_C; - VP8LPredictorsSub[2] = PredictorSub2_C; - VP8LPredictorsSub[3] = PredictorSub3_C; - VP8LPredictorsSub[4] = PredictorSub4_C; - VP8LPredictorsSub[5] = PredictorSub5_C; - VP8LPredictorsSub[6] = PredictorSub6_C; - VP8LPredictorsSub[7] = PredictorSub7_C; - VP8LPredictorsSub[8] = PredictorSub8_C; - VP8LPredictorsSub[9] = PredictorSub9_C; - VP8LPredictorsSub[10] = PredictorSub10_C; - VP8LPredictorsSub[11] = PredictorSub11_C; - VP8LPredictorsSub[12] = PredictorSub12_C; - VP8LPredictorsSub[13] = PredictorSub13_C; - VP8LPredictorsSub[14] = PredictorSub0_C; // <- padding security sentinels - VP8LPredictorsSub[15] = PredictorSub0_C; - - VP8LPredictorsSub_C[0] = PredictorSub0_C; - VP8LPredictorsSub_C[1] = PredictorSub1_C; - VP8LPredictorsSub_C[2] = PredictorSub2_C; - VP8LPredictorsSub_C[3] = PredictorSub3_C; - VP8LPredictorsSub_C[4] = PredictorSub4_C; - VP8LPredictorsSub_C[5] = PredictorSub5_C; - VP8LPredictorsSub_C[6] = PredictorSub6_C; - VP8LPredictorsSub_C[7] = PredictorSub7_C; - VP8LPredictorsSub_C[8] = PredictorSub8_C; - VP8LPredictorsSub_C[9] = PredictorSub9_C; - VP8LPredictorsSub_C[10] = PredictorSub10_C; - VP8LPredictorsSub_C[11] = PredictorSub11_C; - VP8LPredictorsSub_C[12] = PredictorSub12_C; - VP8LPredictorsSub_C[13] = PredictorSub13_C; - VP8LPredictorsSub_C[14] = PredictorSub0_C; // <- padding security sentinels - VP8LPredictorsSub_C[15] = PredictorSub0_C; - - // If defined, use CPUInfo() to overwrite some pointers with faster versions. - if (VP8GetCPUInfo != NULL) { -#if defined(WEBP_HAVE_SSE2) - if (VP8GetCPUInfo(kSSE2)) { - VP8LEncDspInitSSE2(); -#if defined(WEBP_HAVE_SSE41) - if (VP8GetCPUInfo(kSSE4_1)) { - VP8LEncDspInitSSE41(); - } -#endif - } -#endif -#if defined(WEBP_USE_MIPS32) - if (VP8GetCPUInfo(kMIPS32)) { - VP8LEncDspInitMIPS32(); - } -#endif -#if defined(WEBP_USE_MIPS_DSP_R2) - if (VP8GetCPUInfo(kMIPSdspR2)) { - VP8LEncDspInitMIPSdspR2(); - } -#endif -#if defined(WEBP_USE_MSA) - if (VP8GetCPUInfo(kMSA)) { - VP8LEncDspInitMSA(); - } -#endif - } - -#if defined(WEBP_HAVE_NEON) - if (WEBP_NEON_OMIT_C_CODE || - (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) { - VP8LEncDspInitNEON(); - } -#endif - - assert(VP8LSubtractGreenFromBlueAndRed != NULL); - assert(VP8LTransformColor != NULL); - assert(VP8LCollectColorBlueTransforms != NULL); - assert(VP8LCollectColorRedTransforms != NULL); - assert(VP8LFastLog2Slow != NULL); - assert(VP8LFastSLog2Slow != NULL); - assert(VP8LExtraCost != NULL); - assert(VP8LExtraCostCombined != NULL); - assert(VP8LCombinedShannonEntropy != NULL); - assert(VP8LGetEntropyUnrefined != NULL); - assert(VP8LGetCombinedEntropyUnrefined != NULL); - assert(VP8LAddVector != NULL); - assert(VP8LAddVectorEq != NULL); - assert(VP8LVectorMismatch != NULL); - assert(VP8LBundleColorMap != NULL); - assert(VP8LPredictorsSub[0] != NULL); - assert(VP8LPredictorsSub[1] != NULL); - assert(VP8LPredictorsSub[2] != NULL); - assert(VP8LPredictorsSub[3] != NULL); - assert(VP8LPredictorsSub[4] != NULL); - assert(VP8LPredictorsSub[5] != NULL); - assert(VP8LPredictorsSub[6] != NULL); - assert(VP8LPredictorsSub[7] != NULL); - assert(VP8LPredictorsSub[8] != NULL); - assert(VP8LPredictorsSub[9] != NULL); - assert(VP8LPredictorsSub[10] != NULL); - assert(VP8LPredictorsSub[11] != NULL); - assert(VP8LPredictorsSub[12] != NULL); - assert(VP8LPredictorsSub[13] != NULL); - assert(VP8LPredictorsSub[14] != NULL); - assert(VP8LPredictorsSub[15] != NULL); - assert(VP8LPredictorsSub_C[0] != NULL); - assert(VP8LPredictorsSub_C[1] != NULL); - assert(VP8LPredictorsSub_C[2] != NULL); - assert(VP8LPredictorsSub_C[3] != NULL); - assert(VP8LPredictorsSub_C[4] != NULL); - assert(VP8LPredictorsSub_C[5] != NULL); - assert(VP8LPredictorsSub_C[6] != NULL); - assert(VP8LPredictorsSub_C[7] != NULL); - assert(VP8LPredictorsSub_C[8] != NULL); - assert(VP8LPredictorsSub_C[9] != NULL); - assert(VP8LPredictorsSub_C[10] != NULL); - assert(VP8LPredictorsSub_C[11] != NULL); - assert(VP8LPredictorsSub_C[12] != NULL); - assert(VP8LPredictorsSub_C[13] != NULL); - assert(VP8LPredictorsSub_C[14] != NULL); - assert(VP8LPredictorsSub_C[15] != NULL); -} - -//------------------------------------------------------------------------------ diff --git a/libwebp/src/dsp/lossless_enc_mips32.c b/libwebp/src/dsp/lossless_enc_mips32.c deleted file mode 100644 index e10f12da..00000000 --- a/libwebp/src/dsp/lossless_enc_mips32.c +++ /dev/null @@ -1,397 +0,0 @@ -// Copyright 2015 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// MIPS version of lossless functions -// -// Author(s): Djordje Pesut (djordje.pesut@imgtec.com) -// Jovan Zelincevic (jovan.zelincevic@imgtec.com) - -#include "src/dsp/dsp.h" -#include "src/dsp/lossless.h" -#include "src/dsp/lossless_common.h" - -#if defined(WEBP_USE_MIPS32) - -#include -#include -#include -#include - -static float FastSLog2Slow_MIPS32(uint32_t v) { - assert(v >= LOG_LOOKUP_IDX_MAX); - if (v < APPROX_LOG_WITH_CORRECTION_MAX) { - uint32_t log_cnt, y, correction; - const int c24 = 24; - const float v_f = (float)v; - uint32_t temp; - - // Xf = 256 = 2^8 - // log_cnt is index of leading one in upper 24 bits - __asm__ volatile( - "clz %[log_cnt], %[v] \n\t" - "addiu %[y], $zero, 1 \n\t" - "subu %[log_cnt], %[c24], %[log_cnt] \n\t" - "sllv %[y], %[y], %[log_cnt] \n\t" - "srlv %[temp], %[v], %[log_cnt] \n\t" - : [log_cnt]"=&r"(log_cnt), [y]"=&r"(y), - [temp]"=r"(temp) - : [c24]"r"(c24), [v]"r"(v) - ); - - // vf = (2^log_cnt) * Xf; where y = 2^log_cnt and Xf < 256 - // Xf = floor(Xf) * (1 + (v % y) / v) - // log2(Xf) = log2(floor(Xf)) + log2(1 + (v % y) / v) - // The correction factor: log(1 + d) ~ d; for very small d values, so - // log2(1 + (v % y) / v) ~ LOG_2_RECIPROCAL * (v % y)/v - // LOG_2_RECIPROCAL ~ 23/16 - - // (v % y) = (v % 2^log_cnt) = v & (2^log_cnt - 1) - correction = (23 * (v & (y - 1))) >> 4; - return v_f * (kLog2Table[temp] + log_cnt) + correction; - } else { - return (float)(LOG_2_RECIPROCAL * v * log((double)v)); - } -} - -static float FastLog2Slow_MIPS32(uint32_t v) { - assert(v >= LOG_LOOKUP_IDX_MAX); - if (v < APPROX_LOG_WITH_CORRECTION_MAX) { - uint32_t log_cnt, y; - const int c24 = 24; - double log_2; - uint32_t temp; - - __asm__ volatile( - "clz %[log_cnt], %[v] \n\t" - "addiu %[y], $zero, 1 \n\t" - "subu %[log_cnt], %[c24], %[log_cnt] \n\t" - "sllv %[y], %[y], %[log_cnt] \n\t" - "srlv %[temp], %[v], %[log_cnt] \n\t" - : [log_cnt]"=&r"(log_cnt), [y]"=&r"(y), - [temp]"=r"(temp) - : [c24]"r"(c24), [v]"r"(v) - ); - - log_2 = kLog2Table[temp] + log_cnt; - if (v >= APPROX_LOG_MAX) { - // Since the division is still expensive, add this correction factor only - // for large values of 'v'. - - const uint32_t correction = (23 * (v & (y - 1))) >> 4; - log_2 += (double)correction / v; - } - return (float)log_2; - } else { - return (float)(LOG_2_RECIPROCAL * log((double)v)); - } -} - -// C version of this function: -// int i = 0; -// int64_t cost = 0; -// const uint32_t* pop = &population[4]; -// const uint32_t* LoopEnd = &population[length]; -// while (pop != LoopEnd) { -// ++i; -// cost += i * *pop; -// cost += i * *(pop + 1); -// pop += 2; -// } -// return cost; -static uint32_t ExtraCost_MIPS32(const uint32_t* const population, int length) { - int i, temp0, temp1; - const uint32_t* pop = &population[4]; - const uint32_t* const LoopEnd = &population[length]; - - __asm__ volatile( - "mult $zero, $zero \n\t" - "xor %[i], %[i], %[i] \n\t" - "beq %[pop], %[LoopEnd], 2f \n\t" - "1: \n\t" - "lw %[temp0], 0(%[pop]) \n\t" - "lw %[temp1], 4(%[pop]) \n\t" - "addiu %[i], %[i], 1 \n\t" - "addiu %[pop], %[pop], 8 \n\t" - "madd %[i], %[temp0] \n\t" - "madd %[i], %[temp1] \n\t" - "bne %[pop], %[LoopEnd], 1b \n\t" - "2: \n\t" - "mfhi %[temp0] \n\t" - "mflo %[temp1] \n\t" - : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), - [i]"=&r"(i), [pop]"+r"(pop) - : [LoopEnd]"r"(LoopEnd) - : "memory", "hi", "lo" - ); - - return ((int64_t)temp0 << 32 | temp1); -} - -// C version of this function: -// int i = 0; -// int64_t cost = 0; -// const uint32_t* pX = &X[4]; -// const uint32_t* pY = &Y[4]; -// const uint32_t* LoopEnd = &X[length]; -// while (pX != LoopEnd) { -// const uint32_t xy0 = *pX + *pY; -// const uint32_t xy1 = *(pX + 1) + *(pY + 1); -// ++i; -// cost += i * xy0; -// cost += i * xy1; -// pX += 2; -// pY += 2; -// } -// return cost; -static uint32_t ExtraCostCombined_MIPS32(const uint32_t* const X, - const uint32_t* const Y, int length) { - int i, temp0, temp1, temp2, temp3; - const uint32_t* pX = &X[4]; - const uint32_t* pY = &Y[4]; - const uint32_t* const LoopEnd = &X[length]; - - __asm__ volatile( - "mult $zero, $zero \n\t" - "xor %[i], %[i], %[i] \n\t" - "beq %[pX], %[LoopEnd], 2f \n\t" - "1: \n\t" - "lw %[temp0], 0(%[pX]) \n\t" - "lw %[temp1], 0(%[pY]) \n\t" - "lw %[temp2], 4(%[pX]) \n\t" - "lw %[temp3], 4(%[pY]) \n\t" - "addiu %[i], %[i], 1 \n\t" - "addu %[temp0], %[temp0], %[temp1] \n\t" - "addu %[temp2], %[temp2], %[temp3] \n\t" - "addiu %[pX], %[pX], 8 \n\t" - "addiu %[pY], %[pY], 8 \n\t" - "madd %[i], %[temp0] \n\t" - "madd %[i], %[temp2] \n\t" - "bne %[pX], %[LoopEnd], 1b \n\t" - "2: \n\t" - "mfhi %[temp0] \n\t" - "mflo %[temp1] \n\t" - : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), - [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), - [i]"=&r"(i), [pX]"+r"(pX), [pY]"+r"(pY) - : [LoopEnd]"r"(LoopEnd) - : "memory", "hi", "lo" - ); - - return ((int64_t)temp0 << 32 | temp1); -} - -#define HUFFMAN_COST_PASS \ - __asm__ volatile( \ - "sll %[temp1], %[temp0], 3 \n\t" \ - "addiu %[temp3], %[streak], -3 \n\t" \ - "addu %[temp2], %[pstreaks], %[temp1] \n\t" \ - "blez %[temp3], 1f \n\t" \ - "srl %[temp1], %[temp1], 1 \n\t" \ - "addu %[temp3], %[pcnts], %[temp1] \n\t" \ - "lw %[temp0], 4(%[temp2]) \n\t" \ - "lw %[temp1], 0(%[temp3]) \n\t" \ - "addu %[temp0], %[temp0], %[streak] \n\t" \ - "addiu %[temp1], %[temp1], 1 \n\t" \ - "sw %[temp0], 4(%[temp2]) \n\t" \ - "sw %[temp1], 0(%[temp3]) \n\t" \ - "b 2f \n\t" \ - "1: \n\t" \ - "lw %[temp0], 0(%[temp2]) \n\t" \ - "addu %[temp0], %[temp0], %[streak] \n\t" \ - "sw %[temp0], 0(%[temp2]) \n\t" \ - "2: \n\t" \ - : [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), \ - [temp3]"=&r"(temp3), [temp0]"+r"(temp0) \ - : [pstreaks]"r"(pstreaks), [pcnts]"r"(pcnts), \ - [streak]"r"(streak) \ - : "memory" \ - ); - -// Returns the various RLE counts -static WEBP_INLINE void GetEntropyUnrefinedHelper( - uint32_t val, int i, uint32_t* const val_prev, int* const i_prev, - VP8LBitEntropy* const bit_entropy, VP8LStreaks* const stats) { - int* const pstreaks = &stats->streaks[0][0]; - int* const pcnts = &stats->counts[0]; - int temp0, temp1, temp2, temp3; - const int streak = i - *i_prev; - - // Gather info for the bit entropy. - if (*val_prev != 0) { - bit_entropy->sum += (*val_prev) * streak; - bit_entropy->nonzeros += streak; - bit_entropy->nonzero_code = *i_prev; - bit_entropy->entropy -= VP8LFastSLog2(*val_prev) * streak; - if (bit_entropy->max_val < *val_prev) { - bit_entropy->max_val = *val_prev; - } - } - - // Gather info for the Huffman cost. - temp0 = (*val_prev != 0); - HUFFMAN_COST_PASS - - *val_prev = val; - *i_prev = i; -} - -static void GetEntropyUnrefined_MIPS32(const uint32_t X[], int length, - VP8LBitEntropy* const bit_entropy, - VP8LStreaks* const stats) { - int i; - int i_prev = 0; - uint32_t x_prev = X[0]; - - memset(stats, 0, sizeof(*stats)); - VP8LBitEntropyInit(bit_entropy); - - for (i = 1; i < length; ++i) { - const uint32_t x = X[i]; - if (x != x_prev) { - GetEntropyUnrefinedHelper(x, i, &x_prev, &i_prev, bit_entropy, stats); - } - } - GetEntropyUnrefinedHelper(0, i, &x_prev, &i_prev, bit_entropy, stats); - - bit_entropy->entropy += VP8LFastSLog2(bit_entropy->sum); -} - -static void GetCombinedEntropyUnrefined_MIPS32(const uint32_t X[], - const uint32_t Y[], - int length, - VP8LBitEntropy* const entropy, - VP8LStreaks* const stats) { - int i = 1; - int i_prev = 0; - uint32_t xy_prev = X[0] + Y[0]; - - memset(stats, 0, sizeof(*stats)); - VP8LBitEntropyInit(entropy); - - for (i = 1; i < length; ++i) { - const uint32_t xy = X[i] + Y[i]; - if (xy != xy_prev) { - GetEntropyUnrefinedHelper(xy, i, &xy_prev, &i_prev, entropy, stats); - } - } - GetEntropyUnrefinedHelper(0, i, &xy_prev, &i_prev, entropy, stats); - - entropy->entropy += VP8LFastSLog2(entropy->sum); -} - -#define ASM_START \ - __asm__ volatile( \ - ".set push \n\t" \ - ".set at \n\t" \ - ".set macro \n\t" \ - "1: \n\t" - -// P2 = P0 + P1 -// A..D - offsets -// E - temp variable to tell macro -// if pointer should be incremented -// literal_ and successive histograms could be unaligned -// so we must use ulw and usw -#define ADD_TO_OUT(A, B, C, D, E, P0, P1, P2) \ - "ulw %[temp0], " #A "(%[" #P0 "]) \n\t" \ - "ulw %[temp1], " #B "(%[" #P0 "]) \n\t" \ - "ulw %[temp2], " #C "(%[" #P0 "]) \n\t" \ - "ulw %[temp3], " #D "(%[" #P0 "]) \n\t" \ - "ulw %[temp4], " #A "(%[" #P1 "]) \n\t" \ - "ulw %[temp5], " #B "(%[" #P1 "]) \n\t" \ - "ulw %[temp6], " #C "(%[" #P1 "]) \n\t" \ - "ulw %[temp7], " #D "(%[" #P1 "]) \n\t" \ - "addu %[temp4], %[temp4], %[temp0] \n\t" \ - "addu %[temp5], %[temp5], %[temp1] \n\t" \ - "addu %[temp6], %[temp6], %[temp2] \n\t" \ - "addu %[temp7], %[temp7], %[temp3] \n\t" \ - "addiu %[" #P0 "], %[" #P0 "], 16 \n\t" \ - ".if " #E " == 1 \n\t" \ - "addiu %[" #P1 "], %[" #P1 "], 16 \n\t" \ - ".endif \n\t" \ - "usw %[temp4], " #A "(%[" #P2 "]) \n\t" \ - "usw %[temp5], " #B "(%[" #P2 "]) \n\t" \ - "usw %[temp6], " #C "(%[" #P2 "]) \n\t" \ - "usw %[temp7], " #D "(%[" #P2 "]) \n\t" \ - "addiu %[" #P2 "], %[" #P2 "], 16 \n\t" \ - "bne %[" #P0 "], %[LoopEnd], 1b \n\t" \ - ".set pop \n\t" \ - -#define ASM_END_COMMON_0 \ - : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), \ - [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), \ - [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), \ - [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), \ - [pa]"+r"(pa), [pout]"+r"(pout) - -#define ASM_END_COMMON_1 \ - : [LoopEnd]"r"(LoopEnd) \ - : "memory", "at" \ - ); - -#define ASM_END_0 \ - ASM_END_COMMON_0 \ - , [pb]"+r"(pb) \ - ASM_END_COMMON_1 - -#define ASM_END_1 \ - ASM_END_COMMON_0 \ - ASM_END_COMMON_1 - -static void AddVector_MIPS32(const uint32_t* pa, const uint32_t* pb, - uint32_t* pout, int size) { - uint32_t temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7; - const int end = ((size) / 4) * 4; - const uint32_t* const LoopEnd = pa + end; - int i; - ASM_START - ADD_TO_OUT(0, 4, 8, 12, 1, pa, pb, pout) - ASM_END_0 - for (i = 0; i < size - end; ++i) pout[i] = pa[i] + pb[i]; -} - -static void AddVectorEq_MIPS32(const uint32_t* pa, uint32_t* pout, int size) { - uint32_t temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7; - const int end = ((size) / 4) * 4; - const uint32_t* const LoopEnd = pa + end; - int i; - ASM_START - ADD_TO_OUT(0, 4, 8, 12, 0, pa, pout, pout) - ASM_END_1 - for (i = 0; i < size - end; ++i) pout[i] += pa[i]; -} - -#undef ASM_END_1 -#undef ASM_END_0 -#undef ASM_END_COMMON_1 -#undef ASM_END_COMMON_0 -#undef ADD_TO_OUT -#undef ASM_START - -//------------------------------------------------------------------------------ -// Entry point - -extern void VP8LEncDspInitMIPS32(void); - -WEBP_TSAN_IGNORE_FUNCTION void VP8LEncDspInitMIPS32(void) { - VP8LFastSLog2Slow = FastSLog2Slow_MIPS32; - VP8LFastLog2Slow = FastLog2Slow_MIPS32; - VP8LExtraCost = ExtraCost_MIPS32; - VP8LExtraCostCombined = ExtraCostCombined_MIPS32; - VP8LGetEntropyUnrefined = GetEntropyUnrefined_MIPS32; - VP8LGetCombinedEntropyUnrefined = GetCombinedEntropyUnrefined_MIPS32; - VP8LAddVector = AddVector_MIPS32; - VP8LAddVectorEq = AddVectorEq_MIPS32; -} - -#else // !WEBP_USE_MIPS32 - -WEBP_DSP_INIT_STUB(VP8LEncDspInitMIPS32) - -#endif // WEBP_USE_MIPS32 diff --git a/libwebp/src/dsp/lossless_enc_mips_dsp_r2.c b/libwebp/src/dsp/lossless_enc_mips_dsp_r2.c deleted file mode 100644 index 5855e6ae..00000000 --- a/libwebp/src/dsp/lossless_enc_mips_dsp_r2.c +++ /dev/null @@ -1,281 +0,0 @@ -// Copyright 2015 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Image transform methods for lossless encoder. -// -// Author(s): Djordje Pesut (djordje.pesut@imgtec.com) -// Jovan Zelincevic (jovan.zelincevic@imgtec.com) - -#include "src/dsp/dsp.h" - -#if defined(WEBP_USE_MIPS_DSP_R2) - -#include "src/dsp/lossless.h" - -static void SubtractGreenFromBlueAndRed_MIPSdspR2(uint32_t* argb_data, - int num_pixels) { - uint32_t temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7; - uint32_t* const p_loop1_end = argb_data + (num_pixels & ~3); - uint32_t* const p_loop2_end = p_loop1_end + (num_pixels & 3); - __asm__ volatile ( - ".set push \n\t" - ".set noreorder \n\t" - "beq %[argb_data], %[p_loop1_end], 3f \n\t" - " nop \n\t" - "0: \n\t" - "lw %[temp0], 0(%[argb_data]) \n\t" - "lw %[temp1], 4(%[argb_data]) \n\t" - "lw %[temp2], 8(%[argb_data]) \n\t" - "lw %[temp3], 12(%[argb_data]) \n\t" - "ext %[temp4], %[temp0], 8, 8 \n\t" - "ext %[temp5], %[temp1], 8, 8 \n\t" - "ext %[temp6], %[temp2], 8, 8 \n\t" - "ext %[temp7], %[temp3], 8, 8 \n\t" - "addiu %[argb_data], %[argb_data], 16 \n\t" - "replv.ph %[temp4], %[temp4] \n\t" - "replv.ph %[temp5], %[temp5] \n\t" - "replv.ph %[temp6], %[temp6] \n\t" - "replv.ph %[temp7], %[temp7] \n\t" - "subu.qb %[temp0], %[temp0], %[temp4] \n\t" - "subu.qb %[temp1], %[temp1], %[temp5] \n\t" - "subu.qb %[temp2], %[temp2], %[temp6] \n\t" - "subu.qb %[temp3], %[temp3], %[temp7] \n\t" - "sw %[temp0], -16(%[argb_data]) \n\t" - "sw %[temp1], -12(%[argb_data]) \n\t" - "sw %[temp2], -8(%[argb_data]) \n\t" - "bne %[argb_data], %[p_loop1_end], 0b \n\t" - " sw %[temp3], -4(%[argb_data]) \n\t" - "3: \n\t" - "beq %[argb_data], %[p_loop2_end], 2f \n\t" - " nop \n\t" - "1: \n\t" - "lw %[temp0], 0(%[argb_data]) \n\t" - "addiu %[argb_data], %[argb_data], 4 \n\t" - "ext %[temp4], %[temp0], 8, 8 \n\t" - "replv.ph %[temp4], %[temp4] \n\t" - "subu.qb %[temp0], %[temp0], %[temp4] \n\t" - "bne %[argb_data], %[p_loop2_end], 1b \n\t" - " sw %[temp0], -4(%[argb_data]) \n\t" - "2: \n\t" - ".set pop \n\t" - : [argb_data]"+&r"(argb_data), [temp0]"=&r"(temp0), - [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), - [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [temp6]"=&r"(temp6), - [temp7]"=&r"(temp7) - : [p_loop1_end]"r"(p_loop1_end), [p_loop2_end]"r"(p_loop2_end) - : "memory" - ); -} - -static WEBP_INLINE uint32_t ColorTransformDelta(int8_t color_pred, - int8_t color) { - return (uint32_t)((int)(color_pred) * color) >> 5; -} - -static void TransformColor_MIPSdspR2(const VP8LMultipliers* const m, - uint32_t* data, int num_pixels) { - int temp0, temp1, temp2, temp3, temp4, temp5; - uint32_t argb, argb1, new_red, new_red1; - const uint32_t G_to_R = m->green_to_red_; - const uint32_t G_to_B = m->green_to_blue_; - const uint32_t R_to_B = m->red_to_blue_; - uint32_t* const p_loop_end = data + (num_pixels & ~1); - __asm__ volatile ( - ".set push \n\t" - ".set noreorder \n\t" - "beq %[data], %[p_loop_end], 1f \n\t" - " nop \n\t" - "replv.ph %[temp0], %[G_to_R] \n\t" - "replv.ph %[temp1], %[G_to_B] \n\t" - "replv.ph %[temp2], %[R_to_B] \n\t" - "shll.ph %[temp0], %[temp0], 8 \n\t" - "shll.ph %[temp1], %[temp1], 8 \n\t" - "shll.ph %[temp2], %[temp2], 8 \n\t" - "shra.ph %[temp0], %[temp0], 8 \n\t" - "shra.ph %[temp1], %[temp1], 8 \n\t" - "shra.ph %[temp2], %[temp2], 8 \n\t" - "0: \n\t" - "lw %[argb], 0(%[data]) \n\t" - "lw %[argb1], 4(%[data]) \n\t" - "lhu %[new_red], 2(%[data]) \n\t" - "lhu %[new_red1], 6(%[data]) \n\t" - "precrq.qb.ph %[temp3], %[argb], %[argb1] \n\t" - "precr.qb.ph %[temp4], %[argb], %[argb1] \n\t" - "preceu.ph.qbra %[temp3], %[temp3] \n\t" - "preceu.ph.qbla %[temp4], %[temp4] \n\t" - "shll.ph %[temp3], %[temp3], 8 \n\t" - "shll.ph %[temp4], %[temp4], 8 \n\t" - "shra.ph %[temp3], %[temp3], 8 \n\t" - "shra.ph %[temp4], %[temp4], 8 \n\t" - "mul.ph %[temp5], %[temp3], %[temp0] \n\t" - "mul.ph %[temp3], %[temp3], %[temp1] \n\t" - "mul.ph %[temp4], %[temp4], %[temp2] \n\t" - "addiu %[data], %[data], 8 \n\t" - "ins %[new_red1], %[new_red], 16, 16 \n\t" - "ins %[argb1], %[argb], 16, 16 \n\t" - "shra.ph %[temp5], %[temp5], 5 \n\t" - "shra.ph %[temp3], %[temp3], 5 \n\t" - "shra.ph %[temp4], %[temp4], 5 \n\t" - "subu.ph %[new_red1], %[new_red1], %[temp5] \n\t" - "subu.ph %[argb1], %[argb1], %[temp3] \n\t" - "preceu.ph.qbra %[temp5], %[new_red1] \n\t" - "subu.ph %[argb1], %[argb1], %[temp4] \n\t" - "preceu.ph.qbra %[temp3], %[argb1] \n\t" - "sb %[temp5], -2(%[data]) \n\t" - "sb %[temp3], -4(%[data]) \n\t" - "sra %[temp5], %[temp5], 16 \n\t" - "sra %[temp3], %[temp3], 16 \n\t" - "sb %[temp5], -6(%[data]) \n\t" - "bne %[data], %[p_loop_end], 0b \n\t" - " sb %[temp3], -8(%[data]) \n\t" - "1: \n\t" - ".set pop \n\t" - : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), - [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), - [new_red1]"=&r"(new_red1), [new_red]"=&r"(new_red), - [argb]"=&r"(argb), [argb1]"=&r"(argb1), [data]"+&r"(data) - : [G_to_R]"r"(G_to_R), [R_to_B]"r"(R_to_B), - [G_to_B]"r"(G_to_B), [p_loop_end]"r"(p_loop_end) - : "memory", "hi", "lo" - ); - - if (num_pixels & 1) { - const uint32_t argb_ = data[0]; - const uint32_t green = argb_ >> 8; - const uint32_t red = argb_ >> 16; - uint32_t new_blue = argb_; - new_red = red; - new_red -= ColorTransformDelta(m->green_to_red_, green); - new_red &= 0xff; - new_blue -= ColorTransformDelta(m->green_to_blue_, green); - new_blue -= ColorTransformDelta(m->red_to_blue_, red); - new_blue &= 0xff; - data[0] = (argb_ & 0xff00ff00u) | (new_red << 16) | (new_blue); - } -} - -static WEBP_INLINE uint8_t TransformColorBlue(uint8_t green_to_blue, - uint8_t red_to_blue, - uint32_t argb) { - const uint32_t green = argb >> 8; - const uint32_t red = argb >> 16; - uint8_t new_blue = argb; - new_blue -= ColorTransformDelta(green_to_blue, green); - new_blue -= ColorTransformDelta(red_to_blue, red); - return (new_blue & 0xff); -} - -static void CollectColorBlueTransforms_MIPSdspR2(const uint32_t* argb, - int stride, - int tile_width, - int tile_height, - int green_to_blue, - int red_to_blue, - int histo[]) { - const int rtb = (red_to_blue << 16) | (red_to_blue & 0xffff); - const int gtb = (green_to_blue << 16) | (green_to_blue & 0xffff); - const uint32_t mask = 0xff00ffu; - while (tile_height-- > 0) { - int x; - const uint32_t* p_argb = argb; - argb += stride; - for (x = 0; x < (tile_width >> 1); ++x) { - int temp0, temp1, temp2, temp3, temp4, temp5, temp6; - __asm__ volatile ( - "lw %[temp0], 0(%[p_argb]) \n\t" - "lw %[temp1], 4(%[p_argb]) \n\t" - "precr.qb.ph %[temp2], %[temp0], %[temp1] \n\t" - "ins %[temp1], %[temp0], 16, 16 \n\t" - "shra.ph %[temp2], %[temp2], 8 \n\t" - "shra.ph %[temp3], %[temp1], 8 \n\t" - "mul.ph %[temp5], %[temp2], %[rtb] \n\t" - "mul.ph %[temp6], %[temp3], %[gtb] \n\t" - "and %[temp4], %[temp1], %[mask] \n\t" - "addiu %[p_argb], %[p_argb], 8 \n\t" - "shra.ph %[temp5], %[temp5], 5 \n\t" - "shra.ph %[temp6], %[temp6], 5 \n\t" - "subu.qb %[temp2], %[temp4], %[temp5] \n\t" - "subu.qb %[temp2], %[temp2], %[temp6] \n\t" - : [p_argb]"+&r"(p_argb), [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), - [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), - [temp5]"=&r"(temp5), [temp6]"=&r"(temp6) - : [rtb]"r"(rtb), [gtb]"r"(gtb), [mask]"r"(mask) - : "memory", "hi", "lo" - ); - ++histo[(uint8_t)(temp2 >> 16)]; - ++histo[(uint8_t)temp2]; - } - if (tile_width & 1) { - ++histo[TransformColorBlue(green_to_blue, red_to_blue, *p_argb)]; - } - } -} - -static WEBP_INLINE uint8_t TransformColorRed(uint8_t green_to_red, - uint32_t argb) { - const uint32_t green = argb >> 8; - uint32_t new_red = argb >> 16; - new_red -= ColorTransformDelta(green_to_red, green); - return (new_red & 0xff); -} - -static void CollectColorRedTransforms_MIPSdspR2(const uint32_t* argb, - int stride, - int tile_width, - int tile_height, - int green_to_red, - int histo[]) { - const int gtr = (green_to_red << 16) | (green_to_red & 0xffff); - while (tile_height-- > 0) { - int x; - const uint32_t* p_argb = argb; - argb += stride; - for (x = 0; x < (tile_width >> 1); ++x) { - int temp0, temp1, temp2, temp3, temp4; - __asm__ volatile ( - "lw %[temp0], 0(%[p_argb]) \n\t" - "lw %[temp1], 4(%[p_argb]) \n\t" - "precrq.ph.w %[temp4], %[temp0], %[temp1] \n\t" - "ins %[temp1], %[temp0], 16, 16 \n\t" - "shra.ph %[temp3], %[temp1], 8 \n\t" - "mul.ph %[temp2], %[temp3], %[gtr] \n\t" - "addiu %[p_argb], %[p_argb], 8 \n\t" - "shra.ph %[temp2], %[temp2], 5 \n\t" - "subu.qb %[temp2], %[temp4], %[temp2] \n\t" - : [p_argb]"+&r"(p_argb), [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), - [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), [temp4]"=&r"(temp4) - : [gtr]"r"(gtr) - : "memory", "hi", "lo" - ); - ++histo[(uint8_t)(temp2 >> 16)]; - ++histo[(uint8_t)temp2]; - } - if (tile_width & 1) { - ++histo[TransformColorRed(green_to_red, *p_argb)]; - } - } -} - -//------------------------------------------------------------------------------ -// Entry point - -extern void VP8LEncDspInitMIPSdspR2(void); - -WEBP_TSAN_IGNORE_FUNCTION void VP8LEncDspInitMIPSdspR2(void) { - VP8LSubtractGreenFromBlueAndRed = SubtractGreenFromBlueAndRed_MIPSdspR2; - VP8LTransformColor = TransformColor_MIPSdspR2; - VP8LCollectColorBlueTransforms = CollectColorBlueTransforms_MIPSdspR2; - VP8LCollectColorRedTransforms = CollectColorRedTransforms_MIPSdspR2; -} - -#else // !WEBP_USE_MIPS_DSP_R2 - -WEBP_DSP_INIT_STUB(VP8LEncDspInitMIPSdspR2) - -#endif // WEBP_USE_MIPS_DSP_R2 diff --git a/libwebp/src/dsp/lossless_enc_msa.c b/libwebp/src/dsp/lossless_enc_msa.c deleted file mode 100644 index 600dddfb..00000000 --- a/libwebp/src/dsp/lossless_enc_msa.c +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 2016 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// MSA variant of Image transform methods for lossless encoder. -// -// Authors: Prashant Patil (Prashant.Patil@imgtec.com) - -#include "src/dsp/dsp.h" - -#if defined(WEBP_USE_MSA) - -#include "src/dsp/lossless.h" -#include "src/dsp/msa_macro.h" - -#define TRANSFORM_COLOR_8(src0, src1, dst0, dst1, c0, c1, mask0, mask1) do { \ - v8i16 g0, g1, t0, t1, t2, t3; \ - v4i32 t4, t5; \ - VSHF_B2_SH(src0, src0, src1, src1, mask0, mask0, g0, g1); \ - DOTP_SB2_SH(g0, g1, c0, c0, t0, t1); \ - SRAI_H2_SH(t0, t1, 5); \ - t0 = __msa_subv_h((v8i16)src0, t0); \ - t1 = __msa_subv_h((v8i16)src1, t1); \ - t4 = __msa_srli_w((v4i32)src0, 16); \ - t5 = __msa_srli_w((v4i32)src1, 16); \ - DOTP_SB2_SH(t4, t5, c1, c1, t2, t3); \ - SRAI_H2_SH(t2, t3, 5); \ - SUB2(t0, t2, t1, t3, t0, t1); \ - VSHF_B2_UB(src0, t0, src1, t1, mask1, mask1, dst0, dst1); \ -} while (0) - -#define TRANSFORM_COLOR_4(src, dst, c0, c1, mask0, mask1) do { \ - const v16i8 g0 = VSHF_SB(src, src, mask0); \ - v8i16 t0 = __msa_dotp_s_h(c0, g0); \ - v8i16 t1; \ - v4i32 t2; \ - t0 = SRAI_H(t0, 5); \ - t0 = __msa_subv_h((v8i16)src, t0); \ - t2 = __msa_srli_w((v4i32)src, 16); \ - t1 = __msa_dotp_s_h(c1, (v16i8)t2); \ - t1 = SRAI_H(t1, 5); \ - t0 = t0 - t1; \ - dst = VSHF_UB(src, t0, mask1); \ -} while (0) - -static void TransformColor_MSA(const VP8LMultipliers* const m, uint32_t* data, - int num_pixels) { - v16u8 src0, dst0; - const v16i8 g2br = (v16i8)__msa_fill_w(m->green_to_blue_ | - (m->green_to_red_ << 16)); - const v16i8 r2b = (v16i8)__msa_fill_w(m->red_to_blue_); - const v16u8 mask0 = { 1, 255, 1, 255, 5, 255, 5, 255, 9, 255, 9, 255, - 13, 255, 13, 255 }; - const v16u8 mask1 = { 16, 1, 18, 3, 20, 5, 22, 7, 24, 9, 26, 11, - 28, 13, 30, 15 }; - - while (num_pixels >= 8) { - v16u8 src1, dst1; - LD_UB2(data, 4, src0, src1); - TRANSFORM_COLOR_8(src0, src1, dst0, dst1, g2br, r2b, mask0, mask1); - ST_UB2(dst0, dst1, data, 4); - data += 8; - num_pixels -= 8; - } - if (num_pixels > 0) { - if (num_pixels >= 4) { - src0 = LD_UB(data); - TRANSFORM_COLOR_4(src0, dst0, g2br, r2b, mask0, mask1); - ST_UB(dst0, data); - data += 4; - num_pixels -= 4; - } - if (num_pixels > 0) { - src0 = LD_UB(data); - TRANSFORM_COLOR_4(src0, dst0, g2br, r2b, mask0, mask1); - if (num_pixels == 3) { - const uint64_t pix_d = __msa_copy_s_d((v2i64)dst0, 0); - const uint32_t pix_w = __msa_copy_s_w((v4i32)dst0, 2); - SD(pix_d, data + 0); - SW(pix_w, data + 2); - } else if (num_pixels == 2) { - const uint64_t pix_d = __msa_copy_s_d((v2i64)dst0, 0); - SD(pix_d, data); - } else { - const uint32_t pix_w = __msa_copy_s_w((v4i32)dst0, 0); - SW(pix_w, data); - } - } - } -} - -static void SubtractGreenFromBlueAndRed_MSA(uint32_t* argb_data, - int num_pixels) { - int i; - uint8_t* ptemp_data = (uint8_t*)argb_data; - v16u8 src0, dst0, tmp0; - const v16u8 mask = { 1, 255, 1, 255, 5, 255, 5, 255, 9, 255, 9, 255, - 13, 255, 13, 255 }; - - while (num_pixels >= 8) { - v16u8 src1, dst1, tmp1; - LD_UB2(ptemp_data, 16, src0, src1); - VSHF_B2_UB(src0, src1, src1, src0, mask, mask, tmp0, tmp1); - SUB2(src0, tmp0, src1, tmp1, dst0, dst1); - ST_UB2(dst0, dst1, ptemp_data, 16); - ptemp_data += 8 * 4; - num_pixels -= 8; - } - if (num_pixels > 0) { - if (num_pixels >= 4) { - src0 = LD_UB(ptemp_data); - tmp0 = VSHF_UB(src0, src0, mask); - dst0 = src0 - tmp0; - ST_UB(dst0, ptemp_data); - ptemp_data += 4 * 4; - num_pixels -= 4; - } - for (i = 0; i < num_pixels; i++) { - const uint8_t b = ptemp_data[0]; - const uint8_t g = ptemp_data[1]; - const uint8_t r = ptemp_data[2]; - ptemp_data[0] = (b - g) & 0xff; - ptemp_data[2] = (r - g) & 0xff; - ptemp_data += 4; - } - } -} - -//------------------------------------------------------------------------------ -// Entry point - -extern void VP8LEncDspInitMSA(void); - -WEBP_TSAN_IGNORE_FUNCTION void VP8LEncDspInitMSA(void) { - VP8LSubtractGreenFromBlueAndRed = SubtractGreenFromBlueAndRed_MSA; - VP8LTransformColor = TransformColor_MSA; -} - -#else // !WEBP_USE_MSA - -WEBP_DSP_INIT_STUB(VP8LEncDspInitMSA) - -#endif // WEBP_USE_MSA diff --git a/libwebp/src/dsp/lossless_enc_neon.c b/libwebp/src/dsp/lossless_enc_neon.c deleted file mode 100644 index e32c7961..00000000 --- a/libwebp/src/dsp/lossless_enc_neon.c +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright 2015 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// NEON variant of methods for lossless encoder -// -// Author: Skal (pascal.massimino@gmail.com) - -#include "src/dsp/dsp.h" - -#if defined(WEBP_USE_NEON) - -#include - -#include "src/dsp/lossless.h" -#include "src/dsp/neon.h" - -//------------------------------------------------------------------------------ -// Subtract-Green Transform - -// vtbl?_u8 are marked unavailable for iOS arm64 with Xcode < 6.3, use -// non-standard versions there. -#if defined(__APPLE__) && WEBP_AARCH64 && \ - defined(__apple_build_version__) && (__apple_build_version__< 6020037) -#define USE_VTBLQ -#endif - -#ifdef USE_VTBLQ -// 255 = byte will be zeroed -static const uint8_t kGreenShuffle[16] = { - 1, 255, 1, 255, 5, 255, 5, 255, 9, 255, 9, 255, 13, 255, 13, 255 -}; - -static WEBP_INLINE uint8x16_t DoGreenShuffle_NEON(const uint8x16_t argb, - const uint8x16_t shuffle) { - return vcombine_u8(vtbl1q_u8(argb, vget_low_u8(shuffle)), - vtbl1q_u8(argb, vget_high_u8(shuffle))); -} -#else // !USE_VTBLQ -// 255 = byte will be zeroed -static const uint8_t kGreenShuffle[8] = { 1, 255, 1, 255, 5, 255, 5, 255 }; - -static WEBP_INLINE uint8x16_t DoGreenShuffle_NEON(const uint8x16_t argb, - const uint8x8_t shuffle) { - return vcombine_u8(vtbl1_u8(vget_low_u8(argb), shuffle), - vtbl1_u8(vget_high_u8(argb), shuffle)); -} -#endif // USE_VTBLQ - -static void SubtractGreenFromBlueAndRed_NEON(uint32_t* argb_data, - int num_pixels) { - const uint32_t* const end = argb_data + (num_pixels & ~3); -#ifdef USE_VTBLQ - const uint8x16_t shuffle = vld1q_u8(kGreenShuffle); -#else - const uint8x8_t shuffle = vld1_u8(kGreenShuffle); -#endif - for (; argb_data < end; argb_data += 4) { - const uint8x16_t argb = vld1q_u8((uint8_t*)argb_data); - const uint8x16_t greens = DoGreenShuffle_NEON(argb, shuffle); - vst1q_u8((uint8_t*)argb_data, vsubq_u8(argb, greens)); - } - // fallthrough and finish off with plain-C - VP8LSubtractGreenFromBlueAndRed_C(argb_data, num_pixels & 3); -} - -//------------------------------------------------------------------------------ -// Color Transform - -static void TransformColor_NEON(const VP8LMultipliers* const m, - uint32_t* argb_data, int num_pixels) { - // sign-extended multiplying constants, pre-shifted by 6. -#define CST(X) (((int16_t)(m->X << 8)) >> 6) - const int16_t rb[8] = { - CST(green_to_blue_), CST(green_to_red_), - CST(green_to_blue_), CST(green_to_red_), - CST(green_to_blue_), CST(green_to_red_), - CST(green_to_blue_), CST(green_to_red_) - }; - const int16x8_t mults_rb = vld1q_s16(rb); - const int16_t b2[8] = { - 0, CST(red_to_blue_), 0, CST(red_to_blue_), - 0, CST(red_to_blue_), 0, CST(red_to_blue_), - }; - const int16x8_t mults_b2 = vld1q_s16(b2); -#undef CST -#ifdef USE_VTBLQ - static const uint8_t kg0g0[16] = { - 255, 1, 255, 1, 255, 5, 255, 5, 255, 9, 255, 9, 255, 13, 255, 13 - }; - const uint8x16_t shuffle = vld1q_u8(kg0g0); -#else - static const uint8_t k0g0g[8] = { 255, 1, 255, 1, 255, 5, 255, 5 }; - const uint8x8_t shuffle = vld1_u8(k0g0g); -#endif - const uint32x4_t mask_rb = vdupq_n_u32(0x00ff00ffu); // red-blue masks - int i; - for (i = 0; i + 4 <= num_pixels; i += 4) { - const uint8x16_t in = vld1q_u8((uint8_t*)(argb_data + i)); - // 0 g 0 g - const uint8x16_t greens = DoGreenShuffle_NEON(in, shuffle); - // x dr x db1 - const int16x8_t A = vqdmulhq_s16(vreinterpretq_s16_u8(greens), mults_rb); - // r 0 b 0 - const int16x8_t B = vshlq_n_s16(vreinterpretq_s16_u8(in), 8); - // x db2 0 0 - const int16x8_t C = vqdmulhq_s16(B, mults_b2); - // 0 0 x db2 - const uint32x4_t D = vshrq_n_u32(vreinterpretq_u32_s16(C), 16); - // x dr x db - const int8x16_t E = vaddq_s8(vreinterpretq_s8_u32(D), - vreinterpretq_s8_s16(A)); - // 0 dr 0 db - const uint32x4_t F = vandq_u32(vreinterpretq_u32_s8(E), mask_rb); - const int8x16_t out = vsubq_s8(vreinterpretq_s8_u8(in), - vreinterpretq_s8_u32(F)); - vst1q_s8((int8_t*)(argb_data + i), out); - } - // fallthrough and finish off with plain-C - VP8LTransformColor_C(m, argb_data + i, num_pixels - i); -} - -#undef USE_VTBLQ - -//------------------------------------------------------------------------------ -// Entry point - -extern void VP8LEncDspInitNEON(void); - -WEBP_TSAN_IGNORE_FUNCTION void VP8LEncDspInitNEON(void) { - VP8LSubtractGreenFromBlueAndRed = SubtractGreenFromBlueAndRed_NEON; - VP8LTransformColor = TransformColor_NEON; -} - -#else // !WEBP_USE_NEON - -WEBP_DSP_INIT_STUB(VP8LEncDspInitNEON) - -#endif // WEBP_USE_NEON diff --git a/libwebp/src/dsp/lossless_enc_sse2.c b/libwebp/src/dsp/lossless_enc_sse2.c deleted file mode 100644 index 66cbaab7..00000000 --- a/libwebp/src/dsp/lossless_enc_sse2.c +++ /dev/null @@ -1,669 +0,0 @@ -// Copyright 2015 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// SSE2 variant of methods for lossless encoder -// -// Author: Skal (pascal.massimino@gmail.com) - -#include "src/dsp/dsp.h" - -#if defined(WEBP_USE_SSE2) -#include -#include -#include "src/dsp/lossless.h" -#include "src/dsp/common_sse2.h" -#include "src/dsp/lossless_common.h" - -// For sign-extended multiplying constants, pre-shifted by 5: -#define CST_5b(X) (((int16_t)((uint16_t)(X) << 8)) >> 5) - -//------------------------------------------------------------------------------ -// Subtract-Green Transform - -static void SubtractGreenFromBlueAndRed_SSE2(uint32_t* argb_data, - int num_pixels) { - int i; - for (i = 0; i + 4 <= num_pixels; i += 4) { - const __m128i in = _mm_loadu_si128((__m128i*)&argb_data[i]); // argb - const __m128i A = _mm_srli_epi16(in, 8); // 0 a 0 g - const __m128i B = _mm_shufflelo_epi16(A, _MM_SHUFFLE(2, 2, 0, 0)); - const __m128i C = _mm_shufflehi_epi16(B, _MM_SHUFFLE(2, 2, 0, 0)); // 0g0g - const __m128i out = _mm_sub_epi8(in, C); - _mm_storeu_si128((__m128i*)&argb_data[i], out); - } - // fallthrough and finish off with plain-C - if (i != num_pixels) { - VP8LSubtractGreenFromBlueAndRed_C(argb_data + i, num_pixels - i); - } -} - -//------------------------------------------------------------------------------ -// Color Transform - -#define MK_CST_16(HI, LO) \ - _mm_set1_epi32((int)(((uint32_t)(HI) << 16) | ((LO) & 0xffff))) - -static void TransformColor_SSE2(const VP8LMultipliers* const m, - uint32_t* argb_data, int num_pixels) { - const __m128i mults_rb = MK_CST_16(CST_5b(m->green_to_red_), - CST_5b(m->green_to_blue_)); - const __m128i mults_b2 = MK_CST_16(CST_5b(m->red_to_blue_), 0); - const __m128i mask_ag = _mm_set1_epi32((int)0xff00ff00); // alpha-green masks - const __m128i mask_rb = _mm_set1_epi32(0x00ff00ff); // red-blue masks - int i; - for (i = 0; i + 4 <= num_pixels; i += 4) { - const __m128i in = _mm_loadu_si128((__m128i*)&argb_data[i]); // argb - const __m128i A = _mm_and_si128(in, mask_ag); // a 0 g 0 - const __m128i B = _mm_shufflelo_epi16(A, _MM_SHUFFLE(2, 2, 0, 0)); - const __m128i C = _mm_shufflehi_epi16(B, _MM_SHUFFLE(2, 2, 0, 0)); // g0g0 - const __m128i D = _mm_mulhi_epi16(C, mults_rb); // x dr x db1 - const __m128i E = _mm_slli_epi16(in, 8); // r 0 b 0 - const __m128i F = _mm_mulhi_epi16(E, mults_b2); // x db2 0 0 - const __m128i G = _mm_srli_epi32(F, 16); // 0 0 x db2 - const __m128i H = _mm_add_epi8(G, D); // x dr x db - const __m128i I = _mm_and_si128(H, mask_rb); // 0 dr 0 db - const __m128i out = _mm_sub_epi8(in, I); - _mm_storeu_si128((__m128i*)&argb_data[i], out); - } - // fallthrough and finish off with plain-C - if (i != num_pixels) { - VP8LTransformColor_C(m, argb_data + i, num_pixels - i); - } -} - -//------------------------------------------------------------------------------ -#define SPAN 8 -static void CollectColorBlueTransforms_SSE2(const uint32_t* argb, int stride, - int tile_width, int tile_height, - int green_to_blue, int red_to_blue, - int histo[]) { - const __m128i mults_r = MK_CST_16(CST_5b(red_to_blue), 0); - const __m128i mults_g = MK_CST_16(0, CST_5b(green_to_blue)); - const __m128i mask_g = _mm_set1_epi32(0x00ff00); // green mask - const __m128i mask_b = _mm_set1_epi32(0x0000ff); // blue mask - int y; - for (y = 0; y < tile_height; ++y) { - const uint32_t* const src = argb + y * stride; - int i, x; - for (x = 0; x + SPAN <= tile_width; x += SPAN) { - uint16_t values[SPAN]; - const __m128i in0 = _mm_loadu_si128((__m128i*)&src[x + 0]); - const __m128i in1 = _mm_loadu_si128((__m128i*)&src[x + SPAN / 2]); - const __m128i A0 = _mm_slli_epi16(in0, 8); // r 0 | b 0 - const __m128i A1 = _mm_slli_epi16(in1, 8); - const __m128i B0 = _mm_and_si128(in0, mask_g); // 0 0 | g 0 - const __m128i B1 = _mm_and_si128(in1, mask_g); - const __m128i C0 = _mm_mulhi_epi16(A0, mults_r); // x db | 0 0 - const __m128i C1 = _mm_mulhi_epi16(A1, mults_r); - const __m128i D0 = _mm_mulhi_epi16(B0, mults_g); // 0 0 | x db - const __m128i D1 = _mm_mulhi_epi16(B1, mults_g); - const __m128i E0 = _mm_sub_epi8(in0, D0); // x x | x b' - const __m128i E1 = _mm_sub_epi8(in1, D1); - const __m128i F0 = _mm_srli_epi32(C0, 16); // 0 0 | x db - const __m128i F1 = _mm_srli_epi32(C1, 16); - const __m128i G0 = _mm_sub_epi8(E0, F0); // 0 0 | x b' - const __m128i G1 = _mm_sub_epi8(E1, F1); - const __m128i H0 = _mm_and_si128(G0, mask_b); // 0 0 | 0 b - const __m128i H1 = _mm_and_si128(G1, mask_b); - const __m128i I = _mm_packs_epi32(H0, H1); // 0 b' | 0 b' - _mm_storeu_si128((__m128i*)values, I); - for (i = 0; i < SPAN; ++i) ++histo[values[i]]; - } - } - { - const int left_over = tile_width & (SPAN - 1); - if (left_over > 0) { - VP8LCollectColorBlueTransforms_C(argb + tile_width - left_over, stride, - left_over, tile_height, - green_to_blue, red_to_blue, histo); - } - } -} - -static void CollectColorRedTransforms_SSE2(const uint32_t* argb, int stride, - int tile_width, int tile_height, - int green_to_red, int histo[]) { - const __m128i mults_g = MK_CST_16(0, CST_5b(green_to_red)); - const __m128i mask_g = _mm_set1_epi32(0x00ff00); // green mask - const __m128i mask = _mm_set1_epi32(0xff); - - int y; - for (y = 0; y < tile_height; ++y) { - const uint32_t* const src = argb + y * stride; - int i, x; - for (x = 0; x + SPAN <= tile_width; x += SPAN) { - uint16_t values[SPAN]; - const __m128i in0 = _mm_loadu_si128((__m128i*)&src[x + 0]); - const __m128i in1 = _mm_loadu_si128((__m128i*)&src[x + SPAN / 2]); - const __m128i A0 = _mm_and_si128(in0, mask_g); // 0 0 | g 0 - const __m128i A1 = _mm_and_si128(in1, mask_g); - const __m128i B0 = _mm_srli_epi32(in0, 16); // 0 0 | x r - const __m128i B1 = _mm_srli_epi32(in1, 16); - const __m128i C0 = _mm_mulhi_epi16(A0, mults_g); // 0 0 | x dr - const __m128i C1 = _mm_mulhi_epi16(A1, mults_g); - const __m128i E0 = _mm_sub_epi8(B0, C0); // x x | x r' - const __m128i E1 = _mm_sub_epi8(B1, C1); - const __m128i F0 = _mm_and_si128(E0, mask); // 0 0 | 0 r' - const __m128i F1 = _mm_and_si128(E1, mask); - const __m128i I = _mm_packs_epi32(F0, F1); - _mm_storeu_si128((__m128i*)values, I); - for (i = 0; i < SPAN; ++i) ++histo[values[i]]; - } - } - { - const int left_over = tile_width & (SPAN - 1); - if (left_over > 0) { - VP8LCollectColorRedTransforms_C(argb + tile_width - left_over, stride, - left_over, tile_height, - green_to_red, histo); - } - } -} -#undef SPAN -#undef MK_CST_16 - -//------------------------------------------------------------------------------ - -// Note we are adding uint32_t's as *signed* int32's (using _mm_add_epi32). But -// that's ok since the histogram values are less than 1<<28 (max picture size). -#define LINE_SIZE 16 // 8 or 16 -static void AddVector_SSE2(const uint32_t* a, const uint32_t* b, uint32_t* out, - int size) { - int i; - for (i = 0; i + LINE_SIZE <= size; i += LINE_SIZE) { - const __m128i a0 = _mm_loadu_si128((const __m128i*)&a[i + 0]); - const __m128i a1 = _mm_loadu_si128((const __m128i*)&a[i + 4]); -#if (LINE_SIZE == 16) - const __m128i a2 = _mm_loadu_si128((const __m128i*)&a[i + 8]); - const __m128i a3 = _mm_loadu_si128((const __m128i*)&a[i + 12]); -#endif - const __m128i b0 = _mm_loadu_si128((const __m128i*)&b[i + 0]); - const __m128i b1 = _mm_loadu_si128((const __m128i*)&b[i + 4]); -#if (LINE_SIZE == 16) - const __m128i b2 = _mm_loadu_si128((const __m128i*)&b[i + 8]); - const __m128i b3 = _mm_loadu_si128((const __m128i*)&b[i + 12]); -#endif - _mm_storeu_si128((__m128i*)&out[i + 0], _mm_add_epi32(a0, b0)); - _mm_storeu_si128((__m128i*)&out[i + 4], _mm_add_epi32(a1, b1)); -#if (LINE_SIZE == 16) - _mm_storeu_si128((__m128i*)&out[i + 8], _mm_add_epi32(a2, b2)); - _mm_storeu_si128((__m128i*)&out[i + 12], _mm_add_epi32(a3, b3)); -#endif - } - for (; i < size; ++i) { - out[i] = a[i] + b[i]; - } -} - -static void AddVectorEq_SSE2(const uint32_t* a, uint32_t* out, int size) { - int i; - for (i = 0; i + LINE_SIZE <= size; i += LINE_SIZE) { - const __m128i a0 = _mm_loadu_si128((const __m128i*)&a[i + 0]); - const __m128i a1 = _mm_loadu_si128((const __m128i*)&a[i + 4]); -#if (LINE_SIZE == 16) - const __m128i a2 = _mm_loadu_si128((const __m128i*)&a[i + 8]); - const __m128i a3 = _mm_loadu_si128((const __m128i*)&a[i + 12]); -#endif - const __m128i b0 = _mm_loadu_si128((const __m128i*)&out[i + 0]); - const __m128i b1 = _mm_loadu_si128((const __m128i*)&out[i + 4]); -#if (LINE_SIZE == 16) - const __m128i b2 = _mm_loadu_si128((const __m128i*)&out[i + 8]); - const __m128i b3 = _mm_loadu_si128((const __m128i*)&out[i + 12]); -#endif - _mm_storeu_si128((__m128i*)&out[i + 0], _mm_add_epi32(a0, b0)); - _mm_storeu_si128((__m128i*)&out[i + 4], _mm_add_epi32(a1, b1)); -#if (LINE_SIZE == 16) - _mm_storeu_si128((__m128i*)&out[i + 8], _mm_add_epi32(a2, b2)); - _mm_storeu_si128((__m128i*)&out[i + 12], _mm_add_epi32(a3, b3)); -#endif - } - for (; i < size; ++i) { - out[i] += a[i]; - } -} -#undef LINE_SIZE - -//------------------------------------------------------------------------------ -// Entropy - -// TODO(https://crbug.com/webp/499): this function produces different results -// from the C code due to use of double/float resulting in output differences -// when compared to -noasm. -#if !(defined(WEBP_HAVE_SLOW_CLZ_CTZ) || defined(__i386__) || defined(_M_IX86)) - -static float CombinedShannonEntropy_SSE2(const int X[256], const int Y[256]) { - int i; - float retval = 0.f; - int sumX = 0, sumXY = 0; - const __m128i zero = _mm_setzero_si128(); - - for (i = 0; i < 256; i += 16) { - const __m128i x0 = _mm_loadu_si128((const __m128i*)(X + i + 0)); - const __m128i y0 = _mm_loadu_si128((const __m128i*)(Y + i + 0)); - const __m128i x1 = _mm_loadu_si128((const __m128i*)(X + i + 4)); - const __m128i y1 = _mm_loadu_si128((const __m128i*)(Y + i + 4)); - const __m128i x2 = _mm_loadu_si128((const __m128i*)(X + i + 8)); - const __m128i y2 = _mm_loadu_si128((const __m128i*)(Y + i + 8)); - const __m128i x3 = _mm_loadu_si128((const __m128i*)(X + i + 12)); - const __m128i y3 = _mm_loadu_si128((const __m128i*)(Y + i + 12)); - const __m128i x4 = _mm_packs_epi16(_mm_packs_epi32(x0, x1), - _mm_packs_epi32(x2, x3)); - const __m128i y4 = _mm_packs_epi16(_mm_packs_epi32(y0, y1), - _mm_packs_epi32(y2, y3)); - const int32_t mx = _mm_movemask_epi8(_mm_cmpgt_epi8(x4, zero)); - int32_t my = _mm_movemask_epi8(_mm_cmpgt_epi8(y4, zero)) | mx; - while (my) { - const int32_t j = BitsCtz(my); - int xy; - if ((mx >> j) & 1) { - const int x = X[i + j]; - sumXY += x; - retval -= VP8LFastSLog2(x); - } - xy = X[i + j] + Y[i + j]; - sumX += xy; - retval -= VP8LFastSLog2(xy); - my &= my - 1; - } - } - retval += VP8LFastSLog2(sumX) + VP8LFastSLog2(sumXY); - return retval; -} - -#else - -#define DONT_USE_COMBINED_SHANNON_ENTROPY_SSE2_FUNC // won't be faster - -#endif - -//------------------------------------------------------------------------------ - -static int VectorMismatch_SSE2(const uint32_t* const array1, - const uint32_t* const array2, int length) { - int match_len; - - if (length >= 12) { - __m128i A0 = _mm_loadu_si128((const __m128i*)&array1[0]); - __m128i A1 = _mm_loadu_si128((const __m128i*)&array2[0]); - match_len = 0; - do { - // Loop unrolling and early load both provide a speedup of 10% for the - // current function. Also, max_limit can be MAX_LENGTH=4096 at most. - const __m128i cmpA = _mm_cmpeq_epi32(A0, A1); - const __m128i B0 = - _mm_loadu_si128((const __m128i*)&array1[match_len + 4]); - const __m128i B1 = - _mm_loadu_si128((const __m128i*)&array2[match_len + 4]); - if (_mm_movemask_epi8(cmpA) != 0xffff) break; - match_len += 4; - - { - const __m128i cmpB = _mm_cmpeq_epi32(B0, B1); - A0 = _mm_loadu_si128((const __m128i*)&array1[match_len + 4]); - A1 = _mm_loadu_si128((const __m128i*)&array2[match_len + 4]); - if (_mm_movemask_epi8(cmpB) != 0xffff) break; - match_len += 4; - } - } while (match_len + 12 < length); - } else { - match_len = 0; - // Unroll the potential first two loops. - if (length >= 4 && - _mm_movemask_epi8(_mm_cmpeq_epi32( - _mm_loadu_si128((const __m128i*)&array1[0]), - _mm_loadu_si128((const __m128i*)&array2[0]))) == 0xffff) { - match_len = 4; - if (length >= 8 && - _mm_movemask_epi8(_mm_cmpeq_epi32( - _mm_loadu_si128((const __m128i*)&array1[4]), - _mm_loadu_si128((const __m128i*)&array2[4]))) == 0xffff) { - match_len = 8; - } - } - } - - while (match_len < length && array1[match_len] == array2[match_len]) { - ++match_len; - } - return match_len; -} - -// Bundles multiple (1, 2, 4 or 8) pixels into a single pixel. -static void BundleColorMap_SSE2(const uint8_t* const row, int width, int xbits, - uint32_t* dst) { - int x; - assert(xbits >= 0); - assert(xbits <= 3); - switch (xbits) { - case 0: { - const __m128i ff = _mm_set1_epi16((short)0xff00); - const __m128i zero = _mm_setzero_si128(); - // Store 0xff000000 | (row[x] << 8). - for (x = 0; x + 16 <= width; x += 16, dst += 16) { - const __m128i in = _mm_loadu_si128((const __m128i*)&row[x]); - const __m128i in_lo = _mm_unpacklo_epi8(zero, in); - const __m128i dst0 = _mm_unpacklo_epi16(in_lo, ff); - const __m128i dst1 = _mm_unpackhi_epi16(in_lo, ff); - const __m128i in_hi = _mm_unpackhi_epi8(zero, in); - const __m128i dst2 = _mm_unpacklo_epi16(in_hi, ff); - const __m128i dst3 = _mm_unpackhi_epi16(in_hi, ff); - _mm_storeu_si128((__m128i*)&dst[0], dst0); - _mm_storeu_si128((__m128i*)&dst[4], dst1); - _mm_storeu_si128((__m128i*)&dst[8], dst2); - _mm_storeu_si128((__m128i*)&dst[12], dst3); - } - break; - } - case 1: { - const __m128i ff = _mm_set1_epi16((short)0xff00); - const __m128i mul = _mm_set1_epi16(0x110); - for (x = 0; x + 16 <= width; x += 16, dst += 8) { - // 0a0b | (where a/b are 4 bits). - const __m128i in = _mm_loadu_si128((const __m128i*)&row[x]); - const __m128i tmp = _mm_mullo_epi16(in, mul); // aba0 - const __m128i pack = _mm_and_si128(tmp, ff); // ab00 - const __m128i dst0 = _mm_unpacklo_epi16(pack, ff); - const __m128i dst1 = _mm_unpackhi_epi16(pack, ff); - _mm_storeu_si128((__m128i*)&dst[0], dst0); - _mm_storeu_si128((__m128i*)&dst[4], dst1); - } - break; - } - case 2: { - const __m128i mask_or = _mm_set1_epi32((int)0xff000000); - const __m128i mul_cst = _mm_set1_epi16(0x0104); - const __m128i mask_mul = _mm_set1_epi16(0x0f00); - for (x = 0; x + 16 <= width; x += 16, dst += 4) { - // 000a000b000c000d | (where a/b/c/d are 2 bits). - const __m128i in = _mm_loadu_si128((const __m128i*)&row[x]); - const __m128i mul = _mm_mullo_epi16(in, mul_cst); // 00ab00b000cd00d0 - const __m128i tmp = _mm_and_si128(mul, mask_mul); // 00ab000000cd0000 - const __m128i shift = _mm_srli_epi32(tmp, 12); // 00000000ab000000 - const __m128i pack = _mm_or_si128(shift, tmp); // 00000000abcd0000 - // Convert to 0xff00**00. - const __m128i res = _mm_or_si128(pack, mask_or); - _mm_storeu_si128((__m128i*)dst, res); - } - break; - } - default: { - assert(xbits == 3); - for (x = 0; x + 16 <= width; x += 16, dst += 2) { - // 0000000a00000000b... | (where a/b are 1 bit). - const __m128i in = _mm_loadu_si128((const __m128i*)&row[x]); - const __m128i shift = _mm_slli_epi64(in, 7); - const uint32_t move = _mm_movemask_epi8(shift); - dst[0] = 0xff000000 | ((move & 0xff) << 8); - dst[1] = 0xff000000 | (move & 0xff00); - } - break; - } - } - if (x != width) { - VP8LBundleColorMap_C(row + x, width - x, xbits, dst); - } -} - -//------------------------------------------------------------------------------ -// Batch version of Predictor Transform subtraction - -static WEBP_INLINE void Average2_m128i(const __m128i* const a0, - const __m128i* const a1, - __m128i* const avg) { - // (a + b) >> 1 = ((a + b + 1) >> 1) - ((a ^ b) & 1) - const __m128i ones = _mm_set1_epi8(1); - const __m128i avg1 = _mm_avg_epu8(*a0, *a1); - const __m128i one = _mm_and_si128(_mm_xor_si128(*a0, *a1), ones); - *avg = _mm_sub_epi8(avg1, one); -} - -// Predictor0: ARGB_BLACK. -static void PredictorSub0_SSE2(const uint32_t* in, const uint32_t* upper, - int num_pixels, uint32_t* out) { - int i; - const __m128i black = _mm_set1_epi32((int)ARGB_BLACK); - for (i = 0; i + 4 <= num_pixels; i += 4) { - const __m128i src = _mm_loadu_si128((const __m128i*)&in[i]); - const __m128i res = _mm_sub_epi8(src, black); - _mm_storeu_si128((__m128i*)&out[i], res); - } - if (i != num_pixels) { - VP8LPredictorsSub_C[0](in + i, NULL, num_pixels - i, out + i); - } - (void)upper; -} - -#define GENERATE_PREDICTOR_1(X, IN) \ - static void PredictorSub##X##_SSE2(const uint32_t* const in, \ - const uint32_t* const upper, \ - int num_pixels, uint32_t* const out) { \ - int i; \ - for (i = 0; i + 4 <= num_pixels; i += 4) { \ - const __m128i src = _mm_loadu_si128((const __m128i*)&in[i]); \ - const __m128i pred = _mm_loadu_si128((const __m128i*)&(IN)); \ - const __m128i res = _mm_sub_epi8(src, pred); \ - _mm_storeu_si128((__m128i*)&out[i], res); \ - } \ - if (i != num_pixels) { \ - VP8LPredictorsSub_C[(X)](in + i, WEBP_OFFSET_PTR(upper, i), \ - num_pixels - i, out + i); \ - } \ - } - -GENERATE_PREDICTOR_1(1, in[i - 1]) // Predictor1: L -GENERATE_PREDICTOR_1(2, upper[i]) // Predictor2: T -GENERATE_PREDICTOR_1(3, upper[i + 1]) // Predictor3: TR -GENERATE_PREDICTOR_1(4, upper[i - 1]) // Predictor4: TL -#undef GENERATE_PREDICTOR_1 - -// Predictor5: avg2(avg2(L, TR), T) -static void PredictorSub5_SSE2(const uint32_t* in, const uint32_t* upper, - int num_pixels, uint32_t* out) { - int i; - for (i = 0; i + 4 <= num_pixels; i += 4) { - const __m128i L = _mm_loadu_si128((const __m128i*)&in[i - 1]); - const __m128i T = _mm_loadu_si128((const __m128i*)&upper[i]); - const __m128i TR = _mm_loadu_si128((const __m128i*)&upper[i + 1]); - const __m128i src = _mm_loadu_si128((const __m128i*)&in[i]); - __m128i avg, pred, res; - Average2_m128i(&L, &TR, &avg); - Average2_m128i(&avg, &T, &pred); - res = _mm_sub_epi8(src, pred); - _mm_storeu_si128((__m128i*)&out[i], res); - } - if (i != num_pixels) { - VP8LPredictorsSub_C[5](in + i, upper + i, num_pixels - i, out + i); - } -} - -#define GENERATE_PREDICTOR_2(X, A, B) \ -static void PredictorSub##X##_SSE2(const uint32_t* in, const uint32_t* upper, \ - int num_pixels, uint32_t* out) { \ - int i; \ - for (i = 0; i + 4 <= num_pixels; i += 4) { \ - const __m128i tA = _mm_loadu_si128((const __m128i*)&(A)); \ - const __m128i tB = _mm_loadu_si128((const __m128i*)&(B)); \ - const __m128i src = _mm_loadu_si128((const __m128i*)&in[i]); \ - __m128i pred, res; \ - Average2_m128i(&tA, &tB, &pred); \ - res = _mm_sub_epi8(src, pred); \ - _mm_storeu_si128((__m128i*)&out[i], res); \ - } \ - if (i != num_pixels) { \ - VP8LPredictorsSub_C[(X)](in + i, upper + i, num_pixels - i, out + i); \ - } \ -} - -GENERATE_PREDICTOR_2(6, in[i - 1], upper[i - 1]) // Predictor6: avg(L, TL) -GENERATE_PREDICTOR_2(7, in[i - 1], upper[i]) // Predictor7: avg(L, T) -GENERATE_PREDICTOR_2(8, upper[i - 1], upper[i]) // Predictor8: avg(TL, T) -GENERATE_PREDICTOR_2(9, upper[i], upper[i + 1]) // Predictor9: average(T, TR) -#undef GENERATE_PREDICTOR_2 - -// Predictor10: avg(avg(L,TL), avg(T, TR)). -static void PredictorSub10_SSE2(const uint32_t* in, const uint32_t* upper, - int num_pixels, uint32_t* out) { - int i; - for (i = 0; i + 4 <= num_pixels; i += 4) { - const __m128i L = _mm_loadu_si128((const __m128i*)&in[i - 1]); - const __m128i src = _mm_loadu_si128((const __m128i*)&in[i]); - const __m128i TL = _mm_loadu_si128((const __m128i*)&upper[i - 1]); - const __m128i T = _mm_loadu_si128((const __m128i*)&upper[i]); - const __m128i TR = _mm_loadu_si128((const __m128i*)&upper[i + 1]); - __m128i avgTTR, avgLTL, avg, res; - Average2_m128i(&T, &TR, &avgTTR); - Average2_m128i(&L, &TL, &avgLTL); - Average2_m128i(&avgTTR, &avgLTL, &avg); - res = _mm_sub_epi8(src, avg); - _mm_storeu_si128((__m128i*)&out[i], res); - } - if (i != num_pixels) { - VP8LPredictorsSub_C[10](in + i, upper + i, num_pixels - i, out + i); - } -} - -// Predictor11: select. -static void GetSumAbsDiff32_SSE2(const __m128i* const A, const __m128i* const B, - __m128i* const out) { - // We can unpack with any value on the upper 32 bits, provided it's the same - // on both operands (to that their sum of abs diff is zero). Here we use *A. - const __m128i A_lo = _mm_unpacklo_epi32(*A, *A); - const __m128i B_lo = _mm_unpacklo_epi32(*B, *A); - const __m128i A_hi = _mm_unpackhi_epi32(*A, *A); - const __m128i B_hi = _mm_unpackhi_epi32(*B, *A); - const __m128i s_lo = _mm_sad_epu8(A_lo, B_lo); - const __m128i s_hi = _mm_sad_epu8(A_hi, B_hi); - *out = _mm_packs_epi32(s_lo, s_hi); -} - -static void PredictorSub11_SSE2(const uint32_t* in, const uint32_t* upper, - int num_pixels, uint32_t* out) { - int i; - for (i = 0; i + 4 <= num_pixels; i += 4) { - const __m128i L = _mm_loadu_si128((const __m128i*)&in[i - 1]); - const __m128i T = _mm_loadu_si128((const __m128i*)&upper[i]); - const __m128i TL = _mm_loadu_si128((const __m128i*)&upper[i - 1]); - const __m128i src = _mm_loadu_si128((const __m128i*)&in[i]); - __m128i pa, pb; - GetSumAbsDiff32_SSE2(&T, &TL, &pa); // pa = sum |T-TL| - GetSumAbsDiff32_SSE2(&L, &TL, &pb); // pb = sum |L-TL| - { - const __m128i mask = _mm_cmpgt_epi32(pb, pa); - const __m128i A = _mm_and_si128(mask, L); - const __m128i B = _mm_andnot_si128(mask, T); - const __m128i pred = _mm_or_si128(A, B); // pred = (L > T)? L : T - const __m128i res = _mm_sub_epi8(src, pred); - _mm_storeu_si128((__m128i*)&out[i], res); - } - } - if (i != num_pixels) { - VP8LPredictorsSub_C[11](in + i, upper + i, num_pixels - i, out + i); - } -} - -// Predictor12: ClampedSubSubtractFull. -static void PredictorSub12_SSE2(const uint32_t* in, const uint32_t* upper, - int num_pixels, uint32_t* out) { - int i; - const __m128i zero = _mm_setzero_si128(); - for (i = 0; i + 4 <= num_pixels; i += 4) { - const __m128i src = _mm_loadu_si128((const __m128i*)&in[i]); - const __m128i L = _mm_loadu_si128((const __m128i*)&in[i - 1]); - const __m128i L_lo = _mm_unpacklo_epi8(L, zero); - const __m128i L_hi = _mm_unpackhi_epi8(L, zero); - const __m128i T = _mm_loadu_si128((const __m128i*)&upper[i]); - const __m128i T_lo = _mm_unpacklo_epi8(T, zero); - const __m128i T_hi = _mm_unpackhi_epi8(T, zero); - const __m128i TL = _mm_loadu_si128((const __m128i*)&upper[i - 1]); - const __m128i TL_lo = _mm_unpacklo_epi8(TL, zero); - const __m128i TL_hi = _mm_unpackhi_epi8(TL, zero); - const __m128i diff_lo = _mm_sub_epi16(T_lo, TL_lo); - const __m128i diff_hi = _mm_sub_epi16(T_hi, TL_hi); - const __m128i pred_lo = _mm_add_epi16(L_lo, diff_lo); - const __m128i pred_hi = _mm_add_epi16(L_hi, diff_hi); - const __m128i pred = _mm_packus_epi16(pred_lo, pred_hi); - const __m128i res = _mm_sub_epi8(src, pred); - _mm_storeu_si128((__m128i*)&out[i], res); - } - if (i != num_pixels) { - VP8LPredictorsSub_C[12](in + i, upper + i, num_pixels - i, out + i); - } -} - -// Predictors13: ClampedAddSubtractHalf -static void PredictorSub13_SSE2(const uint32_t* in, const uint32_t* upper, - int num_pixels, uint32_t* out) { - int i; - const __m128i zero = _mm_setzero_si128(); - for (i = 0; i + 2 <= num_pixels; i += 2) { - // we can only process two pixels at a time - const __m128i L = _mm_loadl_epi64((const __m128i*)&in[i - 1]); - const __m128i src = _mm_loadl_epi64((const __m128i*)&in[i]); - const __m128i T = _mm_loadl_epi64((const __m128i*)&upper[i]); - const __m128i TL = _mm_loadl_epi64((const __m128i*)&upper[i - 1]); - const __m128i L_lo = _mm_unpacklo_epi8(L, zero); - const __m128i T_lo = _mm_unpacklo_epi8(T, zero); - const __m128i TL_lo = _mm_unpacklo_epi8(TL, zero); - const __m128i sum = _mm_add_epi16(T_lo, L_lo); - const __m128i avg = _mm_srli_epi16(sum, 1); - const __m128i A1 = _mm_sub_epi16(avg, TL_lo); - const __m128i bit_fix = _mm_cmpgt_epi16(TL_lo, avg); - const __m128i A2 = _mm_sub_epi16(A1, bit_fix); - const __m128i A3 = _mm_srai_epi16(A2, 1); - const __m128i A4 = _mm_add_epi16(avg, A3); - const __m128i pred = _mm_packus_epi16(A4, A4); - const __m128i res = _mm_sub_epi8(src, pred); - _mm_storel_epi64((__m128i*)&out[i], res); - } - if (i != num_pixels) { - VP8LPredictorsSub_C[13](in + i, upper + i, num_pixels - i, out + i); - } -} - -//------------------------------------------------------------------------------ -// Entry point - -extern void VP8LEncDspInitSSE2(void); - -WEBP_TSAN_IGNORE_FUNCTION void VP8LEncDspInitSSE2(void) { - VP8LSubtractGreenFromBlueAndRed = SubtractGreenFromBlueAndRed_SSE2; - VP8LTransformColor = TransformColor_SSE2; - VP8LCollectColorBlueTransforms = CollectColorBlueTransforms_SSE2; - VP8LCollectColorRedTransforms = CollectColorRedTransforms_SSE2; - VP8LAddVector = AddVector_SSE2; - VP8LAddVectorEq = AddVectorEq_SSE2; -#if !defined(DONT_USE_COMBINED_SHANNON_ENTROPY_SSE2_FUNC) - VP8LCombinedShannonEntropy = CombinedShannonEntropy_SSE2; -#endif - VP8LVectorMismatch = VectorMismatch_SSE2; - VP8LBundleColorMap = BundleColorMap_SSE2; - - VP8LPredictorsSub[0] = PredictorSub0_SSE2; - VP8LPredictorsSub[1] = PredictorSub1_SSE2; - VP8LPredictorsSub[2] = PredictorSub2_SSE2; - VP8LPredictorsSub[3] = PredictorSub3_SSE2; - VP8LPredictorsSub[4] = PredictorSub4_SSE2; - VP8LPredictorsSub[5] = PredictorSub5_SSE2; - VP8LPredictorsSub[6] = PredictorSub6_SSE2; - VP8LPredictorsSub[7] = PredictorSub7_SSE2; - VP8LPredictorsSub[8] = PredictorSub8_SSE2; - VP8LPredictorsSub[9] = PredictorSub9_SSE2; - VP8LPredictorsSub[10] = PredictorSub10_SSE2; - VP8LPredictorsSub[11] = PredictorSub11_SSE2; - VP8LPredictorsSub[12] = PredictorSub12_SSE2; - VP8LPredictorsSub[13] = PredictorSub13_SSE2; - VP8LPredictorsSub[14] = PredictorSub0_SSE2; // <- padding security sentinels - VP8LPredictorsSub[15] = PredictorSub0_SSE2; -} - -#else // !WEBP_USE_SSE2 - -WEBP_DSP_INIT_STUB(VP8LEncDspInitSSE2) - -#endif // WEBP_USE_SSE2 diff --git a/libwebp/src/dsp/lossless_enc_sse41.c b/libwebp/src/dsp/lossless_enc_sse41.c deleted file mode 100644 index 7ab83c26..00000000 --- a/libwebp/src/dsp/lossless_enc_sse41.c +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright 2015 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// SSE4.1 variant of methods for lossless encoder -// -// Author: Skal (pascal.massimino@gmail.com) - -#include "src/dsp/dsp.h" - -#if defined(WEBP_USE_SSE41) -#include -#include -#include "src/dsp/lossless.h" - -//------------------------------------------------------------------------------ -// Cost operations. - -static WEBP_INLINE uint32_t HorizontalSum_SSE41(__m128i cost) { - cost = _mm_add_epi32(cost, _mm_srli_si128(cost, 8)); - cost = _mm_add_epi32(cost, _mm_srli_si128(cost, 4)); - return _mm_cvtsi128_si32(cost); -} - -static uint32_t ExtraCost_SSE41(const uint32_t* const a, int length) { - int i; - __m128i cost = _mm_set_epi32(2 * a[7], 2 * a[6], a[5], a[4]); - assert(length % 8 == 0); - - for (i = 8; i + 8 <= length; i += 8) { - const int j = (i - 2) >> 1; - const __m128i a0 = _mm_loadu_si128((const __m128i*)&a[i]); - const __m128i a1 = _mm_loadu_si128((const __m128i*)&a[i + 4]); - const __m128i w = _mm_set_epi32(j + 3, j + 2, j + 1, j); - const __m128i a2 = _mm_hadd_epi32(a0, a1); - const __m128i mul = _mm_mullo_epi32(a2, w); - cost = _mm_add_epi32(mul, cost); - } - return HorizontalSum_SSE41(cost); -} - -static uint32_t ExtraCostCombined_SSE41(const uint32_t* const a, - const uint32_t* const b, int length) { - int i; - __m128i cost = _mm_add_epi32(_mm_set_epi32(2 * a[7], 2 * a[6], a[5], a[4]), - _mm_set_epi32(2 * b[7], 2 * b[6], b[5], b[4])); - assert(length % 8 == 0); - - for (i = 8; i + 8 <= length; i += 8) { - const int j = (i - 2) >> 1; - const __m128i a0 = _mm_loadu_si128((const __m128i*)&a[i]); - const __m128i a1 = _mm_loadu_si128((const __m128i*)&a[i + 4]); - const __m128i b0 = _mm_loadu_si128((const __m128i*)&b[i]); - const __m128i b1 = _mm_loadu_si128((const __m128i*)&b[i + 4]); - const __m128i w = _mm_set_epi32(j + 3, j + 2, j + 1, j); - const __m128i a2 = _mm_hadd_epi32(a0, a1); - const __m128i b2 = _mm_hadd_epi32(b0, b1); - const __m128i mul = _mm_mullo_epi32(_mm_add_epi32(a2, b2), w); - cost = _mm_add_epi32(mul, cost); - } - return HorizontalSum_SSE41(cost); -} - -//------------------------------------------------------------------------------ -// Subtract-Green Transform - -static void SubtractGreenFromBlueAndRed_SSE41(uint32_t* argb_data, - int num_pixels) { - int i; - const __m128i kCstShuffle = _mm_set_epi8(-1, 13, -1, 13, -1, 9, -1, 9, - -1, 5, -1, 5, -1, 1, -1, 1); - for (i = 0; i + 4 <= num_pixels; i += 4) { - const __m128i in = _mm_loadu_si128((__m128i*)&argb_data[i]); - const __m128i in_0g0g = _mm_shuffle_epi8(in, kCstShuffle); - const __m128i out = _mm_sub_epi8(in, in_0g0g); - _mm_storeu_si128((__m128i*)&argb_data[i], out); - } - // fallthrough and finish off with plain-C - if (i != num_pixels) { - VP8LSubtractGreenFromBlueAndRed_C(argb_data + i, num_pixels - i); - } -} - -//------------------------------------------------------------------------------ -// Color Transform - -// For sign-extended multiplying constants, pre-shifted by 5: -#define CST_5b(X) (((int16_t)((uint16_t)(X) << 8)) >> 5) - -#define MK_CST_16(HI, LO) \ - _mm_set1_epi32((int)(((uint32_t)(HI) << 16) | ((LO) & 0xffff))) - -static void CollectColorBlueTransforms_SSE41(const uint32_t* argb, int stride, - int tile_width, int tile_height, - int green_to_blue, int red_to_blue, - int histo[]) { - const __m128i mult = - MK_CST_16(CST_5b(red_to_blue) + 256,CST_5b(green_to_blue)); - const __m128i perm = - _mm_setr_epi8(-1, 1, -1, 2, -1, 5, -1, 6, -1, 9, -1, 10, -1, 13, -1, 14); - if (tile_width >= 4) { - int y; - for (y = 0; y < tile_height; ++y) { - const uint32_t* const src = argb + y * stride; - const __m128i A1 = _mm_loadu_si128((const __m128i*)src); - const __m128i B1 = _mm_shuffle_epi8(A1, perm); - const __m128i C1 = _mm_mulhi_epi16(B1, mult); - const __m128i D1 = _mm_sub_epi16(A1, C1); - __m128i E = _mm_add_epi16(_mm_srli_epi32(D1, 16), D1); - int x; - for (x = 4; x + 4 <= tile_width; x += 4) { - const __m128i A2 = _mm_loadu_si128((const __m128i*)(src + x)); - __m128i B2, C2, D2; - ++histo[_mm_extract_epi8(E, 0)]; - B2 = _mm_shuffle_epi8(A2, perm); - ++histo[_mm_extract_epi8(E, 4)]; - C2 = _mm_mulhi_epi16(B2, mult); - ++histo[_mm_extract_epi8(E, 8)]; - D2 = _mm_sub_epi16(A2, C2); - ++histo[_mm_extract_epi8(E, 12)]; - E = _mm_add_epi16(_mm_srli_epi32(D2, 16), D2); - } - ++histo[_mm_extract_epi8(E, 0)]; - ++histo[_mm_extract_epi8(E, 4)]; - ++histo[_mm_extract_epi8(E, 8)]; - ++histo[_mm_extract_epi8(E, 12)]; - } - } - { - const int left_over = tile_width & 3; - if (left_over > 0) { - VP8LCollectColorBlueTransforms_C(argb + tile_width - left_over, stride, - left_over, tile_height, - green_to_blue, red_to_blue, histo); - } - } -} - -static void CollectColorRedTransforms_SSE41(const uint32_t* argb, int stride, - int tile_width, int tile_height, - int green_to_red, int histo[]) { - - const __m128i mult = MK_CST_16(0, CST_5b(green_to_red)); - const __m128i mask_g = _mm_set1_epi32(0x0000ff00); - if (tile_width >= 4) { - int y; - for (y = 0; y < tile_height; ++y) { - const uint32_t* const src = argb + y * stride; - const __m128i A1 = _mm_loadu_si128((const __m128i*)src); - const __m128i B1 = _mm_and_si128(A1, mask_g); - const __m128i C1 = _mm_madd_epi16(B1, mult); - __m128i D = _mm_sub_epi16(A1, C1); - int x; - for (x = 4; x + 4 <= tile_width; x += 4) { - const __m128i A2 = _mm_loadu_si128((const __m128i*)(src + x)); - __m128i B2, C2; - ++histo[_mm_extract_epi8(D, 2)]; - B2 = _mm_and_si128(A2, mask_g); - ++histo[_mm_extract_epi8(D, 6)]; - C2 = _mm_madd_epi16(B2, mult); - ++histo[_mm_extract_epi8(D, 10)]; - ++histo[_mm_extract_epi8(D, 14)]; - D = _mm_sub_epi16(A2, C2); - } - ++histo[_mm_extract_epi8(D, 2)]; - ++histo[_mm_extract_epi8(D, 6)]; - ++histo[_mm_extract_epi8(D, 10)]; - ++histo[_mm_extract_epi8(D, 14)]; - } - } - { - const int left_over = tile_width & 3; - if (left_over > 0) { - VP8LCollectColorRedTransforms_C(argb + tile_width - left_over, stride, - left_over, tile_height, green_to_red, - histo); - } - } -} - -#undef MK_CST_16 - -//------------------------------------------------------------------------------ -// Entry point - -extern void VP8LEncDspInitSSE41(void); - -WEBP_TSAN_IGNORE_FUNCTION void VP8LEncDspInitSSE41(void) { - VP8LExtraCost = ExtraCost_SSE41; - VP8LExtraCostCombined = ExtraCostCombined_SSE41; - VP8LSubtractGreenFromBlueAndRed = SubtractGreenFromBlueAndRed_SSE41; - VP8LCollectColorBlueTransforms = CollectColorBlueTransforms_SSE41; - VP8LCollectColorRedTransforms = CollectColorRedTransforms_SSE41; -} - -#else // !WEBP_USE_SSE41 - -WEBP_DSP_INIT_STUB(VP8LEncDspInitSSE41) - -#endif // WEBP_USE_SSE41 diff --git a/libwebp/src/dsp/lossless_mips_dsp_r2.c b/libwebp/src/dsp/lossless_mips_dsp_r2.c index bfe5ea6b..4b4f0564 100644 --- a/libwebp/src/dsp/lossless_mips_dsp_r2.c +++ b/libwebp/src/dsp/lossless_mips_dsp_r2.c @@ -299,9 +299,9 @@ static void TransformColorInverse_MIPSdspR2(const VP8LMultipliers* const m, uint32_t* dst) { int temp0, temp1, temp2, temp3, temp4, temp5; uint32_t argb, argb1, new_red; - const uint32_t G_to_R = m->green_to_red_; - const uint32_t G_to_B = m->green_to_blue_; - const uint32_t R_to_B = m->red_to_blue_; + const uint32_t G_to_R = m->green_to_red; + const uint32_t G_to_B = m->green_to_blue; + const uint32_t R_to_B = m->red_to_blue; const uint32_t* const p_loop_end = src + (num_pixels & ~1); __asm__ volatile ( ".set push \n\t" diff --git a/libwebp/src/dsp/lossless_msa.c b/libwebp/src/dsp/lossless_msa.c index 9f547207..0f8ef410 100644 --- a/libwebp/src/dsp/lossless_msa.c +++ b/libwebp/src/dsp/lossless_msa.c @@ -290,9 +290,9 @@ static void TransformColorInverse_MSA(const VP8LMultipliers* const m, const uint32_t* src, int num_pixels, uint32_t* dst) { v16u8 src0, dst0; - const v16i8 g2br = (v16i8)__msa_fill_w(m->green_to_blue_ | - (m->green_to_red_ << 16)); - const v16i8 r2b = (v16i8)__msa_fill_w(m->red_to_blue_); + const v16i8 g2br = (v16i8)__msa_fill_w(m->green_to_blue | + (m->green_to_red << 16)); + const v16i8 r2b = (v16i8)__msa_fill_w(m->red_to_blue); const v16u8 mask0 = { 1, 255, 1, 255, 5, 255, 5, 255, 9, 255, 9, 255, 13, 255, 13, 255 }; const v16u8 mask1 = { 16, 1, 18, 3, 20, 5, 22, 7, 24, 9, 26, 11, diff --git a/libwebp/src/dsp/lossless_neon.c b/libwebp/src/dsp/lossless_neon.c index e9960db3..0a85edd4 100644 --- a/libwebp/src/dsp/lossless_neon.c +++ b/libwebp/src/dsp/lossless_neon.c @@ -19,6 +19,7 @@ #include "src/dsp/lossless.h" #include "src/dsp/neon.h" +#include "src/webp/format_constants.h" //------------------------------------------------------------------------------ // Colorspace conversion functions @@ -26,8 +27,8 @@ #if !defined(WORK_AROUND_GCC) // gcc 4.6.0 had some trouble (NDK-r9) with this code. We only use it for // gcc-4.8.x at least. -static void ConvertBGRAToRGBA_NEON(const uint32_t* src, - int num_pixels, uint8_t* dst) { +static void ConvertBGRAToRGBA_NEON(const uint32_t* WEBP_RESTRICT src, + int num_pixels, uint8_t* WEBP_RESTRICT dst) { const uint32_t* const end = src + (num_pixels & ~15); for (; src < end; src += 16) { uint8x16x4_t pixel = vld4q_u8((uint8_t*)src); @@ -41,8 +42,8 @@ static void ConvertBGRAToRGBA_NEON(const uint32_t* src, VP8LConvertBGRAToRGBA_C(src, num_pixels & 15, dst); // left-overs } -static void ConvertBGRAToBGR_NEON(const uint32_t* src, - int num_pixels, uint8_t* dst) { +static void ConvertBGRAToBGR_NEON(const uint32_t* WEBP_RESTRICT src, + int num_pixels, uint8_t* WEBP_RESTRICT dst) { const uint32_t* const end = src + (num_pixels & ~15); for (; src < end; src += 16) { const uint8x16x4_t pixel = vld4q_u8((uint8_t*)src); @@ -53,8 +54,8 @@ static void ConvertBGRAToBGR_NEON(const uint32_t* src, VP8LConvertBGRAToBGR_C(src, num_pixels & 15, dst); // left-overs } -static void ConvertBGRAToRGB_NEON(const uint32_t* src, - int num_pixels, uint8_t* dst) { +static void ConvertBGRAToRGB_NEON(const uint32_t* WEBP_RESTRICT src, + int num_pixels, uint8_t* WEBP_RESTRICT dst) { const uint32_t* const end = src + (num_pixels & ~15); for (; src < end; src += 16) { const uint8x16x4_t pixel = vld4q_u8((uint8_t*)src); @@ -71,8 +72,8 @@ static void ConvertBGRAToRGB_NEON(const uint32_t* src, static const uint8_t kRGBAShuffle[8] = { 2, 1, 0, 3, 6, 5, 4, 7 }; -static void ConvertBGRAToRGBA_NEON(const uint32_t* src, - int num_pixels, uint8_t* dst) { +static void ConvertBGRAToRGBA_NEON(const uint32_t* WEBP_RESTRICT src, + int num_pixels, uint8_t* WEBP_RESTRICT dst) { const uint32_t* const end = src + (num_pixels & ~1); const uint8x8_t shuffle = vld1_u8(kRGBAShuffle); for (; src < end; src += 2) { @@ -89,8 +90,8 @@ static const uint8_t kBGRShuffle[3][8] = { { 21, 22, 24, 25, 26, 28, 29, 30 } }; -static void ConvertBGRAToBGR_NEON(const uint32_t* src, - int num_pixels, uint8_t* dst) { +static void ConvertBGRAToBGR_NEON(const uint32_t* WEBP_RESTRICT src, + int num_pixels, uint8_t* WEBP_RESTRICT dst) { const uint32_t* const end = src + (num_pixels & ~7); const uint8x8_t shuffle0 = vld1_u8(kBGRShuffle[0]); const uint8x8_t shuffle1 = vld1_u8(kBGRShuffle[1]); @@ -116,8 +117,8 @@ static const uint8_t kRGBShuffle[3][8] = { { 21, 20, 26, 25, 24, 30, 29, 28 } }; -static void ConvertBGRAToRGB_NEON(const uint32_t* src, - int num_pixels, uint8_t* dst) { +static void ConvertBGRAToRGB_NEON(const uint32_t* WEBP_RESTRICT src, + int num_pixels, uint8_t* WEBP_RESTRICT dst) { const uint32_t* const end = src + (num_pixels & ~7); const uint8x8_t shuffle0 = vld1_u8(kRGBShuffle[0]); const uint8x8_t shuffle1 = vld1_u8(kRGBShuffle[1]); @@ -209,7 +210,7 @@ static uint32_t Predictor13_NEON(const uint32_t* const left, // Predictor0: ARGB_BLACK. static void PredictorAdd0_NEON(const uint32_t* in, const uint32_t* upper, - int num_pixels, uint32_t* out) { + int num_pixels, uint32_t* WEBP_RESTRICT out) { int i; const uint8x16_t black = vreinterpretq_u8_u32(vdupq_n_u32(ARGB_BLACK)); for (i = 0; i + 4 <= num_pixels; i += 4) { @@ -222,7 +223,7 @@ static void PredictorAdd0_NEON(const uint32_t* in, const uint32_t* upper, // Predictor1: left. static void PredictorAdd1_NEON(const uint32_t* in, const uint32_t* upper, - int num_pixels, uint32_t* out) { + int num_pixels, uint32_t* WEBP_RESTRICT out) { int i; const uint8x16_t zero = LOADQ_U32_AS_U8(0); for (i = 0; i + 4 <= num_pixels; i += 4) { @@ -248,7 +249,7 @@ static void PredictorAdd1_NEON(const uint32_t* in, const uint32_t* upper, #define GENERATE_PREDICTOR_1(X, IN) \ static void PredictorAdd##X##_NEON(const uint32_t* in, \ const uint32_t* upper, int num_pixels, \ - uint32_t* out) { \ + uint32_t* WEBP_RESTRICT out) { \ int i; \ for (i = 0; i + 4 <= num_pixels; i += 4) { \ const uint8x16_t src = LOADQ_U32P_AS_U8(&in[i]); \ @@ -276,7 +277,7 @@ GENERATE_PREDICTOR_1(4, upper[i - 1]) } while (0) static void PredictorAdd5_NEON(const uint32_t* in, const uint32_t* upper, - int num_pixels, uint32_t* out) { + int num_pixels, uint32_t* WEBP_RESTRICT out) { int i; uint8x16_t L = LOADQ_U32_AS_U8(out[-1]); for (i = 0; i + 4 <= num_pixels; i += 4) { @@ -301,7 +302,7 @@ static void PredictorAdd5_NEON(const uint32_t* in, const uint32_t* upper, // Predictor6: average(left, TL) static void PredictorAdd6_NEON(const uint32_t* in, const uint32_t* upper, - int num_pixels, uint32_t* out) { + int num_pixels, uint32_t* WEBP_RESTRICT out) { int i; uint8x16_t L = LOADQ_U32_AS_U8(out[-1]); for (i = 0; i + 4 <= num_pixels; i += 4) { @@ -317,7 +318,7 @@ static void PredictorAdd6_NEON(const uint32_t* in, const uint32_t* upper, // Predictor7: average(left, T) static void PredictorAdd7_NEON(const uint32_t* in, const uint32_t* upper, - int num_pixels, uint32_t* out) { + int num_pixels, uint32_t* WEBP_RESTRICT out) { int i; uint8x16_t L = LOADQ_U32_AS_U8(out[-1]); for (i = 0; i + 4 <= num_pixels; i += 4) { @@ -335,7 +336,7 @@ static void PredictorAdd7_NEON(const uint32_t* in, const uint32_t* upper, #define GENERATE_PREDICTOR_2(X, IN) \ static void PredictorAdd##X##_NEON(const uint32_t* in, \ const uint32_t* upper, int num_pixels, \ - uint32_t* out) { \ + uint32_t* WEBP_RESTRICT out) { \ int i; \ for (i = 0; i + 4 <= num_pixels; i += 4) { \ const uint8x16_t src = LOADQ_U32P_AS_U8(&in[i]); \ @@ -363,7 +364,7 @@ GENERATE_PREDICTOR_2(9, upper[i + 1]) } while (0) static void PredictorAdd10_NEON(const uint32_t* in, const uint32_t* upper, - int num_pixels, uint32_t* out) { + int num_pixels, uint32_t* WEBP_RESTRICT out) { int i; uint8x16_t L = LOADQ_U32_AS_U8(out[-1]); for (i = 0; i + 4 <= num_pixels; i += 4) { @@ -394,7 +395,7 @@ static void PredictorAdd10_NEON(const uint32_t* in, const uint32_t* upper, } while (0) static void PredictorAdd11_NEON(const uint32_t* in, const uint32_t* upper, - int num_pixels, uint32_t* out) { + int num_pixels, uint32_t* WEBP_RESTRICT out) { int i; uint8x16_t L = LOADQ_U32_AS_U8(out[-1]); for (i = 0; i + 4 <= num_pixels; i += 4) { @@ -427,7 +428,7 @@ static void PredictorAdd11_NEON(const uint32_t* in, const uint32_t* upper, } while (0) static void PredictorAdd12_NEON(const uint32_t* in, const uint32_t* upper, - int num_pixels, uint32_t* out) { + int num_pixels, uint32_t* WEBP_RESTRICT out) { int i; uint16x8_t L = vmovl_u8(LOAD_U32_AS_U8(out[-1])); for (i = 0; i + 4 <= num_pixels; i += 4) { @@ -468,7 +469,7 @@ static void PredictorAdd12_NEON(const uint32_t* in, const uint32_t* upper, } while (0) static void PredictorAdd13_NEON(const uint32_t* in, const uint32_t* upper, - int num_pixels, uint32_t* out) { + int num_pixels, uint32_t* WEBP_RESTRICT out) { int i; uint8x16_t L = LOADQ_U32_AS_U8(out[-1]); for (i = 0; i + 4 <= num_pixels; i += 4) { @@ -551,15 +552,15 @@ static void TransformColorInverse_NEON(const VP8LMultipliers* const m, // sign-extended multiplying constants, pre-shifted by 6. #define CST(X) (((int16_t)(m->X << 8)) >> 6) const int16_t rb[8] = { - CST(green_to_blue_), CST(green_to_red_), - CST(green_to_blue_), CST(green_to_red_), - CST(green_to_blue_), CST(green_to_red_), - CST(green_to_blue_), CST(green_to_red_) + CST(green_to_blue), CST(green_to_red), + CST(green_to_blue), CST(green_to_red), + CST(green_to_blue), CST(green_to_red), + CST(green_to_blue), CST(green_to_red) }; const int16x8_t mults_rb = vld1q_s16(rb); const int16_t b2[8] = { - 0, CST(red_to_blue_), 0, CST(red_to_blue_), - 0, CST(red_to_blue_), 0, CST(red_to_blue_), + 0, CST(red_to_blue), 0, CST(red_to_blue), + 0, CST(red_to_blue), 0, CST(red_to_blue), }; const int16x8_t mults_b2 = vld1q_s16(b2); #undef CST diff --git a/libwebp/src/dsp/lossless_sse2.c b/libwebp/src/dsp/lossless_sse2.c index 4b6a532c..3c6608be 100644 --- a/libwebp/src/dsp/lossless_sse2.c +++ b/libwebp/src/dsp/lossless_sse2.c @@ -15,10 +15,15 @@ #if defined(WEBP_USE_SSE2) +#include +#include + #include "src/dsp/common_sse2.h" +#include "src/dsp/cpu.h" #include "src/dsp/lossless.h" #include "src/dsp/lossless_common.h" -#include +#include "src/webp/format_constants.h" +#include "src/webp/types.h" //------------------------------------------------------------------------------ // Predictor Transform @@ -186,7 +191,7 @@ static uint32_t Predictor13_SSE2(const uint32_t* const left, // Predictor0: ARGB_BLACK. static void PredictorAdd0_SSE2(const uint32_t* in, const uint32_t* upper, - int num_pixels, uint32_t* out) { + int num_pixels, uint32_t* WEBP_RESTRICT out) { int i; const __m128i black = _mm_set1_epi32((int)ARGB_BLACK); for (i = 0; i + 4 <= num_pixels; i += 4) { @@ -202,7 +207,7 @@ static void PredictorAdd0_SSE2(const uint32_t* in, const uint32_t* upper, // Predictor1: left. static void PredictorAdd1_SSE2(const uint32_t* in, const uint32_t* upper, - int num_pixels, uint32_t* out) { + int num_pixels, uint32_t* WEBP_RESTRICT out) { int i; __m128i prev = _mm_set1_epi32((int)out[-1]); for (i = 0; i + 4 <= num_pixels; i += 4) { @@ -230,7 +235,8 @@ static void PredictorAdd1_SSE2(const uint32_t* in, const uint32_t* upper, // per 8 bit channel. #define GENERATE_PREDICTOR_1(X, IN) \ static void PredictorAdd##X##_SSE2(const uint32_t* in, const uint32_t* upper, \ - int num_pixels, uint32_t* out) { \ + int num_pixels, \ + uint32_t* WEBP_RESTRICT out) { \ int i; \ for (i = 0; i + 4 <= num_pixels; i += 4) { \ const __m128i src = _mm_loadu_si128((const __m128i*)&in[i]); \ @@ -259,7 +265,8 @@ GENERATE_PREDICTOR_ADD(Predictor7_SSE2, PredictorAdd7_SSE2) #define GENERATE_PREDICTOR_2(X, IN) \ static void PredictorAdd##X##_SSE2(const uint32_t* in, const uint32_t* upper, \ - int num_pixels, uint32_t* out) { \ + int num_pixels, \ + uint32_t* WEBP_RESTRICT out) { \ int i; \ for (i = 0; i + 4 <= num_pixels; i += 4) { \ const __m128i Tother = _mm_loadu_si128((const __m128i*)&(IN)); \ @@ -297,7 +304,7 @@ GENERATE_PREDICTOR_2(9, upper[i + 1]) } while (0) static void PredictorAdd10_SSE2(const uint32_t* in, const uint32_t* upper, - int num_pixels, uint32_t* out) { + int num_pixels, uint32_t* WEBP_RESTRICT out) { int i; __m128i L = _mm_cvtsi32_si128((int)out[-1]); for (i = 0; i + 4 <= num_pixels; i += 4) { @@ -344,7 +351,7 @@ static void PredictorAdd10_SSE2(const uint32_t* in, const uint32_t* upper, } while (0) static void PredictorAdd11_SSE2(const uint32_t* in, const uint32_t* upper, - int num_pixels, uint32_t* out) { + int num_pixels, uint32_t* WEBP_RESTRICT out) { int i; __m128i pa; __m128i L = _mm_cvtsi32_si128((int)out[-1]); @@ -395,7 +402,7 @@ static void PredictorAdd11_SSE2(const uint32_t* in, const uint32_t* upper, } while (0) static void PredictorAdd12_SSE2(const uint32_t* in, const uint32_t* upper, - int num_pixels, uint32_t* out) { + int num_pixels, uint32_t* WEBP_RESTRICT out) { int i; const __m128i zero = _mm_setzero_si128(); const __m128i L8 = _mm_cvtsi32_si128((int)out[-1]); @@ -460,8 +467,8 @@ static void TransformColorInverse_SSE2(const VP8LMultipliers* const m, #define CST(X) (((int16_t)(m->X << 8)) >> 5) // sign-extend #define MK_CST_16(HI, LO) \ _mm_set1_epi32((int)(((uint32_t)(HI) << 16) | ((LO) & 0xffff))) - const __m128i mults_rb = MK_CST_16(CST(green_to_red_), CST(green_to_blue_)); - const __m128i mults_b2 = MK_CST_16(CST(red_to_blue_), 0); + const __m128i mults_rb = MK_CST_16(CST(green_to_red), CST(green_to_blue)); + const __m128i mults_b2 = MK_CST_16(CST(red_to_blue), 0); #undef MK_CST_16 #undef CST const __m128i mask_ag = _mm_set1_epi32((int)0xff00ff00); // alpha-green masks @@ -490,8 +497,8 @@ static void TransformColorInverse_SSE2(const VP8LMultipliers* const m, //------------------------------------------------------------------------------ // Color-space conversion functions -static void ConvertBGRAToRGB_SSE2(const uint32_t* src, int num_pixels, - uint8_t* dst) { +static void ConvertBGRAToRGB_SSE2(const uint32_t* WEBP_RESTRICT src, + int num_pixels, uint8_t* WEBP_RESTRICT dst) { const __m128i* in = (const __m128i*)src; __m128i* out = (__m128i*)dst; @@ -526,8 +533,8 @@ static void ConvertBGRAToRGB_SSE2(const uint32_t* src, int num_pixels, } } -static void ConvertBGRAToRGBA_SSE2(const uint32_t* src, - int num_pixels, uint8_t* dst) { +static void ConvertBGRAToRGBA_SSE2(const uint32_t* WEBP_RESTRICT src, + int num_pixels, uint8_t* WEBP_RESTRICT dst) { const __m128i red_blue_mask = _mm_set1_epi32(0x00ff00ff); const __m128i* in = (const __m128i*)src; __m128i* out = (__m128i*)dst; @@ -554,8 +561,9 @@ static void ConvertBGRAToRGBA_SSE2(const uint32_t* src, } } -static void ConvertBGRAToRGBA4444_SSE2(const uint32_t* src, - int num_pixels, uint8_t* dst) { +static void ConvertBGRAToRGBA4444_SSE2(const uint32_t* WEBP_RESTRICT src, + int num_pixels, + uint8_t* WEBP_RESTRICT dst) { const __m128i mask_0x0f = _mm_set1_epi8(0x0f); const __m128i mask_0xf0 = _mm_set1_epi8((char)0xf0); const __m128i* in = (const __m128i*)src; @@ -590,8 +598,9 @@ static void ConvertBGRAToRGBA4444_SSE2(const uint32_t* src, } } -static void ConvertBGRAToRGB565_SSE2(const uint32_t* src, - int num_pixels, uint8_t* dst) { +static void ConvertBGRAToRGB565_SSE2(const uint32_t* WEBP_RESTRICT src, + int num_pixels, + uint8_t* WEBP_RESTRICT dst) { const __m128i mask_0xe0 = _mm_set1_epi8((char)0xe0); const __m128i mask_0xf8 = _mm_set1_epi8((char)0xf8); const __m128i mask_0x07 = _mm_set1_epi8(0x07); @@ -631,8 +640,8 @@ static void ConvertBGRAToRGB565_SSE2(const uint32_t* src, } } -static void ConvertBGRAToBGR_SSE2(const uint32_t* src, - int num_pixels, uint8_t* dst) { +static void ConvertBGRAToBGR_SSE2(const uint32_t* WEBP_RESTRICT src, + int num_pixels, uint8_t* WEBP_RESTRICT dst) { const __m128i mask_l = _mm_set_epi32(0, 0x00ffffff, 0, 0x00ffffff); const __m128i mask_h = _mm_set_epi32(0x00ffffff, 0, 0x00ffffff, 0); const __m128i* in = (const __m128i*)src; @@ -703,6 +712,15 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInitSSE2(void) { VP8LConvertBGRAToRGBA4444 = ConvertBGRAToRGBA4444_SSE2; VP8LConvertBGRAToRGB565 = ConvertBGRAToRGB565_SSE2; VP8LConvertBGRAToBGR = ConvertBGRAToBGR_SSE2; + + // SSE exports for AVX and above. + memcpy(VP8LPredictorsAdd_SSE, VP8LPredictorsAdd, sizeof(VP8LPredictorsAdd)); + + VP8LAddGreenToBlueAndRed_SSE = AddGreenToBlueAndRed_SSE2; + VP8LTransformColorInverse_SSE = TransformColorInverse_SSE2; + + VP8LConvertBGRAToRGB_SSE = ConvertBGRAToRGB_SSE2; + VP8LConvertBGRAToRGBA_SSE = ConvertBGRAToRGBA_SSE2; } #else // !WEBP_USE_SSE2 diff --git a/libwebp/src/dsp/lossless_sse41.c b/libwebp/src/dsp/lossless_sse41.c index bb7ce761..598e6794 100644 --- a/libwebp/src/dsp/lossless_sse41.c +++ b/libwebp/src/dsp/lossless_sse41.c @@ -12,10 +12,12 @@ #include "src/dsp/dsp.h" #if defined(WEBP_USE_SSE41) +#include +#include -#include "src/dsp/common_sse41.h" +#include "src/webp/types.h" +#include "src/dsp/cpu.h" #include "src/dsp/lossless.h" -#include "src/dsp/lossless_common.h" //------------------------------------------------------------------------------ // Color-space conversion functions @@ -26,9 +28,9 @@ static void TransformColorInverse_SSE41(const VP8LMultipliers* const m, // sign-extended multiplying constants, pre-shifted by 5. #define CST(X) (((int16_t)(m->X << 8)) >> 5) // sign-extend const __m128i mults_rb = - _mm_set1_epi32((int)((uint32_t)CST(green_to_red_) << 16 | - (CST(green_to_blue_) & 0xffff))); - const __m128i mults_b2 = _mm_set1_epi32(CST(red_to_blue_)); + _mm_set1_epi32((int)((uint32_t)CST(green_to_red) << 16 | + (CST(green_to_blue) & 0xffff))); + const __m128i mults_b2 = _mm_set1_epi32(CST(red_to_blue)); #undef CST const __m128i mask_ag = _mm_set1_epi32((int)0xff00ff00); const __m128i perm1 = _mm_setr_epi8(-1, 1, -1, 1, -1, 5, -1, 5, @@ -77,8 +79,8 @@ static void TransformColorInverse_SSE41(const VP8LMultipliers* const m, } \ } while (0) -static void ConvertBGRAToRGB_SSE41(const uint32_t* src, int num_pixels, - uint8_t* dst) { +static void ConvertBGRAToRGB_SSE41(const uint32_t* WEBP_RESTRICT src, + int num_pixels, uint8_t* WEBP_RESTRICT dst) { const __m128i* in = (const __m128i*)src; __m128i* out = (__m128i*)dst; const __m128i perm0 = _mm_setr_epi8(2, 1, 0, 6, 5, 4, 10, 9, @@ -95,8 +97,8 @@ static void ConvertBGRAToRGB_SSE41(const uint32_t* src, int num_pixels, } } -static void ConvertBGRAToBGR_SSE41(const uint32_t* src, - int num_pixels, uint8_t* dst) { +static void ConvertBGRAToBGR_SSE41(const uint32_t* WEBP_RESTRICT src, + int num_pixels, uint8_t* WEBP_RESTRICT dst) { const __m128i* in = (const __m128i*)src; __m128i* out = (__m128i*)dst; const __m128i perm0 = _mm_setr_epi8(0, 1, 2, 4, 5, 6, 8, 9, 10, @@ -124,6 +126,10 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInitSSE41(void) { VP8LTransformColorInverse = TransformColorInverse_SSE41; VP8LConvertBGRAToRGB = ConvertBGRAToRGB_SSE41; VP8LConvertBGRAToBGR = ConvertBGRAToBGR_SSE41; + + // SSE exports for AVX and above. + VP8LTransformColorInverse_SSE = TransformColorInverse_SSE41; + VP8LConvertBGRAToRGB_SSE = ConvertBGRAToRGB_SSE41; } #else // !WEBP_USE_SSE41 diff --git a/libwebp/src/dsp/rescaler.c b/libwebp/src/dsp/rescaler.c index 325d8be1..eafccd44 100644 --- a/libwebp/src/dsp/rescaler.c +++ b/libwebp/src/dsp/rescaler.c @@ -12,7 +12,10 @@ // Author: Skal (pascal.massimino@gmail.com) #include +#include +#include "src/dsp/cpu.h" +#include "src/webp/types.h" #include "src/dsp/dsp.h" #include "src/utils/rescaler_utils.h" @@ -26,8 +29,8 @@ //------------------------------------------------------------------------------ // Row import -void WebPRescalerImportRowExpand_C(WebPRescaler* const wrk, - const uint8_t* src) { +void WebPRescalerImportRowExpand_C(WebPRescaler* WEBP_RESTRICT const wrk, + const uint8_t* WEBP_RESTRICT src) { const int x_stride = wrk->num_channels; const int x_out_max = wrk->dst_width * wrk->num_channels; int channel; @@ -59,8 +62,8 @@ void WebPRescalerImportRowExpand_C(WebPRescaler* const wrk, } } -void WebPRescalerImportRowShrink_C(WebPRescaler* const wrk, - const uint8_t* src) { +void WebPRescalerImportRowShrink_C(WebPRescaler* WEBP_RESTRICT const wrk, + const uint8_t* WEBP_RESTRICT src) { const int x_stride = wrk->num_channels; const int x_out_max = wrk->dst_width * wrk->num_channels; int channel; @@ -158,7 +161,8 @@ void WebPRescalerExportRowShrink_C(WebPRescaler* const wrk) { //------------------------------------------------------------------------------ // Main entry calls -void WebPRescalerImportRow(WebPRescaler* const wrk, const uint8_t* src) { +void WebPRescalerImportRow(WebPRescaler* WEBP_RESTRICT const wrk, + const uint8_t* WEBP_RESTRICT src) { assert(!WebPRescalerInputDone(wrk)); if (!wrk->x_expand) { WebPRescalerImportRowShrink(wrk, src); diff --git a/libwebp/src/dsp/rescaler_mips32.c b/libwebp/src/dsp/rescaler_mips32.c index 61f63c61..b5168caa 100644 --- a/libwebp/src/dsp/rescaler_mips32.c +++ b/libwebp/src/dsp/rescaler_mips32.c @@ -21,8 +21,8 @@ //------------------------------------------------------------------------------ // Row import -static void ImportRowShrink_MIPS32(WebPRescaler* const wrk, - const uint8_t* src) { +static void ImportRowShrink_MIPS32(WebPRescaler* WEBP_RESTRICT const wrk, + const uint8_t* WEBP_RESTRICT src) { const int x_stride = wrk->num_channels; const int x_out_max = wrk->dst_width * wrk->num_channels; const int fx_scale = wrk->fx_scale; @@ -81,8 +81,8 @@ static void ImportRowShrink_MIPS32(WebPRescaler* const wrk, } } -static void ImportRowExpand_MIPS32(WebPRescaler* const wrk, - const uint8_t* src) { +static void ImportRowExpand_MIPS32(WebPRescaler* WEBP_RESTRICT const wrk, + const uint8_t* WEBP_RESTRICT src) { const int x_stride = wrk->num_channels; const int x_out_max = wrk->dst_width * wrk->num_channels; const int x_add = wrk->x_add; diff --git a/libwebp/src/dsp/rescaler_msa.c b/libwebp/src/dsp/rescaler_msa.c index 256dbdd4..954d0fdf 100644 --- a/libwebp/src/dsp/rescaler_msa.c +++ b/libwebp/src/dsp/rescaler_msa.c @@ -114,9 +114,9 @@ dst = __msa_copy_s_w((v4i32)t0, 0); \ } while (0) -static WEBP_INLINE void ExportRowExpand_0(const uint32_t* frow, uint8_t* dst, - int length, - WebPRescaler* const wrk) { +static WEBP_INLINE void ExportRowExpand_0( + const uint32_t* WEBP_RESTRICT frow, uint8_t* WEBP_RESTRICT dst, int length, + WebPRescaler* WEBP_RESTRICT const wrk) { const v4u32 scale = (v4u32)__msa_fill_w(wrk->fy_scale); const v4u32 shift = (v4u32)__msa_fill_w(WEBP_RESCALER_RFIX); const v4i32 zero = { 0 }; @@ -171,9 +171,10 @@ static WEBP_INLINE void ExportRowExpand_0(const uint32_t* frow, uint8_t* dst, } } -static WEBP_INLINE void ExportRowExpand_1(const uint32_t* frow, uint32_t* irow, - uint8_t* dst, int length, - WebPRescaler* const wrk) { +static WEBP_INLINE void ExportRowExpand_1( + const uint32_t* WEBP_RESTRICT frow, uint32_t* WEBP_RESTRICT irow, + uint8_t* WEBP_RESTRICT dst, int length, + WebPRescaler* WEBP_RESTRICT const wrk) { const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub); const uint32_t A = (uint32_t)(WEBP_RESCALER_ONE - B); const v4i32 B1 = __msa_fill_w(B); @@ -262,10 +263,10 @@ static void RescalerExportRowExpand_MIPSdspR2(WebPRescaler* const wrk) { } #if 0 // disabled for now. TODO(skal): make match the C-code -static WEBP_INLINE void ExportRowShrink_0(const uint32_t* frow, uint32_t* irow, - uint8_t* dst, int length, - const uint32_t yscale, - WebPRescaler* const wrk) { +static WEBP_INLINE void ExportRowShrink_0( + const uint32_t* WEBP_RESTRICT frow, uint32_t* WEBP_RESTRICT irow, + uint8_t* WEBP_RESTRICT dst, int length, const uint32_t yscale, + WebPRescaler* WEBP_RESTRICT const wrk) { const v4u32 y_scale = (v4u32)__msa_fill_w(yscale); const v4u32 fxyscale = (v4u32)__msa_fill_w(wrk->fxy_scale); const v4u32 shiftval = (v4u32)__msa_fill_w(WEBP_RESCALER_RFIX); @@ -348,9 +349,9 @@ static WEBP_INLINE void ExportRowShrink_0(const uint32_t* frow, uint32_t* irow, } } -static WEBP_INLINE void ExportRowShrink_1(uint32_t* irow, uint8_t* dst, - int length, - WebPRescaler* const wrk) { +static WEBP_INLINE void ExportRowShrink_1( + uint32_t* WEBP_RESTRICT irow, uint8_t* WEBP_RESTRICT dst, int length, + WebPRescaler* WEBP_RESTRICT const wrk) { const v4u32 scale = (v4u32)__msa_fill_w(wrk->fxy_scale); const v4u32 shift = (v4u32)__msa_fill_w(WEBP_RESCALER_RFIX); const v4i32 zero = { 0 }; diff --git a/libwebp/src/dsp/rescaler_neon.c b/libwebp/src/dsp/rescaler_neon.c index 957a92db..ab4ddc00 100644 --- a/libwebp/src/dsp/rescaler_neon.c +++ b/libwebp/src/dsp/rescaler_neon.c @@ -45,8 +45,8 @@ #error "MULT_FIX/WEBP_RESCALER_RFIX need some more work" #endif -static uint32x4_t Interpolate_NEON(const rescaler_t* const frow, - const rescaler_t* const irow, +static uint32x4_t Interpolate_NEON(const rescaler_t* WEBP_RESTRICT const frow, + const rescaler_t* WEBP_RESTRICT const irow, uint32_t A, uint32_t B) { LOAD_32x4(frow, A0); LOAD_32x4(irow, B0); diff --git a/libwebp/src/dsp/rescaler_sse2.c b/libwebp/src/dsp/rescaler_sse2.c index 3f18e94e..be5508ca 100644 --- a/libwebp/src/dsp/rescaler_sse2.c +++ b/libwebp/src/dsp/rescaler_sse2.c @@ -17,8 +17,12 @@ #include #include +#include + +#include "src/dsp/cpu.h" #include "src/utils/rescaler_utils.h" #include "src/utils/utils.h" +#include "src/webp/types.h" //------------------------------------------------------------------------------ // Implementations of critical functions ImportRow / ExportRow @@ -43,8 +47,8 @@ static void LoadEightPixels_SSE2(const uint8_t* const src, __m128i* out) { *out = _mm_unpacklo_epi8(A, zero); } -static void RescalerImportRowExpand_SSE2(WebPRescaler* const wrk, - const uint8_t* src) { +static void RescalerImportRowExpand_SSE2(WebPRescaler* WEBP_RESTRICT const wrk, + const uint8_t* WEBP_RESTRICT src) { rescaler_t* frow = wrk->frow; const rescaler_t* const frow_end = frow + wrk->dst_width * wrk->num_channels; const int x_add = wrk->x_add; @@ -109,8 +113,8 @@ static void RescalerImportRowExpand_SSE2(WebPRescaler* const wrk, assert(accum == 0); } -static void RescalerImportRowShrink_SSE2(WebPRescaler* const wrk, - const uint8_t* src) { +static void RescalerImportRowShrink_SSE2(WebPRescaler* WEBP_RESTRICT const wrk, + const uint8_t* WEBP_RESTRICT src) { const int x_sub = wrk->x_sub; int accum = 0; const __m128i zero = _mm_setzero_si128(); @@ -168,12 +172,10 @@ static void RescalerImportRowShrink_SSE2(WebPRescaler* const wrk, // Row export // load *src as epi64, multiply by mult and store result in [out0 ... out3] -static WEBP_INLINE void LoadDispatchAndMult_SSE2(const rescaler_t* const src, - const __m128i* const mult, - __m128i* const out0, - __m128i* const out1, - __m128i* const out2, - __m128i* const out3) { +static WEBP_INLINE void LoadDispatchAndMult_SSE2( + const rescaler_t* WEBP_RESTRICT const src, const __m128i* const mult, + __m128i* const out0, __m128i* const out1, __m128i* const out2, + __m128i* const out3) { const __m128i A0 = _mm_loadu_si128((const __m128i*)(src + 0)); const __m128i A1 = _mm_loadu_si128((const __m128i*)(src + 4)); const __m128i A2 = _mm_srli_epi64(A0, 32); diff --git a/libwebp/src/dsp/ssim.c b/libwebp/src/dsp/ssim.c deleted file mode 100644 index 9a1341ed..00000000 --- a/libwebp/src/dsp/ssim.c +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright 2017 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// distortion calculation -// -// Author: Skal (pascal.massimino@gmail.com) - -#include -#include // for abs() - -#include "src/dsp/dsp.h" - -#if !defined(WEBP_REDUCE_SIZE) - -//------------------------------------------------------------------------------ -// SSIM / PSNR - -// hat-shaped filter. Sum of coefficients is equal to 16. -static const uint32_t kWeight[2 * VP8_SSIM_KERNEL + 1] = { - 1, 2, 3, 4, 3, 2, 1 -}; -static const uint32_t kWeightSum = 16 * 16; // sum{kWeight}^2 - -static WEBP_INLINE double SSIMCalculation( - const VP8DistoStats* const stats, uint32_t N /*num samples*/) { - const uint32_t w2 = N * N; - const uint32_t C1 = 20 * w2; - const uint32_t C2 = 60 * w2; - const uint32_t C3 = 8 * 8 * w2; // 'dark' limit ~= 6 - const uint64_t xmxm = (uint64_t)stats->xm * stats->xm; - const uint64_t ymym = (uint64_t)stats->ym * stats->ym; - if (xmxm + ymym >= C3) { - const int64_t xmym = (int64_t)stats->xm * stats->ym; - const int64_t sxy = (int64_t)stats->xym * N - xmym; // can be negative - const uint64_t sxx = (uint64_t)stats->xxm * N - xmxm; - const uint64_t syy = (uint64_t)stats->yym * N - ymym; - // we descale by 8 to prevent overflow during the fnum/fden multiply. - const uint64_t num_S = (2 * (uint64_t)(sxy < 0 ? 0 : sxy) + C2) >> 8; - const uint64_t den_S = (sxx + syy + C2) >> 8; - const uint64_t fnum = (2 * xmym + C1) * num_S; - const uint64_t fden = (xmxm + ymym + C1) * den_S; - const double r = (double)fnum / fden; - assert(r >= 0. && r <= 1.0); - return r; - } - return 1.; // area is too dark to contribute meaningfully -} - -double VP8SSIMFromStats(const VP8DistoStats* const stats) { - return SSIMCalculation(stats, kWeightSum); -} - -double VP8SSIMFromStatsClipped(const VP8DistoStats* const stats) { - return SSIMCalculation(stats, stats->w); -} - -static double SSIMGetClipped_C(const uint8_t* src1, int stride1, - const uint8_t* src2, int stride2, - int xo, int yo, int W, int H) { - VP8DistoStats stats = { 0, 0, 0, 0, 0, 0 }; - const int ymin = (yo - VP8_SSIM_KERNEL < 0) ? 0 : yo - VP8_SSIM_KERNEL; - const int ymax = (yo + VP8_SSIM_KERNEL > H - 1) ? H - 1 - : yo + VP8_SSIM_KERNEL; - const int xmin = (xo - VP8_SSIM_KERNEL < 0) ? 0 : xo - VP8_SSIM_KERNEL; - const int xmax = (xo + VP8_SSIM_KERNEL > W - 1) ? W - 1 - : xo + VP8_SSIM_KERNEL; - int x, y; - src1 += ymin * stride1; - src2 += ymin * stride2; - for (y = ymin; y <= ymax; ++y, src1 += stride1, src2 += stride2) { - for (x = xmin; x <= xmax; ++x) { - const uint32_t w = kWeight[VP8_SSIM_KERNEL + x - xo] - * kWeight[VP8_SSIM_KERNEL + y - yo]; - const uint32_t s1 = src1[x]; - const uint32_t s2 = src2[x]; - stats.w += w; - stats.xm += w * s1; - stats.ym += w * s2; - stats.xxm += w * s1 * s1; - stats.xym += w * s1 * s2; - stats.yym += w * s2 * s2; - } - } - return VP8SSIMFromStatsClipped(&stats); -} - -static double SSIMGet_C(const uint8_t* src1, int stride1, - const uint8_t* src2, int stride2) { - VP8DistoStats stats = { 0, 0, 0, 0, 0, 0 }; - int x, y; - for (y = 0; y <= 2 * VP8_SSIM_KERNEL; ++y, src1 += stride1, src2 += stride2) { - for (x = 0; x <= 2 * VP8_SSIM_KERNEL; ++x) { - const uint32_t w = kWeight[x] * kWeight[y]; - const uint32_t s1 = src1[x]; - const uint32_t s2 = src2[x]; - stats.xm += w * s1; - stats.ym += w * s2; - stats.xxm += w * s1 * s1; - stats.xym += w * s1 * s2; - stats.yym += w * s2 * s2; - } - } - return VP8SSIMFromStats(&stats); -} - -#endif // !defined(WEBP_REDUCE_SIZE) - -//------------------------------------------------------------------------------ - -#if !defined(WEBP_DISABLE_STATS) -static uint32_t AccumulateSSE_C(const uint8_t* src1, - const uint8_t* src2, int len) { - int i; - uint32_t sse2 = 0; - assert(len <= 65535); // to ensure that accumulation fits within uint32_t - for (i = 0; i < len; ++i) { - const int32_t diff = src1[i] - src2[i]; - sse2 += diff * diff; - } - return sse2; -} -#endif - -//------------------------------------------------------------------------------ - -#if !defined(WEBP_REDUCE_SIZE) -VP8SSIMGetFunc VP8SSIMGet; -VP8SSIMGetClippedFunc VP8SSIMGetClipped; -#endif -#if !defined(WEBP_DISABLE_STATS) -VP8AccumulateSSEFunc VP8AccumulateSSE; -#endif - -extern VP8CPUInfo VP8GetCPUInfo; -extern void VP8SSIMDspInitSSE2(void); - -WEBP_DSP_INIT_FUNC(VP8SSIMDspInit) { -#if !defined(WEBP_REDUCE_SIZE) - VP8SSIMGetClipped = SSIMGetClipped_C; - VP8SSIMGet = SSIMGet_C; -#endif - -#if !defined(WEBP_DISABLE_STATS) - VP8AccumulateSSE = AccumulateSSE_C; -#endif - - if (VP8GetCPUInfo != NULL) { -#if defined(WEBP_HAVE_SSE2) - if (VP8GetCPUInfo(kSSE2)) { - VP8SSIMDspInitSSE2(); - } -#endif - } -} diff --git a/libwebp/src/dsp/ssim_sse2.c b/libwebp/src/dsp/ssim_sse2.c deleted file mode 100644 index 1dcb0eb0..00000000 --- a/libwebp/src/dsp/ssim_sse2.c +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright 2017 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// SSE2 version of distortion calculation -// -// Author: Skal (pascal.massimino@gmail.com) - -#include "src/dsp/dsp.h" - -#if defined(WEBP_USE_SSE2) - -#include -#include - -#include "src/dsp/common_sse2.h" - -#if !defined(WEBP_DISABLE_STATS) - -// Helper function -static WEBP_INLINE void SubtractAndSquare_SSE2(const __m128i a, const __m128i b, - __m128i* const sum) { - // take abs(a-b) in 8b - const __m128i a_b = _mm_subs_epu8(a, b); - const __m128i b_a = _mm_subs_epu8(b, a); - const __m128i abs_a_b = _mm_or_si128(a_b, b_a); - // zero-extend to 16b - const __m128i zero = _mm_setzero_si128(); - const __m128i C0 = _mm_unpacklo_epi8(abs_a_b, zero); - const __m128i C1 = _mm_unpackhi_epi8(abs_a_b, zero); - // multiply with self - const __m128i sum1 = _mm_madd_epi16(C0, C0); - const __m128i sum2 = _mm_madd_epi16(C1, C1); - *sum = _mm_add_epi32(sum1, sum2); -} - -//------------------------------------------------------------------------------ -// SSIM / PSNR entry point - -static uint32_t AccumulateSSE_SSE2(const uint8_t* src1, - const uint8_t* src2, int len) { - int i = 0; - uint32_t sse2 = 0; - if (len >= 16) { - const int limit = len - 32; - int32_t tmp[4]; - __m128i sum1; - __m128i sum = _mm_setzero_si128(); - __m128i a0 = _mm_loadu_si128((const __m128i*)&src1[i]); - __m128i b0 = _mm_loadu_si128((const __m128i*)&src2[i]); - i += 16; - while (i <= limit) { - const __m128i a1 = _mm_loadu_si128((const __m128i*)&src1[i]); - const __m128i b1 = _mm_loadu_si128((const __m128i*)&src2[i]); - __m128i sum2; - i += 16; - SubtractAndSquare_SSE2(a0, b0, &sum1); - sum = _mm_add_epi32(sum, sum1); - a0 = _mm_loadu_si128((const __m128i*)&src1[i]); - b0 = _mm_loadu_si128((const __m128i*)&src2[i]); - i += 16; - SubtractAndSquare_SSE2(a1, b1, &sum2); - sum = _mm_add_epi32(sum, sum2); - } - SubtractAndSquare_SSE2(a0, b0, &sum1); - sum = _mm_add_epi32(sum, sum1); - _mm_storeu_si128((__m128i*)tmp, sum); - sse2 += (tmp[3] + tmp[2] + tmp[1] + tmp[0]); - } - - for (; i < len; ++i) { - const int32_t diff = src1[i] - src2[i]; - sse2 += diff * diff; - } - return sse2; -} -#endif // !defined(WEBP_DISABLE_STATS) - -#if !defined(WEBP_REDUCE_SIZE) - -static uint32_t HorizontalAdd16b_SSE2(const __m128i* const m) { - uint16_t tmp[8]; - const __m128i a = _mm_srli_si128(*m, 8); - const __m128i b = _mm_add_epi16(*m, a); - _mm_storeu_si128((__m128i*)tmp, b); - return (uint32_t)tmp[3] + tmp[2] + tmp[1] + tmp[0]; -} - -static uint32_t HorizontalAdd32b_SSE2(const __m128i* const m) { - const __m128i a = _mm_srli_si128(*m, 8); - const __m128i b = _mm_add_epi32(*m, a); - const __m128i c = _mm_add_epi32(b, _mm_srli_si128(b, 4)); - return (uint32_t)_mm_cvtsi128_si32(c); -} - -static const uint16_t kWeight[] = { 1, 2, 3, 4, 3, 2, 1, 0 }; - -#define ACCUMULATE_ROW(WEIGHT) do { \ - /* compute row weight (Wx * Wy) */ \ - const __m128i Wy = _mm_set1_epi16((WEIGHT)); \ - const __m128i W = _mm_mullo_epi16(Wx, Wy); \ - /* process 8 bytes at a time (7 bytes, actually) */ \ - const __m128i a0 = _mm_loadl_epi64((const __m128i*)src1); \ - const __m128i b0 = _mm_loadl_epi64((const __m128i*)src2); \ - /* convert to 16b and multiply by weight */ \ - const __m128i a1 = _mm_unpacklo_epi8(a0, zero); \ - const __m128i b1 = _mm_unpacklo_epi8(b0, zero); \ - const __m128i wa1 = _mm_mullo_epi16(a1, W); \ - const __m128i wb1 = _mm_mullo_epi16(b1, W); \ - /* accumulate */ \ - xm = _mm_add_epi16(xm, wa1); \ - ym = _mm_add_epi16(ym, wb1); \ - xxm = _mm_add_epi32(xxm, _mm_madd_epi16(a1, wa1)); \ - xym = _mm_add_epi32(xym, _mm_madd_epi16(a1, wb1)); \ - yym = _mm_add_epi32(yym, _mm_madd_epi16(b1, wb1)); \ - src1 += stride1; \ - src2 += stride2; \ -} while (0) - -static double SSIMGet_SSE2(const uint8_t* src1, int stride1, - const uint8_t* src2, int stride2) { - VP8DistoStats stats; - const __m128i zero = _mm_setzero_si128(); - __m128i xm = zero, ym = zero; // 16b accums - __m128i xxm = zero, yym = zero, xym = zero; // 32b accum - const __m128i Wx = _mm_loadu_si128((const __m128i*)kWeight); - assert(2 * VP8_SSIM_KERNEL + 1 == 7); - ACCUMULATE_ROW(1); - ACCUMULATE_ROW(2); - ACCUMULATE_ROW(3); - ACCUMULATE_ROW(4); - ACCUMULATE_ROW(3); - ACCUMULATE_ROW(2); - ACCUMULATE_ROW(1); - stats.xm = HorizontalAdd16b_SSE2(&xm); - stats.ym = HorizontalAdd16b_SSE2(&ym); - stats.xxm = HorizontalAdd32b_SSE2(&xxm); - stats.xym = HorizontalAdd32b_SSE2(&xym); - stats.yym = HorizontalAdd32b_SSE2(&yym); - return VP8SSIMFromStats(&stats); -} - -#endif // !defined(WEBP_REDUCE_SIZE) - -extern void VP8SSIMDspInitSSE2(void); - -WEBP_TSAN_IGNORE_FUNCTION void VP8SSIMDspInitSSE2(void) { -#if !defined(WEBP_DISABLE_STATS) - VP8AccumulateSSE = AccumulateSSE_SSE2; -#endif -#if !defined(WEBP_REDUCE_SIZE) - VP8SSIMGet = SSIMGet_SSE2; -#endif -} - -#else // !WEBP_USE_SSE2 - -WEBP_DSP_INIT_STUB(VP8SSIMDspInitSSE2) - -#endif // WEBP_USE_SSE2 diff --git a/libwebp/src/dsp/upsampling.c b/libwebp/src/dsp/upsampling.c index 983b9c42..c57f66c3 100644 --- a/libwebp/src/dsp/upsampling.c +++ b/libwebp/src/dsp/upsampling.c @@ -11,10 +11,14 @@ // // Author: somnath@google.com (Somnath Banerjee) +#include +#include + +#include "src/dsp/cpu.h" +#include "src/webp/types.h" #include "src/dsp/dsp.h" #include "src/dsp/yuv.h" - -#include +#include "src/webp/decode.h" //------------------------------------------------------------------------------ // Fancy upsampler @@ -35,10 +39,14 @@ WebPUpsampleLinePairFunc WebPUpsamplers[MODE_LAST]; #define LOAD_UV(u, v) ((u) | ((v) << 16)) #define UPSAMPLE_FUNC(FUNC_NAME, FUNC, XSTEP) \ -static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \ - const uint8_t* top_u, const uint8_t* top_v, \ - const uint8_t* cur_u, const uint8_t* cur_v, \ - uint8_t* top_dst, uint8_t* bottom_dst, int len) { \ +static void FUNC_NAME(const uint8_t* WEBP_RESTRICT top_y, \ + const uint8_t* WEBP_RESTRICT bottom_y, \ + const uint8_t* WEBP_RESTRICT top_u, \ + const uint8_t* WEBP_RESTRICT top_v, \ + const uint8_t* WEBP_RESTRICT cur_u, \ + const uint8_t* WEBP_RESTRICT cur_v, \ + uint8_t* WEBP_RESTRICT top_dst, \ + uint8_t* WEBP_RESTRICT bottom_dst, int len) { \ int x; \ const int last_pixel_pair = (len - 1) >> 1; \ uint32_t tl_uv = LOAD_UV(top_u[0], top_v[0]); /* top-left sample */ \ @@ -136,10 +144,14 @@ static void EmptyUpsampleFunc(const uint8_t* top_y, const uint8_t* bottom_y, #if !defined(FANCY_UPSAMPLING) #define DUAL_SAMPLE_FUNC(FUNC_NAME, FUNC) \ -static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bot_y, \ - const uint8_t* top_u, const uint8_t* top_v, \ - const uint8_t* bot_u, const uint8_t* bot_v, \ - uint8_t* top_dst, uint8_t* bot_dst, int len) { \ +static void FUNC_NAME(const uint8_t* WEBP_RESTRICT top_y, \ + const uint8_t* WEBP_RESTRICT bot_y, \ + const uint8_t* WEBP_RESTRICT top_u, \ + const uint8_t* WEBP_RESTRICT top_v, \ + const uint8_t* WEBP_RESTRICT bot_u, \ + const uint8_t* WEBP_RESTRICT bot_v, \ + uint8_t* WEBP_RESTRICT top_dst, \ + uint8_t* WEBP_RESTRICT bot_dst, int len) { \ const int half_len = len >> 1; \ int x; \ assert(top_dst != NULL); \ @@ -178,10 +190,14 @@ WebPUpsampleLinePairFunc WebPGetLinePairConverter(int alpha_is_last) { // YUV444 converter #define YUV444_FUNC(FUNC_NAME, FUNC, XSTEP) \ -extern void FUNC_NAME(const uint8_t* y, const uint8_t* u, const uint8_t* v, \ - uint8_t* dst, int len); \ -void FUNC_NAME(const uint8_t* y, const uint8_t* u, const uint8_t* v, \ - uint8_t* dst, int len) { \ +extern void FUNC_NAME(const uint8_t* WEBP_RESTRICT y, \ + const uint8_t* WEBP_RESTRICT u, \ + const uint8_t* WEBP_RESTRICT v, \ + uint8_t* WEBP_RESTRICT dst, int len); \ +void FUNC_NAME(const uint8_t* WEBP_RESTRICT y, \ + const uint8_t* WEBP_RESTRICT u, \ + const uint8_t* WEBP_RESTRICT v, \ + uint8_t* WEBP_RESTRICT dst, int len) { \ int i; \ for (i = 0; i < len; ++i) FUNC(y[i], u[i], v[i], &dst[i * (XSTEP)]); \ } diff --git a/libwebp/src/dsp/upsampling_mips_dsp_r2.c b/libwebp/src/dsp/upsampling_mips_dsp_r2.c index 10d499d7..cbe8e71d 100644 --- a/libwebp/src/dsp/upsampling_mips_dsp_r2.c +++ b/libwebp/src/dsp/upsampling_mips_dsp_r2.c @@ -143,10 +143,14 @@ static WEBP_INLINE void YuvToRgba(uint8_t y, uint8_t u, uint8_t v, #define LOAD_UV(u, v) ((u) | ((v) << 16)) #define UPSAMPLE_FUNC(FUNC_NAME, FUNC, XSTEP) \ -static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \ - const uint8_t* top_u, const uint8_t* top_v, \ - const uint8_t* cur_u, const uint8_t* cur_v, \ - uint8_t* top_dst, uint8_t* bottom_dst, int len) { \ +static void FUNC_NAME(const uint8_t* WEBP_RESTRICT top_y, \ + const uint8_t* WEBP_RESTRICT bottom_y, \ + const uint8_t* WEBP_RESTRICT top_u, \ + const uint8_t* WEBP_RESTRICT top_v, \ + const uint8_t* WEBP_RESTRICT cur_u, \ + const uint8_t* WEBP_RESTRICT cur_v, \ + uint8_t* WEBP_RESTRICT top_dst, \ + uint8_t* WEBP_RESTRICT bottom_dst, int len) { \ int x; \ const int last_pixel_pair = (len - 1) >> 1; \ uint32_t tl_uv = LOAD_UV(top_u[0], top_v[0]); /* top-left sample */ \ @@ -241,8 +245,10 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitUpsamplersMIPSdspR2(void) { // YUV444 converter #define YUV444_FUNC(FUNC_NAME, FUNC, XSTEP) \ -static void FUNC_NAME(const uint8_t* y, const uint8_t* u, const uint8_t* v, \ - uint8_t* dst, int len) { \ +static void FUNC_NAME(const uint8_t* WEBP_RESTRICT y, \ + const uint8_t* WEBP_RESTRICT u, \ + const uint8_t* WEBP_RESTRICT v, \ + uint8_t* WEBP_RESTRICT dst, int len) { \ int i; \ for (i = 0; i < len; ++i) FUNC(y[i], u[i], v[i], &dst[i * XSTEP]); \ } diff --git a/libwebp/src/dsp/upsampling_msa.c b/libwebp/src/dsp/upsampling_msa.c index f2e03e85..72a526bc 100644 --- a/libwebp/src/dsp/upsampling_msa.c +++ b/libwebp/src/dsp/upsampling_msa.c @@ -320,8 +320,10 @@ static void YuvToRgba(uint8_t y, uint8_t u, uint8_t v, uint8_t* const rgba) { } #if !defined(WEBP_REDUCE_CSP) -static void YuvToRgbLine(const uint8_t* y, const uint8_t* u, - const uint8_t* v, uint8_t* dst, int length) { +static void YuvToRgbLine(const uint8_t* WEBP_RESTRICT y, + const uint8_t* WEBP_RESTRICT u, + const uint8_t* WEBP_RESTRICT v, + uint8_t* WEBP_RESTRICT dst, int length) { v16u8 R, G, B; while (length >= 16) { CALC_RGB16(y, u, v, R, G, B); @@ -347,8 +349,10 @@ static void YuvToRgbLine(const uint8_t* y, const uint8_t* u, } } -static void YuvToBgrLine(const uint8_t* y, const uint8_t* u, - const uint8_t* v, uint8_t* dst, int length) { +static void YuvToBgrLine(const uint8_t* WEBP_RESTRICT y, + const uint8_t* WEBP_RESTRICT u, + const uint8_t* WEBP_RESTRICT v, + uint8_t* WEBP_RESTRICT dst, int length) { v16u8 R, G, B; while (length >= 16) { CALC_RGB16(y, u, v, R, G, B); @@ -375,8 +379,10 @@ static void YuvToBgrLine(const uint8_t* y, const uint8_t* u, } #endif // WEBP_REDUCE_CSP -static void YuvToRgbaLine(const uint8_t* y, const uint8_t* u, - const uint8_t* v, uint8_t* dst, int length) { +static void YuvToRgbaLine(const uint8_t* WEBP_RESTRICT y, + const uint8_t* WEBP_RESTRICT u, + const uint8_t* WEBP_RESTRICT v, + uint8_t* WEBP_RESTRICT dst, int length) { v16u8 R, G, B; const v16u8 A = (v16u8)__msa_ldi_b(ALPHAVAL); while (length >= 16) { @@ -403,8 +409,10 @@ static void YuvToRgbaLine(const uint8_t* y, const uint8_t* u, } } -static void YuvToBgraLine(const uint8_t* y, const uint8_t* u, - const uint8_t* v, uint8_t* dst, int length) { +static void YuvToBgraLine(const uint8_t* WEBP_RESTRICT y, + const uint8_t* WEBP_RESTRICT u, + const uint8_t* WEBP_RESTRICT v, + uint8_t* WEBP_RESTRICT dst, int length) { v16u8 R, G, B; const v16u8 A = (v16u8)__msa_ldi_b(ALPHAVAL); while (length >= 16) { @@ -432,8 +440,10 @@ static void YuvToBgraLine(const uint8_t* y, const uint8_t* u, } #if !defined(WEBP_REDUCE_CSP) -static void YuvToArgbLine(const uint8_t* y, const uint8_t* u, - const uint8_t* v, uint8_t* dst, int length) { +static void YuvToArgbLine(const uint8_t* WEBP_RESTRICT y, + const uint8_t* WEBP_RESTRICT u, + const uint8_t* WEBP_RESTRICT v, + uint8_t* WEBP_RESTRICT dst, int length) { v16u8 R, G, B; const v16u8 A = (v16u8)__msa_ldi_b(ALPHAVAL); while (length >= 16) { @@ -460,8 +470,10 @@ static void YuvToArgbLine(const uint8_t* y, const uint8_t* u, } } -static void YuvToRgba4444Line(const uint8_t* y, const uint8_t* u, - const uint8_t* v, uint8_t* dst, int length) { +static void YuvToRgba4444Line(const uint8_t* WEBP_RESTRICT y, + const uint8_t* WEBP_RESTRICT u, + const uint8_t* WEBP_RESTRICT v, + uint8_t* WEBP_RESTRICT dst, int length) { v16u8 R, G, B, RG, BA, tmp0, tmp1; while (length >= 16) { #if (WEBP_SWAP_16BIT_CSP == 1) @@ -496,8 +508,10 @@ static void YuvToRgba4444Line(const uint8_t* y, const uint8_t* u, } } -static void YuvToRgb565Line(const uint8_t* y, const uint8_t* u, - const uint8_t* v, uint8_t* dst, int length) { +static void YuvToRgb565Line(const uint8_t* WEBP_RESTRICT y, + const uint8_t* WEBP_RESTRICT u, + const uint8_t* WEBP_RESTRICT v, + uint8_t* WEBP_RESTRICT dst, int length) { v16u8 R, G, B, RG, GB, tmp0, tmp1; while (length >= 16) { #if (WEBP_SWAP_16BIT_CSP == 1) @@ -564,11 +578,14 @@ static void YuvToRgb565Line(const uint8_t* y, const uint8_t* u, } while (0) #define UPSAMPLE_FUNC(FUNC_NAME, FUNC, XSTEP) \ -static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bot_y, \ - const uint8_t* top_u, const uint8_t* top_v, \ - const uint8_t* cur_u, const uint8_t* cur_v, \ - uint8_t* top_dst, uint8_t* bot_dst, int len) \ -{ \ +static void FUNC_NAME(const uint8_t* WEBP_RESTRICT top_y, \ + const uint8_t* WEBP_RESTRICT bot_y, \ + const uint8_t* WEBP_RESTRICT top_u, \ + const uint8_t* WEBP_RESTRICT top_v, \ + const uint8_t* WEBP_RESTRICT cur_u, \ + const uint8_t* WEBP_RESTRICT cur_v, \ + uint8_t* WEBP_RESTRICT top_dst, \ + uint8_t* WEBP_RESTRICT bot_dst, int len) { \ int size = (len - 1) >> 1; \ uint8_t temp_u[64]; \ uint8_t temp_v[64]; \ diff --git a/libwebp/src/dsp/upsampling_neon.c b/libwebp/src/dsp/upsampling_neon.c index bbc000ca..2bd3e931 100644 --- a/libwebp/src/dsp/upsampling_neon.c +++ b/libwebp/src/dsp/upsampling_neon.c @@ -58,8 +58,9 @@ } while (0) // Turn the macro into a function for reducing code-size when non-critical -static void Upsample16Pixels_NEON(const uint8_t* r1, const uint8_t* r2, - uint8_t* out) { +static void Upsample16Pixels_NEON(const uint8_t* WEBP_RESTRICT const r1, + const uint8_t* WEBP_RESTRICT const r2, + uint8_t* WEBP_RESTRICT const out) { UPSAMPLE_16PIXELS(r1, r2, out); } @@ -189,57 +190,61 @@ static const int16_t kCoeffs1[4] = { 19077, 26149, 6419, 13320 }; } \ } -#define NEON_UPSAMPLE_FUNC(FUNC_NAME, FMT, XSTEP) \ -static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \ - const uint8_t* top_u, const uint8_t* top_v, \ - const uint8_t* cur_u, const uint8_t* cur_v, \ - uint8_t* top_dst, uint8_t* bottom_dst, int len) { \ - int block; \ - /* 16 byte aligned array to cache reconstructed u and v */ \ - uint8_t uv_buf[2 * 32 + 15]; \ - uint8_t* const r_uv = (uint8_t*)((uintptr_t)(uv_buf + 15) & ~15); \ - const int uv_len = (len + 1) >> 1; \ - /* 9 pixels must be read-able for each block */ \ - const int num_blocks = (uv_len - 1) >> 3; \ - const int leftover = uv_len - num_blocks * 8; \ - const int last_pos = 1 + 16 * num_blocks; \ - \ - const int u_diag = ((top_u[0] + cur_u[0]) >> 1) + 1; \ - const int v_diag = ((top_v[0] + cur_v[0]) >> 1) + 1; \ - \ - const int16x4_t coeff1 = vld1_s16(kCoeffs1); \ - const int16x8_t R_Rounder = vdupq_n_s16(-14234); \ - const int16x8_t G_Rounder = vdupq_n_s16(8708); \ - const int16x8_t B_Rounder = vdupq_n_s16(-17685); \ - \ - /* Treat the first pixel in regular way */ \ - assert(top_y != NULL); \ - { \ - const int u0 = (top_u[0] + u_diag) >> 1; \ - const int v0 = (top_v[0] + v_diag) >> 1; \ - VP8YuvTo ## FMT(top_y[0], u0, v0, top_dst); \ - } \ - if (bottom_y != NULL) { \ - const int u0 = (cur_u[0] + u_diag) >> 1; \ - const int v0 = (cur_v[0] + v_diag) >> 1; \ - VP8YuvTo ## FMT(bottom_y[0], u0, v0, bottom_dst); \ - } \ - \ - for (block = 0; block < num_blocks; ++block) { \ - UPSAMPLE_16PIXELS(top_u, cur_u, r_uv); \ - UPSAMPLE_16PIXELS(top_v, cur_v, r_uv + 16); \ - CONVERT2RGB_8(FMT, XSTEP, top_y, bottom_y, r_uv, \ - top_dst, bottom_dst, 16 * block + 1, 16); \ - top_u += 8; \ - cur_u += 8; \ - top_v += 8; \ - cur_v += 8; \ - } \ - \ - UPSAMPLE_LAST_BLOCK(top_u, cur_u, leftover, r_uv); \ - UPSAMPLE_LAST_BLOCK(top_v, cur_v, leftover, r_uv + 16); \ - CONVERT2RGB_1(VP8YuvTo ## FMT, XSTEP, top_y, bottom_y, r_uv, \ - top_dst, bottom_dst, last_pos, len - last_pos); \ +#define NEON_UPSAMPLE_FUNC(FUNC_NAME, FMT, XSTEP) \ +static void FUNC_NAME(const uint8_t* WEBP_RESTRICT top_y, \ + const uint8_t* WEBP_RESTRICT bottom_y, \ + const uint8_t* WEBP_RESTRICT top_u, \ + const uint8_t* WEBP_RESTRICT top_v, \ + const uint8_t* WEBP_RESTRICT cur_u, \ + const uint8_t* WEBP_RESTRICT cur_v, \ + uint8_t* WEBP_RESTRICT top_dst, \ + uint8_t* WEBP_RESTRICT bottom_dst, int len) { \ + int block; \ + /* 16 byte aligned array to cache reconstructed u and v */ \ + uint8_t uv_buf[2 * 32 + 15]; \ + uint8_t* const r_uv = (uint8_t*)((uintptr_t)(uv_buf + 15) & ~(uintptr_t)15); \ + const int uv_len = (len + 1) >> 1; \ + /* 9 pixels must be read-able for each block */ \ + const int num_blocks = (uv_len - 1) >> 3; \ + const int leftover = uv_len - num_blocks * 8; \ + const int last_pos = 1 + 16 * num_blocks; \ + \ + const int u_diag = ((top_u[0] + cur_u[0]) >> 1) + 1; \ + const int v_diag = ((top_v[0] + cur_v[0]) >> 1) + 1; \ + \ + const int16x4_t coeff1 = vld1_s16(kCoeffs1); \ + const int16x8_t R_Rounder = vdupq_n_s16(-14234); \ + const int16x8_t G_Rounder = vdupq_n_s16(8708); \ + const int16x8_t B_Rounder = vdupq_n_s16(-17685); \ + \ + /* Treat the first pixel in regular way */ \ + assert(top_y != NULL); \ + { \ + const int u0 = (top_u[0] + u_diag) >> 1; \ + const int v0 = (top_v[0] + v_diag) >> 1; \ + VP8YuvTo ## FMT(top_y[0], u0, v0, top_dst); \ + } \ + if (bottom_y != NULL) { \ + const int u0 = (cur_u[0] + u_diag) >> 1; \ + const int v0 = (cur_v[0] + v_diag) >> 1; \ + VP8YuvTo ## FMT(bottom_y[0], u0, v0, bottom_dst); \ + } \ + \ + for (block = 0; block < num_blocks; ++block) { \ + UPSAMPLE_16PIXELS(top_u, cur_u, r_uv); \ + UPSAMPLE_16PIXELS(top_v, cur_v, r_uv + 16); \ + CONVERT2RGB_8(FMT, XSTEP, top_y, bottom_y, r_uv, \ + top_dst, bottom_dst, 16 * block + 1, 16); \ + top_u += 8; \ + cur_u += 8; \ + top_v += 8; \ + cur_v += 8; \ + } \ + \ + UPSAMPLE_LAST_BLOCK(top_u, cur_u, leftover, r_uv); \ + UPSAMPLE_LAST_BLOCK(top_v, cur_v, leftover, r_uv + 16); \ + CONVERT2RGB_1(VP8YuvTo ## FMT, XSTEP, top_y, bottom_y, r_uv, \ + top_dst, bottom_dst, last_pos, len - last_pos); \ } // NEON variants of the fancy upsampler. diff --git a/libwebp/src/dsp/upsampling_sse2.c b/libwebp/src/dsp/upsampling_sse2.c index 77b4f722..0eecb11c 100644 --- a/libwebp/src/dsp/upsampling_sse2.c +++ b/libwebp/src/dsp/upsampling_sse2.c @@ -14,11 +14,15 @@ #include "src/dsp/dsp.h" #if defined(WEBP_USE_SSE2) +#include #include -#include #include + +#include "src/webp/types.h" +#include "src/dsp/cpu.h" #include "src/dsp/yuv.h" +#include "src/webp/decode.h" #ifdef FANCY_UPSAMPLING @@ -88,8 +92,9 @@ } while (0) // Turn the macro into a function for reducing code-size when non-critical -static void Upsample32Pixels_SSE2(const uint8_t r1[], const uint8_t r2[], - uint8_t* const out) { +static void Upsample32Pixels_SSE2(const uint8_t* WEBP_RESTRICT const r1, + const uint8_t* WEBP_RESTRICT const r2, + uint8_t* WEBP_RESTRICT const out) { UPSAMPLE_32PIXELS(r1, r2, out); } @@ -114,10 +119,14 @@ static void Upsample32Pixels_SSE2(const uint8_t r1[], const uint8_t r2[], } while (0) #define SSE2_UPSAMPLE_FUNC(FUNC_NAME, FUNC, XSTEP) \ -static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \ - const uint8_t* top_u, const uint8_t* top_v, \ - const uint8_t* cur_u, const uint8_t* cur_v, \ - uint8_t* top_dst, uint8_t* bottom_dst, int len) { \ +static void FUNC_NAME(const uint8_t* WEBP_RESTRICT top_y, \ + const uint8_t* WEBP_RESTRICT bottom_y, \ + const uint8_t* WEBP_RESTRICT top_u, \ + const uint8_t* WEBP_RESTRICT top_v, \ + const uint8_t* WEBP_RESTRICT cur_u, \ + const uint8_t* WEBP_RESTRICT cur_v, \ + uint8_t* WEBP_RESTRICT top_dst, \ + uint8_t* WEBP_RESTRICT bottom_dst, int len) { \ int uv_pos, pos; \ /* 16byte-aligned array to cache reconstructed u and v */ \ uint8_t uv_buf[14 * 32 + 15] = { 0 }; \ @@ -215,10 +224,14 @@ extern WebPYUV444Converter WebPYUV444Converters[/* MODE_LAST */]; extern void WebPInitYUV444ConvertersSSE2(void); #define YUV444_FUNC(FUNC_NAME, CALL, CALL_C, XSTEP) \ -extern void CALL_C(const uint8_t* y, const uint8_t* u, const uint8_t* v, \ - uint8_t* dst, int len); \ -static void FUNC_NAME(const uint8_t* y, const uint8_t* u, const uint8_t* v, \ - uint8_t* dst, int len) { \ +extern void CALL_C(const uint8_t* WEBP_RESTRICT y, \ + const uint8_t* WEBP_RESTRICT u, \ + const uint8_t* WEBP_RESTRICT v, \ + uint8_t* WEBP_RESTRICT dst, int len); \ +static void FUNC_NAME(const uint8_t* WEBP_RESTRICT y, \ + const uint8_t* WEBP_RESTRICT u, \ + const uint8_t* WEBP_RESTRICT v, \ + uint8_t* WEBP_RESTRICT dst, int len) { \ int i; \ const int max_len = len & ~31; \ for (i = 0; i < max_len; i += 32) { \ diff --git a/libwebp/src/dsp/upsampling_sse41.c b/libwebp/src/dsp/upsampling_sse41.c index e38c88d5..cac9567a 100644 --- a/libwebp/src/dsp/upsampling_sse41.c +++ b/libwebp/src/dsp/upsampling_sse41.c @@ -14,11 +14,15 @@ #include "src/dsp/dsp.h" #if defined(WEBP_USE_SSE41) +#include #include -#include #include + +#include "src/webp/types.h" +#include "src/dsp/cpu.h" #include "src/dsp/yuv.h" +#include "src/webp/decode.h" #ifdef FANCY_UPSAMPLING @@ -90,8 +94,9 @@ } while (0) // Turn the macro into a function for reducing code-size when non-critical -static void Upsample32Pixels_SSE41(const uint8_t r1[], const uint8_t r2[], - uint8_t* const out) { +static void Upsample32Pixels_SSE41(const uint8_t* WEBP_RESTRICT const r1, + const uint8_t* WEBP_RESTRICT const r2, + uint8_t* WEBP_RESTRICT const out) { UPSAMPLE_32PIXELS(r1, r2, out); } @@ -116,14 +121,18 @@ static void Upsample32Pixels_SSE41(const uint8_t r1[], const uint8_t r2[], } while (0) #define SSE4_UPSAMPLE_FUNC(FUNC_NAME, FUNC, XSTEP) \ -static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \ - const uint8_t* top_u, const uint8_t* top_v, \ - const uint8_t* cur_u, const uint8_t* cur_v, \ - uint8_t* top_dst, uint8_t* bottom_dst, int len) { \ +static void FUNC_NAME(const uint8_t* WEBP_RESTRICT top_y, \ + const uint8_t* WEBP_RESTRICT bottom_y, \ + const uint8_t* WEBP_RESTRICT top_u, \ + const uint8_t* WEBP_RESTRICT top_v, \ + const uint8_t* WEBP_RESTRICT cur_u, \ + const uint8_t* WEBP_RESTRICT cur_v, \ + uint8_t* WEBP_RESTRICT top_dst, \ + uint8_t* WEBP_RESTRICT bottom_dst, int len) { \ int uv_pos, pos; \ /* 16byte-aligned array to cache reconstructed u and v */ \ uint8_t uv_buf[14 * 32 + 15] = { 0 }; \ - uint8_t* const r_u = (uint8_t*)((uintptr_t)(uv_buf + 15) & ~15); \ + uint8_t* const r_u = (uint8_t*)((uintptr_t)(uv_buf + 15) & ~(uintptr_t)15); \ uint8_t* const r_v = r_u + 32; \ \ assert(top_y != NULL); \ @@ -202,10 +211,14 @@ extern WebPYUV444Converter WebPYUV444Converters[/* MODE_LAST */]; extern void WebPInitYUV444ConvertersSSE41(void); #define YUV444_FUNC(FUNC_NAME, CALL, CALL_C, XSTEP) \ -extern void CALL_C(const uint8_t* y, const uint8_t* u, const uint8_t* v, \ - uint8_t* dst, int len); \ -static void FUNC_NAME(const uint8_t* y, const uint8_t* u, const uint8_t* v, \ - uint8_t* dst, int len) { \ +extern void CALL_C(const uint8_t* WEBP_RESTRICT y, \ + const uint8_t* WEBP_RESTRICT u, \ + const uint8_t* WEBP_RESTRICT v, \ + uint8_t* WEBP_RESTRICT dst, int len); \ +static void FUNC_NAME(const uint8_t* WEBP_RESTRICT y, \ + const uint8_t* WEBP_RESTRICT u, \ + const uint8_t* WEBP_RESTRICT v, \ + uint8_t* WEBP_RESTRICT dst, int len) { \ int i; \ const int max_len = len & ~31; \ for (i = 0; i < max_len; i += 32) { \ diff --git a/libwebp/src/dsp/yuv.c b/libwebp/src/dsp/yuv.c index 8a04b85d..62f1ecc1 100644 --- a/libwebp/src/dsp/yuv.c +++ b/libwebp/src/dsp/yuv.c @@ -11,18 +11,23 @@ // // Author: Skal (pascal.massimino@gmail.com) -#include "src/dsp/yuv.h" - #include #include +#include "src/dsp/cpu.h" +#include "src/webp/types.h" +#include "src/dsp/dsp.h" +#include "src/dsp/yuv.h" +#include "src/webp/decode.h" + //----------------------------------------------------------------------------- // Plain-C version #define ROW_FUNC(FUNC_NAME, FUNC, XSTEP) \ -static void FUNC_NAME(const uint8_t* y, \ - const uint8_t* u, const uint8_t* v, \ - uint8_t* dst, int len) { \ +static void FUNC_NAME(const uint8_t* WEBP_RESTRICT y, \ + const uint8_t* WEBP_RESTRICT u, \ + const uint8_t* WEBP_RESTRICT v, \ + uint8_t* WEBP_RESTRICT dst, int len) { \ const uint8_t* const end = dst + (len & ~1) * (XSTEP); \ while (dst != end) { \ FUNC(y[0], u[0], v[0], dst); \ @@ -49,9 +54,10 @@ ROW_FUNC(YuvToRgb565Row, VP8YuvToRgb565, 2) #undef ROW_FUNC // Main call for processing a plane with a WebPSamplerRowFunc function: -void WebPSamplerProcessPlane(const uint8_t* y, int y_stride, - const uint8_t* u, const uint8_t* v, int uv_stride, - uint8_t* dst, int dst_stride, +void WebPSamplerProcessPlane(const uint8_t* WEBP_RESTRICT y, int y_stride, + const uint8_t* WEBP_RESTRICT u, + const uint8_t* WEBP_RESTRICT v, int uv_stride, + uint8_t* WEBP_RESTRICT dst, int dst_stride, int width, int height, WebPSamplerRowFunc func) { int j; for (j = 0; j < height; ++j) { @@ -117,7 +123,8 @@ WEBP_DSP_INIT_FUNC(WebPInitSamplers) { //----------------------------------------------------------------------------- // ARGB -> YUV converters -static void ConvertARGBToY_C(const uint32_t* argb, uint8_t* y, int width) { +static void ConvertARGBToY_C(const uint32_t* WEBP_RESTRICT argb, + uint8_t* WEBP_RESTRICT y, int width) { int i; for (i = 0; i < width; ++i) { const uint32_t p = argb[i]; @@ -126,7 +133,8 @@ static void ConvertARGBToY_C(const uint32_t* argb, uint8_t* y, int width) { } } -void WebPConvertARGBToUV_C(const uint32_t* argb, uint8_t* u, uint8_t* v, +void WebPConvertARGBToUV_C(const uint32_t* WEBP_RESTRICT argb, + uint8_t* WEBP_RESTRICT u, uint8_t* WEBP_RESTRICT v, int src_width, int do_store) { // No rounding. Last pixel is dealt with separately. const int uv_width = src_width >> 1; @@ -169,22 +177,25 @@ void WebPConvertARGBToUV_C(const uint32_t* argb, uint8_t* u, uint8_t* v, //----------------------------------------------------------------------------- -static void ConvertRGB24ToY_C(const uint8_t* rgb, uint8_t* y, int width) { +static void ConvertRGB24ToY_C(const uint8_t* WEBP_RESTRICT rgb, + uint8_t* WEBP_RESTRICT y, int width) { int i; for (i = 0; i < width; ++i, rgb += 3) { y[i] = VP8RGBToY(rgb[0], rgb[1], rgb[2], YUV_HALF); } } -static void ConvertBGR24ToY_C(const uint8_t* bgr, uint8_t* y, int width) { +static void ConvertBGR24ToY_C(const uint8_t* WEBP_RESTRICT bgr, + uint8_t* WEBP_RESTRICT y, int width) { int i; for (i = 0; i < width; ++i, bgr += 3) { y[i] = VP8RGBToY(bgr[2], bgr[1], bgr[0], YUV_HALF); } } -void WebPConvertRGBA32ToUV_C(const uint16_t* rgb, - uint8_t* u, uint8_t* v, int width) { +void WebPConvertRGBA32ToUV_C(const uint16_t* WEBP_RESTRICT rgb, + uint8_t* WEBP_RESTRICT u, uint8_t* WEBP_RESTRICT v, + int width) { int i; for (i = 0; i < width; i += 1, rgb += 4) { const int r = rgb[0], g = rgb[1], b = rgb[2]; @@ -195,13 +206,18 @@ void WebPConvertRGBA32ToUV_C(const uint16_t* rgb, //----------------------------------------------------------------------------- -void (*WebPConvertRGB24ToY)(const uint8_t* rgb, uint8_t* y, int width); -void (*WebPConvertBGR24ToY)(const uint8_t* bgr, uint8_t* y, int width); -void (*WebPConvertRGBA32ToUV)(const uint16_t* rgb, - uint8_t* u, uint8_t* v, int width); +void (*WebPConvertRGB24ToY)(const uint8_t* WEBP_RESTRICT rgb, + uint8_t* WEBP_RESTRICT y, int width); +void (*WebPConvertBGR24ToY)(const uint8_t* WEBP_RESTRICT bgr, + uint8_t* WEBP_RESTRICT y, int width); +void (*WebPConvertRGBA32ToUV)(const uint16_t* WEBP_RESTRICT rgb, + uint8_t* WEBP_RESTRICT u, + uint8_t* WEBP_RESTRICT v, int width); -void (*WebPConvertARGBToY)(const uint32_t* argb, uint8_t* y, int width); -void (*WebPConvertARGBToUV)(const uint32_t* argb, uint8_t* u, uint8_t* v, +void (*WebPConvertARGBToY)(const uint32_t* WEBP_RESTRICT argb, + uint8_t* WEBP_RESTRICT y, int width); +void (*WebPConvertARGBToUV)(const uint32_t* WEBP_RESTRICT argb, + uint8_t* WEBP_RESTRICT u, uint8_t* WEBP_RESTRICT v, int src_width, int do_store); extern void WebPInitConvertARGBToYUVSSE2(void); diff --git a/libwebp/src/dsp/yuv.h b/libwebp/src/dsp/yuv.h index 66a397d1..6f218cf7 100644 --- a/libwebp/src/dsp/yuv.h +++ b/libwebp/src/dsp/yuv.h @@ -11,15 +11,15 @@ // // The exact naming is Y'CbCr, following the ITU-R BT.601 standard. // More information at: https://en.wikipedia.org/wiki/YCbCr -// Y = 0.2569 * R + 0.5044 * G + 0.0979 * B + 16 -// U = -0.1483 * R - 0.2911 * G + 0.4394 * B + 128 -// V = 0.4394 * R - 0.3679 * G - 0.0715 * B + 128 +// Y = 0.2568 * R + 0.5041 * G + 0.0979 * B + 16 +// U = -0.1482 * R - 0.2910 * G + 0.4392 * B + 128 +// V = 0.4392 * R - 0.3678 * G - 0.0714 * B + 128 // We use 16bit fixed point operations for RGB->YUV conversion (YUV_FIX). // // For the Y'CbCr to RGB conversion, the BT.601 specification reads: // R = 1.164 * (Y-16) + 1.596 * (V-128) -// G = 1.164 * (Y-16) - 0.813 * (V-128) - 0.391 * (U-128) -// B = 1.164 * (Y-16) + 2.018 * (U-128) +// G = 1.164 * (Y-16) - 0.813 * (V-128) - 0.392 * (U-128) +// B = 1.164 * (Y-16) + 2.017 * (U-128) // where Y is in the [16,235] range, and U/V in the [16,240] range. // // The fixed-point implementation used here is: @@ -35,8 +35,10 @@ #ifndef WEBP_DSP_YUV_H_ #define WEBP_DSP_YUV_H_ -#include "src/dsp/dsp.h" #include "src/dec/vp8_dec.h" +#include "src/dsp/cpu.h" +#include "src/dsp/dsp.h" +#include "src/webp/types.h" //------------------------------------------------------------------------------ // YUV -> RGB conversion @@ -149,20 +151,34 @@ static WEBP_INLINE void VP8YuvToRgba(uint8_t y, uint8_t u, uint8_t v, #if defined(WEBP_USE_SSE2) // Process 32 pixels and store the result (16b, 24b or 32b per pixel) in *dst. -void VP8YuvToRgba32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v, - uint8_t* dst); -void VP8YuvToRgb32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v, - uint8_t* dst); -void VP8YuvToBgra32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v, - uint8_t* dst); -void VP8YuvToBgr32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v, - uint8_t* dst); -void VP8YuvToArgb32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v, - uint8_t* dst); -void VP8YuvToRgba444432_SSE2(const uint8_t* y, const uint8_t* u, - const uint8_t* v, uint8_t* dst); -void VP8YuvToRgb56532_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v, - uint8_t* dst); +void VP8YuvToRgba32_SSE2(const uint8_t* WEBP_RESTRICT y, + const uint8_t* WEBP_RESTRICT u, + const uint8_t* WEBP_RESTRICT v, + uint8_t* WEBP_RESTRICT dst); +void VP8YuvToRgb32_SSE2(const uint8_t* WEBP_RESTRICT y, + const uint8_t* WEBP_RESTRICT u, + const uint8_t* WEBP_RESTRICT v, + uint8_t* WEBP_RESTRICT dst); +void VP8YuvToBgra32_SSE2(const uint8_t* WEBP_RESTRICT y, + const uint8_t* WEBP_RESTRICT u, + const uint8_t* WEBP_RESTRICT v, + uint8_t* WEBP_RESTRICT dst); +void VP8YuvToBgr32_SSE2(const uint8_t* WEBP_RESTRICT y, + const uint8_t* WEBP_RESTRICT u, + const uint8_t* WEBP_RESTRICT v, + uint8_t* WEBP_RESTRICT dst); +void VP8YuvToArgb32_SSE2(const uint8_t* WEBP_RESTRICT y, + const uint8_t* WEBP_RESTRICT u, + const uint8_t* WEBP_RESTRICT v, + uint8_t* WEBP_RESTRICT dst); +void VP8YuvToRgba444432_SSE2(const uint8_t* WEBP_RESTRICT y, + const uint8_t* WEBP_RESTRICT u, + const uint8_t* WEBP_RESTRICT v, + uint8_t* WEBP_RESTRICT dst); +void VP8YuvToRgb56532_SSE2(const uint8_t* WEBP_RESTRICT y, + const uint8_t* WEBP_RESTRICT u, + const uint8_t* WEBP_RESTRICT v, + uint8_t* WEBP_RESTRICT dst); #endif // WEBP_USE_SSE2 @@ -172,10 +188,14 @@ void VP8YuvToRgb56532_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v, #if defined(WEBP_USE_SSE41) // Process 32 pixels and store the result (16b, 24b or 32b per pixel) in *dst. -void VP8YuvToRgb32_SSE41(const uint8_t* y, const uint8_t* u, const uint8_t* v, - uint8_t* dst); -void VP8YuvToBgr32_SSE41(const uint8_t* y, const uint8_t* u, const uint8_t* v, - uint8_t* dst); +void VP8YuvToRgb32_SSE41(const uint8_t* WEBP_RESTRICT y, + const uint8_t* WEBP_RESTRICT u, + const uint8_t* WEBP_RESTRICT v, + uint8_t* WEBP_RESTRICT dst); +void VP8YuvToBgr32_SSE41(const uint8_t* WEBP_RESTRICT y, + const uint8_t* WEBP_RESTRICT u, + const uint8_t* WEBP_RESTRICT v, + uint8_t* WEBP_RESTRICT dst); #endif // WEBP_USE_SSE41 diff --git a/libwebp/src/dsp/yuv_mips32.c b/libwebp/src/dsp/yuv_mips32.c index 9d0a8878..1f634858 100644 --- a/libwebp/src/dsp/yuv_mips32.c +++ b/libwebp/src/dsp/yuv_mips32.c @@ -22,9 +22,10 @@ // simple point-sampling #define ROW_FUNC(FUNC_NAME, XSTEP, R, G, B, A) \ -static void FUNC_NAME(const uint8_t* y, \ - const uint8_t* u, const uint8_t* v, \ - uint8_t* dst, int len) { \ +static void FUNC_NAME(const uint8_t* WEBP_RESTRICT y, \ + const uint8_t* WEBP_RESTRICT u, \ + const uint8_t* WEBP_RESTRICT v, \ + uint8_t* WEBP_RESTRICT dst, int len) { \ int i, r, g, b; \ int temp0, temp1, temp2, temp3, temp4; \ for (i = 0; i < (len >> 1); i++) { \ diff --git a/libwebp/src/dsp/yuv_mips_dsp_r2.c b/libwebp/src/dsp/yuv_mips_dsp_r2.c index cc8afcc7..816340fe 100644 --- a/libwebp/src/dsp/yuv_mips_dsp_r2.c +++ b/libwebp/src/dsp/yuv_mips_dsp_r2.c @@ -69,9 +69,10 @@ : "memory", "hi", "lo" \ #define ROW_FUNC(FUNC_NAME, XSTEP, R, G, B, A) \ -static void FUNC_NAME(const uint8_t* y, \ - const uint8_t* u, const uint8_t* v, \ - uint8_t* dst, int len) { \ +static void FUNC_NAME(const uint8_t* WEBP_RESTRICT y, \ + const uint8_t* WEBP_RESTRICT u, \ + const uint8_t* WEBP_RESTRICT v, \ + uint8_t* WEBP_RESTRICT dst, int len) { \ int i; \ uint32_t temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7; \ const int t_con_1 = 26149; \ diff --git a/libwebp/src/dsp/yuv_neon.c b/libwebp/src/dsp/yuv_neon.c index ff77b009..44745cf7 100644 --- a/libwebp/src/dsp/yuv_neon.c +++ b/libwebp/src/dsp/yuv_neon.c @@ -18,6 +18,7 @@ #include #include +#include "src/dsp/dsp.h" #include "src/dsp/neon.h" //----------------------------------------------------------------------------- @@ -46,7 +47,8 @@ static uint8x8_t ConvertRGBToY_NEON(const uint8x8_t R, return vqmovn_u16(Y2); } -static void ConvertRGB24ToY_NEON(const uint8_t* rgb, uint8_t* y, int width) { +static void ConvertRGB24ToY_NEON(const uint8_t* WEBP_RESTRICT rgb, + uint8_t* WEBP_RESTRICT y, int width) { int i; for (i = 0; i + 8 <= width; i += 8, rgb += 3 * 8) { const uint8x8x3_t RGB = vld3_u8(rgb); @@ -58,7 +60,8 @@ static void ConvertRGB24ToY_NEON(const uint8_t* rgb, uint8_t* y, int width) { } } -static void ConvertBGR24ToY_NEON(const uint8_t* bgr, uint8_t* y, int width) { +static void ConvertBGR24ToY_NEON(const uint8_t* WEBP_RESTRICT bgr, + uint8_t* WEBP_RESTRICT y, int width) { int i; for (i = 0; i + 8 <= width; i += 8, bgr += 3 * 8) { const uint8x8x3_t BGR = vld3_u8(bgr); @@ -70,7 +73,8 @@ static void ConvertBGR24ToY_NEON(const uint8_t* bgr, uint8_t* y, int width) { } } -static void ConvertARGBToY_NEON(const uint32_t* argb, uint8_t* y, int width) { +static void ConvertARGBToY_NEON(const uint32_t* WEBP_RESTRICT argb, + uint8_t* WEBP_RESTRICT y, int width) { int i; for (i = 0; i + 8 <= width; i += 8) { const uint8x8x4_t RGB = vld4_u8((const uint8_t*)&argb[i]); @@ -114,8 +118,9 @@ static void ConvertARGBToY_NEON(const uint32_t* argb, uint8_t* y, int width) { MULTIPLY_16b(28800, -24116, -4684, 128 << SHIFT, V_DST); \ } while (0) -static void ConvertRGBA32ToUV_NEON(const uint16_t* rgb, - uint8_t* u, uint8_t* v, int width) { +static void ConvertRGBA32ToUV_NEON(const uint16_t* WEBP_RESTRICT rgb, + uint8_t* WEBP_RESTRICT u, + uint8_t* WEBP_RESTRICT v, int width) { int i; for (i = 0; i + 8 <= width; i += 8, rgb += 4 * 8) { const uint16x8x4_t RGB = vld4q_u16((const uint16_t*)rgb); @@ -131,7 +136,9 @@ static void ConvertRGBA32ToUV_NEON(const uint16_t* rgb, } } -static void ConvertARGBToUV_NEON(const uint32_t* argb, uint8_t* u, uint8_t* v, +static void ConvertARGBToUV_NEON(const uint32_t* WEBP_RESTRICT argb, + uint8_t* WEBP_RESTRICT u, + uint8_t* WEBP_RESTRICT v, int src_width, int do_store) { int i; for (i = 0; i + 16 <= src_width; i += 16, u += 8, v += 8) { diff --git a/libwebp/src/dsp/yuv_sse2.c b/libwebp/src/dsp/yuv_sse2.c index 01a48f9a..f1abf217 100644 --- a/libwebp/src/dsp/yuv_sse2.c +++ b/libwebp/src/dsp/yuv_sse2.c @@ -14,12 +14,16 @@ #include "src/dsp/yuv.h" #if defined(WEBP_USE_SSE2) +#include #include -#include #include "src/dsp/common_sse2.h" +#include "src/dsp/cpu.h" +#include "src/dsp/dsp.h" #include "src/utils/utils.h" +#include "src/webp/decode.h" +#include "src/webp/types.h" //----------------------------------------------------------------------------- // Convert spans of 32 pixels to various RGB formats for the fancy upsampler. @@ -82,9 +86,9 @@ static WEBP_INLINE __m128i Load_UV_HI_8_SSE2(const uint8_t* src) { } // Convert 32 samples of YUV444 to R/G/B -static void YUV444ToRGB_SSE2(const uint8_t* const y, - const uint8_t* const u, - const uint8_t* const v, +static void YUV444ToRGB_SSE2(const uint8_t* WEBP_RESTRICT const y, + const uint8_t* WEBP_RESTRICT const u, + const uint8_t* WEBP_RESTRICT const v, __m128i* const R, __m128i* const G, __m128i* const B) { const __m128i Y0 = Load_HI_16_SSE2(y), U0 = Load_HI_16_SSE2(u), @@ -93,9 +97,9 @@ static void YUV444ToRGB_SSE2(const uint8_t* const y, } // Convert 32 samples of YUV420 to R/G/B -static void YUV420ToRGB_SSE2(const uint8_t* const y, - const uint8_t* const u, - const uint8_t* const v, +static void YUV420ToRGB_SSE2(const uint8_t* WEBP_RESTRICT const y, + const uint8_t* WEBP_RESTRICT const u, + const uint8_t* WEBP_RESTRICT const v, __m128i* const R, __m128i* const G, __m128i* const B) { const __m128i Y0 = Load_HI_16_SSE2(y), U0 = Load_UV_HI_8_SSE2(u), @@ -108,7 +112,7 @@ static WEBP_INLINE void PackAndStore4_SSE2(const __m128i* const R, const __m128i* const G, const __m128i* const B, const __m128i* const A, - uint8_t* const dst) { + uint8_t* WEBP_RESTRICT const dst) { const __m128i rb = _mm_packus_epi16(*R, *B); const __m128i ga = _mm_packus_epi16(*G, *A); const __m128i rg = _mm_unpacklo_epi8(rb, ga); @@ -120,11 +124,9 @@ static WEBP_INLINE void PackAndStore4_SSE2(const __m128i* const R, } // Pack R/G/B/A results into 16b output. -static WEBP_INLINE void PackAndStore4444_SSE2(const __m128i* const R, - const __m128i* const G, - const __m128i* const B, - const __m128i* const A, - uint8_t* const dst) { +static WEBP_INLINE void PackAndStore4444_SSE2( + const __m128i* const R, const __m128i* const G, const __m128i* const B, + const __m128i* const A, uint8_t* WEBP_RESTRICT const dst) { #if (WEBP_SWAP_16BIT_CSP == 0) const __m128i rg0 = _mm_packus_epi16(*R, *G); const __m128i ba0 = _mm_packus_epi16(*B, *A); @@ -145,7 +147,7 @@ static WEBP_INLINE void PackAndStore4444_SSE2(const __m128i* const R, static WEBP_INLINE void PackAndStore565_SSE2(const __m128i* const R, const __m128i* const G, const __m128i* const B, - uint8_t* const dst) { + uint8_t* WEBP_RESTRICT const dst) { const __m128i r0 = _mm_packus_epi16(*R, *R); const __m128i g0 = _mm_packus_epi16(*G, *G); const __m128i b0 = _mm_packus_epi16(*B, *B); @@ -170,7 +172,7 @@ static WEBP_INLINE void PackAndStore565_SSE2(const __m128i* const R, static WEBP_INLINE void PlanarTo24b_SSE2(__m128i* const in0, __m128i* const in1, __m128i* const in2, __m128i* const in3, __m128i* const in4, __m128i* const in5, - uint8_t* const rgb) { + uint8_t* WEBP_RESTRICT const rgb) { // The input is 6 registers of sixteen 8b but for the sake of explanation, // let's take 6 registers of four 8b values. // To pack, we will keep taking one every two 8b integer and move it @@ -193,8 +195,10 @@ static WEBP_INLINE void PlanarTo24b_SSE2(__m128i* const in0, __m128i* const in1, _mm_storeu_si128((__m128i*)(rgb + 80), *in5); } -void VP8YuvToRgba32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v, - uint8_t* dst) { +void VP8YuvToRgba32_SSE2(const uint8_t* WEBP_RESTRICT y, + const uint8_t* WEBP_RESTRICT u, + const uint8_t* WEBP_RESTRICT v, + uint8_t* WEBP_RESTRICT dst) { const __m128i kAlpha = _mm_set1_epi16(255); int n; for (n = 0; n < 32; n += 8, dst += 32) { @@ -204,8 +208,10 @@ void VP8YuvToRgba32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v, } } -void VP8YuvToBgra32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v, - uint8_t* dst) { +void VP8YuvToBgra32_SSE2(const uint8_t* WEBP_RESTRICT y, + const uint8_t* WEBP_RESTRICT u, + const uint8_t* WEBP_RESTRICT v, + uint8_t* WEBP_RESTRICT dst) { const __m128i kAlpha = _mm_set1_epi16(255); int n; for (n = 0; n < 32; n += 8, dst += 32) { @@ -215,8 +221,10 @@ void VP8YuvToBgra32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v, } } -void VP8YuvToArgb32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v, - uint8_t* dst) { +void VP8YuvToArgb32_SSE2(const uint8_t* WEBP_RESTRICT y, + const uint8_t* WEBP_RESTRICT u, + const uint8_t* WEBP_RESTRICT v, + uint8_t* WEBP_RESTRICT dst) { const __m128i kAlpha = _mm_set1_epi16(255); int n; for (n = 0; n < 32; n += 8, dst += 32) { @@ -226,8 +234,10 @@ void VP8YuvToArgb32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v, } } -void VP8YuvToRgba444432_SSE2(const uint8_t* y, const uint8_t* u, - const uint8_t* v, uint8_t* dst) { +void VP8YuvToRgba444432_SSE2(const uint8_t* WEBP_RESTRICT y, + const uint8_t* WEBP_RESTRICT u, + const uint8_t* WEBP_RESTRICT v, + uint8_t* WEBP_RESTRICT dst) { const __m128i kAlpha = _mm_set1_epi16(255); int n; for (n = 0; n < 32; n += 8, dst += 16) { @@ -237,8 +247,10 @@ void VP8YuvToRgba444432_SSE2(const uint8_t* y, const uint8_t* u, } } -void VP8YuvToRgb56532_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v, - uint8_t* dst) { +void VP8YuvToRgb56532_SSE2(const uint8_t* WEBP_RESTRICT y, + const uint8_t* WEBP_RESTRICT u, + const uint8_t* WEBP_RESTRICT v, + uint8_t* WEBP_RESTRICT dst) { int n; for (n = 0; n < 32; n += 8, dst += 16) { __m128i R, G, B; @@ -247,8 +259,10 @@ void VP8YuvToRgb56532_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v, } } -void VP8YuvToRgb32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v, - uint8_t* dst) { +void VP8YuvToRgb32_SSE2(const uint8_t* WEBP_RESTRICT y, + const uint8_t* WEBP_RESTRICT u, + const uint8_t* WEBP_RESTRICT v, + uint8_t* WEBP_RESTRICT dst) { __m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3; __m128i rgb0, rgb1, rgb2, rgb3, rgb4, rgb5; @@ -269,8 +283,10 @@ void VP8YuvToRgb32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v, PlanarTo24b_SSE2(&rgb0, &rgb1, &rgb2, &rgb3, &rgb4, &rgb5, dst); } -void VP8YuvToBgr32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v, - uint8_t* dst) { +void VP8YuvToBgr32_SSE2(const uint8_t* WEBP_RESTRICT y, + const uint8_t* WEBP_RESTRICT u, + const uint8_t* WEBP_RESTRICT v, + uint8_t* WEBP_RESTRICT dst) { __m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3; __m128i bgr0, bgr1, bgr2, bgr3, bgr4, bgr5; @@ -294,9 +310,10 @@ void VP8YuvToBgr32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v, //----------------------------------------------------------------------------- // Arbitrary-length row conversion functions -static void YuvToRgbaRow_SSE2(const uint8_t* y, - const uint8_t* u, const uint8_t* v, - uint8_t* dst, int len) { +static void YuvToRgbaRow_SSE2(const uint8_t* WEBP_RESTRICT y, + const uint8_t* WEBP_RESTRICT u, + const uint8_t* WEBP_RESTRICT v, + uint8_t* WEBP_RESTRICT dst, int len) { const __m128i kAlpha = _mm_set1_epi16(255); int n; for (n = 0; n + 8 <= len; n += 8, dst += 32) { @@ -316,9 +333,10 @@ static void YuvToRgbaRow_SSE2(const uint8_t* y, } } -static void YuvToBgraRow_SSE2(const uint8_t* y, - const uint8_t* u, const uint8_t* v, - uint8_t* dst, int len) { +static void YuvToBgraRow_SSE2(const uint8_t* WEBP_RESTRICT y, + const uint8_t* WEBP_RESTRICT u, + const uint8_t* WEBP_RESTRICT v, + uint8_t* WEBP_RESTRICT dst, int len) { const __m128i kAlpha = _mm_set1_epi16(255); int n; for (n = 0; n + 8 <= len; n += 8, dst += 32) { @@ -338,9 +356,10 @@ static void YuvToBgraRow_SSE2(const uint8_t* y, } } -static void YuvToArgbRow_SSE2(const uint8_t* y, - const uint8_t* u, const uint8_t* v, - uint8_t* dst, int len) { +static void YuvToArgbRow_SSE2(const uint8_t* WEBP_RESTRICT y, + const uint8_t* WEBP_RESTRICT u, + const uint8_t* WEBP_RESTRICT v, + uint8_t* WEBP_RESTRICT dst, int len) { const __m128i kAlpha = _mm_set1_epi16(255); int n; for (n = 0; n + 8 <= len; n += 8, dst += 32) { @@ -360,9 +379,10 @@ static void YuvToArgbRow_SSE2(const uint8_t* y, } } -static void YuvToRgbRow_SSE2(const uint8_t* y, - const uint8_t* u, const uint8_t* v, - uint8_t* dst, int len) { +static void YuvToRgbRow_SSE2(const uint8_t* WEBP_RESTRICT y, + const uint8_t* WEBP_RESTRICT u, + const uint8_t* WEBP_RESTRICT v, + uint8_t* WEBP_RESTRICT dst, int len) { int n; for (n = 0; n + 32 <= len; n += 32, dst += 32 * 3) { __m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3; @@ -397,9 +417,10 @@ static void YuvToRgbRow_SSE2(const uint8_t* y, } } -static void YuvToBgrRow_SSE2(const uint8_t* y, - const uint8_t* u, const uint8_t* v, - uint8_t* dst, int len) { +static void YuvToBgrRow_SSE2(const uint8_t* WEBP_RESTRICT y, + const uint8_t* WEBP_RESTRICT u, + const uint8_t* WEBP_RESTRICT v, + uint8_t* WEBP_RESTRICT dst, int len) { int n; for (n = 0; n + 32 <= len; n += 32, dst += 32 * 3) { __m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3; @@ -471,7 +492,7 @@ static WEBP_INLINE void RGB24PackedToPlanarHelper_SSE2( // rrrr... rrrr... gggg... gggg... bbbb... bbbb.... // Similar to PlanarTo24bHelper(), but in reverse order. static WEBP_INLINE void RGB24PackedToPlanar_SSE2( - const uint8_t* const rgb, __m128i* const out /*out[6]*/) { + const uint8_t* WEBP_RESTRICT const rgb, __m128i* const out /*out[6]*/) { __m128i tmp[6]; tmp[0] = _mm_loadu_si128((const __m128i*)(rgb + 0)); tmp[1] = _mm_loadu_si128((const __m128i*)(rgb + 16)); @@ -488,8 +509,8 @@ static WEBP_INLINE void RGB24PackedToPlanar_SSE2( } // Convert 8 packed ARGB to r[], g[], b[] -static WEBP_INLINE void RGB32PackedToPlanar_SSE2(const uint32_t* const argb, - __m128i* const rgb /*in[6]*/) { +static WEBP_INLINE void RGB32PackedToPlanar_SSE2( + const uint32_t* WEBP_RESTRICT const argb, __m128i* const rgb /*in[6]*/) { const __m128i zero = _mm_setzero_si128(); __m128i a0 = LOAD_16(argb + 0); __m128i a1 = LOAD_16(argb + 4); @@ -562,7 +583,8 @@ static WEBP_INLINE void ConvertRGBToUV_SSE2(const __m128i* const R, #undef MK_CST_16 #undef TRANSFORM -static void ConvertRGB24ToY_SSE2(const uint8_t* rgb, uint8_t* y, int width) { +static void ConvertRGB24ToY_SSE2(const uint8_t* WEBP_RESTRICT rgb, + uint8_t* WEBP_RESTRICT y, int width) { const int max_width = width & ~31; int i; for (i = 0; i < max_width; rgb += 3 * 16 * 2) { @@ -596,7 +618,8 @@ static void ConvertRGB24ToY_SSE2(const uint8_t* rgb, uint8_t* y, int width) { } } -static void ConvertBGR24ToY_SSE2(const uint8_t* bgr, uint8_t* y, int width) { +static void ConvertBGR24ToY_SSE2(const uint8_t* WEBP_RESTRICT bgr, + uint8_t* WEBP_RESTRICT y, int width) { const int max_width = width & ~31; int i; for (i = 0; i < max_width; bgr += 3 * 16 * 2) { @@ -630,7 +653,8 @@ static void ConvertBGR24ToY_SSE2(const uint8_t* bgr, uint8_t* y, int width) { } } -static void ConvertARGBToY_SSE2(const uint32_t* argb, uint8_t* y, int width) { +static void ConvertARGBToY_SSE2(const uint32_t* WEBP_RESTRICT argb, + uint8_t* WEBP_RESTRICT y, int width) { const int max_width = width & ~15; int i; for (i = 0; i < max_width; i += 16) { @@ -658,8 +682,9 @@ static void HorizontalAddPack_SSE2(const __m128i* const A, *out = _mm_packs_epi32(C, D); } -static void ConvertARGBToUV_SSE2(const uint32_t* argb, - uint8_t* u, uint8_t* v, +static void ConvertARGBToUV_SSE2(const uint32_t* WEBP_RESTRICT argb, + uint8_t* WEBP_RESTRICT u, + uint8_t* WEBP_RESTRICT v, int src_width, int do_store) { const int max_width = src_width & ~31; int i; @@ -695,7 +720,7 @@ static void ConvertARGBToUV_SSE2(const uint32_t* argb, // Convert 16 packed ARGB 16b-values to r[], g[], b[] static WEBP_INLINE void RGBA32PackedToPlanar_16b_SSE2( - const uint16_t* const rgbx, + const uint16_t* WEBP_RESTRICT const rgbx, __m128i* const r, __m128i* const g, __m128i* const b) { const __m128i in0 = LOAD_16(rgbx + 0); // r0 | g0 | b0 |x| r1 | g1 | b1 |x const __m128i in1 = LOAD_16(rgbx + 8); // r2 | g2 | b2 |x| r3 | g3 | b3 |x @@ -715,8 +740,9 @@ static WEBP_INLINE void RGBA32PackedToPlanar_16b_SSE2( *b = _mm_unpacklo_epi64(B1, B3); } -static void ConvertRGBA32ToUV_SSE2(const uint16_t* rgb, - uint8_t* u, uint8_t* v, int width) { +static void ConvertRGBA32ToUV_SSE2(const uint16_t* WEBP_RESTRICT rgb, + uint8_t* WEBP_RESTRICT u, + uint8_t* WEBP_RESTRICT v, int width) { const int max_width = width & ~15; const uint16_t* const last_rgb = rgb + 4 * max_width; while (rgb < last_rgb) { diff --git a/libwebp/src/dsp/yuv_sse41.c b/libwebp/src/dsp/yuv_sse41.c index f79b802e..e1b80846 100644 --- a/libwebp/src/dsp/yuv_sse41.c +++ b/libwebp/src/dsp/yuv_sse41.c @@ -14,12 +14,17 @@ #include "src/dsp/yuv.h" #if defined(WEBP_USE_SSE41) +#include +#include #include -#include #include "src/dsp/common_sse41.h" +#include "src/dsp/cpu.h" +#include "src/dsp/dsp.h" #include "src/utils/utils.h" +#include "src/webp/decode.h" +#include "src/webp/types.h" //----------------------------------------------------------------------------- // Convert spans of 32 pixels to various RGB formats for the fancy upsampler. @@ -82,9 +87,9 @@ static WEBP_INLINE __m128i Load_UV_HI_8_SSE41(const uint8_t* src) { } // Convert 32 samples of YUV444 to R/G/B -static void YUV444ToRGB_SSE41(const uint8_t* const y, - const uint8_t* const u, - const uint8_t* const v, +static void YUV444ToRGB_SSE41(const uint8_t* WEBP_RESTRICT const y, + const uint8_t* WEBP_RESTRICT const u, + const uint8_t* WEBP_RESTRICT const v, __m128i* const R, __m128i* const G, __m128i* const B) { const __m128i Y0 = Load_HI_16_SSE41(y), U0 = Load_HI_16_SSE41(u), @@ -93,9 +98,9 @@ static void YUV444ToRGB_SSE41(const uint8_t* const y, } // Convert 32 samples of YUV420 to R/G/B -static void YUV420ToRGB_SSE41(const uint8_t* const y, - const uint8_t* const u, - const uint8_t* const v, +static void YUV420ToRGB_SSE41(const uint8_t* WEBP_RESTRICT const y, + const uint8_t* WEBP_RESTRICT const u, + const uint8_t* WEBP_RESTRICT const v, __m128i* const R, __m128i* const G, __m128i* const B) { const __m128i Y0 = Load_HI_16_SSE41(y), U0 = Load_UV_HI_8_SSE41(u), @@ -109,7 +114,7 @@ static void YUV420ToRGB_SSE41(const uint8_t* const y, static WEBP_INLINE void PlanarTo24b_SSE41( __m128i* const in0, __m128i* const in1, __m128i* const in2, __m128i* const in3, __m128i* const in4, __m128i* const in5, - uint8_t* const rgb) { + uint8_t* WEBP_RESTRICT const rgb) { // The input is 6 registers of sixteen 8b but for the sake of explanation, // let's take 6 registers of four 8b values. // To pack, we will keep taking one every two 8b integer and move it @@ -132,8 +137,10 @@ static WEBP_INLINE void PlanarTo24b_SSE41( _mm_storeu_si128((__m128i*)(rgb + 80), *in5); } -void VP8YuvToRgb32_SSE41(const uint8_t* y, const uint8_t* u, const uint8_t* v, - uint8_t* dst) { +void VP8YuvToRgb32_SSE41(const uint8_t* WEBP_RESTRICT y, + const uint8_t* WEBP_RESTRICT u, + const uint8_t* WEBP_RESTRICT v, + uint8_t* WEBP_RESTRICT dst) { __m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3; __m128i rgb0, rgb1, rgb2, rgb3, rgb4, rgb5; @@ -154,8 +161,10 @@ void VP8YuvToRgb32_SSE41(const uint8_t* y, const uint8_t* u, const uint8_t* v, PlanarTo24b_SSE41(&rgb0, &rgb1, &rgb2, &rgb3, &rgb4, &rgb5, dst); } -void VP8YuvToBgr32_SSE41(const uint8_t* y, const uint8_t* u, const uint8_t* v, - uint8_t* dst) { +void VP8YuvToBgr32_SSE41(const uint8_t* WEBP_RESTRICT y, + const uint8_t* WEBP_RESTRICT u, + const uint8_t* WEBP_RESTRICT v, + uint8_t* WEBP_RESTRICT dst) { __m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3; __m128i bgr0, bgr1, bgr2, bgr3, bgr4, bgr5; @@ -179,9 +188,10 @@ void VP8YuvToBgr32_SSE41(const uint8_t* y, const uint8_t* u, const uint8_t* v, //----------------------------------------------------------------------------- // Arbitrary-length row conversion functions -static void YuvToRgbRow_SSE41(const uint8_t* y, - const uint8_t* u, const uint8_t* v, - uint8_t* dst, int len) { +static void YuvToRgbRow_SSE41(const uint8_t* WEBP_RESTRICT y, + const uint8_t* WEBP_RESTRICT u, + const uint8_t* WEBP_RESTRICT v, + uint8_t* WEBP_RESTRICT dst, int len) { int n; for (n = 0; n + 32 <= len; n += 32, dst += 32 * 3) { __m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3; @@ -216,9 +226,10 @@ static void YuvToRgbRow_SSE41(const uint8_t* y, } } -static void YuvToBgrRow_SSE41(const uint8_t* y, - const uint8_t* u, const uint8_t* v, - uint8_t* dst, int len) { +static void YuvToBgrRow_SSE41(const uint8_t* WEBP_RESTRICT y, + const uint8_t* WEBP_RESTRICT u, + const uint8_t* WEBP_RESTRICT v, + uint8_t* WEBP_RESTRICT dst, int len) { int n; for (n = 0; n + 32 <= len; n += 32, dst += 32 * 3) { __m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3; @@ -290,7 +301,7 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitSamplersSSE41(void) { // rrrr... rrrr... gggg... gggg... bbbb... bbbb.... // Similar to PlanarTo24bHelper(), but in reverse order. static WEBP_INLINE void RGB24PackedToPlanar_SSE41( - const uint8_t* const rgb, __m128i* const out /*out[6]*/) { + const uint8_t* WEBP_RESTRICT const rgb, __m128i* const out /*out[6]*/) { const __m128i A0 = _mm_loadu_si128((const __m128i*)(rgb + 0)); const __m128i A1 = _mm_loadu_si128((const __m128i*)(rgb + 16)); const __m128i A2 = _mm_loadu_si128((const __m128i*)(rgb + 32)); @@ -334,7 +345,7 @@ static WEBP_INLINE void RGB24PackedToPlanar_SSE41( // Convert 8 packed ARGB to r[], g[], b[] static WEBP_INLINE void RGB32PackedToPlanar_SSE41( - const uint32_t* const argb, __m128i* const rgb /*in[6]*/) { + const uint32_t* WEBP_RESTRICT const argb, __m128i* const rgb /*in[6]*/) { const __m128i zero = _mm_setzero_si128(); __m128i a0 = LOAD_16(argb + 0); __m128i a1 = LOAD_16(argb + 4); @@ -407,7 +418,8 @@ static WEBP_INLINE void ConvertRGBToUV_SSE41(const __m128i* const R, #undef MK_CST_16 #undef TRANSFORM -static void ConvertRGB24ToY_SSE41(const uint8_t* rgb, uint8_t* y, int width) { +static void ConvertRGB24ToY_SSE41(const uint8_t* WEBP_RESTRICT rgb, + uint8_t* WEBP_RESTRICT y, int width) { const int max_width = width & ~31; int i; for (i = 0; i < max_width; rgb += 3 * 16 * 2) { @@ -441,7 +453,8 @@ static void ConvertRGB24ToY_SSE41(const uint8_t* rgb, uint8_t* y, int width) { } } -static void ConvertBGR24ToY_SSE41(const uint8_t* bgr, uint8_t* y, int width) { +static void ConvertBGR24ToY_SSE41(const uint8_t* WEBP_RESTRICT bgr, + uint8_t* WEBP_RESTRICT y, int width) { const int max_width = width & ~31; int i; for (i = 0; i < max_width; bgr += 3 * 16 * 2) { @@ -475,7 +488,8 @@ static void ConvertBGR24ToY_SSE41(const uint8_t* bgr, uint8_t* y, int width) { } } -static void ConvertARGBToY_SSE41(const uint32_t* argb, uint8_t* y, int width) { +static void ConvertARGBToY_SSE41(const uint32_t* WEBP_RESTRICT argb, + uint8_t* WEBP_RESTRICT y, int width) { const int max_width = width & ~15; int i; for (i = 0; i < max_width; i += 16) { @@ -503,8 +517,9 @@ static void HorizontalAddPack_SSE41(const __m128i* const A, *out = _mm_packs_epi32(C, D); } -static void ConvertARGBToUV_SSE41(const uint32_t* argb, - uint8_t* u, uint8_t* v, +static void ConvertARGBToUV_SSE41(const uint32_t* WEBP_RESTRICT argb, + uint8_t* WEBP_RESTRICT u, + uint8_t* WEBP_RESTRICT v, int src_width, int do_store) { const int max_width = src_width & ~31; int i; @@ -540,7 +555,7 @@ static void ConvertARGBToUV_SSE41(const uint32_t* argb, // Convert 16 packed ARGB 16b-values to r[], g[], b[] static WEBP_INLINE void RGBA32PackedToPlanar_16b_SSE41( - const uint16_t* const rgbx, + const uint16_t* WEBP_RESTRICT const rgbx, __m128i* const r, __m128i* const g, __m128i* const b) { const __m128i in0 = LOAD_16(rgbx + 0); // r0 | g0 | b0 |x| r1 | g1 | b1 |x const __m128i in1 = LOAD_16(rgbx + 8); // r2 | g2 | b2 |x| r3 | g3 | b3 |x @@ -570,8 +585,9 @@ static WEBP_INLINE void RGBA32PackedToPlanar_16b_SSE41( *b = _mm_unpackhi_epi64(B1, B3); } -static void ConvertRGBA32ToUV_SSE41(const uint16_t* rgb, - uint8_t* u, uint8_t* v, int width) { +static void ConvertRGBA32ToUV_SSE41(const uint16_t* WEBP_RESTRICT rgb, + uint8_t* WEBP_RESTRICT u, + uint8_t* WEBP_RESTRICT v, int width) { const int max_width = width & ~15; const uint16_t* const last_rgb = rgb + 4 * max_width; while (rgb < last_rgb) { diff --git a/libwebp/src/enc/Makefile.am b/libwebp/src/enc/Makefile.am deleted file mode 100644 index 2fec804c..00000000 --- a/libwebp/src/enc/Makefile.am +++ /dev/null @@ -1,43 +0,0 @@ -AM_CPPFLAGS += -I$(top_builddir) -I$(top_srcdir) -noinst_LTLIBRARIES = libwebpencode.la - -libwebpencode_la_SOURCES = -libwebpencode_la_SOURCES += alpha_enc.c -libwebpencode_la_SOURCES += analysis_enc.c -libwebpencode_la_SOURCES += backward_references_cost_enc.c -libwebpencode_la_SOURCES += backward_references_enc.c -libwebpencode_la_SOURCES += backward_references_enc.h -libwebpencode_la_SOURCES += config_enc.c -libwebpencode_la_SOURCES += cost_enc.c -libwebpencode_la_SOURCES += cost_enc.h -libwebpencode_la_SOURCES += filter_enc.c -libwebpencode_la_SOURCES += frame_enc.c -libwebpencode_la_SOURCES += histogram_enc.c -libwebpencode_la_SOURCES += histogram_enc.h -libwebpencode_la_SOURCES += iterator_enc.c -libwebpencode_la_SOURCES += near_lossless_enc.c -libwebpencode_la_SOURCES += picture_enc.c -libwebpencode_la_SOURCES += picture_csp_enc.c -libwebpencode_la_SOURCES += picture_psnr_enc.c -libwebpencode_la_SOURCES += picture_rescale_enc.c -libwebpencode_la_SOURCES += picture_tools_enc.c -libwebpencode_la_SOURCES += predictor_enc.c -libwebpencode_la_SOURCES += quant_enc.c -libwebpencode_la_SOURCES += syntax_enc.c -libwebpencode_la_SOURCES += token_enc.c -libwebpencode_la_SOURCES += tree_enc.c -libwebpencode_la_SOURCES += vp8i_enc.h -libwebpencode_la_SOURCES += vp8l_enc.c -libwebpencode_la_SOURCES += vp8li_enc.h -libwebpencode_la_SOURCES += webp_enc.c - -libwebpencodeinclude_HEADERS = -libwebpencodeinclude_HEADERS += ../webp/encode.h -libwebpencodeinclude_HEADERS += ../webp/types.h -noinst_HEADERS = -noinst_HEADERS += ../webp/format_constants.h - -libwebpencode_la_LIBADD = ../../sharpyuv/libsharpyuv.la -libwebpencode_la_LDFLAGS = -lm -libwebpencode_la_CPPFLAGS = $(AM_CPPFLAGS) -libwebpencodeincludedir = $(includedir)/webp diff --git a/libwebp/src/enc/alpha_enc.c b/libwebp/src/enc/alpha_enc.c deleted file mode 100644 index c11a261c..00000000 --- a/libwebp/src/enc/alpha_enc.c +++ /dev/null @@ -1,450 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Alpha-plane compression. -// -// Author: Skal (pascal.massimino@gmail.com) - -#include -#include -#include - -#include "src/enc/vp8i_enc.h" -#include "src/dsp/dsp.h" -#include "src/utils/filters_utils.h" -#include "src/utils/quant_levels_utils.h" -#include "src/utils/utils.h" -#include "src/webp/encode.h" -#include "src/webp/format_constants.h" - -// ----------------------------------------------------------------------------- -// Encodes the given alpha data via specified compression method 'method'. -// The pre-processing (quantization) is performed if 'quality' is less than 100. -// For such cases, the encoding is lossy. The valid range is [0, 100] for -// 'quality' and [0, 1] for 'method': -// 'method = 0' - No compression; -// 'method = 1' - Use lossless coder on the alpha plane only -// 'filter' values [0, 4] correspond to prediction modes none, horizontal, -// vertical & gradient filters. The prediction mode 4 will try all the -// prediction modes 0 to 3 and pick the best one. -// 'effort_level': specifies how much effort must be spent to try and reduce -// the compressed output size. In range 0 (quick) to 6 (slow). -// -// 'output' corresponds to the buffer containing compressed alpha data. -// This buffer is allocated by this method and caller should call -// WebPSafeFree(*output) when done. -// 'output_size' corresponds to size of this compressed alpha buffer. -// -// Returns 1 on successfully encoding the alpha and -// 0 if either: -// invalid quality or method, or -// memory allocation for the compressed data fails. - -#include "src/enc/vp8li_enc.h" - -static int EncodeLossless(const uint8_t* const data, int width, int height, - int effort_level, // in [0..6] range - int use_quality_100, VP8LBitWriter* const bw, - WebPAuxStats* const stats) { - int ok = 0; - WebPConfig config; - WebPPicture picture; - - if (!WebPPictureInit(&picture)) return 0; - picture.width = width; - picture.height = height; - picture.use_argb = 1; - picture.stats = stats; - if (!WebPPictureAlloc(&picture)) return 0; - - // Transfer the alpha values to the green channel. - WebPDispatchAlphaToGreen(data, width, picture.width, picture.height, - picture.argb, picture.argb_stride); - - if (!WebPConfigInit(&config)) return 0; - config.lossless = 1; - // Enable exact, or it would alter RGB values of transparent alpha, which is - // normally OK but not here since we are not encoding the input image but an - // internal encoding-related image containing necessary exact information in - // RGB channels. - config.exact = 1; - config.method = effort_level; // impact is very small - // Set a low default quality for encoding alpha. Ensure that Alpha quality at - // lower methods (3 and below) is less than the threshold for triggering - // costly 'BackwardReferencesTraceBackwards'. - // If the alpha quality is set to 100 and the method to 6, allow for a high - // lossless quality to trigger the cruncher. - config.quality = - (use_quality_100 && effort_level == 6) ? 100 : 8.f * effort_level; - assert(config.quality >= 0 && config.quality <= 100.f); - - ok = VP8LEncodeStream(&config, &picture, bw); - WebPPictureFree(&picture); - ok = ok && !bw->error_; - if (!ok) { - VP8LBitWriterWipeOut(bw); - return 0; - } - return 1; -} - -// ----------------------------------------------------------------------------- - -// Small struct to hold the result of a filter mode compression attempt. -typedef struct { - size_t score; - VP8BitWriter bw; - WebPAuxStats stats; -} FilterTrial; - -// This function always returns an initialized 'bw' object, even upon error. -static int EncodeAlphaInternal(const uint8_t* const data, int width, int height, - int method, int filter, int reduce_levels, - int effort_level, // in [0..6] range - uint8_t* const tmp_alpha, - FilterTrial* result) { - int ok = 0; - const uint8_t* alpha_src; - WebPFilterFunc filter_func; - uint8_t header; - const size_t data_size = width * height; - const uint8_t* output = NULL; - size_t output_size = 0; - VP8LBitWriter tmp_bw; - - assert((uint64_t)data_size == (uint64_t)width * height); // as per spec - assert(filter >= 0 && filter < WEBP_FILTER_LAST); - assert(method >= ALPHA_NO_COMPRESSION); - assert(method <= ALPHA_LOSSLESS_COMPRESSION); - assert(sizeof(header) == ALPHA_HEADER_LEN); - - filter_func = WebPFilters[filter]; - if (filter_func != NULL) { - filter_func(data, width, height, width, tmp_alpha); - alpha_src = tmp_alpha; - } else { - alpha_src = data; - } - - if (method != ALPHA_NO_COMPRESSION) { - ok = VP8LBitWriterInit(&tmp_bw, data_size >> 3); - ok = ok && EncodeLossless(alpha_src, width, height, effort_level, - !reduce_levels, &tmp_bw, &result->stats); - if (ok) { - output = VP8LBitWriterFinish(&tmp_bw); - if (tmp_bw.error_) { - VP8LBitWriterWipeOut(&tmp_bw); - memset(&result->bw, 0, sizeof(result->bw)); - return 0; - } - output_size = VP8LBitWriterNumBytes(&tmp_bw); - if (output_size > data_size) { - // compressed size is larger than source! Revert to uncompressed mode. - method = ALPHA_NO_COMPRESSION; - VP8LBitWriterWipeOut(&tmp_bw); - } - } else { - VP8LBitWriterWipeOut(&tmp_bw); - memset(&result->bw, 0, sizeof(result->bw)); - return 0; - } - } - - if (method == ALPHA_NO_COMPRESSION) { - output = alpha_src; - output_size = data_size; - ok = 1; - } - - // Emit final result. - header = method | (filter << 2); - if (reduce_levels) header |= ALPHA_PREPROCESSED_LEVELS << 4; - - if (!VP8BitWriterInit(&result->bw, ALPHA_HEADER_LEN + output_size)) ok = 0; - ok = ok && VP8BitWriterAppend(&result->bw, &header, ALPHA_HEADER_LEN); - ok = ok && VP8BitWriterAppend(&result->bw, output, output_size); - - if (method != ALPHA_NO_COMPRESSION) { - VP8LBitWriterWipeOut(&tmp_bw); - } - ok = ok && !result->bw.error_; - result->score = VP8BitWriterSize(&result->bw); - return ok; -} - -// ----------------------------------------------------------------------------- - -static int GetNumColors(const uint8_t* data, int width, int height, - int stride) { - int j; - int colors = 0; - uint8_t color[256] = { 0 }; - - for (j = 0; j < height; ++j) { - int i; - const uint8_t* const p = data + j * stride; - for (i = 0; i < width; ++i) { - color[p[i]] = 1; - } - } - for (j = 0; j < 256; ++j) { - if (color[j] > 0) ++colors; - } - return colors; -} - -#define FILTER_TRY_NONE (1 << WEBP_FILTER_NONE) -#define FILTER_TRY_ALL ((1 << WEBP_FILTER_LAST) - 1) - -// Given the input 'filter' option, return an OR'd bit-set of filters to try. -static uint32_t GetFilterMap(const uint8_t* alpha, int width, int height, - int filter, int effort_level) { - uint32_t bit_map = 0U; - if (filter == WEBP_FILTER_FAST) { - // Quick estimate of the best candidate. - int try_filter_none = (effort_level > 3); - const int kMinColorsForFilterNone = 16; - const int kMaxColorsForFilterNone = 192; - const int num_colors = GetNumColors(alpha, width, height, width); - // For low number of colors, NONE yields better compression. - filter = (num_colors <= kMinColorsForFilterNone) - ? WEBP_FILTER_NONE - : WebPEstimateBestFilter(alpha, width, height, width); - bit_map |= 1 << filter; - // For large number of colors, try FILTER_NONE in addition to the best - // filter as well. - if (try_filter_none || num_colors > kMaxColorsForFilterNone) { - bit_map |= FILTER_TRY_NONE; - } - } else if (filter == WEBP_FILTER_NONE) { - bit_map = FILTER_TRY_NONE; - } else { // WEBP_FILTER_BEST -> try all - bit_map = FILTER_TRY_ALL; - } - return bit_map; -} - -static void InitFilterTrial(FilterTrial* const score) { - score->score = (size_t)~0U; - VP8BitWriterInit(&score->bw, 0); -} - -static int ApplyFiltersAndEncode(const uint8_t* alpha, int width, int height, - size_t data_size, int method, int filter, - int reduce_levels, int effort_level, - uint8_t** const output, - size_t* const output_size, - WebPAuxStats* const stats) { - int ok = 1; - FilterTrial best; - uint32_t try_map = - GetFilterMap(alpha, width, height, filter, effort_level); - InitFilterTrial(&best); - - if (try_map != FILTER_TRY_NONE) { - uint8_t* filtered_alpha = (uint8_t*)WebPSafeMalloc(1ULL, data_size); - if (filtered_alpha == NULL) return 0; - - for (filter = WEBP_FILTER_NONE; ok && try_map; ++filter, try_map >>= 1) { - if (try_map & 1) { - FilterTrial trial; - ok = EncodeAlphaInternal(alpha, width, height, method, filter, - reduce_levels, effort_level, filtered_alpha, - &trial); - if (ok && trial.score < best.score) { - VP8BitWriterWipeOut(&best.bw); - best = trial; - } else { - VP8BitWriterWipeOut(&trial.bw); - } - } - } - WebPSafeFree(filtered_alpha); - } else { - ok = EncodeAlphaInternal(alpha, width, height, method, WEBP_FILTER_NONE, - reduce_levels, effort_level, NULL, &best); - } - if (ok) { -#if !defined(WEBP_DISABLE_STATS) - if (stats != NULL) { - stats->lossless_features = best.stats.lossless_features; - stats->histogram_bits = best.stats.histogram_bits; - stats->transform_bits = best.stats.transform_bits; - stats->cache_bits = best.stats.cache_bits; - stats->palette_size = best.stats.palette_size; - stats->lossless_size = best.stats.lossless_size; - stats->lossless_hdr_size = best.stats.lossless_hdr_size; - stats->lossless_data_size = best.stats.lossless_data_size; - } -#else - (void)stats; -#endif - *output_size = VP8BitWriterSize(&best.bw); - *output = VP8BitWriterBuf(&best.bw); - } else { - VP8BitWriterWipeOut(&best.bw); - } - return ok; -} - -static int EncodeAlpha(VP8Encoder* const enc, - int quality, int method, int filter, - int effort_level, - uint8_t** const output, size_t* const output_size) { - const WebPPicture* const pic = enc->pic_; - const int width = pic->width; - const int height = pic->height; - - uint8_t* quant_alpha = NULL; - const size_t data_size = width * height; - uint64_t sse = 0; - int ok = 1; - const int reduce_levels = (quality < 100); - - // quick correctness checks - assert((uint64_t)data_size == (uint64_t)width * height); // as per spec - assert(enc != NULL && pic != NULL && pic->a != NULL); - assert(output != NULL && output_size != NULL); - assert(width > 0 && height > 0); - assert(pic->a_stride >= width); - assert(filter >= WEBP_FILTER_NONE && filter <= WEBP_FILTER_FAST); - - if (quality < 0 || quality > 100) { - return WebPEncodingSetError(pic, VP8_ENC_ERROR_INVALID_CONFIGURATION); - } - - if (method < ALPHA_NO_COMPRESSION || method > ALPHA_LOSSLESS_COMPRESSION) { - return WebPEncodingSetError(pic, VP8_ENC_ERROR_INVALID_CONFIGURATION); - } - - if (method == ALPHA_NO_COMPRESSION) { - // Don't filter, as filtering will make no impact on compressed size. - filter = WEBP_FILTER_NONE; - } - - quant_alpha = (uint8_t*)WebPSafeMalloc(1ULL, data_size); - if (quant_alpha == NULL) { - return WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); - } - - // Extract alpha data (width x height) from raw_data (stride x height). - WebPCopyPlane(pic->a, pic->a_stride, quant_alpha, width, width, height); - - if (reduce_levels) { // No Quantization required for 'quality = 100'. - // 16 alpha levels gives quite a low MSE w.r.t original alpha plane hence - // mapped to moderate quality 70. Hence Quality:[0, 70] -> Levels:[2, 16] - // and Quality:]70, 100] -> Levels:]16, 256]. - const int alpha_levels = (quality <= 70) ? (2 + quality / 5) - : (16 + (quality - 70) * 8); - ok = QuantizeLevels(quant_alpha, width, height, alpha_levels, &sse); - } - - if (ok) { - VP8FiltersInit(); - ok = ApplyFiltersAndEncode(quant_alpha, width, height, data_size, method, - filter, reduce_levels, effort_level, output, - output_size, pic->stats); - if (!ok) { - WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); // imprecise - } -#if !defined(WEBP_DISABLE_STATS) - if (pic->stats != NULL) { // need stats? - pic->stats->coded_size += (int)(*output_size); - enc->sse_[3] = sse; - } -#endif - } - - WebPSafeFree(quant_alpha); - return ok; -} - -//------------------------------------------------------------------------------ -// Main calls - -static int CompressAlphaJob(void* arg1, void* unused) { - VP8Encoder* const enc = (VP8Encoder*)arg1; - const WebPConfig* config = enc->config_; - uint8_t* alpha_data = NULL; - size_t alpha_size = 0; - const int effort_level = config->method; // maps to [0..6] - const WEBP_FILTER_TYPE filter = - (config->alpha_filtering == 0) ? WEBP_FILTER_NONE : - (config->alpha_filtering == 1) ? WEBP_FILTER_FAST : - WEBP_FILTER_BEST; - if (!EncodeAlpha(enc, config->alpha_quality, config->alpha_compression, - filter, effort_level, &alpha_data, &alpha_size)) { - return 0; - } - if (alpha_size != (uint32_t)alpha_size) { // Soundness check. - WebPSafeFree(alpha_data); - return 0; - } - enc->alpha_data_size_ = (uint32_t)alpha_size; - enc->alpha_data_ = alpha_data; - (void)unused; - return 1; -} - -void VP8EncInitAlpha(VP8Encoder* const enc) { - WebPInitAlphaProcessing(); - enc->has_alpha_ = WebPPictureHasTransparency(enc->pic_); - enc->alpha_data_ = NULL; - enc->alpha_data_size_ = 0; - if (enc->thread_level_ > 0) { - WebPWorker* const worker = &enc->alpha_worker_; - WebPGetWorkerInterface()->Init(worker); - worker->data1 = enc; - worker->data2 = NULL; - worker->hook = CompressAlphaJob; - } -} - -int VP8EncStartAlpha(VP8Encoder* const enc) { - if (enc->has_alpha_) { - if (enc->thread_level_ > 0) { - WebPWorker* const worker = &enc->alpha_worker_; - // Makes sure worker is good to go. - if (!WebPGetWorkerInterface()->Reset(worker)) { - return WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY); - } - WebPGetWorkerInterface()->Launch(worker); - return 1; - } else { - return CompressAlphaJob(enc, NULL); // just do the job right away - } - } - return 1; -} - -int VP8EncFinishAlpha(VP8Encoder* const enc) { - if (enc->has_alpha_) { - if (enc->thread_level_ > 0) { - WebPWorker* const worker = &enc->alpha_worker_; - if (!WebPGetWorkerInterface()->Sync(worker)) return 0; // error - } - } - return WebPReportProgress(enc->pic_, enc->percent_ + 20, &enc->percent_); -} - -int VP8EncDeleteAlpha(VP8Encoder* const enc) { - int ok = 1; - if (enc->thread_level_ > 0) { - WebPWorker* const worker = &enc->alpha_worker_; - // finish anything left in flight - ok = WebPGetWorkerInterface()->Sync(worker); - // still need to end the worker, even if !ok - WebPGetWorkerInterface()->End(worker); - } - WebPSafeFree(enc->alpha_data_); - enc->alpha_data_ = NULL; - enc->alpha_data_size_ = 0; - enc->has_alpha_ = 0; - return ok; -} diff --git a/libwebp/src/enc/analysis_enc.c b/libwebp/src/enc/analysis_enc.c deleted file mode 100644 index 962eaa99..00000000 --- a/libwebp/src/enc/analysis_enc.c +++ /dev/null @@ -1,483 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Macroblock analysis -// -// Author: Skal (pascal.massimino@gmail.com) - -#include -#include -#include - -#include "src/enc/vp8i_enc.h" -#include "src/enc/cost_enc.h" -#include "src/utils/utils.h" - -#define MAX_ITERS_K_MEANS 6 - -//------------------------------------------------------------------------------ -// Smooth the segment map by replacing isolated block by the majority of its -// neighbours. - -static void SmoothSegmentMap(VP8Encoder* const enc) { - int n, x, y; - const int w = enc->mb_w_; - const int h = enc->mb_h_; - const int majority_cnt_3_x_3_grid = 5; - uint8_t* const tmp = (uint8_t*)WebPSafeMalloc(w * h, sizeof(*tmp)); - assert((uint64_t)(w * h) == (uint64_t)w * h); // no overflow, as per spec - - if (tmp == NULL) return; - for (y = 1; y < h - 1; ++y) { - for (x = 1; x < w - 1; ++x) { - int cnt[NUM_MB_SEGMENTS] = { 0 }; - const VP8MBInfo* const mb = &enc->mb_info_[x + w * y]; - int majority_seg = mb->segment_; - // Check the 8 neighbouring segment values. - cnt[mb[-w - 1].segment_]++; // top-left - cnt[mb[-w + 0].segment_]++; // top - cnt[mb[-w + 1].segment_]++; // top-right - cnt[mb[ - 1].segment_]++; // left - cnt[mb[ + 1].segment_]++; // right - cnt[mb[ w - 1].segment_]++; // bottom-left - cnt[mb[ w + 0].segment_]++; // bottom - cnt[mb[ w + 1].segment_]++; // bottom-right - for (n = 0; n < NUM_MB_SEGMENTS; ++n) { - if (cnt[n] >= majority_cnt_3_x_3_grid) { - majority_seg = n; - break; - } - } - tmp[x + y * w] = majority_seg; - } - } - for (y = 1; y < h - 1; ++y) { - for (x = 1; x < w - 1; ++x) { - VP8MBInfo* const mb = &enc->mb_info_[x + w * y]; - mb->segment_ = tmp[x + y * w]; - } - } - WebPSafeFree(tmp); -} - -//------------------------------------------------------------------------------ -// set segment susceptibility alpha_ / beta_ - -static WEBP_INLINE int clip(int v, int m, int M) { - return (v < m) ? m : (v > M) ? M : v; -} - -static void SetSegmentAlphas(VP8Encoder* const enc, - const int centers[NUM_MB_SEGMENTS], - int mid) { - const int nb = enc->segment_hdr_.num_segments_; - int min = centers[0], max = centers[0]; - int n; - - if (nb > 1) { - for (n = 0; n < nb; ++n) { - if (min > centers[n]) min = centers[n]; - if (max < centers[n]) max = centers[n]; - } - } - if (max == min) max = min + 1; - assert(mid <= max && mid >= min); - for (n = 0; n < nb; ++n) { - const int alpha = 255 * (centers[n] - mid) / (max - min); - const int beta = 255 * (centers[n] - min) / (max - min); - enc->dqm_[n].alpha_ = clip(alpha, -127, 127); - enc->dqm_[n].beta_ = clip(beta, 0, 255); - } -} - -//------------------------------------------------------------------------------ -// Compute susceptibility based on DCT-coeff histograms: -// the higher, the "easier" the macroblock is to compress. - -#define MAX_ALPHA 255 // 8b of precision for susceptibilities. -#define ALPHA_SCALE (2 * MAX_ALPHA) // scaling factor for alpha. -#define DEFAULT_ALPHA (-1) -#define IS_BETTER_ALPHA(alpha, best_alpha) ((alpha) > (best_alpha)) - -static int FinalAlphaValue(int alpha) { - alpha = MAX_ALPHA - alpha; - return clip(alpha, 0, MAX_ALPHA); -} - -static int GetAlpha(const VP8Histogram* const histo) { - // 'alpha' will later be clipped to [0..MAX_ALPHA] range, clamping outer - // values which happen to be mostly noise. This leaves the maximum precision - // for handling the useful small values which contribute most. - const int max_value = histo->max_value; - const int last_non_zero = histo->last_non_zero; - const int alpha = - (max_value > 1) ? ALPHA_SCALE * last_non_zero / max_value : 0; - return alpha; -} - -static void InitHistogram(VP8Histogram* const histo) { - histo->max_value = 0; - histo->last_non_zero = 1; -} - -//------------------------------------------------------------------------------ -// Simplified k-Means, to assign Nb segments based on alpha-histogram - -static void AssignSegments(VP8Encoder* const enc, - const int alphas[MAX_ALPHA + 1]) { - // 'num_segments_' is previously validated and <= NUM_MB_SEGMENTS, but an - // explicit check is needed to avoid spurious warning about 'n + 1' exceeding - // array bounds of 'centers' with some compilers (noticed with gcc-4.9). - const int nb = (enc->segment_hdr_.num_segments_ < NUM_MB_SEGMENTS) ? - enc->segment_hdr_.num_segments_ : NUM_MB_SEGMENTS; - int centers[NUM_MB_SEGMENTS]; - int weighted_average = 0; - int map[MAX_ALPHA + 1]; - int a, n, k; - int min_a = 0, max_a = MAX_ALPHA, range_a; - // 'int' type is ok for histo, and won't overflow - int accum[NUM_MB_SEGMENTS], dist_accum[NUM_MB_SEGMENTS]; - - assert(nb >= 1); - assert(nb <= NUM_MB_SEGMENTS); - - // bracket the input - for (n = 0; n <= MAX_ALPHA && alphas[n] == 0; ++n) {} - min_a = n; - for (n = MAX_ALPHA; n > min_a && alphas[n] == 0; --n) {} - max_a = n; - range_a = max_a - min_a; - - // Spread initial centers evenly - for (k = 0, n = 1; k < nb; ++k, n += 2) { - assert(n < 2 * nb); - centers[k] = min_a + (n * range_a) / (2 * nb); - } - - for (k = 0; k < MAX_ITERS_K_MEANS; ++k) { // few iters are enough - int total_weight; - int displaced; - // Reset stats - for (n = 0; n < nb; ++n) { - accum[n] = 0; - dist_accum[n] = 0; - } - // Assign nearest center for each 'a' - n = 0; // track the nearest center for current 'a' - for (a = min_a; a <= max_a; ++a) { - if (alphas[a]) { - while (n + 1 < nb && abs(a - centers[n + 1]) < abs(a - centers[n])) { - n++; - } - map[a] = n; - // accumulate contribution into best centroid - dist_accum[n] += a * alphas[a]; - accum[n] += alphas[a]; - } - } - // All point are classified. Move the centroids to the - // center of their respective cloud. - displaced = 0; - weighted_average = 0; - total_weight = 0; - for (n = 0; n < nb; ++n) { - if (accum[n]) { - const int new_center = (dist_accum[n] + accum[n] / 2) / accum[n]; - displaced += abs(centers[n] - new_center); - centers[n] = new_center; - weighted_average += new_center * accum[n]; - total_weight += accum[n]; - } - } - weighted_average = (weighted_average + total_weight / 2) / total_weight; - if (displaced < 5) break; // no need to keep on looping... - } - - // Map each original value to the closest centroid - for (n = 0; n < enc->mb_w_ * enc->mb_h_; ++n) { - VP8MBInfo* const mb = &enc->mb_info_[n]; - const int alpha = mb->alpha_; - mb->segment_ = map[alpha]; - mb->alpha_ = centers[map[alpha]]; // for the record. - } - - if (nb > 1) { - const int smooth = (enc->config_->preprocessing & 1); - if (smooth) SmoothSegmentMap(enc); - } - - SetSegmentAlphas(enc, centers, weighted_average); // pick some alphas. -} - -//------------------------------------------------------------------------------ -// Macroblock analysis: collect histogram for each mode, deduce the maximal -// susceptibility and set best modes for this macroblock. -// Segment assignment is done later. - -// Number of modes to inspect for alpha_ evaluation. We don't need to test all -// the possible modes during the analysis phase: we risk falling into a local -// optimum, or be subject to boundary effect -#define MAX_INTRA16_MODE 2 -#define MAX_INTRA4_MODE 2 -#define MAX_UV_MODE 2 - -static int MBAnalyzeBestIntra16Mode(VP8EncIterator* const it) { - const int max_mode = MAX_INTRA16_MODE; - int mode; - int best_alpha = DEFAULT_ALPHA; - int best_mode = 0; - - VP8MakeLuma16Preds(it); - for (mode = 0; mode < max_mode; ++mode) { - VP8Histogram histo; - int alpha; - - InitHistogram(&histo); - VP8CollectHistogram(it->yuv_in_ + Y_OFF_ENC, - it->yuv_p_ + VP8I16ModeOffsets[mode], - 0, 16, &histo); - alpha = GetAlpha(&histo); - if (IS_BETTER_ALPHA(alpha, best_alpha)) { - best_alpha = alpha; - best_mode = mode; - } - } - VP8SetIntra16Mode(it, best_mode); - return best_alpha; -} - -static int FastMBAnalyze(VP8EncIterator* const it) { - // Empirical cut-off value, should be around 16 (~=block size). We use the - // [8-17] range and favor intra4 at high quality, intra16 for low quality. - const int q = (int)it->enc_->config_->quality; - const uint32_t kThreshold = 8 + (17 - 8) * q / 100; - int k; - uint32_t dc[16], m, m2; - for (k = 0; k < 16; k += 4) { - VP8Mean16x4(it->yuv_in_ + Y_OFF_ENC + k * BPS, &dc[k]); - } - for (m = 0, m2 = 0, k = 0; k < 16; ++k) { - m += dc[k]; - m2 += dc[k] * dc[k]; - } - if (kThreshold * m2 < m * m) { - VP8SetIntra16Mode(it, 0); // DC16 - } else { - const uint8_t modes[16] = { 0 }; // DC4 - VP8SetIntra4Mode(it, modes); - } - return 0; -} - -static int MBAnalyzeBestUVMode(VP8EncIterator* const it) { - int best_alpha = DEFAULT_ALPHA; - int smallest_alpha = 0; - int best_mode = 0; - const int max_mode = MAX_UV_MODE; - int mode; - - VP8MakeChroma8Preds(it); - for (mode = 0; mode < max_mode; ++mode) { - VP8Histogram histo; - int alpha; - InitHistogram(&histo); - VP8CollectHistogram(it->yuv_in_ + U_OFF_ENC, - it->yuv_p_ + VP8UVModeOffsets[mode], - 16, 16 + 4 + 4, &histo); - alpha = GetAlpha(&histo); - if (IS_BETTER_ALPHA(alpha, best_alpha)) { - best_alpha = alpha; - } - // The best prediction mode tends to be the one with the smallest alpha. - if (mode == 0 || alpha < smallest_alpha) { - smallest_alpha = alpha; - best_mode = mode; - } - } - VP8SetIntraUVMode(it, best_mode); - return best_alpha; -} - -static void MBAnalyze(VP8EncIterator* const it, - int alphas[MAX_ALPHA + 1], - int* const alpha, int* const uv_alpha) { - const VP8Encoder* const enc = it->enc_; - int best_alpha, best_uv_alpha; - - VP8SetIntra16Mode(it, 0); // default: Intra16, DC_PRED - VP8SetSkip(it, 0); // not skipped - VP8SetSegment(it, 0); // default segment, spec-wise. - - if (enc->method_ <= 1) { - best_alpha = FastMBAnalyze(it); - } else { - best_alpha = MBAnalyzeBestIntra16Mode(it); - } - best_uv_alpha = MBAnalyzeBestUVMode(it); - - // Final susceptibility mix - best_alpha = (3 * best_alpha + best_uv_alpha + 2) >> 2; - best_alpha = FinalAlphaValue(best_alpha); - alphas[best_alpha]++; - it->mb_->alpha_ = best_alpha; // for later remapping. - - // Accumulate for later complexity analysis. - *alpha += best_alpha; // mixed susceptibility (not just luma) - *uv_alpha += best_uv_alpha; -} - -static void DefaultMBInfo(VP8MBInfo* const mb) { - mb->type_ = 1; // I16x16 - mb->uv_mode_ = 0; - mb->skip_ = 0; // not skipped - mb->segment_ = 0; // default segment - mb->alpha_ = 0; -} - -//------------------------------------------------------------------------------ -// Main analysis loop: -// Collect all susceptibilities for each macroblock and record their -// distribution in alphas[]. Segments is assigned a-posteriori, based on -// this histogram. -// We also pick an intra16 prediction mode, which shouldn't be considered -// final except for fast-encode settings. We can also pick some intra4 modes -// and decide intra4/intra16, but that's usually almost always a bad choice at -// this stage. - -static void ResetAllMBInfo(VP8Encoder* const enc) { - int n; - for (n = 0; n < enc->mb_w_ * enc->mb_h_; ++n) { - DefaultMBInfo(&enc->mb_info_[n]); - } - // Default susceptibilities. - enc->dqm_[0].alpha_ = 0; - enc->dqm_[0].beta_ = 0; - // Note: we can't compute this alpha_ / uv_alpha_ -> set to default value. - enc->alpha_ = 0; - enc->uv_alpha_ = 0; - WebPReportProgress(enc->pic_, enc->percent_ + 20, &enc->percent_); -} - -// struct used to collect job result -typedef struct { - WebPWorker worker; - int alphas[MAX_ALPHA + 1]; - int alpha, uv_alpha; - VP8EncIterator it; - int delta_progress; -} SegmentJob; - -// main work call -static int DoSegmentsJob(void* arg1, void* arg2) { - SegmentJob* const job = (SegmentJob*)arg1; - VP8EncIterator* const it = (VP8EncIterator*)arg2; - int ok = 1; - if (!VP8IteratorIsDone(it)) { - uint8_t tmp[32 + WEBP_ALIGN_CST]; - uint8_t* const scratch = (uint8_t*)WEBP_ALIGN(tmp); - do { - // Let's pretend we have perfect lossless reconstruction. - VP8IteratorImport(it, scratch); - MBAnalyze(it, job->alphas, &job->alpha, &job->uv_alpha); - ok = VP8IteratorProgress(it, job->delta_progress); - } while (ok && VP8IteratorNext(it)); - } - return ok; -} - -#ifdef WEBP_USE_THREAD -static void MergeJobs(const SegmentJob* const src, SegmentJob* const dst) { - int i; - for (i = 0; i <= MAX_ALPHA; ++i) dst->alphas[i] += src->alphas[i]; - dst->alpha += src->alpha; - dst->uv_alpha += src->uv_alpha; -} -#endif - -// initialize the job struct with some tasks to perform -static void InitSegmentJob(VP8Encoder* const enc, SegmentJob* const job, - int start_row, int end_row) { - WebPGetWorkerInterface()->Init(&job->worker); - job->worker.data1 = job; - job->worker.data2 = &job->it; - job->worker.hook = DoSegmentsJob; - VP8IteratorInit(enc, &job->it); - VP8IteratorSetRow(&job->it, start_row); - VP8IteratorSetCountDown(&job->it, (end_row - start_row) * enc->mb_w_); - memset(job->alphas, 0, sizeof(job->alphas)); - job->alpha = 0; - job->uv_alpha = 0; - // only one of both jobs can record the progress, since we don't - // expect the user's hook to be multi-thread safe - job->delta_progress = (start_row == 0) ? 20 : 0; -} - -// main entry point -int VP8EncAnalyze(VP8Encoder* const enc) { - int ok = 1; - const int do_segments = - enc->config_->emulate_jpeg_size || // We need the complexity evaluation. - (enc->segment_hdr_.num_segments_ > 1) || - (enc->method_ <= 1); // for method 0 - 1, we need preds_[] to be filled. - if (do_segments) { - const int last_row = enc->mb_h_; - const int total_mb = last_row * enc->mb_w_; -#ifdef WEBP_USE_THREAD - // We give a little more than a half work to the main thread. - const int split_row = (9 * last_row + 15) >> 4; - const int kMinSplitRow = 2; // minimal rows needed for mt to be worth it - const int do_mt = (enc->thread_level_ > 0) && (split_row >= kMinSplitRow); -#else - const int do_mt = 0; -#endif - const WebPWorkerInterface* const worker_interface = - WebPGetWorkerInterface(); - SegmentJob main_job; - if (do_mt) { -#ifdef WEBP_USE_THREAD - SegmentJob side_job; - // Note the use of '&' instead of '&&' because we must call the functions - // no matter what. - InitSegmentJob(enc, &main_job, 0, split_row); - InitSegmentJob(enc, &side_job, split_row, last_row); - // we don't need to call Reset() on main_job.worker, since we're calling - // WebPWorkerExecute() on it - ok &= worker_interface->Reset(&side_job.worker); - // launch the two jobs in parallel - if (ok) { - worker_interface->Launch(&side_job.worker); - worker_interface->Execute(&main_job.worker); - ok &= worker_interface->Sync(&side_job.worker); - ok &= worker_interface->Sync(&main_job.worker); - } - worker_interface->End(&side_job.worker); - if (ok) MergeJobs(&side_job, &main_job); // merge results together -#endif // WEBP_USE_THREAD - } else { - // Even for single-thread case, we use the generic Worker tools. - InitSegmentJob(enc, &main_job, 0, last_row); - worker_interface->Execute(&main_job.worker); - ok &= worker_interface->Sync(&main_job.worker); - } - worker_interface->End(&main_job.worker); - if (ok) { - enc->alpha_ = main_job.alpha / total_mb; - enc->uv_alpha_ = main_job.uv_alpha / total_mb; - AssignSegments(enc, main_job.alphas); - } - } else { // Use only one default segment. - ResetAllMBInfo(enc); - } - if (!ok) { - return WebPEncodingSetError(enc->pic_, - VP8_ENC_ERROR_OUT_OF_MEMORY); // imprecise - } - return ok; -} - diff --git a/libwebp/src/enc/backward_references_cost_enc.c b/libwebp/src/enc/backward_references_cost_enc.c deleted file mode 100644 index 6968ef3c..00000000 --- a/libwebp/src/enc/backward_references_cost_enc.c +++ /dev/null @@ -1,795 +0,0 @@ -// Copyright 2017 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Improves a given set of backward references by analyzing its bit cost. -// The algorithm is similar to the Zopfli compression algorithm but tailored to -// images. -// -// Author: Vincent Rabaud (vrabaud@google.com) -// - -#include -#include - -#include "src/dsp/lossless_common.h" -#include "src/enc/backward_references_enc.h" -#include "src/enc/histogram_enc.h" -#include "src/utils/color_cache_utils.h" -#include "src/utils/utils.h" - -#define VALUES_IN_BYTE 256 - -extern void VP8LClearBackwardRefs(VP8LBackwardRefs* const refs); -extern int VP8LDistanceToPlaneCode(int xsize, int dist); -extern void VP8LBackwardRefsCursorAdd(VP8LBackwardRefs* const refs, - const PixOrCopy v); - -typedef struct { - float alpha_[VALUES_IN_BYTE]; - float red_[VALUES_IN_BYTE]; - float blue_[VALUES_IN_BYTE]; - float distance_[NUM_DISTANCE_CODES]; - float* literal_; -} CostModel; - -static void ConvertPopulationCountTableToBitEstimates( - int num_symbols, const uint32_t population_counts[], float output[]) { - uint32_t sum = 0; - int nonzeros = 0; - int i; - for (i = 0; i < num_symbols; ++i) { - sum += population_counts[i]; - if (population_counts[i] > 0) { - ++nonzeros; - } - } - if (nonzeros <= 1) { - memset(output, 0, num_symbols * sizeof(*output)); - } else { - const float logsum = VP8LFastLog2(sum); - for (i = 0; i < num_symbols; ++i) { - output[i] = logsum - VP8LFastLog2(population_counts[i]); - } - } -} - -static int CostModelBuild(CostModel* const m, int xsize, int cache_bits, - const VP8LBackwardRefs* const refs) { - int ok = 0; - VP8LRefsCursor c = VP8LRefsCursorInit(refs); - VP8LHistogram* const histo = VP8LAllocateHistogram(cache_bits); - if (histo == NULL) goto Error; - - // The following code is similar to VP8LHistogramCreate but converts the - // distance to plane code. - VP8LHistogramInit(histo, cache_bits, /*init_arrays=*/ 1); - while (VP8LRefsCursorOk(&c)) { - VP8LHistogramAddSinglePixOrCopy(histo, c.cur_pos, VP8LDistanceToPlaneCode, - xsize); - VP8LRefsCursorNext(&c); - } - - ConvertPopulationCountTableToBitEstimates( - VP8LHistogramNumCodes(histo->palette_code_bits_), histo->literal_, - m->literal_); - ConvertPopulationCountTableToBitEstimates( - VALUES_IN_BYTE, histo->red_, m->red_); - ConvertPopulationCountTableToBitEstimates( - VALUES_IN_BYTE, histo->blue_, m->blue_); - ConvertPopulationCountTableToBitEstimates( - VALUES_IN_BYTE, histo->alpha_, m->alpha_); - ConvertPopulationCountTableToBitEstimates( - NUM_DISTANCE_CODES, histo->distance_, m->distance_); - ok = 1; - - Error: - VP8LFreeHistogram(histo); - return ok; -} - -static WEBP_INLINE float GetLiteralCost(const CostModel* const m, uint32_t v) { - return m->alpha_[v >> 24] + - m->red_[(v >> 16) & 0xff] + - m->literal_[(v >> 8) & 0xff] + - m->blue_[v & 0xff]; -} - -static WEBP_INLINE float GetCacheCost(const CostModel* const m, uint32_t idx) { - const int literal_idx = VALUES_IN_BYTE + NUM_LENGTH_CODES + idx; - return m->literal_[literal_idx]; -} - -static WEBP_INLINE float GetLengthCost(const CostModel* const m, - uint32_t length) { - int code, extra_bits; - VP8LPrefixEncodeBits(length, &code, &extra_bits); - return m->literal_[VALUES_IN_BYTE + code] + extra_bits; -} - -static WEBP_INLINE float GetDistanceCost(const CostModel* const m, - uint32_t distance) { - int code, extra_bits; - VP8LPrefixEncodeBits(distance, &code, &extra_bits); - return m->distance_[code] + extra_bits; -} - -static WEBP_INLINE void AddSingleLiteralWithCostModel( - const uint32_t* const argb, VP8LColorCache* const hashers, - const CostModel* const cost_model, int idx, int use_color_cache, - float prev_cost, float* const cost, uint16_t* const dist_array) { - float cost_val = prev_cost; - const uint32_t color = argb[idx]; - const int ix = use_color_cache ? VP8LColorCacheContains(hashers, color) : -1; - if (ix >= 0) { - // use_color_cache is true and hashers contains color - const float mul0 = 0.68f; - cost_val += GetCacheCost(cost_model, ix) * mul0; - } else { - const float mul1 = 0.82f; - if (use_color_cache) VP8LColorCacheInsert(hashers, color); - cost_val += GetLiteralCost(cost_model, color) * mul1; - } - if (cost[idx] > cost_val) { - cost[idx] = cost_val; - dist_array[idx] = 1; // only one is inserted. - } -} - -// ----------------------------------------------------------------------------- -// CostManager and interval handling - -// Empirical value to avoid high memory consumption but good for performance. -#define COST_CACHE_INTERVAL_SIZE_MAX 500 - -// To perform backward reference every pixel at index index_ is considered and -// the cost for the MAX_LENGTH following pixels computed. Those following pixels -// at index index_ + k (k from 0 to MAX_LENGTH) have a cost of: -// cost_ = distance cost at index + GetLengthCost(cost_model, k) -// and the minimum value is kept. GetLengthCost(cost_model, k) is cached in an -// array of size MAX_LENGTH. -// Instead of performing MAX_LENGTH comparisons per pixel, we keep track of the -// minimal values using intervals of constant cost. -// An interval is defined by the index_ of the pixel that generated it and -// is only useful in a range of indices from start_ to end_ (exclusive), i.e. -// it contains the minimum value for pixels between start_ and end_. -// Intervals are stored in a linked list and ordered by start_. When a new -// interval has a better value, old intervals are split or removed. There are -// therefore no overlapping intervals. -typedef struct CostInterval CostInterval; -struct CostInterval { - float cost_; - int start_; - int end_; - int index_; - CostInterval* previous_; - CostInterval* next_; -}; - -// The GetLengthCost(cost_model, k) are cached in a CostCacheInterval. -typedef struct { - float cost_; - int start_; - int end_; // Exclusive. -} CostCacheInterval; - -// This structure is in charge of managing intervals and costs. -// It caches the different CostCacheInterval, caches the different -// GetLengthCost(cost_model, k) in cost_cache_ and the CostInterval's (whose -// count_ is limited by COST_CACHE_INTERVAL_SIZE_MAX). -#define COST_MANAGER_MAX_FREE_LIST 10 -typedef struct { - CostInterval* head_; - int count_; // The number of stored intervals. - CostCacheInterval* cache_intervals_; - size_t cache_intervals_size_; - float cost_cache_[MAX_LENGTH]; // Contains the GetLengthCost(cost_model, k). - float* costs_; - uint16_t* dist_array_; - // Most of the time, we only need few intervals -> use a free-list, to avoid - // fragmentation with small allocs in most common cases. - CostInterval intervals_[COST_MANAGER_MAX_FREE_LIST]; - CostInterval* free_intervals_; - // These are regularly malloc'd remains. This list can't grow larger than than - // size COST_CACHE_INTERVAL_SIZE_MAX - COST_MANAGER_MAX_FREE_LIST, note. - CostInterval* recycled_intervals_; -} CostManager; - -static void CostIntervalAddToFreeList(CostManager* const manager, - CostInterval* const interval) { - interval->next_ = manager->free_intervals_; - manager->free_intervals_ = interval; -} - -static int CostIntervalIsInFreeList(const CostManager* const manager, - const CostInterval* const interval) { - return (interval >= &manager->intervals_[0] && - interval <= &manager->intervals_[COST_MANAGER_MAX_FREE_LIST - 1]); -} - -static void CostManagerInitFreeList(CostManager* const manager) { - int i; - manager->free_intervals_ = NULL; - for (i = 0; i < COST_MANAGER_MAX_FREE_LIST; ++i) { - CostIntervalAddToFreeList(manager, &manager->intervals_[i]); - } -} - -static void DeleteIntervalList(CostManager* const manager, - const CostInterval* interval) { - while (interval != NULL) { - const CostInterval* const next = interval->next_; - if (!CostIntervalIsInFreeList(manager, interval)) { - WebPSafeFree((void*)interval); - } // else: do nothing - interval = next; - } -} - -static void CostManagerClear(CostManager* const manager) { - if (manager == NULL) return; - - WebPSafeFree(manager->costs_); - WebPSafeFree(manager->cache_intervals_); - - // Clear the interval lists. - DeleteIntervalList(manager, manager->head_); - manager->head_ = NULL; - DeleteIntervalList(manager, manager->recycled_intervals_); - manager->recycled_intervals_ = NULL; - - // Reset pointers, count_ and cache_intervals_size_. - memset(manager, 0, sizeof(*manager)); - CostManagerInitFreeList(manager); -} - -static int CostManagerInit(CostManager* const manager, - uint16_t* const dist_array, int pix_count, - const CostModel* const cost_model) { - int i; - const int cost_cache_size = (pix_count > MAX_LENGTH) ? MAX_LENGTH : pix_count; - - manager->costs_ = NULL; - manager->cache_intervals_ = NULL; - manager->head_ = NULL; - manager->recycled_intervals_ = NULL; - manager->count_ = 0; - manager->dist_array_ = dist_array; - CostManagerInitFreeList(manager); - - // Fill in the cost_cache_. - // Has to be done in two passes due to a GCC bug on i686 - // related to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=323 - for (i = 0; i < cost_cache_size; ++i) { - manager->cost_cache_[i] = GetLengthCost(cost_model, i); - } - manager->cache_intervals_size_ = 1; - for (i = 1; i < cost_cache_size; ++i) { - // Get the number of bound intervals. - if (manager->cost_cache_[i] != manager->cost_cache_[i - 1]) { - ++manager->cache_intervals_size_; - } - } - - // With the current cost model, we usually have below 20 intervals. - // The worst case scenario with a cost model would be if every length has a - // different cost, hence MAX_LENGTH but that is impossible with the current - // implementation that spirals around a pixel. - assert(manager->cache_intervals_size_ <= MAX_LENGTH); - manager->cache_intervals_ = (CostCacheInterval*)WebPSafeMalloc( - manager->cache_intervals_size_, sizeof(*manager->cache_intervals_)); - if (manager->cache_intervals_ == NULL) { - CostManagerClear(manager); - return 0; - } - - // Fill in the cache_intervals_. - { - CostCacheInterval* cur = manager->cache_intervals_; - - // Consecutive values in cost_cache_ are compared and if a big enough - // difference is found, a new interval is created and bounded. - cur->start_ = 0; - cur->end_ = 1; - cur->cost_ = manager->cost_cache_[0]; - for (i = 1; i < cost_cache_size; ++i) { - const float cost_val = manager->cost_cache_[i]; - if (cost_val != cur->cost_) { - ++cur; - // Initialize an interval. - cur->start_ = i; - cur->cost_ = cost_val; - } - cur->end_ = i + 1; - } - assert((size_t)(cur - manager->cache_intervals_) + 1 == - manager->cache_intervals_size_); - } - - manager->costs_ = (float*)WebPSafeMalloc(pix_count, sizeof(*manager->costs_)); - if (manager->costs_ == NULL) { - CostManagerClear(manager); - return 0; - } - // Set the initial costs_ high for every pixel as we will keep the minimum. - for (i = 0; i < pix_count; ++i) manager->costs_[i] = FLT_MAX; - - return 1; -} - -// Given the cost and the position that define an interval, update the cost at -// pixel 'i' if it is smaller than the previously computed value. -static WEBP_INLINE void UpdateCost(CostManager* const manager, int i, - int position, float cost) { - const int k = i - position; - assert(k >= 0 && k < MAX_LENGTH); - - if (manager->costs_[i] > cost) { - manager->costs_[i] = cost; - manager->dist_array_[i] = k + 1; - } -} - -// Given the cost and the position that define an interval, update the cost for -// all the pixels between 'start' and 'end' excluded. -static WEBP_INLINE void UpdateCostPerInterval(CostManager* const manager, - int start, int end, int position, - float cost) { - int i; - for (i = start; i < end; ++i) UpdateCost(manager, i, position, cost); -} - -// Given two intervals, make 'prev' be the previous one of 'next' in 'manager'. -static WEBP_INLINE void ConnectIntervals(CostManager* const manager, - CostInterval* const prev, - CostInterval* const next) { - if (prev != NULL) { - prev->next_ = next; - } else { - manager->head_ = next; - } - - if (next != NULL) next->previous_ = prev; -} - -// Pop an interval in the manager. -static WEBP_INLINE void PopInterval(CostManager* const manager, - CostInterval* const interval) { - if (interval == NULL) return; - - ConnectIntervals(manager, interval->previous_, interval->next_); - if (CostIntervalIsInFreeList(manager, interval)) { - CostIntervalAddToFreeList(manager, interval); - } else { // recycle regularly malloc'd intervals too - interval->next_ = manager->recycled_intervals_; - manager->recycled_intervals_ = interval; - } - --manager->count_; - assert(manager->count_ >= 0); -} - -// Update the cost at index i by going over all the stored intervals that -// overlap with i. -// If 'do_clean_intervals' is set to something different than 0, intervals that -// end before 'i' will be popped. -static WEBP_INLINE void UpdateCostAtIndex(CostManager* const manager, int i, - int do_clean_intervals) { - CostInterval* current = manager->head_; - - while (current != NULL && current->start_ <= i) { - CostInterval* const next = current->next_; - if (current->end_ <= i) { - if (do_clean_intervals) { - // We have an outdated interval, remove it. - PopInterval(manager, current); - } - } else { - UpdateCost(manager, i, current->index_, current->cost_); - } - current = next; - } -} - -// Given a current orphan interval and its previous interval, before -// it was orphaned (which can be NULL), set it at the right place in the list -// of intervals using the start_ ordering and the previous interval as a hint. -static WEBP_INLINE void PositionOrphanInterval(CostManager* const manager, - CostInterval* const current, - CostInterval* previous) { - assert(current != NULL); - - if (previous == NULL) previous = manager->head_; - while (previous != NULL && current->start_ < previous->start_) { - previous = previous->previous_; - } - while (previous != NULL && previous->next_ != NULL && - previous->next_->start_ < current->start_) { - previous = previous->next_; - } - - if (previous != NULL) { - ConnectIntervals(manager, current, previous->next_); - } else { - ConnectIntervals(manager, current, manager->head_); - } - ConnectIntervals(manager, previous, current); -} - -// Insert an interval in the list contained in the manager by starting at -// interval_in as a hint. The intervals are sorted by start_ value. -static WEBP_INLINE void InsertInterval(CostManager* const manager, - CostInterval* const interval_in, - float cost, int position, int start, - int end) { - CostInterval* interval_new; - - if (start >= end) return; - if (manager->count_ >= COST_CACHE_INTERVAL_SIZE_MAX) { - // Serialize the interval if we cannot store it. - UpdateCostPerInterval(manager, start, end, position, cost); - return; - } - if (manager->free_intervals_ != NULL) { - interval_new = manager->free_intervals_; - manager->free_intervals_ = interval_new->next_; - } else if (manager->recycled_intervals_ != NULL) { - interval_new = manager->recycled_intervals_; - manager->recycled_intervals_ = interval_new->next_; - } else { // malloc for good - interval_new = (CostInterval*)WebPSafeMalloc(1, sizeof(*interval_new)); - if (interval_new == NULL) { - // Write down the interval if we cannot create it. - UpdateCostPerInterval(manager, start, end, position, cost); - return; - } - } - - interval_new->cost_ = cost; - interval_new->index_ = position; - interval_new->start_ = start; - interval_new->end_ = end; - PositionOrphanInterval(manager, interval_new, interval_in); - - ++manager->count_; -} - -// Given a new cost interval defined by its start at position, its length value -// and distance_cost, add its contributions to the previous intervals and costs. -// If handling the interval or one of its subintervals becomes to heavy, its -// contribution is added to the costs right away. -static WEBP_INLINE void PushInterval(CostManager* const manager, - float distance_cost, int position, - int len) { - size_t i; - CostInterval* interval = manager->head_; - CostInterval* interval_next; - const CostCacheInterval* const cost_cache_intervals = - manager->cache_intervals_; - // If the interval is small enough, no need to deal with the heavy - // interval logic, just serialize it right away. This constant is empirical. - const int kSkipDistance = 10; - - if (len < kSkipDistance) { - int j; - for (j = position; j < position + len; ++j) { - const int k = j - position; - float cost_tmp; - assert(k >= 0 && k < MAX_LENGTH); - cost_tmp = distance_cost + manager->cost_cache_[k]; - - if (manager->costs_[j] > cost_tmp) { - manager->costs_[j] = cost_tmp; - manager->dist_array_[j] = k + 1; - } - } - return; - } - - for (i = 0; i < manager->cache_intervals_size_ && - cost_cache_intervals[i].start_ < len; - ++i) { - // Define the intersection of the ith interval with the new one. - int start = position + cost_cache_intervals[i].start_; - const int end = position + (cost_cache_intervals[i].end_ > len - ? len - : cost_cache_intervals[i].end_); - const float cost = distance_cost + cost_cache_intervals[i].cost_; - - for (; interval != NULL && interval->start_ < end; - interval = interval_next) { - interval_next = interval->next_; - - // Make sure we have some overlap - if (start >= interval->end_) continue; - - if (cost >= interval->cost_) { - // When intervals are represented, the lower, the better. - // [**********************************************************[ - // start end - // [----------------------------------[ - // interval->start_ interval->end_ - // If we are worse than what we already have, add whatever we have so - // far up to interval. - const int start_new = interval->end_; - InsertInterval(manager, interval, cost, position, start, - interval->start_); - start = start_new; - if (start >= end) break; - continue; - } - - if (start <= interval->start_) { - if (interval->end_ <= end) { - // [----------------------------------[ - // interval->start_ interval->end_ - // [**************************************************************[ - // start end - // We can safely remove the old interval as it is fully included. - PopInterval(manager, interval); - } else { - // [------------------------------------[ - // interval->start_ interval->end_ - // [*****************************[ - // start end - interval->start_ = end; - break; - } - } else { - if (end < interval->end_) { - // [--------------------------------------------------------------[ - // interval->start_ interval->end_ - // [*****************************[ - // start end - // We have to split the old interval as it fully contains the new one. - const int end_original = interval->end_; - interval->end_ = start; - InsertInterval(manager, interval, interval->cost_, interval->index_, - end, end_original); - interval = interval->next_; - break; - } else { - // [------------------------------------[ - // interval->start_ interval->end_ - // [*****************************[ - // start end - interval->end_ = start; - } - } - } - // Insert the remaining interval from start to end. - InsertInterval(manager, interval, cost, position, start, end); - } -} - -static int BackwardReferencesHashChainDistanceOnly( - int xsize, int ysize, const uint32_t* const argb, int cache_bits, - const VP8LHashChain* const hash_chain, const VP8LBackwardRefs* const refs, - uint16_t* const dist_array) { - int i; - int ok = 0; - int cc_init = 0; - const int pix_count = xsize * ysize; - const int use_color_cache = (cache_bits > 0); - const size_t literal_array_size = - sizeof(float) * (VP8LHistogramNumCodes(cache_bits)); - const size_t cost_model_size = sizeof(CostModel) + literal_array_size; - CostModel* const cost_model = - (CostModel*)WebPSafeCalloc(1ULL, cost_model_size); - VP8LColorCache hashers; - CostManager* cost_manager = - (CostManager*)WebPSafeCalloc(1ULL, sizeof(*cost_manager)); - int offset_prev = -1, len_prev = -1; - float offset_cost = -1.f; - int first_offset_is_constant = -1; // initialized with 'impossible' value - int reach = 0; - - if (cost_model == NULL || cost_manager == NULL) goto Error; - - cost_model->literal_ = (float*)(cost_model + 1); - if (use_color_cache) { - cc_init = VP8LColorCacheInit(&hashers, cache_bits); - if (!cc_init) goto Error; - } - - if (!CostModelBuild(cost_model, xsize, cache_bits, refs)) { - goto Error; - } - - if (!CostManagerInit(cost_manager, dist_array, pix_count, cost_model)) { - goto Error; - } - - // We loop one pixel at a time, but store all currently best points to - // non-processed locations from this point. - dist_array[0] = 0; - // Add first pixel as literal. - AddSingleLiteralWithCostModel(argb, &hashers, cost_model, 0, use_color_cache, - 0.f, cost_manager->costs_, dist_array); - - for (i = 1; i < pix_count; ++i) { - const float prev_cost = cost_manager->costs_[i - 1]; - int offset, len; - VP8LHashChainFindCopy(hash_chain, i, &offset, &len); - - // Try adding the pixel as a literal. - AddSingleLiteralWithCostModel(argb, &hashers, cost_model, i, - use_color_cache, prev_cost, - cost_manager->costs_, dist_array); - - // If we are dealing with a non-literal. - if (len >= 2) { - if (offset != offset_prev) { - const int code = VP8LDistanceToPlaneCode(xsize, offset); - offset_cost = GetDistanceCost(cost_model, code); - first_offset_is_constant = 1; - PushInterval(cost_manager, prev_cost + offset_cost, i, len); - } else { - assert(offset_cost >= 0); - assert(len_prev >= 0); - assert(first_offset_is_constant == 0 || first_offset_is_constant == 1); - // Instead of considering all contributions from a pixel i by calling: - // PushInterval(cost_manager, prev_cost + offset_cost, i, len); - // we optimize these contributions in case offset_cost stays the same - // for consecutive pixels. This describes a set of pixels similar to a - // previous set (e.g. constant color regions). - if (first_offset_is_constant) { - reach = i - 1 + len_prev - 1; - first_offset_is_constant = 0; - } - - if (i + len - 1 > reach) { - // We can only be go further with the same offset if the previous - // length was maxed, hence len_prev == len == MAX_LENGTH. - // TODO(vrabaud), bump i to the end right away (insert cache and - // update cost). - // TODO(vrabaud), check if one of the points in between does not have - // a lower cost. - // Already consider the pixel at "reach" to add intervals that are - // better than whatever we add. - int offset_j, len_j = 0; - int j; - assert(len == MAX_LENGTH || len == pix_count - i); - // Figure out the last consecutive pixel within [i, reach + 1] with - // the same offset. - for (j = i; j <= reach; ++j) { - VP8LHashChainFindCopy(hash_chain, j + 1, &offset_j, &len_j); - if (offset_j != offset) { - VP8LHashChainFindCopy(hash_chain, j, &offset_j, &len_j); - break; - } - } - // Update the cost at j - 1 and j. - UpdateCostAtIndex(cost_manager, j - 1, 0); - UpdateCostAtIndex(cost_manager, j, 0); - - PushInterval(cost_manager, cost_manager->costs_[j - 1] + offset_cost, - j, len_j); - reach = j + len_j - 1; - } - } - } - - UpdateCostAtIndex(cost_manager, i, 1); - offset_prev = offset; - len_prev = len; - } - - ok = !refs->error_; - Error: - if (cc_init) VP8LColorCacheClear(&hashers); - CostManagerClear(cost_manager); - WebPSafeFree(cost_model); - WebPSafeFree(cost_manager); - return ok; -} - -// We pack the path at the end of *dist_array and return -// a pointer to this part of the array. Example: -// dist_array = [1x2xx3x2] => packed [1x2x1232], chosen_path = [1232] -static void TraceBackwards(uint16_t* const dist_array, - int dist_array_size, - uint16_t** const chosen_path, - int* const chosen_path_size) { - uint16_t* path = dist_array + dist_array_size; - uint16_t* cur = dist_array + dist_array_size - 1; - while (cur >= dist_array) { - const int k = *cur; - --path; - *path = k; - cur -= k; - } - *chosen_path = path; - *chosen_path_size = (int)(dist_array + dist_array_size - path); -} - -static int BackwardReferencesHashChainFollowChosenPath( - const uint32_t* const argb, int cache_bits, - const uint16_t* const chosen_path, int chosen_path_size, - const VP8LHashChain* const hash_chain, VP8LBackwardRefs* const refs) { - const int use_color_cache = (cache_bits > 0); - int ix; - int i = 0; - int ok = 0; - int cc_init = 0; - VP8LColorCache hashers; - - if (use_color_cache) { - cc_init = VP8LColorCacheInit(&hashers, cache_bits); - if (!cc_init) goto Error; - } - - VP8LClearBackwardRefs(refs); - for (ix = 0; ix < chosen_path_size; ++ix) { - const int len = chosen_path[ix]; - if (len != 1) { - int k; - const int offset = VP8LHashChainFindOffset(hash_chain, i); - VP8LBackwardRefsCursorAdd(refs, PixOrCopyCreateCopy(offset, len)); - if (use_color_cache) { - for (k = 0; k < len; ++k) { - VP8LColorCacheInsert(&hashers, argb[i + k]); - } - } - i += len; - } else { - PixOrCopy v; - const int idx = - use_color_cache ? VP8LColorCacheContains(&hashers, argb[i]) : -1; - if (idx >= 0) { - // use_color_cache is true and hashers contains argb[i] - // push pixel as a color cache index - v = PixOrCopyCreateCacheIdx(idx); - } else { - if (use_color_cache) VP8LColorCacheInsert(&hashers, argb[i]); - v = PixOrCopyCreateLiteral(argb[i]); - } - VP8LBackwardRefsCursorAdd(refs, v); - ++i; - } - } - ok = !refs->error_; - Error: - if (cc_init) VP8LColorCacheClear(&hashers); - return ok; -} - -// Returns 1 on success. -extern int VP8LBackwardReferencesTraceBackwards( - int xsize, int ysize, const uint32_t* const argb, int cache_bits, - const VP8LHashChain* const hash_chain, - const VP8LBackwardRefs* const refs_src, VP8LBackwardRefs* const refs_dst); -int VP8LBackwardReferencesTraceBackwards(int xsize, int ysize, - const uint32_t* const argb, - int cache_bits, - const VP8LHashChain* const hash_chain, - const VP8LBackwardRefs* const refs_src, - VP8LBackwardRefs* const refs_dst) { - int ok = 0; - const int dist_array_size = xsize * ysize; - uint16_t* chosen_path = NULL; - int chosen_path_size = 0; - uint16_t* dist_array = - (uint16_t*)WebPSafeMalloc(dist_array_size, sizeof(*dist_array)); - - if (dist_array == NULL) goto Error; - - if (!BackwardReferencesHashChainDistanceOnly( - xsize, ysize, argb, cache_bits, hash_chain, refs_src, dist_array)) { - goto Error; - } - TraceBackwards(dist_array, dist_array_size, &chosen_path, &chosen_path_size); - if (!BackwardReferencesHashChainFollowChosenPath( - argb, cache_bits, chosen_path, chosen_path_size, hash_chain, - refs_dst)) { - goto Error; - } - ok = 1; - Error: - WebPSafeFree(dist_array); - return ok; -} diff --git a/libwebp/src/enc/backward_references_enc.c b/libwebp/src/enc/backward_references_enc.c deleted file mode 100644 index dc98bf17..00000000 --- a/libwebp/src/enc/backward_references_enc.c +++ /dev/null @@ -1,1065 +0,0 @@ -// Copyright 2012 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Author: Jyrki Alakuijala (jyrki@google.com) -// - -#include "src/enc/backward_references_enc.h" - -#include -#include -#include - -#include "src/dsp/dsp.h" -#include "src/dsp/lossless.h" -#include "src/dsp/lossless_common.h" -#include "src/enc/histogram_enc.h" -#include "src/enc/vp8i_enc.h" -#include "src/utils/color_cache_utils.h" -#include "src/utils/utils.h" -#include "src/webp/encode.h" - -#define MIN_BLOCK_SIZE 256 // minimum block size for backward references - -#define MAX_ENTROPY (1e30f) - -// 1M window (4M bytes) minus 120 special codes for short distances. -#define WINDOW_SIZE ((1 << WINDOW_SIZE_BITS) - 120) - -// Minimum number of pixels for which it is cheaper to encode a -// distance + length instead of each pixel as a literal. -#define MIN_LENGTH 4 - -// ----------------------------------------------------------------------------- - -static const uint8_t plane_to_code_lut[128] = { - 96, 73, 55, 39, 23, 13, 5, 1, 255, 255, 255, 255, 255, 255, 255, 255, - 101, 78, 58, 42, 26, 16, 8, 2, 0, 3, 9, 17, 27, 43, 59, 79, - 102, 86, 62, 46, 32, 20, 10, 6, 4, 7, 11, 21, 33, 47, 63, 87, - 105, 90, 70, 52, 37, 28, 18, 14, 12, 15, 19, 29, 38, 53, 71, 91, - 110, 99, 82, 66, 48, 35, 30, 24, 22, 25, 31, 36, 49, 67, 83, 100, - 115, 108, 94, 76, 64, 50, 44, 40, 34, 41, 45, 51, 65, 77, 95, 109, - 118, 113, 103, 92, 80, 68, 60, 56, 54, 57, 61, 69, 81, 93, 104, 114, - 119, 116, 111, 106, 97, 88, 84, 74, 72, 75, 85, 89, 98, 107, 112, 117 -}; - -extern int VP8LDistanceToPlaneCode(int xsize, int dist); -int VP8LDistanceToPlaneCode(int xsize, int dist) { - const int yoffset = dist / xsize; - const int xoffset = dist - yoffset * xsize; - if (xoffset <= 8 && yoffset < 8) { - return plane_to_code_lut[yoffset * 16 + 8 - xoffset] + 1; - } else if (xoffset > xsize - 8 && yoffset < 7) { - return plane_to_code_lut[(yoffset + 1) * 16 + 8 + (xsize - xoffset)] + 1; - } - return dist + 120; -} - -// Returns the exact index where array1 and array2 are different. For an index -// inferior or equal to best_len_match, the return value just has to be strictly -// inferior to best_len_match. The current behavior is to return 0 if this index -// is best_len_match, and the index itself otherwise. -// If no two elements are the same, it returns max_limit. -static WEBP_INLINE int FindMatchLength(const uint32_t* const array1, - const uint32_t* const array2, - int best_len_match, int max_limit) { - // Before 'expensive' linear match, check if the two arrays match at the - // current best length index. - if (array1[best_len_match] != array2[best_len_match]) return 0; - - return VP8LVectorMismatch(array1, array2, max_limit); -} - -// ----------------------------------------------------------------------------- -// VP8LBackwardRefs - -struct PixOrCopyBlock { - PixOrCopyBlock* next_; // next block (or NULL) - PixOrCopy* start_; // data start - int size_; // currently used size -}; - -extern void VP8LClearBackwardRefs(VP8LBackwardRefs* const refs); -void VP8LClearBackwardRefs(VP8LBackwardRefs* const refs) { - assert(refs != NULL); - if (refs->tail_ != NULL) { - *refs->tail_ = refs->free_blocks_; // recycle all blocks at once - } - refs->free_blocks_ = refs->refs_; - refs->tail_ = &refs->refs_; - refs->last_block_ = NULL; - refs->refs_ = NULL; -} - -void VP8LBackwardRefsClear(VP8LBackwardRefs* const refs) { - assert(refs != NULL); - VP8LClearBackwardRefs(refs); - while (refs->free_blocks_ != NULL) { - PixOrCopyBlock* const next = refs->free_blocks_->next_; - WebPSafeFree(refs->free_blocks_); - refs->free_blocks_ = next; - } -} - -// Swaps the content of two VP8LBackwardRefs. -static void BackwardRefsSwap(VP8LBackwardRefs* const refs1, - VP8LBackwardRefs* const refs2) { - const int point_to_refs1 = - (refs1->tail_ != NULL && refs1->tail_ == &refs1->refs_); - const int point_to_refs2 = - (refs2->tail_ != NULL && refs2->tail_ == &refs2->refs_); - const VP8LBackwardRefs tmp = *refs1; - *refs1 = *refs2; - *refs2 = tmp; - if (point_to_refs2) refs1->tail_ = &refs1->refs_; - if (point_to_refs1) refs2->tail_ = &refs2->refs_; -} - -void VP8LBackwardRefsInit(VP8LBackwardRefs* const refs, int block_size) { - assert(refs != NULL); - memset(refs, 0, sizeof(*refs)); - refs->tail_ = &refs->refs_; - refs->block_size_ = - (block_size < MIN_BLOCK_SIZE) ? MIN_BLOCK_SIZE : block_size; -} - -VP8LRefsCursor VP8LRefsCursorInit(const VP8LBackwardRefs* const refs) { - VP8LRefsCursor c; - c.cur_block_ = refs->refs_; - if (refs->refs_ != NULL) { - c.cur_pos = c.cur_block_->start_; - c.last_pos_ = c.cur_pos + c.cur_block_->size_; - } else { - c.cur_pos = NULL; - c.last_pos_ = NULL; - } - return c; -} - -void VP8LRefsCursorNextBlock(VP8LRefsCursor* const c) { - PixOrCopyBlock* const b = c->cur_block_->next_; - c->cur_pos = (b == NULL) ? NULL : b->start_; - c->last_pos_ = (b == NULL) ? NULL : b->start_ + b->size_; - c->cur_block_ = b; -} - -// Create a new block, either from the free list or allocated -static PixOrCopyBlock* BackwardRefsNewBlock(VP8LBackwardRefs* const refs) { - PixOrCopyBlock* b = refs->free_blocks_; - if (b == NULL) { // allocate new memory chunk - const size_t total_size = - sizeof(*b) + refs->block_size_ * sizeof(*b->start_); - b = (PixOrCopyBlock*)WebPSafeMalloc(1ULL, total_size); - if (b == NULL) { - refs->error_ |= 1; - return NULL; - } - b->start_ = (PixOrCopy*)((uint8_t*)b + sizeof(*b)); // not always aligned - } else { // recycle from free-list - refs->free_blocks_ = b->next_; - } - *refs->tail_ = b; - refs->tail_ = &b->next_; - refs->last_block_ = b; - b->next_ = NULL; - b->size_ = 0; - return b; -} - -// Return 1 on success, 0 on error. -static int BackwardRefsClone(const VP8LBackwardRefs* const from, - VP8LBackwardRefs* const to) { - const PixOrCopyBlock* block_from = from->refs_; - VP8LClearBackwardRefs(to); - while (block_from != NULL) { - PixOrCopyBlock* const block_to = BackwardRefsNewBlock(to); - if (block_to == NULL) return 0; - memcpy(block_to->start_, block_from->start_, - block_from->size_ * sizeof(PixOrCopy)); - block_to->size_ = block_from->size_; - block_from = block_from->next_; - } - return 1; -} - -extern void VP8LBackwardRefsCursorAdd(VP8LBackwardRefs* const refs, - const PixOrCopy v); -void VP8LBackwardRefsCursorAdd(VP8LBackwardRefs* const refs, - const PixOrCopy v) { - PixOrCopyBlock* b = refs->last_block_; - if (b == NULL || b->size_ == refs->block_size_) { - b = BackwardRefsNewBlock(refs); - if (b == NULL) return; // refs->error_ is set - } - b->start_[b->size_++] = v; -} - -// ----------------------------------------------------------------------------- -// Hash chains - -int VP8LHashChainInit(VP8LHashChain* const p, int size) { - assert(p->size_ == 0); - assert(p->offset_length_ == NULL); - assert(size > 0); - p->offset_length_ = - (uint32_t*)WebPSafeMalloc(size, sizeof(*p->offset_length_)); - if (p->offset_length_ == NULL) return 0; - p->size_ = size; - - return 1; -} - -void VP8LHashChainClear(VP8LHashChain* const p) { - assert(p != NULL); - WebPSafeFree(p->offset_length_); - - p->size_ = 0; - p->offset_length_ = NULL; -} - -// ----------------------------------------------------------------------------- - -static const uint32_t kHashMultiplierHi = 0xc6a4a793u; -static const uint32_t kHashMultiplierLo = 0x5bd1e996u; - -static WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW WEBP_INLINE -uint32_t GetPixPairHash64(const uint32_t* const argb) { - uint32_t key; - key = argb[1] * kHashMultiplierHi; - key += argb[0] * kHashMultiplierLo; - key = key >> (32 - HASH_BITS); - return key; -} - -// Returns the maximum number of hash chain lookups to do for a -// given compression quality. Return value in range [8, 86]. -static int GetMaxItersForQuality(int quality) { - return 8 + (quality * quality) / 128; -} - -static int GetWindowSizeForHashChain(int quality, int xsize) { - const int max_window_size = (quality > 75) ? WINDOW_SIZE - : (quality > 50) ? (xsize << 8) - : (quality > 25) ? (xsize << 6) - : (xsize << 4); - assert(xsize > 0); - return (max_window_size > WINDOW_SIZE) ? WINDOW_SIZE : max_window_size; -} - -static WEBP_INLINE int MaxFindCopyLength(int len) { - return (len < MAX_LENGTH) ? len : MAX_LENGTH; -} - -int VP8LHashChainFill(VP8LHashChain* const p, int quality, - const uint32_t* const argb, int xsize, int ysize, - int low_effort, const WebPPicture* const pic, - int percent_range, int* const percent) { - const int size = xsize * ysize; - const int iter_max = GetMaxItersForQuality(quality); - const uint32_t window_size = GetWindowSizeForHashChain(quality, xsize); - int remaining_percent = percent_range; - int percent_start = *percent; - int pos; - int argb_comp; - uint32_t base_position; - int32_t* hash_to_first_index; - // Temporarily use the p->offset_length_ as a hash chain. - int32_t* chain = (int32_t*)p->offset_length_; - assert(size > 0); - assert(p->size_ != 0); - assert(p->offset_length_ != NULL); - - if (size <= 2) { - p->offset_length_[0] = p->offset_length_[size - 1] = 0; - return 1; - } - - hash_to_first_index = - (int32_t*)WebPSafeMalloc(HASH_SIZE, sizeof(*hash_to_first_index)); - if (hash_to_first_index == NULL) { - return WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); - } - - percent_range = remaining_percent / 2; - remaining_percent -= percent_range; - - // Set the int32_t array to -1. - memset(hash_to_first_index, 0xff, HASH_SIZE * sizeof(*hash_to_first_index)); - // Fill the chain linking pixels with the same hash. - argb_comp = (argb[0] == argb[1]); - for (pos = 0; pos < size - 2;) { - uint32_t hash_code; - const int argb_comp_next = (argb[pos + 1] == argb[pos + 2]); - if (argb_comp && argb_comp_next) { - // Consecutive pixels with the same color will share the same hash. - // We therefore use a different hash: the color and its repetition - // length. - uint32_t tmp[2]; - uint32_t len = 1; - tmp[0] = argb[pos]; - // Figure out how far the pixels are the same. - // The last pixel has a different 64 bit hash, as its next pixel does - // not have the same color, so we just need to get to the last pixel equal - // to its follower. - while (pos + (int)len + 2 < size && argb[pos + len + 2] == argb[pos]) { - ++len; - } - if (len > MAX_LENGTH) { - // Skip the pixels that match for distance=1 and length>MAX_LENGTH - // because they are linked to their predecessor and we automatically - // check that in the main for loop below. Skipping means setting no - // predecessor in the chain, hence -1. - memset(chain + pos, 0xff, (len - MAX_LENGTH) * sizeof(*chain)); - pos += len - MAX_LENGTH; - len = MAX_LENGTH; - } - // Process the rest of the hash chain. - while (len) { - tmp[1] = len--; - hash_code = GetPixPairHash64(tmp); - chain[pos] = hash_to_first_index[hash_code]; - hash_to_first_index[hash_code] = pos++; - } - argb_comp = 0; - } else { - // Just move one pixel forward. - hash_code = GetPixPairHash64(argb + pos); - chain[pos] = hash_to_first_index[hash_code]; - hash_to_first_index[hash_code] = pos++; - argb_comp = argb_comp_next; - } - - if (!WebPReportProgress( - pic, percent_start + percent_range * pos / (size - 2), percent)) { - WebPSafeFree(hash_to_first_index); - return 0; - } - } - // Process the penultimate pixel. - chain[pos] = hash_to_first_index[GetPixPairHash64(argb + pos)]; - - WebPSafeFree(hash_to_first_index); - - percent_start += percent_range; - if (!WebPReportProgress(pic, percent_start, percent)) return 0; - percent_range = remaining_percent; - - // Find the best match interval at each pixel, defined by an offset to the - // pixel and a length. The right-most pixel cannot match anything to the right - // (hence a best length of 0) and the left-most pixel nothing to the left - // (hence an offset of 0). - assert(size > 2); - p->offset_length_[0] = p->offset_length_[size - 1] = 0; - for (base_position = size - 2; base_position > 0;) { - const int max_len = MaxFindCopyLength(size - 1 - base_position); - const uint32_t* const argb_start = argb + base_position; - int iter = iter_max; - int best_length = 0; - uint32_t best_distance = 0; - uint32_t best_argb; - const int min_pos = - (base_position > window_size) ? base_position - window_size : 0; - const int length_max = (max_len < 256) ? max_len : 256; - uint32_t max_base_position; - - pos = chain[base_position]; - if (!low_effort) { - int curr_length; - // Heuristic: use the comparison with the above line as an initialization. - if (base_position >= (uint32_t)xsize) { - curr_length = FindMatchLength(argb_start - xsize, argb_start, - best_length, max_len); - if (curr_length > best_length) { - best_length = curr_length; - best_distance = xsize; - } - --iter; - } - // Heuristic: compare to the previous pixel. - curr_length = - FindMatchLength(argb_start - 1, argb_start, best_length, max_len); - if (curr_length > best_length) { - best_length = curr_length; - best_distance = 1; - } - --iter; - // Skip the for loop if we already have the maximum. - if (best_length == MAX_LENGTH) pos = min_pos - 1; - } - best_argb = argb_start[best_length]; - - for (; pos >= min_pos && --iter; pos = chain[pos]) { - int curr_length; - assert(base_position > (uint32_t)pos); - - if (argb[pos + best_length] != best_argb) continue; - - curr_length = VP8LVectorMismatch(argb + pos, argb_start, max_len); - if (best_length < curr_length) { - best_length = curr_length; - best_distance = base_position - pos; - best_argb = argb_start[best_length]; - // Stop if we have reached a good enough length. - if (best_length >= length_max) break; - } - } - // We have the best match but in case the two intervals continue matching - // to the left, we have the best matches for the left-extended pixels. - max_base_position = base_position; - while (1) { - assert(best_length <= MAX_LENGTH); - assert(best_distance <= WINDOW_SIZE); - p->offset_length_[base_position] = - (best_distance << MAX_LENGTH_BITS) | (uint32_t)best_length; - --base_position; - // Stop if we don't have a match or if we are out of bounds. - if (best_distance == 0 || base_position == 0) break; - // Stop if we cannot extend the matching intervals to the left. - if (base_position < best_distance || - argb[base_position - best_distance] != argb[base_position]) { - break; - } - // Stop if we are matching at its limit because there could be a closer - // matching interval with the same maximum length. Then again, if the - // matching interval is as close as possible (best_distance == 1), we will - // never find anything better so let's continue. - if (best_length == MAX_LENGTH && best_distance != 1 && - base_position + MAX_LENGTH < max_base_position) { - break; - } - if (best_length < MAX_LENGTH) { - ++best_length; - max_base_position = base_position; - } - } - - if (!WebPReportProgress(pic, - percent_start + percent_range * - (size - 2 - base_position) / - (size - 2), - percent)) { - return 0; - } - } - - return WebPReportProgress(pic, percent_start + percent_range, percent); -} - -static WEBP_INLINE void AddSingleLiteral(uint32_t pixel, int use_color_cache, - VP8LColorCache* const hashers, - VP8LBackwardRefs* const refs) { - PixOrCopy v; - if (use_color_cache) { - const uint32_t key = VP8LColorCacheGetIndex(hashers, pixel); - if (VP8LColorCacheLookup(hashers, key) == pixel) { - v = PixOrCopyCreateCacheIdx(key); - } else { - v = PixOrCopyCreateLiteral(pixel); - VP8LColorCacheSet(hashers, key, pixel); - } - } else { - v = PixOrCopyCreateLiteral(pixel); - } - VP8LBackwardRefsCursorAdd(refs, v); -} - -static int BackwardReferencesRle(int xsize, int ysize, - const uint32_t* const argb, - int cache_bits, VP8LBackwardRefs* const refs) { - const int pix_count = xsize * ysize; - int i, k; - const int use_color_cache = (cache_bits > 0); - VP8LColorCache hashers; - - if (use_color_cache && !VP8LColorCacheInit(&hashers, cache_bits)) { - return 0; - } - VP8LClearBackwardRefs(refs); - // Add first pixel as literal. - AddSingleLiteral(argb[0], use_color_cache, &hashers, refs); - i = 1; - while (i < pix_count) { - const int max_len = MaxFindCopyLength(pix_count - i); - const int rle_len = FindMatchLength(argb + i, argb + i - 1, 0, max_len); - const int prev_row_len = (i < xsize) ? 0 : - FindMatchLength(argb + i, argb + i - xsize, 0, max_len); - if (rle_len >= prev_row_len && rle_len >= MIN_LENGTH) { - VP8LBackwardRefsCursorAdd(refs, PixOrCopyCreateCopy(1, rle_len)); - // We don't need to update the color cache here since it is always the - // same pixel being copied, and that does not change the color cache - // state. - i += rle_len; - } else if (prev_row_len >= MIN_LENGTH) { - VP8LBackwardRefsCursorAdd(refs, PixOrCopyCreateCopy(xsize, prev_row_len)); - if (use_color_cache) { - for (k = 0; k < prev_row_len; ++k) { - VP8LColorCacheInsert(&hashers, argb[i + k]); - } - } - i += prev_row_len; - } else { - AddSingleLiteral(argb[i], use_color_cache, &hashers, refs); - i++; - } - } - if (use_color_cache) VP8LColorCacheClear(&hashers); - return !refs->error_; -} - -static int BackwardReferencesLz77(int xsize, int ysize, - const uint32_t* const argb, int cache_bits, - const VP8LHashChain* const hash_chain, - VP8LBackwardRefs* const refs) { - int i; - int i_last_check = -1; - int ok = 0; - int cc_init = 0; - const int use_color_cache = (cache_bits > 0); - const int pix_count = xsize * ysize; - VP8LColorCache hashers; - - if (use_color_cache) { - cc_init = VP8LColorCacheInit(&hashers, cache_bits); - if (!cc_init) goto Error; - } - VP8LClearBackwardRefs(refs); - for (i = 0; i < pix_count;) { - // Alternative#1: Code the pixels starting at 'i' using backward reference. - int offset = 0; - int len = 0; - int j; - VP8LHashChainFindCopy(hash_chain, i, &offset, &len); - if (len >= MIN_LENGTH) { - const int len_ini = len; - int max_reach = 0; - const int j_max = - (i + len_ini >= pix_count) ? pix_count - 1 : i + len_ini; - // Only start from what we have not checked already. - i_last_check = (i > i_last_check) ? i : i_last_check; - // We know the best match for the current pixel but we try to find the - // best matches for the current pixel AND the next one combined. - // The naive method would use the intervals: - // [i,i+len) + [i+len, length of best match at i+len) - // while we check if we can use: - // [i,j) (where j<=i+len) + [j, length of best match at j) - for (j = i_last_check + 1; j <= j_max; ++j) { - const int len_j = VP8LHashChainFindLength(hash_chain, j); - const int reach = - j + (len_j >= MIN_LENGTH ? len_j : 1); // 1 for single literal. - if (reach > max_reach) { - len = j - i; - max_reach = reach; - if (max_reach >= pix_count) break; - } - } - } else { - len = 1; - } - // Go with literal or backward reference. - assert(len > 0); - if (len == 1) { - AddSingleLiteral(argb[i], use_color_cache, &hashers, refs); - } else { - VP8LBackwardRefsCursorAdd(refs, PixOrCopyCreateCopy(offset, len)); - if (use_color_cache) { - for (j = i; j < i + len; ++j) VP8LColorCacheInsert(&hashers, argb[j]); - } - } - i += len; - } - - ok = !refs->error_; - Error: - if (cc_init) VP8LColorCacheClear(&hashers); - return ok; -} - -// Compute an LZ77 by forcing matches to happen within a given distance cost. -// We therefore limit the algorithm to the lowest 32 values in the PlaneCode -// definition. -#define WINDOW_OFFSETS_SIZE_MAX 32 -static int BackwardReferencesLz77Box(int xsize, int ysize, - const uint32_t* const argb, int cache_bits, - const VP8LHashChain* const hash_chain_best, - VP8LHashChain* hash_chain, - VP8LBackwardRefs* const refs) { - int i; - const int pix_count = xsize * ysize; - uint16_t* counts; - int window_offsets[WINDOW_OFFSETS_SIZE_MAX] = {0}; - int window_offsets_new[WINDOW_OFFSETS_SIZE_MAX] = {0}; - int window_offsets_size = 0; - int window_offsets_new_size = 0; - uint16_t* const counts_ini = - (uint16_t*)WebPSafeMalloc(xsize * ysize, sizeof(*counts_ini)); - int best_offset_prev = -1, best_length_prev = -1; - if (counts_ini == NULL) return 0; - - // counts[i] counts how many times a pixel is repeated starting at position i. - i = pix_count - 2; - counts = counts_ini + i; - counts[1] = 1; - for (; i >= 0; --i, --counts) { - if (argb[i] == argb[i + 1]) { - // Max out the counts to MAX_LENGTH. - counts[0] = counts[1] + (counts[1] != MAX_LENGTH); - } else { - counts[0] = 1; - } - } - - // Figure out the window offsets around a pixel. They are stored in a - // spiraling order around the pixel as defined by VP8LDistanceToPlaneCode. - { - int x, y; - for (y = 0; y <= 6; ++y) { - for (x = -6; x <= 6; ++x) { - const int offset = y * xsize + x; - int plane_code; - // Ignore offsets that bring us after the pixel. - if (offset <= 0) continue; - plane_code = VP8LDistanceToPlaneCode(xsize, offset) - 1; - if (plane_code >= WINDOW_OFFSETS_SIZE_MAX) continue; - window_offsets[plane_code] = offset; - } - } - // For narrow images, not all plane codes are reached, so remove those. - for (i = 0; i < WINDOW_OFFSETS_SIZE_MAX; ++i) { - if (window_offsets[i] == 0) continue; - window_offsets[window_offsets_size++] = window_offsets[i]; - } - // Given a pixel P, find the offsets that reach pixels unreachable from P-1 - // with any of the offsets in window_offsets[]. - for (i = 0; i < window_offsets_size; ++i) { - int j; - int is_reachable = 0; - for (j = 0; j < window_offsets_size && !is_reachable; ++j) { - is_reachable |= (window_offsets[i] == window_offsets[j] + 1); - } - if (!is_reachable) { - window_offsets_new[window_offsets_new_size] = window_offsets[i]; - ++window_offsets_new_size; - } - } - } - - hash_chain->offset_length_[0] = 0; - for (i = 1; i < pix_count; ++i) { - int ind; - int best_length = VP8LHashChainFindLength(hash_chain_best, i); - int best_offset; - int do_compute = 1; - - if (best_length >= MAX_LENGTH) { - // Do not recompute the best match if we already have a maximal one in the - // window. - best_offset = VP8LHashChainFindOffset(hash_chain_best, i); - for (ind = 0; ind < window_offsets_size; ++ind) { - if (best_offset == window_offsets[ind]) { - do_compute = 0; - break; - } - } - } - if (do_compute) { - // Figure out if we should use the offset/length from the previous pixel - // as an initial guess and therefore only inspect the offsets in - // window_offsets_new[]. - const int use_prev = - (best_length_prev > 1) && (best_length_prev < MAX_LENGTH); - const int num_ind = - use_prev ? window_offsets_new_size : window_offsets_size; - best_length = use_prev ? best_length_prev - 1 : 0; - best_offset = use_prev ? best_offset_prev : 0; - // Find the longest match in a window around the pixel. - for (ind = 0; ind < num_ind; ++ind) { - int curr_length = 0; - int j = i; - int j_offset = - use_prev ? i - window_offsets_new[ind] : i - window_offsets[ind]; - if (j_offset < 0 || argb[j_offset] != argb[i]) continue; - // The longest match is the sum of how many times each pixel is - // repeated. - do { - const int counts_j_offset = counts_ini[j_offset]; - const int counts_j = counts_ini[j]; - if (counts_j_offset != counts_j) { - curr_length += - (counts_j_offset < counts_j) ? counts_j_offset : counts_j; - break; - } - // The same color is repeated counts_pos times at j_offset and j. - curr_length += counts_j_offset; - j_offset += counts_j_offset; - j += counts_j_offset; - } while (curr_length <= MAX_LENGTH && j < pix_count && - argb[j_offset] == argb[j]); - if (best_length < curr_length) { - best_offset = - use_prev ? window_offsets_new[ind] : window_offsets[ind]; - if (curr_length >= MAX_LENGTH) { - best_length = MAX_LENGTH; - break; - } else { - best_length = curr_length; - } - } - } - } - - assert(i + best_length <= pix_count); - assert(best_length <= MAX_LENGTH); - if (best_length <= MIN_LENGTH) { - hash_chain->offset_length_[i] = 0; - best_offset_prev = 0; - best_length_prev = 0; - } else { - hash_chain->offset_length_[i] = - (best_offset << MAX_LENGTH_BITS) | (uint32_t)best_length; - best_offset_prev = best_offset; - best_length_prev = best_length; - } - } - hash_chain->offset_length_[0] = 0; - WebPSafeFree(counts_ini); - - return BackwardReferencesLz77(xsize, ysize, argb, cache_bits, hash_chain, - refs); -} - -// ----------------------------------------------------------------------------- - -static void BackwardReferences2DLocality(int xsize, - const VP8LBackwardRefs* const refs) { - VP8LRefsCursor c = VP8LRefsCursorInit(refs); - while (VP8LRefsCursorOk(&c)) { - if (PixOrCopyIsCopy(c.cur_pos)) { - const int dist = c.cur_pos->argb_or_distance; - const int transformed_dist = VP8LDistanceToPlaneCode(xsize, dist); - c.cur_pos->argb_or_distance = transformed_dist; - } - VP8LRefsCursorNext(&c); - } -} - -// Evaluate optimal cache bits for the local color cache. -// The input *best_cache_bits sets the maximum cache bits to use (passing 0 -// implies disabling the local color cache). The local color cache is also -// disabled for the lower (<= 25) quality. -// Returns 0 in case of memory error. -static int CalculateBestCacheSize(const uint32_t* argb, int quality, - const VP8LBackwardRefs* const refs, - int* const best_cache_bits) { - int i; - const int cache_bits_max = (quality <= 25) ? 0 : *best_cache_bits; - float entropy_min = MAX_ENTROPY; - int cc_init[MAX_COLOR_CACHE_BITS + 1] = { 0 }; - VP8LColorCache hashers[MAX_COLOR_CACHE_BITS + 1]; - VP8LRefsCursor c = VP8LRefsCursorInit(refs); - VP8LHistogram* histos[MAX_COLOR_CACHE_BITS + 1] = { NULL }; - int ok = 0; - - assert(cache_bits_max >= 0 && cache_bits_max <= MAX_COLOR_CACHE_BITS); - - if (cache_bits_max == 0) { - *best_cache_bits = 0; - // Local color cache is disabled. - return 1; - } - - // Allocate data. - for (i = 0; i <= cache_bits_max; ++i) { - histos[i] = VP8LAllocateHistogram(i); - if (histos[i] == NULL) goto Error; - VP8LHistogramInit(histos[i], i, /*init_arrays=*/ 1); - if (i == 0) continue; - cc_init[i] = VP8LColorCacheInit(&hashers[i], i); - if (!cc_init[i]) goto Error; - } - - // Find the cache_bits giving the lowest entropy. The search is done in a - // brute-force way as the function (entropy w.r.t cache_bits) can be - // anything in practice. - while (VP8LRefsCursorOk(&c)) { - const PixOrCopy* const v = c.cur_pos; - if (PixOrCopyIsLiteral(v)) { - const uint32_t pix = *argb++; - const uint32_t a = (pix >> 24) & 0xff; - const uint32_t r = (pix >> 16) & 0xff; - const uint32_t g = (pix >> 8) & 0xff; - const uint32_t b = (pix >> 0) & 0xff; - // The keys of the caches can be derived from the longest one. - int key = VP8LHashPix(pix, 32 - cache_bits_max); - // Do not use the color cache for cache_bits = 0. - ++histos[0]->blue_[b]; - ++histos[0]->literal_[g]; - ++histos[0]->red_[r]; - ++histos[0]->alpha_[a]; - // Deal with cache_bits > 0. - for (i = cache_bits_max; i >= 1; --i, key >>= 1) { - if (VP8LColorCacheLookup(&hashers[i], key) == pix) { - ++histos[i]->literal_[NUM_LITERAL_CODES + NUM_LENGTH_CODES + key]; - } else { - VP8LColorCacheSet(&hashers[i], key, pix); - ++histos[i]->blue_[b]; - ++histos[i]->literal_[g]; - ++histos[i]->red_[r]; - ++histos[i]->alpha_[a]; - } - } - } else { - int code, extra_bits, extra_bits_value; - // We should compute the contribution of the (distance,length) - // histograms but those are the same independently from the cache size. - // As those constant contributions are in the end added to the other - // histogram contributions, we can ignore them, except for the length - // prefix that is part of the literal_ histogram. - int len = PixOrCopyLength(v); - uint32_t argb_prev = *argb ^ 0xffffffffu; - VP8LPrefixEncode(len, &code, &extra_bits, &extra_bits_value); - for (i = 0; i <= cache_bits_max; ++i) { - ++histos[i]->literal_[NUM_LITERAL_CODES + code]; - } - // Update the color caches. - do { - if (*argb != argb_prev) { - // Efficiency: insert only if the color changes. - int key = VP8LHashPix(*argb, 32 - cache_bits_max); - for (i = cache_bits_max; i >= 1; --i, key >>= 1) { - hashers[i].colors_[key] = *argb; - } - argb_prev = *argb; - } - argb++; - } while (--len != 0); - } - VP8LRefsCursorNext(&c); - } - - for (i = 0; i <= cache_bits_max; ++i) { - const float entropy = VP8LHistogramEstimateBits(histos[i]); - if (i == 0 || entropy < entropy_min) { - entropy_min = entropy; - *best_cache_bits = i; - } - } - ok = 1; - Error: - for (i = 0; i <= cache_bits_max; ++i) { - if (cc_init[i]) VP8LColorCacheClear(&hashers[i]); - VP8LFreeHistogram(histos[i]); - } - return ok; -} - -// Update (in-place) backward references for specified cache_bits. -static int BackwardRefsWithLocalCache(const uint32_t* const argb, - int cache_bits, - VP8LBackwardRefs* const refs) { - int pixel_index = 0; - VP8LColorCache hashers; - VP8LRefsCursor c = VP8LRefsCursorInit(refs); - if (!VP8LColorCacheInit(&hashers, cache_bits)) return 0; - - while (VP8LRefsCursorOk(&c)) { - PixOrCopy* const v = c.cur_pos; - if (PixOrCopyIsLiteral(v)) { - const uint32_t argb_literal = v->argb_or_distance; - const int ix = VP8LColorCacheContains(&hashers, argb_literal); - if (ix >= 0) { - // hashers contains argb_literal - *v = PixOrCopyCreateCacheIdx(ix); - } else { - VP8LColorCacheInsert(&hashers, argb_literal); - } - ++pixel_index; - } else { - // refs was created without local cache, so it can not have cache indexes. - int k; - assert(PixOrCopyIsCopy(v)); - for (k = 0; k < v->len; ++k) { - VP8LColorCacheInsert(&hashers, argb[pixel_index++]); - } - } - VP8LRefsCursorNext(&c); - } - VP8LColorCacheClear(&hashers); - return 1; -} - -static VP8LBackwardRefs* GetBackwardReferencesLowEffort( - int width, int height, const uint32_t* const argb, - int* const cache_bits, const VP8LHashChain* const hash_chain, - VP8LBackwardRefs* const refs_lz77) { - *cache_bits = 0; - if (!BackwardReferencesLz77(width, height, argb, 0, hash_chain, refs_lz77)) { - return NULL; - } - BackwardReferences2DLocality(width, refs_lz77); - return refs_lz77; -} - -extern int VP8LBackwardReferencesTraceBackwards( - int xsize, int ysize, const uint32_t* const argb, int cache_bits, - const VP8LHashChain* const hash_chain, - const VP8LBackwardRefs* const refs_src, VP8LBackwardRefs* const refs_dst); -static int GetBackwardReferences(int width, int height, - const uint32_t* const argb, int quality, - int lz77_types_to_try, int cache_bits_max, - int do_no_cache, - const VP8LHashChain* const hash_chain, - VP8LBackwardRefs* const refs, - int* const cache_bits_best) { - VP8LHistogram* histo = NULL; - int i, lz77_type; - // Index 0 is for a color cache, index 1 for no cache (if needed). - int lz77_types_best[2] = {0, 0}; - float bit_costs_best[2] = {FLT_MAX, FLT_MAX}; - VP8LHashChain hash_chain_box; - VP8LBackwardRefs* const refs_tmp = &refs[do_no_cache ? 2 : 1]; - int status = 0; - memset(&hash_chain_box, 0, sizeof(hash_chain_box)); - - histo = VP8LAllocateHistogram(MAX_COLOR_CACHE_BITS); - if (histo == NULL) goto Error; - - for (lz77_type = 1; lz77_types_to_try; - lz77_types_to_try &= ~lz77_type, lz77_type <<= 1) { - int res = 0; - float bit_cost = 0.f; - if ((lz77_types_to_try & lz77_type) == 0) continue; - switch (lz77_type) { - case kLZ77RLE: - res = BackwardReferencesRle(width, height, argb, 0, refs_tmp); - break; - case kLZ77Standard: - // Compute LZ77 with no cache (0 bits), as the ideal LZ77 with a color - // cache is not that different in practice. - res = BackwardReferencesLz77(width, height, argb, 0, hash_chain, - refs_tmp); - break; - case kLZ77Box: - if (!VP8LHashChainInit(&hash_chain_box, width * height)) goto Error; - res = BackwardReferencesLz77Box(width, height, argb, 0, hash_chain, - &hash_chain_box, refs_tmp); - break; - default: - assert(0); - } - if (!res) goto Error; - - // Start with the no color cache case. - for (i = 1; i >= 0; --i) { - int cache_bits = (i == 1) ? 0 : cache_bits_max; - - if (i == 1 && !do_no_cache) continue; - - if (i == 0) { - // Try with a color cache. - if (!CalculateBestCacheSize(argb, quality, refs_tmp, &cache_bits)) { - goto Error; - } - if (cache_bits > 0) { - if (!BackwardRefsWithLocalCache(argb, cache_bits, refs_tmp)) { - goto Error; - } - } - } - - if (i == 0 && do_no_cache && cache_bits == 0) { - // No need to re-compute bit_cost as it was computed at i == 1. - } else { - VP8LHistogramCreate(histo, refs_tmp, cache_bits); - bit_cost = VP8LHistogramEstimateBits(histo); - } - - if (bit_cost < bit_costs_best[i]) { - if (i == 1) { - // Do not swap as the full cache analysis would have the wrong - // VP8LBackwardRefs to start with. - if (!BackwardRefsClone(refs_tmp, &refs[1])) goto Error; - } else { - BackwardRefsSwap(refs_tmp, &refs[0]); - } - bit_costs_best[i] = bit_cost; - lz77_types_best[i] = lz77_type; - if (i == 0) *cache_bits_best = cache_bits; - } - } - } - assert(lz77_types_best[0] > 0); - assert(!do_no_cache || lz77_types_best[1] > 0); - - // Improve on simple LZ77 but only for high quality (TraceBackwards is - // costly). - for (i = 1; i >= 0; --i) { - if (i == 1 && !do_no_cache) continue; - if ((lz77_types_best[i] == kLZ77Standard || - lz77_types_best[i] == kLZ77Box) && - quality >= 25) { - const VP8LHashChain* const hash_chain_tmp = - (lz77_types_best[i] == kLZ77Standard) ? hash_chain : &hash_chain_box; - const int cache_bits = (i == 1) ? 0 : *cache_bits_best; - float bit_cost_trace; - if (!VP8LBackwardReferencesTraceBackwards(width, height, argb, cache_bits, - hash_chain_tmp, &refs[i], - refs_tmp)) { - goto Error; - } - VP8LHistogramCreate(histo, refs_tmp, cache_bits); - bit_cost_trace = VP8LHistogramEstimateBits(histo); - if (bit_cost_trace < bit_costs_best[i]) { - BackwardRefsSwap(refs_tmp, &refs[i]); - } - } - - BackwardReferences2DLocality(width, &refs[i]); - - if (i == 1 && lz77_types_best[0] == lz77_types_best[1] && - *cache_bits_best == 0) { - // If the best cache size is 0 and we have the same best LZ77, just copy - // the data over and stop here. - if (!BackwardRefsClone(&refs[1], &refs[0])) goto Error; - break; - } - } - status = 1; - - Error: - VP8LHashChainClear(&hash_chain_box); - VP8LFreeHistogram(histo); - return status; -} - -int VP8LGetBackwardReferences( - int width, int height, const uint32_t* const argb, int quality, - int low_effort, int lz77_types_to_try, int cache_bits_max, int do_no_cache, - const VP8LHashChain* const hash_chain, VP8LBackwardRefs* const refs, - int* const cache_bits_best, const WebPPicture* const pic, int percent_range, - int* const percent) { - if (low_effort) { - VP8LBackwardRefs* refs_best; - *cache_bits_best = cache_bits_max; - refs_best = GetBackwardReferencesLowEffort( - width, height, argb, cache_bits_best, hash_chain, refs); - if (refs_best == NULL) { - return WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); - } - // Set it in first position. - BackwardRefsSwap(refs_best, &refs[0]); - } else { - if (!GetBackwardReferences(width, height, argb, quality, lz77_types_to_try, - cache_bits_max, do_no_cache, hash_chain, refs, - cache_bits_best)) { - return WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); - } - } - - return WebPReportProgress(pic, *percent + percent_range, percent); -} diff --git a/libwebp/src/enc/backward_references_enc.h b/libwebp/src/enc/backward_references_enc.h deleted file mode 100644 index 4dff1c27..00000000 --- a/libwebp/src/enc/backward_references_enc.h +++ /dev/null @@ -1,244 +0,0 @@ -// Copyright 2012 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Author: Jyrki Alakuijala (jyrki@google.com) -// - -#ifndef WEBP_ENC_BACKWARD_REFERENCES_ENC_H_ -#define WEBP_ENC_BACKWARD_REFERENCES_ENC_H_ - -#include -#include -#include "src/webp/types.h" -#include "src/webp/encode.h" -#include "src/webp/format_constants.h" - -#ifdef __cplusplus -extern "C" { -#endif - -// The maximum allowed limit is 11. -#define MAX_COLOR_CACHE_BITS 10 - -// ----------------------------------------------------------------------------- -// PixOrCopy - -enum Mode { - kLiteral, - kCacheIdx, - kCopy, - kNone -}; - -typedef struct { - // mode as uint8_t to make the memory layout to be exactly 8 bytes. - uint8_t mode; - uint16_t len; - uint32_t argb_or_distance; -} PixOrCopy; - -static WEBP_INLINE PixOrCopy PixOrCopyCreateCopy(uint32_t distance, - uint16_t len) { - PixOrCopy retval; - retval.mode = kCopy; - retval.argb_or_distance = distance; - retval.len = len; - return retval; -} - -static WEBP_INLINE PixOrCopy PixOrCopyCreateCacheIdx(int idx) { - PixOrCopy retval; - assert(idx >= 0); - assert(idx < (1 << MAX_COLOR_CACHE_BITS)); - retval.mode = kCacheIdx; - retval.argb_or_distance = idx; - retval.len = 1; - return retval; -} - -static WEBP_INLINE PixOrCopy PixOrCopyCreateLiteral(uint32_t argb) { - PixOrCopy retval; - retval.mode = kLiteral; - retval.argb_or_distance = argb; - retval.len = 1; - return retval; -} - -static WEBP_INLINE int PixOrCopyIsLiteral(const PixOrCopy* const p) { - return (p->mode == kLiteral); -} - -static WEBP_INLINE int PixOrCopyIsCacheIdx(const PixOrCopy* const p) { - return (p->mode == kCacheIdx); -} - -static WEBP_INLINE int PixOrCopyIsCopy(const PixOrCopy* const p) { - return (p->mode == kCopy); -} - -static WEBP_INLINE uint32_t PixOrCopyLiteral(const PixOrCopy* const p, - int component) { - assert(p->mode == kLiteral); - return (p->argb_or_distance >> (component * 8)) & 0xff; -} - -static WEBP_INLINE uint32_t PixOrCopyLength(const PixOrCopy* const p) { - return p->len; -} - -static WEBP_INLINE uint32_t PixOrCopyCacheIdx(const PixOrCopy* const p) { - assert(p->mode == kCacheIdx); - assert(p->argb_or_distance < (1U << MAX_COLOR_CACHE_BITS)); - return p->argb_or_distance; -} - -static WEBP_INLINE uint32_t PixOrCopyDistance(const PixOrCopy* const p) { - assert(p->mode == kCopy); - return p->argb_or_distance; -} - -// ----------------------------------------------------------------------------- -// VP8LHashChain - -#define HASH_BITS 18 -#define HASH_SIZE (1 << HASH_BITS) - -// If you change this, you need MAX_LENGTH_BITS + WINDOW_SIZE_BITS <= 32 as it -// is used in VP8LHashChain. -#define MAX_LENGTH_BITS 12 -#define WINDOW_SIZE_BITS 20 -// We want the max value to be attainable and stored in MAX_LENGTH_BITS bits. -#define MAX_LENGTH ((1 << MAX_LENGTH_BITS) - 1) -#if MAX_LENGTH_BITS + WINDOW_SIZE_BITS > 32 -#error "MAX_LENGTH_BITS + WINDOW_SIZE_BITS > 32" -#endif - -typedef struct VP8LHashChain VP8LHashChain; -struct VP8LHashChain { - // The 20 most significant bits contain the offset at which the best match - // is found. These 20 bits are the limit defined by GetWindowSizeForHashChain - // (through WINDOW_SIZE = 1<<20). - // The lower 12 bits contain the length of the match. The 12 bit limit is - // defined in MaxFindCopyLength with MAX_LENGTH=4096. - uint32_t* offset_length_; - // This is the maximum size of the hash_chain that can be constructed. - // Typically this is the pixel count (width x height) for a given image. - int size_; -}; - -// Must be called first, to set size. -int VP8LHashChainInit(VP8LHashChain* const p, int size); -// Pre-compute the best matches for argb. pic and percent are for progress. -int VP8LHashChainFill(VP8LHashChain* const p, int quality, - const uint32_t* const argb, int xsize, int ysize, - int low_effort, const WebPPicture* const pic, - int percent_range, int* const percent); -void VP8LHashChainClear(VP8LHashChain* const p); // release memory - -static WEBP_INLINE int VP8LHashChainFindOffset(const VP8LHashChain* const p, - const int base_position) { - return p->offset_length_[base_position] >> MAX_LENGTH_BITS; -} - -static WEBP_INLINE int VP8LHashChainFindLength(const VP8LHashChain* const p, - const int base_position) { - return p->offset_length_[base_position] & ((1U << MAX_LENGTH_BITS) - 1); -} - -static WEBP_INLINE void VP8LHashChainFindCopy(const VP8LHashChain* const p, - int base_position, - int* const offset_ptr, - int* const length_ptr) { - *offset_ptr = VP8LHashChainFindOffset(p, base_position); - *length_ptr = VP8LHashChainFindLength(p, base_position); -} - -// ----------------------------------------------------------------------------- -// VP8LBackwardRefs (block-based backward-references storage) - -// maximum number of reference blocks the image will be segmented into -#define MAX_REFS_BLOCK_PER_IMAGE 16 - -typedef struct PixOrCopyBlock PixOrCopyBlock; // forward declaration -typedef struct VP8LBackwardRefs VP8LBackwardRefs; - -// Container for blocks chain -struct VP8LBackwardRefs { - int block_size_; // common block-size - int error_; // set to true if some memory error occurred - PixOrCopyBlock* refs_; // list of currently used blocks - PixOrCopyBlock** tail_; // for list recycling - PixOrCopyBlock* free_blocks_; // free-list - PixOrCopyBlock* last_block_; // used for adding new refs (internal) -}; - -// Initialize the object. 'block_size' is the common block size to store -// references (typically, width * height / MAX_REFS_BLOCK_PER_IMAGE). -void VP8LBackwardRefsInit(VP8LBackwardRefs* const refs, int block_size); -// Release memory for backward references. -void VP8LBackwardRefsClear(VP8LBackwardRefs* const refs); - -// Cursor for iterating on references content -typedef struct { - // public: - PixOrCopy* cur_pos; // current position - // private: - PixOrCopyBlock* cur_block_; // current block in the refs list - const PixOrCopy* last_pos_; // sentinel for switching to next block -} VP8LRefsCursor; - -// Returns a cursor positioned at the beginning of the references list. -VP8LRefsCursor VP8LRefsCursorInit(const VP8LBackwardRefs* const refs); -// Returns true if cursor is pointing at a valid position. -static WEBP_INLINE int VP8LRefsCursorOk(const VP8LRefsCursor* const c) { - return (c->cur_pos != NULL); -} -// Move to next block of references. Internal, not to be called directly. -void VP8LRefsCursorNextBlock(VP8LRefsCursor* const c); -// Move to next position, or NULL. Should not be called if !VP8LRefsCursorOk(). -static WEBP_INLINE void VP8LRefsCursorNext(VP8LRefsCursor* const c) { - assert(c != NULL); - assert(VP8LRefsCursorOk(c)); - if (++c->cur_pos == c->last_pos_) VP8LRefsCursorNextBlock(c); -} - -// ----------------------------------------------------------------------------- -// Main entry points - -enum VP8LLZ77Type { - kLZ77Standard = 1, - kLZ77RLE = 2, - kLZ77Box = 4 -}; - -// Evaluates best possible backward references for specified quality. -// The input cache_bits to 'VP8LGetBackwardReferences' sets the maximum cache -// bits to use (passing 0 implies disabling the local color cache). -// The optimal cache bits is evaluated and set for the *cache_bits_best -// parameter with the matching refs_best. -// If do_no_cache == 0, refs is an array of 2 values and the best -// VP8LBackwardRefs is put in the first element. -// If do_no_cache != 0, refs is an array of 3 values and the best -// VP8LBackwardRefs is put in the first element, the best value with no-cache in -// the second element. -// In both cases, the last element is used as temporary internally. -// pic and percent are for progress. -// Returns false in case of error (stored in pic->error_code). -int VP8LGetBackwardReferences( - int width, int height, const uint32_t* const argb, int quality, - int low_effort, int lz77_types_to_try, int cache_bits_max, int do_no_cache, - const VP8LHashChain* const hash_chain, VP8LBackwardRefs* const refs, - int* const cache_bits_best, const WebPPicture* const pic, int percent_range, - int* const percent); - -#ifdef __cplusplus -} -#endif - -#endif // WEBP_ENC_BACKWARD_REFERENCES_ENC_H_ diff --git a/libwebp/src/enc/config_enc.c b/libwebp/src/enc/config_enc.c deleted file mode 100644 index 3518b414..00000000 --- a/libwebp/src/enc/config_enc.c +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Coding tools configuration -// -// Author: Skal (pascal.massimino@gmail.com) - -#ifdef HAVE_CONFIG_H -#include "src/webp/config.h" -#endif - -#include "src/webp/encode.h" - -//------------------------------------------------------------------------------ -// WebPConfig -//------------------------------------------------------------------------------ - -int WebPConfigInitInternal(WebPConfig* config, - WebPPreset preset, float quality, int version) { - if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_ENCODER_ABI_VERSION)) { - return 0; // caller/system version mismatch! - } - if (config == NULL) return 0; - - config->quality = quality; - config->target_size = 0; - config->target_PSNR = 0.; - config->method = 4; - config->sns_strength = 50; - config->filter_strength = 60; // mid-filtering - config->filter_sharpness = 0; - config->filter_type = 1; // default: strong (so U/V is filtered too) - config->partitions = 0; - config->segments = 4; - config->pass = 1; - config->qmin = 0; - config->qmax = 100; - config->show_compressed = 0; - config->preprocessing = 0; - config->autofilter = 0; - config->partition_limit = 0; - config->alpha_compression = 1; - config->alpha_filtering = 1; - config->alpha_quality = 100; - config->lossless = 0; - config->exact = 0; - config->image_hint = WEBP_HINT_DEFAULT; - config->emulate_jpeg_size = 0; - config->thread_level = 0; - config->low_memory = 0; - config->near_lossless = 100; - config->use_delta_palette = 0; - config->use_sharp_yuv = 0; - - // TODO(skal): tune. - switch (preset) { - case WEBP_PRESET_PICTURE: - config->sns_strength = 80; - config->filter_sharpness = 4; - config->filter_strength = 35; - config->preprocessing &= ~2; // no dithering - break; - case WEBP_PRESET_PHOTO: - config->sns_strength = 80; - config->filter_sharpness = 3; - config->filter_strength = 30; - config->preprocessing |= 2; - break; - case WEBP_PRESET_DRAWING: - config->sns_strength = 25; - config->filter_sharpness = 6; - config->filter_strength = 10; - break; - case WEBP_PRESET_ICON: - config->sns_strength = 0; - config->filter_strength = 0; // disable filtering to retain sharpness - config->preprocessing &= ~2; // no dithering - break; - case WEBP_PRESET_TEXT: - config->sns_strength = 0; - config->filter_strength = 0; // disable filtering to retain sharpness - config->preprocessing &= ~2; // no dithering - config->segments = 2; - break; - case WEBP_PRESET_DEFAULT: - default: - break; - } - return WebPValidateConfig(config); -} - -int WebPValidateConfig(const WebPConfig* config) { - if (config == NULL) return 0; - if (config->quality < 0 || config->quality > 100) return 0; - if (config->target_size < 0) return 0; - if (config->target_PSNR < 0) return 0; - if (config->method < 0 || config->method > 6) return 0; - if (config->segments < 1 || config->segments > 4) return 0; - if (config->sns_strength < 0 || config->sns_strength > 100) return 0; - if (config->filter_strength < 0 || config->filter_strength > 100) return 0; - if (config->filter_sharpness < 0 || config->filter_sharpness > 7) return 0; - if (config->filter_type < 0 || config->filter_type > 1) return 0; - if (config->autofilter < 0 || config->autofilter > 1) return 0; - if (config->pass < 1 || config->pass > 10) return 0; - if (config->qmin < 0 || config->qmax > 100 || config->qmin > config->qmax) { - return 0; - } - if (config->show_compressed < 0 || config->show_compressed > 1) return 0; - if (config->preprocessing < 0 || config->preprocessing > 7) return 0; - if (config->partitions < 0 || config->partitions > 3) return 0; - if (config->partition_limit < 0 || config->partition_limit > 100) return 0; - if (config->alpha_compression < 0) return 0; - if (config->alpha_filtering < 0) return 0; - if (config->alpha_quality < 0 || config->alpha_quality > 100) return 0; - if (config->lossless < 0 || config->lossless > 1) return 0; - if (config->near_lossless < 0 || config->near_lossless > 100) return 0; - if (config->image_hint >= WEBP_HINT_LAST) return 0; - if (config->emulate_jpeg_size < 0 || config->emulate_jpeg_size > 1) return 0; - if (config->thread_level < 0 || config->thread_level > 1) return 0; - if (config->low_memory < 0 || config->low_memory > 1) return 0; - if (config->exact < 0 || config->exact > 1) return 0; - if (config->use_delta_palette < 0 || config->use_delta_palette > 1) { - return 0; - } - if (config->use_sharp_yuv < 0 || config->use_sharp_yuv > 1) return 0; - - return 1; -} - -//------------------------------------------------------------------------------ - -#define MAX_LEVEL 9 - -// Mapping between -z level and -m / -q parameter settings. -static const struct { - uint8_t method_; - uint8_t quality_; -} kLosslessPresets[MAX_LEVEL + 1] = { - { 0, 0 }, { 1, 20 }, { 2, 25 }, { 3, 30 }, { 3, 50 }, - { 4, 50 }, { 4, 75 }, { 4, 90 }, { 5, 90 }, { 6, 100 } -}; - -int WebPConfigLosslessPreset(WebPConfig* config, int level) { - if (config == NULL || level < 0 || level > MAX_LEVEL) return 0; - config->lossless = 1; - config->method = kLosslessPresets[level].method_; - config->quality = kLosslessPresets[level].quality_; - return 1; -} - -//------------------------------------------------------------------------------ diff --git a/libwebp/src/enc/cost_enc.c b/libwebp/src/enc/cost_enc.c deleted file mode 100644 index 48fd9bc3..00000000 --- a/libwebp/src/enc/cost_enc.c +++ /dev/null @@ -1,342 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Cost tables for level and modes -// -// Author: Skal (pascal.massimino@gmail.com) - -#include "src/enc/cost_enc.h" - -//------------------------------------------------------------------------------ -// Level cost tables - -// For each given level, the following table gives the pattern of contexts to -// use for coding it (in [][0]) as well as the bit value to use for each -// context (in [][1]). -const uint16_t VP8LevelCodes[MAX_VARIABLE_LEVEL][2] = { - {0x001, 0x000}, {0x007, 0x001}, {0x00f, 0x005}, - {0x00f, 0x00d}, {0x033, 0x003}, {0x033, 0x003}, {0x033, 0x023}, - {0x033, 0x023}, {0x033, 0x023}, {0x033, 0x023}, {0x0d3, 0x013}, - {0x0d3, 0x013}, {0x0d3, 0x013}, {0x0d3, 0x013}, {0x0d3, 0x013}, - {0x0d3, 0x013}, {0x0d3, 0x013}, {0x0d3, 0x013}, {0x0d3, 0x093}, - {0x0d3, 0x093}, {0x0d3, 0x093}, {0x0d3, 0x093}, {0x0d3, 0x093}, - {0x0d3, 0x093}, {0x0d3, 0x093}, {0x0d3, 0x093}, {0x0d3, 0x093}, - {0x0d3, 0x093}, {0x0d3, 0x093}, {0x0d3, 0x093}, {0x0d3, 0x093}, - {0x0d3, 0x093}, {0x0d3, 0x093}, {0x0d3, 0x093}, {0x153, 0x053}, - {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, - {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, - {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, - {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, - {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, - {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, - {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, - {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x153} -}; - -static int VariableLevelCost(int level, const uint8_t probas[NUM_PROBAS]) { - int pattern = VP8LevelCodes[level - 1][0]; - int bits = VP8LevelCodes[level - 1][1]; - int cost = 0; - int i; - for (i = 2; pattern; ++i) { - if (pattern & 1) { - cost += VP8BitCost(bits & 1, probas[i]); - } - bits >>= 1; - pattern >>= 1; - } - return cost; -} - -//------------------------------------------------------------------------------ -// Pre-calc level costs once for all - -void VP8CalculateLevelCosts(VP8EncProba* const proba) { - int ctype, band, ctx; - - if (!proba->dirty_) return; // nothing to do. - - for (ctype = 0; ctype < NUM_TYPES; ++ctype) { - int n; - for (band = 0; band < NUM_BANDS; ++band) { - for (ctx = 0; ctx < NUM_CTX; ++ctx) { - const uint8_t* const p = proba->coeffs_[ctype][band][ctx]; - uint16_t* const table = proba->level_cost_[ctype][band][ctx]; - const int cost0 = (ctx > 0) ? VP8BitCost(1, p[0]) : 0; - const int cost_base = VP8BitCost(1, p[1]) + cost0; - int v; - table[0] = VP8BitCost(0, p[1]) + cost0; - for (v = 1; v <= MAX_VARIABLE_LEVEL; ++v) { - table[v] = cost_base + VariableLevelCost(v, p); - } - // Starting at level 67 and up, the variable part of the cost is - // actually constant. - } - } - for (n = 0; n < 16; ++n) { // replicate bands. We don't need to sentinel. - for (ctx = 0; ctx < NUM_CTX; ++ctx) { - proba->remapped_costs_[ctype][n][ctx] = - proba->level_cost_[ctype][VP8EncBands[n]][ctx]; - } - } - } - proba->dirty_ = 0; -} - -//------------------------------------------------------------------------------ -// Mode cost tables. - -// These are the fixed probabilities (in the coding trees) turned into bit-cost -// by calling VP8BitCost(). -const uint16_t VP8FixedCostsUV[4] = { 302, 984, 439, 642 }; -// note: these values include the fixed VP8BitCost(1, 145) mode selection cost. -const uint16_t VP8FixedCostsI16[4] = { 663, 919, 872, 919 }; -const uint16_t VP8FixedCostsI4[NUM_BMODES][NUM_BMODES][NUM_BMODES] = { - { { 40, 1151, 1723, 1874, 2103, 2019, 1628, 1777, 2226, 2137 }, - { 192, 469, 1296, 1308, 1849, 1794, 1781, 1703, 1713, 1522 }, - { 142, 910, 762, 1684, 1849, 1576, 1460, 1305, 1801, 1657 }, - { 559, 641, 1370, 421, 1182, 1569, 1612, 1725, 863, 1007 }, - { 299, 1059, 1256, 1108, 636, 1068, 1581, 1883, 869, 1142 }, - { 277, 1111, 707, 1362, 1089, 672, 1603, 1541, 1545, 1291 }, - { 214, 781, 1609, 1303, 1632, 2229, 726, 1560, 1713, 918 }, - { 152, 1037, 1046, 1759, 1983, 2174, 1358, 742, 1740, 1390 }, - { 512, 1046, 1420, 753, 752, 1297, 1486, 1613, 460, 1207 }, - { 424, 827, 1362, 719, 1462, 1202, 1199, 1476, 1199, 538 } }, - { { 240, 402, 1134, 1491, 1659, 1505, 1517, 1555, 1979, 2099 }, - { 467, 242, 960, 1232, 1714, 1620, 1834, 1570, 1676, 1391 }, - { 500, 455, 463, 1507, 1699, 1282, 1564, 982, 2114, 2114 }, - { 672, 643, 1372, 331, 1589, 1667, 1453, 1938, 996, 876 }, - { 458, 783, 1037, 911, 738, 968, 1165, 1518, 859, 1033 }, - { 504, 815, 504, 1139, 1219, 719, 1506, 1085, 1268, 1268 }, - { 333, 630, 1445, 1239, 1883, 3672, 799, 1548, 1865, 598 }, - { 399, 644, 746, 1342, 1856, 1350, 1493, 613, 1855, 1015 }, - { 622, 749, 1205, 608, 1066, 1408, 1290, 1406, 546, 971 }, - { 500, 753, 1041, 668, 1230, 1617, 1297, 1425, 1383, 523 } }, - { { 394, 553, 523, 1502, 1536, 981, 1608, 1142, 1666, 2181 }, - { 655, 430, 375, 1411, 1861, 1220, 1677, 1135, 1978, 1553 }, - { 690, 640, 245, 1954, 2070, 1194, 1528, 982, 1972, 2232 }, - { 559, 834, 741, 867, 1131, 980, 1225, 852, 1092, 784 }, - { 690, 875, 516, 959, 673, 894, 1056, 1190, 1528, 1126 }, - { 740, 951, 384, 1277, 1177, 492, 1579, 1155, 1846, 1513 }, - { 323, 775, 1062, 1776, 3062, 1274, 813, 1188, 1372, 655 }, - { 488, 971, 484, 1767, 1515, 1775, 1115, 503, 1539, 1461 }, - { 740, 1006, 998, 709, 851, 1230, 1337, 788, 741, 721 }, - { 522, 1073, 573, 1045, 1346, 887, 1046, 1146, 1203, 697 } }, - { { 105, 864, 1442, 1009, 1934, 1840, 1519, 1920, 1673, 1579 }, - { 534, 305, 1193, 683, 1388, 2164, 1802, 1894, 1264, 1170 }, - { 305, 518, 877, 1108, 1426, 3215, 1425, 1064, 1320, 1242 }, - { 683, 732, 1927, 257, 1493, 2048, 1858, 1552, 1055, 947 }, - { 394, 814, 1024, 660, 959, 1556, 1282, 1289, 893, 1047 }, - { 528, 615, 996, 940, 1201, 635, 1094, 2515, 803, 1358 }, - { 347, 614, 1609, 1187, 3133, 1345, 1007, 1339, 1017, 667 }, - { 218, 740, 878, 1605, 3650, 3650, 1345, 758, 1357, 1617 }, - { 672, 750, 1541, 558, 1257, 1599, 1870, 2135, 402, 1087 }, - { 592, 684, 1161, 430, 1092, 1497, 1475, 1489, 1095, 822 } }, - { { 228, 1056, 1059, 1368, 752, 982, 1512, 1518, 987, 1782 }, - { 494, 514, 818, 942, 965, 892, 1610, 1356, 1048, 1363 }, - { 512, 648, 591, 1042, 761, 991, 1196, 1454, 1309, 1463 }, - { 683, 749, 1043, 676, 841, 1396, 1133, 1138, 654, 939 }, - { 622, 1101, 1126, 994, 361, 1077, 1203, 1318, 877, 1219 }, - { 631, 1068, 857, 1650, 651, 477, 1650, 1419, 828, 1170 }, - { 555, 727, 1068, 1335, 3127, 1339, 820, 1331, 1077, 429 }, - { 504, 879, 624, 1398, 889, 889, 1392, 808, 891, 1406 }, - { 683, 1602, 1289, 977, 578, 983, 1280, 1708, 406, 1122 }, - { 399, 865, 1433, 1070, 1072, 764, 968, 1477, 1223, 678 } }, - { { 333, 760, 935, 1638, 1010, 529, 1646, 1410, 1472, 2219 }, - { 512, 494, 750, 1160, 1215, 610, 1870, 1868, 1628, 1169 }, - { 572, 646, 492, 1934, 1208, 603, 1580, 1099, 1398, 1995 }, - { 786, 789, 942, 581, 1018, 951, 1599, 1207, 731, 768 }, - { 690, 1015, 672, 1078, 582, 504, 1693, 1438, 1108, 2897 }, - { 768, 1267, 571, 2005, 1243, 244, 2881, 1380, 1786, 1453 }, - { 452, 899, 1293, 903, 1311, 3100, 465, 1311, 1319, 813 }, - { 394, 927, 942, 1103, 1358, 1104, 946, 593, 1363, 1109 }, - { 559, 1005, 1007, 1016, 658, 1173, 1021, 1164, 623, 1028 }, - { 564, 796, 632, 1005, 1014, 863, 2316, 1268, 938, 764 } }, - { { 266, 606, 1098, 1228, 1497, 1243, 948, 1030, 1734, 1461 }, - { 366, 585, 901, 1060, 1407, 1247, 876, 1134, 1620, 1054 }, - { 452, 565, 542, 1729, 1479, 1479, 1016, 886, 2938, 1150 }, - { 555, 1088, 1533, 950, 1354, 895, 834, 1019, 1021, 496 }, - { 704, 815, 1193, 971, 973, 640, 1217, 2214, 832, 578 }, - { 672, 1245, 579, 871, 875, 774, 872, 1273, 1027, 949 }, - { 296, 1134, 2050, 1784, 1636, 3425, 442, 1550, 2076, 722 }, - { 342, 982, 1259, 1846, 1848, 1848, 622, 568, 1847, 1052 }, - { 555, 1064, 1304, 828, 746, 1343, 1075, 1329, 1078, 494 }, - { 288, 1167, 1285, 1174, 1639, 1639, 833, 2254, 1304, 509 } }, - { { 342, 719, 767, 1866, 1757, 1270, 1246, 550, 1746, 2151 }, - { 483, 653, 694, 1509, 1459, 1410, 1218, 507, 1914, 1266 }, - { 488, 757, 447, 2979, 1813, 1268, 1654, 539, 1849, 2109 }, - { 522, 1097, 1085, 851, 1365, 1111, 851, 901, 961, 605 }, - { 709, 716, 841, 728, 736, 945, 941, 862, 2845, 1057 }, - { 512, 1323, 500, 1336, 1083, 681, 1342, 717, 1604, 1350 }, - { 452, 1155, 1372, 1900, 1501, 3290, 311, 944, 1919, 922 }, - { 403, 1520, 977, 2132, 1733, 3522, 1076, 276, 3335, 1547 }, - { 559, 1374, 1101, 615, 673, 2462, 974, 795, 984, 984 }, - { 547, 1122, 1062, 812, 1410, 951, 1140, 622, 1268, 651 } }, - { { 165, 982, 1235, 938, 1334, 1366, 1659, 1578, 964, 1612 }, - { 592, 422, 925, 847, 1139, 1112, 1387, 2036, 861, 1041 }, - { 403, 837, 732, 770, 941, 1658, 1250, 809, 1407, 1407 }, - { 896, 874, 1071, 381, 1568, 1722, 1437, 2192, 480, 1035 }, - { 640, 1098, 1012, 1032, 684, 1382, 1581, 2106, 416, 865 }, - { 559, 1005, 819, 914, 710, 770, 1418, 920, 838, 1435 }, - { 415, 1258, 1245, 870, 1278, 3067, 770, 1021, 1287, 522 }, - { 406, 990, 601, 1009, 1265, 1265, 1267, 759, 1017, 1277 }, - { 968, 1182, 1329, 788, 1032, 1292, 1705, 1714, 203, 1403 }, - { 732, 877, 1279, 471, 901, 1161, 1545, 1294, 755, 755 } }, - { { 111, 931, 1378, 1185, 1933, 1648, 1148, 1714, 1873, 1307 }, - { 406, 414, 1030, 1023, 1910, 1404, 1313, 1647, 1509, 793 }, - { 342, 640, 575, 1088, 1241, 1349, 1161, 1350, 1756, 1502 }, - { 559, 766, 1185, 357, 1682, 1428, 1329, 1897, 1219, 802 }, - { 473, 909, 1164, 771, 719, 2508, 1427, 1432, 722, 782 }, - { 342, 892, 785, 1145, 1150, 794, 1296, 1550, 973, 1057 }, - { 208, 1036, 1326, 1343, 1606, 3395, 815, 1455, 1618, 712 }, - { 228, 928, 890, 1046, 3499, 1711, 994, 829, 1720, 1318 }, - { 768, 724, 1058, 636, 991, 1075, 1319, 1324, 616, 825 }, - { 305, 1167, 1358, 899, 1587, 1587, 987, 1988, 1332, 501 } } -}; - -//------------------------------------------------------------------------------ -// helper functions for residuals struct VP8Residual. - -void VP8InitResidual(int first, int coeff_type, - VP8Encoder* const enc, VP8Residual* const res) { - res->coeff_type = coeff_type; - res->prob = enc->proba_.coeffs_[coeff_type]; - res->stats = enc->proba_.stats_[coeff_type]; - res->costs = enc->proba_.remapped_costs_[coeff_type]; - res->first = first; -} - -//------------------------------------------------------------------------------ -// Mode costs - -int VP8GetCostLuma4(VP8EncIterator* const it, const int16_t levels[16]) { - const int x = (it->i4_ & 3), y = (it->i4_ >> 2); - VP8Residual res; - VP8Encoder* const enc = it->enc_; - int R = 0; - int ctx; - - VP8InitResidual(0, 3, enc, &res); - ctx = it->top_nz_[x] + it->left_nz_[y]; - VP8SetResidualCoeffs(levels, &res); - R += VP8GetResidualCost(ctx, &res); - return R; -} - -int VP8GetCostLuma16(VP8EncIterator* const it, const VP8ModeScore* const rd) { - VP8Residual res; - VP8Encoder* const enc = it->enc_; - int x, y; - int R = 0; - - VP8IteratorNzToBytes(it); // re-import the non-zero context - - // DC - VP8InitResidual(0, 1, enc, &res); - VP8SetResidualCoeffs(rd->y_dc_levels, &res); - R += VP8GetResidualCost(it->top_nz_[8] + it->left_nz_[8], &res); - - // AC - VP8InitResidual(1, 0, enc, &res); - for (y = 0; y < 4; ++y) { - for (x = 0; x < 4; ++x) { - const int ctx = it->top_nz_[x] + it->left_nz_[y]; - VP8SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res); - R += VP8GetResidualCost(ctx, &res); - it->top_nz_[x] = it->left_nz_[y] = (res.last >= 0); - } - } - return R; -} - -int VP8GetCostUV(VP8EncIterator* const it, const VP8ModeScore* const rd) { - VP8Residual res; - VP8Encoder* const enc = it->enc_; - int ch, x, y; - int R = 0; - - VP8IteratorNzToBytes(it); // re-import the non-zero context - - VP8InitResidual(0, 2, enc, &res); - for (ch = 0; ch <= 2; ch += 2) { - for (y = 0; y < 2; ++y) { - for (x = 0; x < 2; ++x) { - const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y]; - VP8SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res); - R += VP8GetResidualCost(ctx, &res); - it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] = (res.last >= 0); - } - } - } - return R; -} - - -//------------------------------------------------------------------------------ -// Recording of token probabilities. - -// We keep the table-free variant around for reference, in case. -#define USE_LEVEL_CODE_TABLE - -// Simulate block coding, but only record statistics. -// Note: no need to record the fixed probas. -int VP8RecordCoeffs(int ctx, const VP8Residual* const res) { - int n = res->first; - // should be stats[VP8EncBands[n]], but it's equivalent for n=0 or 1 - proba_t* s = res->stats[n][ctx]; - if (res->last < 0) { - VP8RecordStats(0, s + 0); - return 0; - } - while (n <= res->last) { - int v; - VP8RecordStats(1, s + 0); // order of record doesn't matter - while ((v = res->coeffs[n++]) == 0) { - VP8RecordStats(0, s + 1); - s = res->stats[VP8EncBands[n]][0]; - } - VP8RecordStats(1, s + 1); - if (!VP8RecordStats(2u < (unsigned int)(v + 1), s + 2)) { // v = -1 or 1 - s = res->stats[VP8EncBands[n]][1]; - } else { - v = abs(v); -#if !defined(USE_LEVEL_CODE_TABLE) - if (!VP8RecordStats(v > 4, s + 3)) { - if (VP8RecordStats(v != 2, s + 4)) - VP8RecordStats(v == 4, s + 5); - } else if (!VP8RecordStats(v > 10, s + 6)) { - VP8RecordStats(v > 6, s + 7); - } else if (!VP8RecordStats((v >= 3 + (8 << 2)), s + 8)) { - VP8RecordStats((v >= 3 + (8 << 1)), s + 9); - } else { - VP8RecordStats((v >= 3 + (8 << 3)), s + 10); - } -#else - if (v > MAX_VARIABLE_LEVEL) { - v = MAX_VARIABLE_LEVEL; - } - - { - const int bits = VP8LevelCodes[v - 1][1]; - int pattern = VP8LevelCodes[v - 1][0]; - int i; - for (i = 0; (pattern >>= 1) != 0; ++i) { - const int mask = 2 << i; - if (pattern & 1) VP8RecordStats(!!(bits & mask), s + 3 + i); - } - } -#endif - s = res->stats[VP8EncBands[n]][2]; - } - } - if (n < 16) VP8RecordStats(0, s + 0); - return 1; -} - -//------------------------------------------------------------------------------ diff --git a/libwebp/src/enc/cost_enc.h b/libwebp/src/enc/cost_enc.h deleted file mode 100644 index a4b177b3..00000000 --- a/libwebp/src/enc/cost_enc.h +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Cost tables for level and modes. -// -// Author: Skal (pascal.massimino@gmail.com) - -#ifndef WEBP_ENC_COST_ENC_H_ -#define WEBP_ENC_COST_ENC_H_ - -#include -#include -#include "src/enc/vp8i_enc.h" - -#ifdef __cplusplus -extern "C" { -#endif - -// On-the-fly info about the current set of residuals. Handy to avoid -// passing zillions of params. -typedef struct VP8Residual VP8Residual; -struct VP8Residual { - int first; - int last; - const int16_t* coeffs; - - int coeff_type; - ProbaArray* prob; - StatsArray* stats; - CostArrayPtr costs; -}; - -void VP8InitResidual(int first, int coeff_type, - VP8Encoder* const enc, VP8Residual* const res); - -int VP8RecordCoeffs(int ctx, const VP8Residual* const res); - -// Record proba context used. -static WEBP_INLINE int VP8RecordStats(int bit, proba_t* const stats) { - proba_t p = *stats; - // An overflow is inbound. Note we handle this at 0xfffe0000u instead of - // 0xffff0000u to make sure p + 1u does not overflow. - if (p >= 0xfffe0000u) { - p = ((p + 1u) >> 1) & 0x7fff7fffu; // -> divide the stats by 2. - } - // record bit count (lower 16 bits) and increment total count (upper 16 bits). - p += 0x00010000u + bit; - *stats = p; - return bit; -} - -// Cost of coding one event with probability 'proba'. -static WEBP_INLINE int VP8BitCost(int bit, uint8_t proba) { - return !bit ? VP8EntropyCost[proba] : VP8EntropyCost[255 - proba]; -} - -// Level cost calculations -extern const uint16_t VP8LevelCodes[MAX_VARIABLE_LEVEL][2]; -void VP8CalculateLevelCosts(VP8EncProba* const proba); -static WEBP_INLINE int VP8LevelCost(const uint16_t* const table, int level) { - return VP8LevelFixedCosts[level] - + table[(level > MAX_VARIABLE_LEVEL) ? MAX_VARIABLE_LEVEL : level]; -} - -// Mode costs -extern const uint16_t VP8FixedCostsUV[4]; -extern const uint16_t VP8FixedCostsI16[4]; -extern const uint16_t VP8FixedCostsI4[NUM_BMODES][NUM_BMODES][NUM_BMODES]; - -//------------------------------------------------------------------------------ - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // WEBP_ENC_COST_ENC_H_ diff --git a/libwebp/src/enc/filter_enc.c b/libwebp/src/enc/filter_enc.c deleted file mode 100644 index 580800bf..00000000 --- a/libwebp/src/enc/filter_enc.c +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Selecting filter level -// -// Author: somnath@google.com (Somnath Banerjee) - -#include -#include "src/enc/vp8i_enc.h" -#include "src/dsp/dsp.h" - -// This table gives, for a given sharpness, the filtering strength to be -// used (at least) in order to filter a given edge step delta. -// This is constructed by brute force inspection: for all delta, we iterate -// over all possible filtering strength / thresh until needs_filter() returns -// true. -#define MAX_DELTA_SIZE 64 -static const uint8_t kLevelsFromDelta[8][MAX_DELTA_SIZE] = { - { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63 }, - { 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 17, 18, - 20, 21, 23, 24, 26, 27, 29, 30, 32, 33, 35, 36, 38, 39, 41, 42, - 44, 45, 47, 48, 50, 51, 53, 54, 56, 57, 59, 60, 62, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 }, - { 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 13, 14, 16, 17, 19, - 20, 22, 23, 25, 26, 28, 29, 31, 32, 34, 35, 37, 38, 40, 41, 43, - 44, 46, 47, 49, 50, 52, 53, 55, 56, 58, 59, 61, 62, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 }, - { 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 13, 15, 16, 18, 19, - 21, 22, 24, 25, 27, 28, 30, 31, 33, 34, 36, 37, 39, 40, 42, 43, - 45, 46, 48, 49, 51, 52, 54, 55, 57, 58, 60, 61, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 }, - { 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 14, 15, 17, 18, 20, - 21, 23, 24, 26, 27, 29, 30, 32, 33, 35, 36, 38, 39, 41, 42, 44, - 45, 47, 48, 50, 51, 53, 54, 56, 57, 59, 60, 62, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 }, - { 0, 1, 2, 4, 5, 7, 8, 9, 11, 12, 13, 15, 16, 17, 19, 20, - 22, 23, 25, 26, 28, 29, 31, 32, 34, 35, 37, 38, 40, 41, 43, 44, - 46, 47, 49, 50, 52, 53, 55, 56, 58, 59, 61, 62, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 }, - { 0, 1, 2, 4, 5, 7, 8, 9, 11, 12, 13, 15, 16, 18, 19, 21, - 22, 24, 25, 27, 28, 30, 31, 33, 34, 36, 37, 39, 40, 42, 43, 45, - 46, 48, 49, 51, 52, 54, 55, 57, 58, 60, 61, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 }, - { 0, 1, 2, 4, 5, 7, 8, 9, 11, 12, 14, 15, 17, 18, 20, 21, - 23, 24, 26, 27, 29, 30, 32, 33, 35, 36, 38, 39, 41, 42, 44, 45, - 47, 48, 50, 51, 53, 54, 56, 57, 59, 60, 62, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 } -}; - -int VP8FilterStrengthFromDelta(int sharpness, int delta) { - const int pos = (delta < MAX_DELTA_SIZE) ? delta : MAX_DELTA_SIZE - 1; - assert(sharpness >= 0 && sharpness <= 7); - return kLevelsFromDelta[sharpness][pos]; -} - -//------------------------------------------------------------------------------ -// Paragraph 15.4: compute the inner-edge filtering strength - -#if !defined(WEBP_REDUCE_SIZE) - -static int GetILevel(int sharpness, int level) { - if (sharpness > 0) { - if (sharpness > 4) { - level >>= 2; - } else { - level >>= 1; - } - if (level > 9 - sharpness) { - level = 9 - sharpness; - } - } - if (level < 1) level = 1; - return level; -} - -static void DoFilter(const VP8EncIterator* const it, int level) { - const VP8Encoder* const enc = it->enc_; - const int ilevel = GetILevel(enc->config_->filter_sharpness, level); - const int limit = 2 * level + ilevel; - - uint8_t* const y_dst = it->yuv_out2_ + Y_OFF_ENC; - uint8_t* const u_dst = it->yuv_out2_ + U_OFF_ENC; - uint8_t* const v_dst = it->yuv_out2_ + V_OFF_ENC; - - // copy current block to yuv_out2_ - memcpy(y_dst, it->yuv_out_, YUV_SIZE_ENC * sizeof(uint8_t)); - - if (enc->filter_hdr_.simple_ == 1) { // simple - VP8SimpleHFilter16i(y_dst, BPS, limit); - VP8SimpleVFilter16i(y_dst, BPS, limit); - } else { // complex - const int hev_thresh = (level >= 40) ? 2 : (level >= 15) ? 1 : 0; - VP8HFilter16i(y_dst, BPS, limit, ilevel, hev_thresh); - VP8HFilter8i(u_dst, v_dst, BPS, limit, ilevel, hev_thresh); - VP8VFilter16i(y_dst, BPS, limit, ilevel, hev_thresh); - VP8VFilter8i(u_dst, v_dst, BPS, limit, ilevel, hev_thresh); - } -} - -//------------------------------------------------------------------------------ -// SSIM metric for one macroblock - -static double GetMBSSIM(const uint8_t* yuv1, const uint8_t* yuv2) { - int x, y; - double sum = 0.; - - // compute SSIM in a 10 x 10 window - for (y = VP8_SSIM_KERNEL; y < 16 - VP8_SSIM_KERNEL; y++) { - for (x = VP8_SSIM_KERNEL; x < 16 - VP8_SSIM_KERNEL; x++) { - sum += VP8SSIMGetClipped(yuv1 + Y_OFF_ENC, BPS, yuv2 + Y_OFF_ENC, BPS, - x, y, 16, 16); - } - } - for (x = 1; x < 7; x++) { - for (y = 1; y < 7; y++) { - sum += VP8SSIMGetClipped(yuv1 + U_OFF_ENC, BPS, yuv2 + U_OFF_ENC, BPS, - x, y, 8, 8); - sum += VP8SSIMGetClipped(yuv1 + V_OFF_ENC, BPS, yuv2 + V_OFF_ENC, BPS, - x, y, 8, 8); - } - } - return sum; -} - -#endif // !defined(WEBP_REDUCE_SIZE) - -//------------------------------------------------------------------------------ -// Exposed APIs: Encoder should call the following 3 functions to adjust -// loop filter strength - -void VP8InitFilter(VP8EncIterator* const it) { -#if !defined(WEBP_REDUCE_SIZE) - if (it->lf_stats_ != NULL) { - int s, i; - for (s = 0; s < NUM_MB_SEGMENTS; s++) { - for (i = 0; i < MAX_LF_LEVELS; i++) { - (*it->lf_stats_)[s][i] = 0; - } - } - VP8SSIMDspInit(); - } -#else - (void)it; -#endif -} - -void VP8StoreFilterStats(VP8EncIterator* const it) { -#if !defined(WEBP_REDUCE_SIZE) - int d; - VP8Encoder* const enc = it->enc_; - const int s = it->mb_->segment_; - const int level0 = enc->dqm_[s].fstrength_; - - // explore +/-quant range of values around level0 - const int delta_min = -enc->dqm_[s].quant_; - const int delta_max = enc->dqm_[s].quant_; - const int step_size = (delta_max - delta_min >= 4) ? 4 : 1; - - if (it->lf_stats_ == NULL) return; - - // NOTE: Currently we are applying filter only across the sublock edges - // There are two reasons for that. - // 1. Applying filter on macro block edges will change the pixels in - // the left and top macro blocks. That will be hard to restore - // 2. Macro Blocks on the bottom and right are not yet compressed. So we - // cannot apply filter on the right and bottom macro block edges. - if (it->mb_->type_ == 1 && it->mb_->skip_) return; - - // Always try filter level zero - (*it->lf_stats_)[s][0] += GetMBSSIM(it->yuv_in_, it->yuv_out_); - - for (d = delta_min; d <= delta_max; d += step_size) { - const int level = level0 + d; - if (level <= 0 || level >= MAX_LF_LEVELS) { - continue; - } - DoFilter(it, level); - (*it->lf_stats_)[s][level] += GetMBSSIM(it->yuv_in_, it->yuv_out2_); - } -#else // defined(WEBP_REDUCE_SIZE) - (void)it; -#endif // !defined(WEBP_REDUCE_SIZE) -} - -void VP8AdjustFilterStrength(VP8EncIterator* const it) { - VP8Encoder* const enc = it->enc_; -#if !defined(WEBP_REDUCE_SIZE) - if (it->lf_stats_ != NULL) { - int s; - for (s = 0; s < NUM_MB_SEGMENTS; s++) { - int i, best_level = 0; - // Improvement over filter level 0 should be at least 1e-5 (relatively) - double best_v = 1.00001 * (*it->lf_stats_)[s][0]; - for (i = 1; i < MAX_LF_LEVELS; i++) { - const double v = (*it->lf_stats_)[s][i]; - if (v > best_v) { - best_v = v; - best_level = i; - } - } - enc->dqm_[s].fstrength_ = best_level; - } - return; - } -#endif // !defined(WEBP_REDUCE_SIZE) - if (enc->config_->filter_strength > 0) { - int max_level = 0; - int s; - for (s = 0; s < NUM_MB_SEGMENTS; s++) { - VP8SegmentInfo* const dqm = &enc->dqm_[s]; - // this '>> 3' accounts for some inverse WHT scaling - const int delta = (dqm->max_edge_ * dqm->y2_.q_[1]) >> 3; - const int level = - VP8FilterStrengthFromDelta(enc->filter_hdr_.sharpness_, delta); - if (level > dqm->fstrength_) { - dqm->fstrength_ = level; - } - if (max_level < dqm->fstrength_) { - max_level = dqm->fstrength_; - } - } - enc->filter_hdr_.level_ = max_level; - } -} - -// ----------------------------------------------------------------------------- diff --git a/libwebp/src/enc/frame_enc.c b/libwebp/src/enc/frame_enc.c deleted file mode 100644 index 01860ca7..00000000 --- a/libwebp/src/enc/frame_enc.c +++ /dev/null @@ -1,905 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// frame coding and analysis -// -// Author: Skal (pascal.massimino@gmail.com) - -#include -#include - -#include "src/enc/cost_enc.h" -#include "src/enc/vp8i_enc.h" -#include "src/dsp/dsp.h" -#include "src/webp/format_constants.h" // RIFF constants - -#define SEGMENT_VISU 0 -#define DEBUG_SEARCH 0 // useful to track search convergence - -//------------------------------------------------------------------------------ -// multi-pass convergence - -#define HEADER_SIZE_ESTIMATE (RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE + \ - VP8_FRAME_HEADER_SIZE) -#define DQ_LIMIT 0.4 // convergence is considered reached if dq < DQ_LIMIT -// we allow 2k of extra head-room in PARTITION0 limit. -#define PARTITION0_SIZE_LIMIT ((VP8_MAX_PARTITION0_SIZE - 2048ULL) << 11) - -static float Clamp(float v, float min, float max) { - return (v < min) ? min : (v > max) ? max : v; -} - -typedef struct { // struct for organizing convergence in either size or PSNR - int is_first; - float dq; - float q, last_q; - float qmin, qmax; - double value, last_value; // PSNR or size - double target; - int do_size_search; -} PassStats; - -static int InitPassStats(const VP8Encoder* const enc, PassStats* const s) { - const uint64_t target_size = (uint64_t)enc->config_->target_size; - const int do_size_search = (target_size != 0); - const float target_PSNR = enc->config_->target_PSNR; - - s->is_first = 1; - s->dq = 10.f; - s->qmin = 1.f * enc->config_->qmin; - s->qmax = 1.f * enc->config_->qmax; - s->q = s->last_q = Clamp(enc->config_->quality, s->qmin, s->qmax); - s->target = do_size_search ? (double)target_size - : (target_PSNR > 0.) ? target_PSNR - : 40.; // default, just in case - s->value = s->last_value = 0.; - s->do_size_search = do_size_search; - return do_size_search; -} - -static float ComputeNextQ(PassStats* const s) { - float dq; - if (s->is_first) { - dq = (s->value > s->target) ? -s->dq : s->dq; - s->is_first = 0; - } else if (s->value != s->last_value) { - const double slope = (s->target - s->value) / (s->last_value - s->value); - dq = (float)(slope * (s->last_q - s->q)); - } else { - dq = 0.; // we're done?! - } - // Limit variable to avoid large swings. - s->dq = Clamp(dq, -30.f, 30.f); - s->last_q = s->q; - s->last_value = s->value; - s->q = Clamp(s->q + s->dq, s->qmin, s->qmax); - return s->q; -} - -//------------------------------------------------------------------------------ -// Tables for level coding - -const uint8_t VP8Cat3[] = { 173, 148, 140 }; -const uint8_t VP8Cat4[] = { 176, 155, 140, 135 }; -const uint8_t VP8Cat5[] = { 180, 157, 141, 134, 130 }; -const uint8_t VP8Cat6[] = - { 254, 254, 243, 230, 196, 177, 153, 140, 133, 130, 129 }; - -//------------------------------------------------------------------------------ -// Reset the statistics about: number of skips, token proba, level cost,... - -static void ResetStats(VP8Encoder* const enc) { - VP8EncProba* const proba = &enc->proba_; - VP8CalculateLevelCosts(proba); - proba->nb_skip_ = 0; -} - -//------------------------------------------------------------------------------ -// Skip decision probability - -#define SKIP_PROBA_THRESHOLD 250 // value below which using skip_proba is OK. - -static int CalcSkipProba(uint64_t nb, uint64_t total) { - return (int)(total ? (total - nb) * 255 / total : 255); -} - -// Returns the bit-cost for coding the skip probability. -static int FinalizeSkipProba(VP8Encoder* const enc) { - VP8EncProba* const proba = &enc->proba_; - const int nb_mbs = enc->mb_w_ * enc->mb_h_; - const int nb_events = proba->nb_skip_; - int size; - proba->skip_proba_ = CalcSkipProba(nb_events, nb_mbs); - proba->use_skip_proba_ = (proba->skip_proba_ < SKIP_PROBA_THRESHOLD); - size = 256; // 'use_skip_proba' bit - if (proba->use_skip_proba_) { - size += nb_events * VP8BitCost(1, proba->skip_proba_) - + (nb_mbs - nb_events) * VP8BitCost(0, proba->skip_proba_); - size += 8 * 256; // cost of signaling the skip_proba_ itself. - } - return size; -} - -// Collect statistics and deduce probabilities for next coding pass. -// Return the total bit-cost for coding the probability updates. -static int CalcTokenProba(int nb, int total) { - assert(nb <= total); - return nb ? (255 - nb * 255 / total) : 255; -} - -// Cost of coding 'nb' 1's and 'total-nb' 0's using 'proba' probability. -static int BranchCost(int nb, int total, int proba) { - return nb * VP8BitCost(1, proba) + (total - nb) * VP8BitCost(0, proba); -} - -static void ResetTokenStats(VP8Encoder* const enc) { - VP8EncProba* const proba = &enc->proba_; - memset(proba->stats_, 0, sizeof(proba->stats_)); -} - -static int FinalizeTokenProbas(VP8EncProba* const proba) { - int has_changed = 0; - int size = 0; - int t, b, c, p; - for (t = 0; t < NUM_TYPES; ++t) { - for (b = 0; b < NUM_BANDS; ++b) { - for (c = 0; c < NUM_CTX; ++c) { - for (p = 0; p < NUM_PROBAS; ++p) { - const proba_t stats = proba->stats_[t][b][c][p]; - const int nb = (stats >> 0) & 0xffff; - const int total = (stats >> 16) & 0xffff; - const int update_proba = VP8CoeffsUpdateProba[t][b][c][p]; - const int old_p = VP8CoeffsProba0[t][b][c][p]; - const int new_p = CalcTokenProba(nb, total); - const int old_cost = BranchCost(nb, total, old_p) - + VP8BitCost(0, update_proba); - const int new_cost = BranchCost(nb, total, new_p) - + VP8BitCost(1, update_proba) - + 8 * 256; - const int use_new_p = (old_cost > new_cost); - size += VP8BitCost(use_new_p, update_proba); - if (use_new_p) { // only use proba that seem meaningful enough. - proba->coeffs_[t][b][c][p] = new_p; - has_changed |= (new_p != old_p); - size += 8 * 256; - } else { - proba->coeffs_[t][b][c][p] = old_p; - } - } - } - } - } - proba->dirty_ = has_changed; - return size; -} - -//------------------------------------------------------------------------------ -// Finalize Segment probability based on the coding tree - -static int GetProba(int a, int b) { - const int total = a + b; - return (total == 0) ? 255 // that's the default probability. - : (255 * a + total / 2) / total; // rounded proba -} - -static void ResetSegments(VP8Encoder* const enc) { - int n; - for (n = 0; n < enc->mb_w_ * enc->mb_h_; ++n) { - enc->mb_info_[n].segment_ = 0; - } -} - -static void SetSegmentProbas(VP8Encoder* const enc) { - int p[NUM_MB_SEGMENTS] = { 0 }; - int n; - - for (n = 0; n < enc->mb_w_ * enc->mb_h_; ++n) { - const VP8MBInfo* const mb = &enc->mb_info_[n]; - ++p[mb->segment_]; - } -#if !defined(WEBP_DISABLE_STATS) - if (enc->pic_->stats != NULL) { - for (n = 0; n < NUM_MB_SEGMENTS; ++n) { - enc->pic_->stats->segment_size[n] = p[n]; - } - } -#endif - if (enc->segment_hdr_.num_segments_ > 1) { - uint8_t* const probas = enc->proba_.segments_; - probas[0] = GetProba(p[0] + p[1], p[2] + p[3]); - probas[1] = GetProba(p[0], p[1]); - probas[2] = GetProba(p[2], p[3]); - - enc->segment_hdr_.update_map_ = - (probas[0] != 255) || (probas[1] != 255) || (probas[2] != 255); - if (!enc->segment_hdr_.update_map_) ResetSegments(enc); - enc->segment_hdr_.size_ = - p[0] * (VP8BitCost(0, probas[0]) + VP8BitCost(0, probas[1])) + - p[1] * (VP8BitCost(0, probas[0]) + VP8BitCost(1, probas[1])) + - p[2] * (VP8BitCost(1, probas[0]) + VP8BitCost(0, probas[2])) + - p[3] * (VP8BitCost(1, probas[0]) + VP8BitCost(1, probas[2])); - } else { - enc->segment_hdr_.update_map_ = 0; - enc->segment_hdr_.size_ = 0; - } -} - -//------------------------------------------------------------------------------ -// Coefficient coding - -static int PutCoeffs(VP8BitWriter* const bw, int ctx, const VP8Residual* res) { - int n = res->first; - // should be prob[VP8EncBands[n]], but it's equivalent for n=0 or 1 - const uint8_t* p = res->prob[n][ctx]; - if (!VP8PutBit(bw, res->last >= 0, p[0])) { - return 0; - } - - while (n < 16) { - const int c = res->coeffs[n++]; - const int sign = c < 0; - int v = sign ? -c : c; - if (!VP8PutBit(bw, v != 0, p[1])) { - p = res->prob[VP8EncBands[n]][0]; - continue; - } - if (!VP8PutBit(bw, v > 1, p[2])) { - p = res->prob[VP8EncBands[n]][1]; - } else { - if (!VP8PutBit(bw, v > 4, p[3])) { - if (VP8PutBit(bw, v != 2, p[4])) { - VP8PutBit(bw, v == 4, p[5]); - } - } else if (!VP8PutBit(bw, v > 10, p[6])) { - if (!VP8PutBit(bw, v > 6, p[7])) { - VP8PutBit(bw, v == 6, 159); - } else { - VP8PutBit(bw, v >= 9, 165); - VP8PutBit(bw, !(v & 1), 145); - } - } else { - int mask; - const uint8_t* tab; - if (v < 3 + (8 << 1)) { // VP8Cat3 (3b) - VP8PutBit(bw, 0, p[8]); - VP8PutBit(bw, 0, p[9]); - v -= 3 + (8 << 0); - mask = 1 << 2; - tab = VP8Cat3; - } else if (v < 3 + (8 << 2)) { // VP8Cat4 (4b) - VP8PutBit(bw, 0, p[8]); - VP8PutBit(bw, 1, p[9]); - v -= 3 + (8 << 1); - mask = 1 << 3; - tab = VP8Cat4; - } else if (v < 3 + (8 << 3)) { // VP8Cat5 (5b) - VP8PutBit(bw, 1, p[8]); - VP8PutBit(bw, 0, p[10]); - v -= 3 + (8 << 2); - mask = 1 << 4; - tab = VP8Cat5; - } else { // VP8Cat6 (11b) - VP8PutBit(bw, 1, p[8]); - VP8PutBit(bw, 1, p[10]); - v -= 3 + (8 << 3); - mask = 1 << 10; - tab = VP8Cat6; - } - while (mask) { - VP8PutBit(bw, !!(v & mask), *tab++); - mask >>= 1; - } - } - p = res->prob[VP8EncBands[n]][2]; - } - VP8PutBitUniform(bw, sign); - if (n == 16 || !VP8PutBit(bw, n <= res->last, p[0])) { - return 1; // EOB - } - } - return 1; -} - -static void CodeResiduals(VP8BitWriter* const bw, VP8EncIterator* const it, - const VP8ModeScore* const rd) { - int x, y, ch; - VP8Residual res; - uint64_t pos1, pos2, pos3; - const int i16 = (it->mb_->type_ == 1); - const int segment = it->mb_->segment_; - VP8Encoder* const enc = it->enc_; - - VP8IteratorNzToBytes(it); - - pos1 = VP8BitWriterPos(bw); - if (i16) { - VP8InitResidual(0, 1, enc, &res); - VP8SetResidualCoeffs(rd->y_dc_levels, &res); - it->top_nz_[8] = it->left_nz_[8] = - PutCoeffs(bw, it->top_nz_[8] + it->left_nz_[8], &res); - VP8InitResidual(1, 0, enc, &res); - } else { - VP8InitResidual(0, 3, enc, &res); - } - - // luma-AC - for (y = 0; y < 4; ++y) { - for (x = 0; x < 4; ++x) { - const int ctx = it->top_nz_[x] + it->left_nz_[y]; - VP8SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res); - it->top_nz_[x] = it->left_nz_[y] = PutCoeffs(bw, ctx, &res); - } - } - pos2 = VP8BitWriterPos(bw); - - // U/V - VP8InitResidual(0, 2, enc, &res); - for (ch = 0; ch <= 2; ch += 2) { - for (y = 0; y < 2; ++y) { - for (x = 0; x < 2; ++x) { - const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y]; - VP8SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res); - it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] = - PutCoeffs(bw, ctx, &res); - } - } - } - pos3 = VP8BitWriterPos(bw); - it->luma_bits_ = pos2 - pos1; - it->uv_bits_ = pos3 - pos2; - it->bit_count_[segment][i16] += it->luma_bits_; - it->bit_count_[segment][2] += it->uv_bits_; - VP8IteratorBytesToNz(it); -} - -// Same as CodeResiduals, but doesn't actually write anything. -// Instead, it just records the event distribution. -static void RecordResiduals(VP8EncIterator* const it, - const VP8ModeScore* const rd) { - int x, y, ch; - VP8Residual res; - VP8Encoder* const enc = it->enc_; - - VP8IteratorNzToBytes(it); - - if (it->mb_->type_ == 1) { // i16x16 - VP8InitResidual(0, 1, enc, &res); - VP8SetResidualCoeffs(rd->y_dc_levels, &res); - it->top_nz_[8] = it->left_nz_[8] = - VP8RecordCoeffs(it->top_nz_[8] + it->left_nz_[8], &res); - VP8InitResidual(1, 0, enc, &res); - } else { - VP8InitResidual(0, 3, enc, &res); - } - - // luma-AC - for (y = 0; y < 4; ++y) { - for (x = 0; x < 4; ++x) { - const int ctx = it->top_nz_[x] + it->left_nz_[y]; - VP8SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res); - it->top_nz_[x] = it->left_nz_[y] = VP8RecordCoeffs(ctx, &res); - } - } - - // U/V - VP8InitResidual(0, 2, enc, &res); - for (ch = 0; ch <= 2; ch += 2) { - for (y = 0; y < 2; ++y) { - for (x = 0; x < 2; ++x) { - const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y]; - VP8SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res); - it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] = - VP8RecordCoeffs(ctx, &res); - } - } - } - - VP8IteratorBytesToNz(it); -} - -//------------------------------------------------------------------------------ -// Token buffer - -#if !defined(DISABLE_TOKEN_BUFFER) - -static int RecordTokens(VP8EncIterator* const it, const VP8ModeScore* const rd, - VP8TBuffer* const tokens) { - int x, y, ch; - VP8Residual res; - VP8Encoder* const enc = it->enc_; - - VP8IteratorNzToBytes(it); - if (it->mb_->type_ == 1) { // i16x16 - const int ctx = it->top_nz_[8] + it->left_nz_[8]; - VP8InitResidual(0, 1, enc, &res); - VP8SetResidualCoeffs(rd->y_dc_levels, &res); - it->top_nz_[8] = it->left_nz_[8] = - VP8RecordCoeffTokens(ctx, &res, tokens); - VP8InitResidual(1, 0, enc, &res); - } else { - VP8InitResidual(0, 3, enc, &res); - } - - // luma-AC - for (y = 0; y < 4; ++y) { - for (x = 0; x < 4; ++x) { - const int ctx = it->top_nz_[x] + it->left_nz_[y]; - VP8SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res); - it->top_nz_[x] = it->left_nz_[y] = - VP8RecordCoeffTokens(ctx, &res, tokens); - } - } - - // U/V - VP8InitResidual(0, 2, enc, &res); - for (ch = 0; ch <= 2; ch += 2) { - for (y = 0; y < 2; ++y) { - for (x = 0; x < 2; ++x) { - const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y]; - VP8SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res); - it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] = - VP8RecordCoeffTokens(ctx, &res, tokens); - } - } - } - VP8IteratorBytesToNz(it); - return !tokens->error_; -} - -#endif // !DISABLE_TOKEN_BUFFER - -//------------------------------------------------------------------------------ -// ExtraInfo map / Debug function - -#if !defined(WEBP_DISABLE_STATS) - -#if SEGMENT_VISU -static void SetBlock(uint8_t* p, int value, int size) { - int y; - for (y = 0; y < size; ++y) { - memset(p, value, size); - p += BPS; - } -} -#endif - -static void ResetSSE(VP8Encoder* const enc) { - enc->sse_[0] = 0; - enc->sse_[1] = 0; - enc->sse_[2] = 0; - // Note: enc->sse_[3] is managed by alpha.c - enc->sse_count_ = 0; -} - -static void StoreSSE(const VP8EncIterator* const it) { - VP8Encoder* const enc = it->enc_; - const uint8_t* const in = it->yuv_in_; - const uint8_t* const out = it->yuv_out_; - // Note: not totally accurate at boundary. And doesn't include in-loop filter. - enc->sse_[0] += VP8SSE16x16(in + Y_OFF_ENC, out + Y_OFF_ENC); - enc->sse_[1] += VP8SSE8x8(in + U_OFF_ENC, out + U_OFF_ENC); - enc->sse_[2] += VP8SSE8x8(in + V_OFF_ENC, out + V_OFF_ENC); - enc->sse_count_ += 16 * 16; -} - -static void StoreSideInfo(const VP8EncIterator* const it) { - VP8Encoder* const enc = it->enc_; - const VP8MBInfo* const mb = it->mb_; - WebPPicture* const pic = enc->pic_; - - if (pic->stats != NULL) { - StoreSSE(it); - enc->block_count_[0] += (mb->type_ == 0); - enc->block_count_[1] += (mb->type_ == 1); - enc->block_count_[2] += (mb->skip_ != 0); - } - - if (pic->extra_info != NULL) { - uint8_t* const info = &pic->extra_info[it->x_ + it->y_ * enc->mb_w_]; - switch (pic->extra_info_type) { - case 1: *info = mb->type_; break; - case 2: *info = mb->segment_; break; - case 3: *info = enc->dqm_[mb->segment_].quant_; break; - case 4: *info = (mb->type_ == 1) ? it->preds_[0] : 0xff; break; - case 5: *info = mb->uv_mode_; break; - case 6: { - const int b = (int)((it->luma_bits_ + it->uv_bits_ + 7) >> 3); - *info = (b > 255) ? 255 : b; break; - } - case 7: *info = mb->alpha_; break; - default: *info = 0; break; - } - } -#if SEGMENT_VISU // visualize segments and prediction modes - SetBlock(it->yuv_out_ + Y_OFF_ENC, mb->segment_ * 64, 16); - SetBlock(it->yuv_out_ + U_OFF_ENC, it->preds_[0] * 64, 8); - SetBlock(it->yuv_out_ + V_OFF_ENC, mb->uv_mode_ * 64, 8); -#endif -} - -static void ResetSideInfo(const VP8EncIterator* const it) { - VP8Encoder* const enc = it->enc_; - WebPPicture* const pic = enc->pic_; - if (pic->stats != NULL) { - memset(enc->block_count_, 0, sizeof(enc->block_count_)); - } - ResetSSE(enc); -} -#else // defined(WEBP_DISABLE_STATS) -static void ResetSSE(VP8Encoder* const enc) { - (void)enc; -} -static void StoreSideInfo(const VP8EncIterator* const it) { - VP8Encoder* const enc = it->enc_; - WebPPicture* const pic = enc->pic_; - if (pic->extra_info != NULL) { - if (it->x_ == 0 && it->y_ == 0) { // only do it once, at start - memset(pic->extra_info, 0, - enc->mb_w_ * enc->mb_h_ * sizeof(*pic->extra_info)); - } - } -} - -static void ResetSideInfo(const VP8EncIterator* const it) { - (void)it; -} -#endif // !defined(WEBP_DISABLE_STATS) - -static double GetPSNR(uint64_t mse, uint64_t size) { - return (mse > 0 && size > 0) ? 10. * log10(255. * 255. * size / mse) : 99; -} - -//------------------------------------------------------------------------------ -// StatLoop(): only collect statistics (number of skips, token usage, ...). -// This is used for deciding optimal probabilities. It also modifies the -// quantizer value if some target (size, PSNR) was specified. - -static void SetLoopParams(VP8Encoder* const enc, float q) { - // Make sure the quality parameter is inside valid bounds - q = Clamp(q, 0.f, 100.f); - - VP8SetSegmentParams(enc, q); // setup segment quantizations and filters - SetSegmentProbas(enc); // compute segment probabilities - - ResetStats(enc); - ResetSSE(enc); -} - -static uint64_t OneStatPass(VP8Encoder* const enc, VP8RDLevel rd_opt, - int nb_mbs, int percent_delta, - PassStats* const s) { - VP8EncIterator it; - uint64_t size = 0; - uint64_t size_p0 = 0; - uint64_t distortion = 0; - const uint64_t pixel_count = (uint64_t)nb_mbs * 384; - - VP8IteratorInit(enc, &it); - SetLoopParams(enc, s->q); - do { - VP8ModeScore info; - VP8IteratorImport(&it, NULL); - if (VP8Decimate(&it, &info, rd_opt)) { - // Just record the number of skips and act like skip_proba is not used. - ++enc->proba_.nb_skip_; - } - RecordResiduals(&it, &info); - size += info.R + info.H; - size_p0 += info.H; - distortion += info.D; - if (percent_delta && !VP8IteratorProgress(&it, percent_delta)) { - return 0; - } - VP8IteratorSaveBoundary(&it); - } while (VP8IteratorNext(&it) && --nb_mbs > 0); - - size_p0 += enc->segment_hdr_.size_; - if (s->do_size_search) { - size += FinalizeSkipProba(enc); - size += FinalizeTokenProbas(&enc->proba_); - size = ((size + size_p0 + 1024) >> 11) + HEADER_SIZE_ESTIMATE; - s->value = (double)size; - } else { - s->value = GetPSNR(distortion, pixel_count); - } - return size_p0; -} - -static int StatLoop(VP8Encoder* const enc) { - const int method = enc->method_; - const int do_search = enc->do_search_; - const int fast_probe = ((method == 0 || method == 3) && !do_search); - int num_pass_left = enc->config_->pass; - const int task_percent = 20; - const int percent_per_pass = - (task_percent + num_pass_left / 2) / num_pass_left; - const int final_percent = enc->percent_ + task_percent; - const VP8RDLevel rd_opt = - (method >= 3 || do_search) ? RD_OPT_BASIC : RD_OPT_NONE; - int nb_mbs = enc->mb_w_ * enc->mb_h_; - PassStats stats; - - InitPassStats(enc, &stats); - ResetTokenStats(enc); - - // Fast mode: quick analysis pass over few mbs. Better than nothing. - if (fast_probe) { - if (method == 3) { // we need more stats for method 3 to be reliable. - nb_mbs = (nb_mbs > 200) ? nb_mbs >> 1 : 100; - } else { - nb_mbs = (nb_mbs > 200) ? nb_mbs >> 2 : 50; - } - } - - while (num_pass_left-- > 0) { - const int is_last_pass = (fabs(stats.dq) <= DQ_LIMIT) || - (num_pass_left == 0) || - (enc->max_i4_header_bits_ == 0); - const uint64_t size_p0 = - OneStatPass(enc, rd_opt, nb_mbs, percent_per_pass, &stats); - if (size_p0 == 0) return 0; -#if (DEBUG_SEARCH > 0) - printf("#%d value:%.1lf -> %.1lf q:%.2f -> %.2f\n", - num_pass_left, stats.last_value, stats.value, stats.last_q, stats.q); -#endif - if (enc->max_i4_header_bits_ > 0 && size_p0 > PARTITION0_SIZE_LIMIT) { - ++num_pass_left; - enc->max_i4_header_bits_ >>= 1; // strengthen header bit limitation... - continue; // ...and start over - } - if (is_last_pass) { - break; - } - // If no target size: just do several pass without changing 'q' - if (do_search) { - ComputeNextQ(&stats); - if (fabs(stats.dq) <= DQ_LIMIT) break; - } - } - if (!do_search || !stats.do_size_search) { - // Need to finalize probas now, since it wasn't done during the search. - FinalizeSkipProba(enc); - FinalizeTokenProbas(&enc->proba_); - } - VP8CalculateLevelCosts(&enc->proba_); // finalize costs - return WebPReportProgress(enc->pic_, final_percent, &enc->percent_); -} - -//------------------------------------------------------------------------------ -// Main loops -// - -static const uint8_t kAverageBytesPerMB[8] = { 50, 24, 16, 9, 7, 5, 3, 2 }; - -static int PreLoopInitialize(VP8Encoder* const enc) { - int p; - int ok = 1; - const int average_bytes_per_MB = kAverageBytesPerMB[enc->base_quant_ >> 4]; - const int bytes_per_parts = - enc->mb_w_ * enc->mb_h_ * average_bytes_per_MB / enc->num_parts_; - // Initialize the bit-writers - for (p = 0; ok && p < enc->num_parts_; ++p) { - ok = VP8BitWriterInit(enc->parts_ + p, bytes_per_parts); - } - if (!ok) { - VP8EncFreeBitWriters(enc); // malloc error occurred - return WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY); - } - return ok; -} - -static int PostLoopFinalize(VP8EncIterator* const it, int ok) { - VP8Encoder* const enc = it->enc_; - if (ok) { // Finalize the partitions, check for extra errors. - int p; - for (p = 0; p < enc->num_parts_; ++p) { - VP8BitWriterFinish(enc->parts_ + p); - ok &= !enc->parts_[p].error_; - } - } - - if (ok) { // All good. Finish up. -#if !defined(WEBP_DISABLE_STATS) - if (enc->pic_->stats != NULL) { // finalize byte counters... - int i, s; - for (i = 0; i <= 2; ++i) { - for (s = 0; s < NUM_MB_SEGMENTS; ++s) { - enc->residual_bytes_[i][s] = (int)((it->bit_count_[s][i] + 7) >> 3); - } - } - } -#endif - VP8AdjustFilterStrength(it); // ...and store filter stats. - } else { - // Something bad happened -> need to do some memory cleanup. - VP8EncFreeBitWriters(enc); - return WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY); - } - return ok; -} - -//------------------------------------------------------------------------------ -// VP8EncLoop(): does the final bitstream coding. - -static void ResetAfterSkip(VP8EncIterator* const it) { - if (it->mb_->type_ == 1) { - *it->nz_ = 0; // reset all predictors - it->left_nz_[8] = 0; - } else { - *it->nz_ &= (1 << 24); // preserve the dc_nz bit - } -} - -int VP8EncLoop(VP8Encoder* const enc) { - VP8EncIterator it; - int ok = PreLoopInitialize(enc); - if (!ok) return 0; - - StatLoop(enc); // stats-collection loop - - VP8IteratorInit(enc, &it); - VP8InitFilter(&it); - do { - VP8ModeScore info; - const int dont_use_skip = !enc->proba_.use_skip_proba_; - const VP8RDLevel rd_opt = enc->rd_opt_level_; - - VP8IteratorImport(&it, NULL); - // Warning! order is important: first call VP8Decimate() and - // *then* decide how to code the skip decision if there's one. - if (!VP8Decimate(&it, &info, rd_opt) || dont_use_skip) { - CodeResiduals(it.bw_, &it, &info); - if (it.bw_->error_) { - // enc->pic_->error_code is set in PostLoopFinalize(). - ok = 0; - break; - } - } else { // reset predictors after a skip - ResetAfterSkip(&it); - } - StoreSideInfo(&it); - VP8StoreFilterStats(&it); - VP8IteratorExport(&it); - ok = VP8IteratorProgress(&it, 20); - VP8IteratorSaveBoundary(&it); - } while (ok && VP8IteratorNext(&it)); - - return PostLoopFinalize(&it, ok); -} - -//------------------------------------------------------------------------------ -// Single pass using Token Buffer. - -#if !defined(DISABLE_TOKEN_BUFFER) - -#define MIN_COUNT 96 // minimum number of macroblocks before updating stats - -int VP8EncTokenLoop(VP8Encoder* const enc) { - // Roughly refresh the proba eight times per pass - int max_count = (enc->mb_w_ * enc->mb_h_) >> 3; - int num_pass_left = enc->config_->pass; - int remaining_progress = 40; // percents - const int do_search = enc->do_search_; - VP8EncIterator it; - VP8EncProba* const proba = &enc->proba_; - const VP8RDLevel rd_opt = enc->rd_opt_level_; - const uint64_t pixel_count = (uint64_t)enc->mb_w_ * enc->mb_h_ * 384; - PassStats stats; - int ok; - - InitPassStats(enc, &stats); - ok = PreLoopInitialize(enc); - if (!ok) return 0; - - if (max_count < MIN_COUNT) max_count = MIN_COUNT; - - assert(enc->num_parts_ == 1); - assert(enc->use_tokens_); - assert(proba->use_skip_proba_ == 0); - assert(rd_opt >= RD_OPT_BASIC); // otherwise, token-buffer won't be useful - assert(num_pass_left > 0); - - while (ok && num_pass_left-- > 0) { - const int is_last_pass = (fabs(stats.dq) <= DQ_LIMIT) || - (num_pass_left == 0) || - (enc->max_i4_header_bits_ == 0); - uint64_t size_p0 = 0; - uint64_t distortion = 0; - int cnt = max_count; - // The final number of passes is not trivial to know in advance. - const int pass_progress = remaining_progress / (2 + num_pass_left); - remaining_progress -= pass_progress; - VP8IteratorInit(enc, &it); - SetLoopParams(enc, stats.q); - if (is_last_pass) { - ResetTokenStats(enc); - VP8InitFilter(&it); // don't collect stats until last pass (too costly) - } - VP8TBufferClear(&enc->tokens_); - do { - VP8ModeScore info; - VP8IteratorImport(&it, NULL); - if (--cnt < 0) { - FinalizeTokenProbas(proba); - VP8CalculateLevelCosts(proba); // refresh cost tables for rd-opt - cnt = max_count; - } - VP8Decimate(&it, &info, rd_opt); - ok = RecordTokens(&it, &info, &enc->tokens_); - if (!ok) { - WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY); - break; - } - size_p0 += info.H; - distortion += info.D; - if (is_last_pass) { - StoreSideInfo(&it); - VP8StoreFilterStats(&it); - VP8IteratorExport(&it); - ok = VP8IteratorProgress(&it, pass_progress); - } - VP8IteratorSaveBoundary(&it); - } while (ok && VP8IteratorNext(&it)); - if (!ok) break; - - size_p0 += enc->segment_hdr_.size_; - if (stats.do_size_search) { - uint64_t size = FinalizeTokenProbas(&enc->proba_); - size += VP8EstimateTokenSize(&enc->tokens_, - (const uint8_t*)proba->coeffs_); - size = (size + size_p0 + 1024) >> 11; // -> size in bytes - size += HEADER_SIZE_ESTIMATE; - stats.value = (double)size; - } else { // compute and store PSNR - stats.value = GetPSNR(distortion, pixel_count); - } - -#if (DEBUG_SEARCH > 0) - printf("#%2d metric:%.1lf -> %.1lf last_q=%.2lf q=%.2lf dq=%.2lf " - " range:[%.1f, %.1f]\n", - num_pass_left, stats.last_value, stats.value, - stats.last_q, stats.q, stats.dq, stats.qmin, stats.qmax); -#endif - if (enc->max_i4_header_bits_ > 0 && size_p0 > PARTITION0_SIZE_LIMIT) { - ++num_pass_left; - enc->max_i4_header_bits_ >>= 1; // strengthen header bit limitation... - if (is_last_pass) { - ResetSideInfo(&it); - } - continue; // ...and start over - } - if (is_last_pass) { - break; // done - } - if (do_search) { - ComputeNextQ(&stats); // Adjust q - } - } - if (ok) { - if (!stats.do_size_search) { - FinalizeTokenProbas(&enc->proba_); - } - ok = VP8EmitTokens(&enc->tokens_, enc->parts_ + 0, - (const uint8_t*)proba->coeffs_, 1); - } - ok = ok && WebPReportProgress(enc->pic_, enc->percent_ + remaining_progress, - &enc->percent_); - return PostLoopFinalize(&it, ok); -} - -#else - -int VP8EncTokenLoop(VP8Encoder* const enc) { - (void)enc; - return 0; // we shouldn't be here. -} - -#endif // DISABLE_TOKEN_BUFFER - -//------------------------------------------------------------------------------ diff --git a/libwebp/src/enc/histogram_enc.c b/libwebp/src/enc/histogram_enc.c deleted file mode 100644 index 3ca67b3a..00000000 --- a/libwebp/src/enc/histogram_enc.c +++ /dev/null @@ -1,1250 +0,0 @@ -// Copyright 2012 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Author: Jyrki Alakuijala (jyrki@google.com) -// -#ifdef HAVE_CONFIG_H -#include "src/webp/config.h" -#endif - -#include -#include - -#include "src/dsp/lossless.h" -#include "src/dsp/lossless_common.h" -#include "src/enc/backward_references_enc.h" -#include "src/enc/histogram_enc.h" -#include "src/enc/vp8i_enc.h" -#include "src/utils/utils.h" - -#define MAX_BIT_COST FLT_MAX - -// Number of partitions for the three dominant (literal, red and blue) symbol -// costs. -#define NUM_PARTITIONS 4 -// The size of the bin-hash corresponding to the three dominant costs. -#define BIN_SIZE (NUM_PARTITIONS * NUM_PARTITIONS * NUM_PARTITIONS) -// Maximum number of histograms allowed in greedy combining algorithm. -#define MAX_HISTO_GREEDY 100 - -static void HistogramClear(VP8LHistogram* const p) { - uint32_t* const literal = p->literal_; - const int cache_bits = p->palette_code_bits_; - const int histo_size = VP8LGetHistogramSize(cache_bits); - memset(p, 0, histo_size); - p->palette_code_bits_ = cache_bits; - p->literal_ = literal; -} - -// Swap two histogram pointers. -static void HistogramSwap(VP8LHistogram** const A, VP8LHistogram** const B) { - VP8LHistogram* const tmp = *A; - *A = *B; - *B = tmp; -} - -static void HistogramCopy(const VP8LHistogram* const src, - VP8LHistogram* const dst) { - uint32_t* const dst_literal = dst->literal_; - const int dst_cache_bits = dst->palette_code_bits_; - const int literal_size = VP8LHistogramNumCodes(dst_cache_bits); - const int histo_size = VP8LGetHistogramSize(dst_cache_bits); - assert(src->palette_code_bits_ == dst_cache_bits); - memcpy(dst, src, histo_size); - dst->literal_ = dst_literal; - memcpy(dst->literal_, src->literal_, literal_size * sizeof(*dst->literal_)); -} - -int VP8LGetHistogramSize(int cache_bits) { - const int literal_size = VP8LHistogramNumCodes(cache_bits); - const size_t total_size = sizeof(VP8LHistogram) + sizeof(int) * literal_size; - assert(total_size <= (size_t)0x7fffffff); - return (int)total_size; -} - -void VP8LFreeHistogram(VP8LHistogram* const histo) { - WebPSafeFree(histo); -} - -void VP8LFreeHistogramSet(VP8LHistogramSet* const histo) { - WebPSafeFree(histo); -} - -void VP8LHistogramStoreRefs(const VP8LBackwardRefs* const refs, - VP8LHistogram* const histo) { - VP8LRefsCursor c = VP8LRefsCursorInit(refs); - while (VP8LRefsCursorOk(&c)) { - VP8LHistogramAddSinglePixOrCopy(histo, c.cur_pos, NULL, 0); - VP8LRefsCursorNext(&c); - } -} - -void VP8LHistogramCreate(VP8LHistogram* const p, - const VP8LBackwardRefs* const refs, - int palette_code_bits) { - if (palette_code_bits >= 0) { - p->palette_code_bits_ = palette_code_bits; - } - HistogramClear(p); - VP8LHistogramStoreRefs(refs, p); -} - -void VP8LHistogramInit(VP8LHistogram* const p, int palette_code_bits, - int init_arrays) { - p->palette_code_bits_ = palette_code_bits; - if (init_arrays) { - HistogramClear(p); - } else { - p->trivial_symbol_ = 0; - p->bit_cost_ = 0.; - p->literal_cost_ = 0.; - p->red_cost_ = 0.; - p->blue_cost_ = 0.; - memset(p->is_used_, 0, sizeof(p->is_used_)); - } -} - -VP8LHistogram* VP8LAllocateHistogram(int cache_bits) { - VP8LHistogram* histo = NULL; - const int total_size = VP8LGetHistogramSize(cache_bits); - uint8_t* const memory = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*memory)); - if (memory == NULL) return NULL; - histo = (VP8LHistogram*)memory; - // literal_ won't necessary be aligned. - histo->literal_ = (uint32_t*)(memory + sizeof(VP8LHistogram)); - VP8LHistogramInit(histo, cache_bits, /*init_arrays=*/ 0); - return histo; -} - -// Resets the pointers of the histograms to point to the bit buffer in the set. -static void HistogramSetResetPointers(VP8LHistogramSet* const set, - int cache_bits) { - int i; - const int histo_size = VP8LGetHistogramSize(cache_bits); - uint8_t* memory = (uint8_t*) (set->histograms); - memory += set->max_size * sizeof(*set->histograms); - for (i = 0; i < set->max_size; ++i) { - memory = (uint8_t*) WEBP_ALIGN(memory); - set->histograms[i] = (VP8LHistogram*) memory; - // literal_ won't necessary be aligned. - set->histograms[i]->literal_ = (uint32_t*)(memory + sizeof(VP8LHistogram)); - memory += histo_size; - } -} - -// Returns the total size of the VP8LHistogramSet. -static size_t HistogramSetTotalSize(int size, int cache_bits) { - const int histo_size = VP8LGetHistogramSize(cache_bits); - return (sizeof(VP8LHistogramSet) + size * (sizeof(VP8LHistogram*) + - histo_size + WEBP_ALIGN_CST)); -} - -VP8LHistogramSet* VP8LAllocateHistogramSet(int size, int cache_bits) { - int i; - VP8LHistogramSet* set; - const size_t total_size = HistogramSetTotalSize(size, cache_bits); - uint8_t* memory = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*memory)); - if (memory == NULL) return NULL; - - set = (VP8LHistogramSet*)memory; - memory += sizeof(*set); - set->histograms = (VP8LHistogram**)memory; - set->max_size = size; - set->size = size; - HistogramSetResetPointers(set, cache_bits); - for (i = 0; i < size; ++i) { - VP8LHistogramInit(set->histograms[i], cache_bits, /*init_arrays=*/ 0); - } - return set; -} - -void VP8LHistogramSetClear(VP8LHistogramSet* const set) { - int i; - const int cache_bits = set->histograms[0]->palette_code_bits_; - const int size = set->max_size; - const size_t total_size = HistogramSetTotalSize(size, cache_bits); - uint8_t* memory = (uint8_t*)set; - - memset(memory, 0, total_size); - memory += sizeof(*set); - set->histograms = (VP8LHistogram**)memory; - set->max_size = size; - set->size = size; - HistogramSetResetPointers(set, cache_bits); - for (i = 0; i < size; ++i) { - set->histograms[i]->palette_code_bits_ = cache_bits; - } -} - -// Removes the histogram 'i' from 'set' by setting it to NULL. -static void HistogramSetRemoveHistogram(VP8LHistogramSet* const set, int i, - int* const num_used) { - assert(set->histograms[i] != NULL); - set->histograms[i] = NULL; - --*num_used; - // If we remove the last valid one, shrink until the next valid one. - if (i == set->size - 1) { - while (set->size >= 1 && set->histograms[set->size - 1] == NULL) { - --set->size; - } - } -} - -// ----------------------------------------------------------------------------- - -void VP8LHistogramAddSinglePixOrCopy(VP8LHistogram* const histo, - const PixOrCopy* const v, - int (*const distance_modifier)(int, int), - int distance_modifier_arg0) { - if (PixOrCopyIsLiteral(v)) { - ++histo->alpha_[PixOrCopyLiteral(v, 3)]; - ++histo->red_[PixOrCopyLiteral(v, 2)]; - ++histo->literal_[PixOrCopyLiteral(v, 1)]; - ++histo->blue_[PixOrCopyLiteral(v, 0)]; - } else if (PixOrCopyIsCacheIdx(v)) { - const int literal_ix = - NUM_LITERAL_CODES + NUM_LENGTH_CODES + PixOrCopyCacheIdx(v); - assert(histo->palette_code_bits_ != 0); - ++histo->literal_[literal_ix]; - } else { - int code, extra_bits; - VP8LPrefixEncodeBits(PixOrCopyLength(v), &code, &extra_bits); - ++histo->literal_[NUM_LITERAL_CODES + code]; - if (distance_modifier == NULL) { - VP8LPrefixEncodeBits(PixOrCopyDistance(v), &code, &extra_bits); - } else { - VP8LPrefixEncodeBits( - distance_modifier(distance_modifier_arg0, PixOrCopyDistance(v)), - &code, &extra_bits); - } - ++histo->distance_[code]; - } -} - -// ----------------------------------------------------------------------------- -// Entropy-related functions. - -static WEBP_INLINE float BitsEntropyRefine(const VP8LBitEntropy* entropy) { - float mix; - if (entropy->nonzeros < 5) { - if (entropy->nonzeros <= 1) { - return 0; - } - // Two symbols, they will be 0 and 1 in a Huffman code. - // Let's mix in a bit of entropy to favor good clustering when - // distributions of these are combined. - if (entropy->nonzeros == 2) { - return 0.99f * entropy->sum + 0.01f * entropy->entropy; - } - // No matter what the entropy says, we cannot be better than min_limit - // with Huffman coding. I am mixing a bit of entropy into the - // min_limit since it produces much better (~0.5 %) compression results - // perhaps because of better entropy clustering. - if (entropy->nonzeros == 3) { - mix = 0.95f; - } else { - mix = 0.7f; // nonzeros == 4. - } - } else { - mix = 0.627f; - } - - { - float min_limit = 2.f * entropy->sum - entropy->max_val; - min_limit = mix * min_limit + (1.f - mix) * entropy->entropy; - return (entropy->entropy < min_limit) ? min_limit : entropy->entropy; - } -} - -float VP8LBitsEntropy(const uint32_t* const array, int n) { - VP8LBitEntropy entropy; - VP8LBitsEntropyUnrefined(array, n, &entropy); - - return BitsEntropyRefine(&entropy); -} - -static float InitialHuffmanCost(void) { - // Small bias because Huffman code length is typically not stored in - // full length. - static const int kHuffmanCodeOfHuffmanCodeSize = CODE_LENGTH_CODES * 3; - static const float kSmallBias = 9.1f; - return kHuffmanCodeOfHuffmanCodeSize - kSmallBias; -} - -// Finalize the Huffman cost based on streak numbers and length type (<3 or >=3) -static float FinalHuffmanCost(const VP8LStreaks* const stats) { - // The constants in this function are experimental and got rounded from - // their original values in 1/8 when switched to 1/1024. - float retval = InitialHuffmanCost(); - // Second coefficient: Many zeros in the histogram are covered efficiently - // by a run-length encode. Originally 2/8. - retval += stats->counts[0] * 1.5625f + 0.234375f * stats->streaks[0][1]; - // Second coefficient: Constant values are encoded less efficiently, but still - // RLE'ed. Originally 6/8. - retval += stats->counts[1] * 2.578125f + 0.703125f * stats->streaks[1][1]; - // 0s are usually encoded more efficiently than non-0s. - // Originally 15/8. - retval += 1.796875f * stats->streaks[0][0]; - // Originally 26/8. - retval += 3.28125f * stats->streaks[1][0]; - return retval; -} - -// Get the symbol entropy for the distribution 'population'. -// Set 'trivial_sym', if there's only one symbol present in the distribution. -static float PopulationCost(const uint32_t* const population, int length, - uint32_t* const trivial_sym, - uint8_t* const is_used) { - VP8LBitEntropy bit_entropy; - VP8LStreaks stats; - VP8LGetEntropyUnrefined(population, length, &bit_entropy, &stats); - if (trivial_sym != NULL) { - *trivial_sym = (bit_entropy.nonzeros == 1) ? bit_entropy.nonzero_code - : VP8L_NON_TRIVIAL_SYM; - } - // The histogram is used if there is at least one non-zero streak. - *is_used = (stats.streaks[1][0] != 0 || stats.streaks[1][1] != 0); - - return BitsEntropyRefine(&bit_entropy) + FinalHuffmanCost(&stats); -} - -// trivial_at_end is 1 if the two histograms only have one element that is -// non-zero: both the zero-th one, or both the last one. -static WEBP_INLINE float GetCombinedEntropy(const uint32_t* const X, - const uint32_t* const Y, int length, - int is_X_used, int is_Y_used, - int trivial_at_end) { - VP8LStreaks stats; - if (trivial_at_end) { - // This configuration is due to palettization that transforms an indexed - // pixel into 0xff000000 | (pixel << 8) in VP8LBundleColorMap. - // BitsEntropyRefine is 0 for histograms with only one non-zero value. - // Only FinalHuffmanCost needs to be evaluated. - memset(&stats, 0, sizeof(stats)); - // Deal with the non-zero value at index 0 or length-1. - stats.streaks[1][0] = 1; - // Deal with the following/previous zero streak. - stats.counts[0] = 1; - stats.streaks[0][1] = length - 1; - return FinalHuffmanCost(&stats); - } else { - VP8LBitEntropy bit_entropy; - if (is_X_used) { - if (is_Y_used) { - VP8LGetCombinedEntropyUnrefined(X, Y, length, &bit_entropy, &stats); - } else { - VP8LGetEntropyUnrefined(X, length, &bit_entropy, &stats); - } - } else { - if (is_Y_used) { - VP8LGetEntropyUnrefined(Y, length, &bit_entropy, &stats); - } else { - memset(&stats, 0, sizeof(stats)); - stats.counts[0] = 1; - stats.streaks[0][length > 3] = length; - VP8LBitEntropyInit(&bit_entropy); - } - } - - return BitsEntropyRefine(&bit_entropy) + FinalHuffmanCost(&stats); - } -} - -// Estimates the Entropy + Huffman + other block overhead size cost. -float VP8LHistogramEstimateBits(VP8LHistogram* const p) { - return PopulationCost(p->literal_, - VP8LHistogramNumCodes(p->palette_code_bits_), NULL, - &p->is_used_[0]) + - PopulationCost(p->red_, NUM_LITERAL_CODES, NULL, &p->is_used_[1]) + - PopulationCost(p->blue_, NUM_LITERAL_CODES, NULL, &p->is_used_[2]) + - PopulationCost(p->alpha_, NUM_LITERAL_CODES, NULL, &p->is_used_[3]) + - PopulationCost(p->distance_, NUM_DISTANCE_CODES, NULL, - &p->is_used_[4]) + - (float)VP8LExtraCost(p->literal_ + NUM_LITERAL_CODES, - NUM_LENGTH_CODES) + - (float)VP8LExtraCost(p->distance_, NUM_DISTANCE_CODES); -} - -// ----------------------------------------------------------------------------- -// Various histogram combine/cost-eval functions - -static int GetCombinedHistogramEntropy(const VP8LHistogram* const a, - const VP8LHistogram* const b, - float cost_threshold, float* cost) { - const int palette_code_bits = a->palette_code_bits_; - int trivial_at_end = 0; - assert(a->palette_code_bits_ == b->palette_code_bits_); - *cost += GetCombinedEntropy(a->literal_, b->literal_, - VP8LHistogramNumCodes(palette_code_bits), - a->is_used_[0], b->is_used_[0], 0); - *cost += (float)VP8LExtraCostCombined(a->literal_ + NUM_LITERAL_CODES, - b->literal_ + NUM_LITERAL_CODES, - NUM_LENGTH_CODES); - if (*cost > cost_threshold) return 0; - - if (a->trivial_symbol_ != VP8L_NON_TRIVIAL_SYM && - a->trivial_symbol_ == b->trivial_symbol_) { - // A, R and B are all 0 or 0xff. - const uint32_t color_a = (a->trivial_symbol_ >> 24) & 0xff; - const uint32_t color_r = (a->trivial_symbol_ >> 16) & 0xff; - const uint32_t color_b = (a->trivial_symbol_ >> 0) & 0xff; - if ((color_a == 0 || color_a == 0xff) && - (color_r == 0 || color_r == 0xff) && - (color_b == 0 || color_b == 0xff)) { - trivial_at_end = 1; - } - } - - *cost += - GetCombinedEntropy(a->red_, b->red_, NUM_LITERAL_CODES, a->is_used_[1], - b->is_used_[1], trivial_at_end); - if (*cost > cost_threshold) return 0; - - *cost += - GetCombinedEntropy(a->blue_, b->blue_, NUM_LITERAL_CODES, a->is_used_[2], - b->is_used_[2], trivial_at_end); - if (*cost > cost_threshold) return 0; - - *cost += - GetCombinedEntropy(a->alpha_, b->alpha_, NUM_LITERAL_CODES, - a->is_used_[3], b->is_used_[3], trivial_at_end); - if (*cost > cost_threshold) return 0; - - *cost += - GetCombinedEntropy(a->distance_, b->distance_, NUM_DISTANCE_CODES, - a->is_used_[4], b->is_used_[4], 0); - *cost += (float)VP8LExtraCostCombined(a->distance_, b->distance_, - NUM_DISTANCE_CODES); - if (*cost > cost_threshold) return 0; - - return 1; -} - -static WEBP_INLINE void HistogramAdd(const VP8LHistogram* const a, - const VP8LHistogram* const b, - VP8LHistogram* const out) { - VP8LHistogramAdd(a, b, out); - out->trivial_symbol_ = (a->trivial_symbol_ == b->trivial_symbol_) - ? a->trivial_symbol_ - : VP8L_NON_TRIVIAL_SYM; -} - -// Performs out = a + b, computing the cost C(a+b) - C(a) - C(b) while comparing -// to the threshold value 'cost_threshold'. The score returned is -// Score = C(a+b) - C(a) - C(b), where C(a) + C(b) is known and fixed. -// Since the previous score passed is 'cost_threshold', we only need to compare -// the partial cost against 'cost_threshold + C(a) + C(b)' to possibly bail-out -// early. -static float HistogramAddEval(const VP8LHistogram* const a, - const VP8LHistogram* const b, - VP8LHistogram* const out, float cost_threshold) { - float cost = 0; - const float sum_cost = a->bit_cost_ + b->bit_cost_; - cost_threshold += sum_cost; - - if (GetCombinedHistogramEntropy(a, b, cost_threshold, &cost)) { - HistogramAdd(a, b, out); - out->bit_cost_ = cost; - out->palette_code_bits_ = a->palette_code_bits_; - } - - return cost - sum_cost; -} - -// Same as HistogramAddEval(), except that the resulting histogram -// is not stored. Only the cost C(a+b) - C(a) is evaluated. We omit -// the term C(b) which is constant over all the evaluations. -static float HistogramAddThresh(const VP8LHistogram* const a, - const VP8LHistogram* const b, - float cost_threshold) { - float cost; - assert(a != NULL && b != NULL); - cost = -a->bit_cost_; - GetCombinedHistogramEntropy(a, b, cost_threshold, &cost); - return cost; -} - -// ----------------------------------------------------------------------------- - -// The structure to keep track of cost range for the three dominant entropy -// symbols. -typedef struct { - float literal_max_; - float literal_min_; - float red_max_; - float red_min_; - float blue_max_; - float blue_min_; -} DominantCostRange; - -static void DominantCostRangeInit(DominantCostRange* const c) { - c->literal_max_ = 0.; - c->literal_min_ = MAX_BIT_COST; - c->red_max_ = 0.; - c->red_min_ = MAX_BIT_COST; - c->blue_max_ = 0.; - c->blue_min_ = MAX_BIT_COST; -} - -static void UpdateDominantCostRange( - const VP8LHistogram* const h, DominantCostRange* const c) { - if (c->literal_max_ < h->literal_cost_) c->literal_max_ = h->literal_cost_; - if (c->literal_min_ > h->literal_cost_) c->literal_min_ = h->literal_cost_; - if (c->red_max_ < h->red_cost_) c->red_max_ = h->red_cost_; - if (c->red_min_ > h->red_cost_) c->red_min_ = h->red_cost_; - if (c->blue_max_ < h->blue_cost_) c->blue_max_ = h->blue_cost_; - if (c->blue_min_ > h->blue_cost_) c->blue_min_ = h->blue_cost_; -} - -static void UpdateHistogramCost(VP8LHistogram* const h) { - uint32_t alpha_sym, red_sym, blue_sym; - const float alpha_cost = - PopulationCost(h->alpha_, NUM_LITERAL_CODES, &alpha_sym, &h->is_used_[3]); - const float distance_cost = - PopulationCost(h->distance_, NUM_DISTANCE_CODES, NULL, &h->is_used_[4]) + - (float)VP8LExtraCost(h->distance_, NUM_DISTANCE_CODES); - const int num_codes = VP8LHistogramNumCodes(h->palette_code_bits_); - h->literal_cost_ = - PopulationCost(h->literal_, num_codes, NULL, &h->is_used_[0]) + - (float)VP8LExtraCost(h->literal_ + NUM_LITERAL_CODES, NUM_LENGTH_CODES); - h->red_cost_ = - PopulationCost(h->red_, NUM_LITERAL_CODES, &red_sym, &h->is_used_[1]); - h->blue_cost_ = - PopulationCost(h->blue_, NUM_LITERAL_CODES, &blue_sym, &h->is_used_[2]); - h->bit_cost_ = h->literal_cost_ + h->red_cost_ + h->blue_cost_ + - alpha_cost + distance_cost; - if ((alpha_sym | red_sym | blue_sym) == VP8L_NON_TRIVIAL_SYM) { - h->trivial_symbol_ = VP8L_NON_TRIVIAL_SYM; - } else { - h->trivial_symbol_ = - ((uint32_t)alpha_sym << 24) | (red_sym << 16) | (blue_sym << 0); - } -} - -static int GetBinIdForEntropy(float min, float max, float val) { - const float range = max - min; - if (range > 0.) { - const float delta = val - min; - return (int)((NUM_PARTITIONS - 1e-6) * delta / range); - } else { - return 0; - } -} - -static int GetHistoBinIndex(const VP8LHistogram* const h, - const DominantCostRange* const c, int low_effort) { - int bin_id = GetBinIdForEntropy(c->literal_min_, c->literal_max_, - h->literal_cost_); - assert(bin_id < NUM_PARTITIONS); - if (!low_effort) { - bin_id = bin_id * NUM_PARTITIONS - + GetBinIdForEntropy(c->red_min_, c->red_max_, h->red_cost_); - bin_id = bin_id * NUM_PARTITIONS - + GetBinIdForEntropy(c->blue_min_, c->blue_max_, h->blue_cost_); - assert(bin_id < BIN_SIZE); - } - return bin_id; -} - -// Construct the histograms from backward references. -static void HistogramBuild( - int xsize, int histo_bits, const VP8LBackwardRefs* const backward_refs, - VP8LHistogramSet* const image_histo) { - int x = 0, y = 0; - const int histo_xsize = VP8LSubSampleSize(xsize, histo_bits); - VP8LHistogram** const histograms = image_histo->histograms; - VP8LRefsCursor c = VP8LRefsCursorInit(backward_refs); - assert(histo_bits > 0); - VP8LHistogramSetClear(image_histo); - while (VP8LRefsCursorOk(&c)) { - const PixOrCopy* const v = c.cur_pos; - const int ix = (y >> histo_bits) * histo_xsize + (x >> histo_bits); - VP8LHistogramAddSinglePixOrCopy(histograms[ix], v, NULL, 0); - x += PixOrCopyLength(v); - while (x >= xsize) { - x -= xsize; - ++y; - } - VP8LRefsCursorNext(&c); - } -} - -// Copies the histograms and computes its bit_cost. -static const uint16_t kInvalidHistogramSymbol = (uint16_t)(-1); -static void HistogramCopyAndAnalyze(VP8LHistogramSet* const orig_histo, - VP8LHistogramSet* const image_histo, - int* const num_used, - uint16_t* const histogram_symbols) { - int i, cluster_id; - int num_used_orig = *num_used; - VP8LHistogram** const orig_histograms = orig_histo->histograms; - VP8LHistogram** const histograms = image_histo->histograms; - assert(image_histo->max_size == orig_histo->max_size); - for (cluster_id = 0, i = 0; i < orig_histo->max_size; ++i) { - VP8LHistogram* const histo = orig_histograms[i]; - UpdateHistogramCost(histo); - - // Skip the histogram if it is completely empty, which can happen for tiles - // with no information (when they are skipped because of LZ77). - if (!histo->is_used_[0] && !histo->is_used_[1] && !histo->is_used_[2] - && !histo->is_used_[3] && !histo->is_used_[4]) { - // The first histogram is always used. If an histogram is empty, we set - // its id to be the same as the previous one: this will improve - // compressibility for later LZ77. - assert(i > 0); - HistogramSetRemoveHistogram(image_histo, i, num_used); - HistogramSetRemoveHistogram(orig_histo, i, &num_used_orig); - histogram_symbols[i] = kInvalidHistogramSymbol; - } else { - // Copy histograms from orig_histo[] to image_histo[]. - HistogramCopy(histo, histograms[i]); - histogram_symbols[i] = cluster_id++; - assert(cluster_id <= image_histo->max_size); - } - } -} - -// Partition histograms to different entropy bins for three dominant (literal, -// red and blue) symbol costs and compute the histogram aggregate bit_cost. -static void HistogramAnalyzeEntropyBin(VP8LHistogramSet* const image_histo, - uint16_t* const bin_map, - int low_effort) { - int i; - VP8LHistogram** const histograms = image_histo->histograms; - const int histo_size = image_histo->size; - DominantCostRange cost_range; - DominantCostRangeInit(&cost_range); - - // Analyze the dominant (literal, red and blue) entropy costs. - for (i = 0; i < histo_size; ++i) { - if (histograms[i] == NULL) continue; - UpdateDominantCostRange(histograms[i], &cost_range); - } - - // bin-hash histograms on three of the dominant (literal, red and blue) - // symbol costs and store the resulting bin_id for each histogram. - for (i = 0; i < histo_size; ++i) { - // bin_map[i] is not set to a special value as its use will later be guarded - // by another (histograms[i] == NULL). - if (histograms[i] == NULL) continue; - bin_map[i] = GetHistoBinIndex(histograms[i], &cost_range, low_effort); - } -} - -// Merges some histograms with same bin_id together if it's advantageous. -// Sets the remaining histograms to NULL. -static void HistogramCombineEntropyBin( - VP8LHistogramSet* const image_histo, int* num_used, - const uint16_t* const clusters, uint16_t* const cluster_mappings, - VP8LHistogram* cur_combo, const uint16_t* const bin_map, int num_bins, - float combine_cost_factor, int low_effort) { - VP8LHistogram** const histograms = image_histo->histograms; - int idx; - struct { - int16_t first; // position of the histogram that accumulates all - // histograms with the same bin_id - uint16_t num_combine_failures; // number of combine failures per bin_id - } bin_info[BIN_SIZE]; - - assert(num_bins <= BIN_SIZE); - for (idx = 0; idx < num_bins; ++idx) { - bin_info[idx].first = -1; - bin_info[idx].num_combine_failures = 0; - } - - // By default, a cluster matches itself. - for (idx = 0; idx < *num_used; ++idx) cluster_mappings[idx] = idx; - for (idx = 0; idx < image_histo->size; ++idx) { - int bin_id, first; - if (histograms[idx] == NULL) continue; - bin_id = bin_map[idx]; - first = bin_info[bin_id].first; - if (first == -1) { - bin_info[bin_id].first = idx; - } else if (low_effort) { - HistogramAdd(histograms[idx], histograms[first], histograms[first]); - HistogramSetRemoveHistogram(image_histo, idx, num_used); - cluster_mappings[clusters[idx]] = clusters[first]; - } else { - // try to merge #idx into #first (both share the same bin_id) - const float bit_cost = histograms[idx]->bit_cost_; - const float bit_cost_thresh = -bit_cost * combine_cost_factor; - const float curr_cost_diff = HistogramAddEval( - histograms[first], histograms[idx], cur_combo, bit_cost_thresh); - if (curr_cost_diff < bit_cost_thresh) { - // Try to merge two histograms only if the combo is a trivial one or - // the two candidate histograms are already non-trivial. - // For some images, 'try_combine' turns out to be false for a lot of - // histogram pairs. In that case, we fallback to combining - // histograms as usual to avoid increasing the header size. - const int try_combine = - (cur_combo->trivial_symbol_ != VP8L_NON_TRIVIAL_SYM) || - ((histograms[idx]->trivial_symbol_ == VP8L_NON_TRIVIAL_SYM) && - (histograms[first]->trivial_symbol_ == VP8L_NON_TRIVIAL_SYM)); - const int max_combine_failures = 32; - if (try_combine || - bin_info[bin_id].num_combine_failures >= max_combine_failures) { - // move the (better) merged histogram to its final slot - HistogramSwap(&cur_combo, &histograms[first]); - HistogramSetRemoveHistogram(image_histo, idx, num_used); - cluster_mappings[clusters[idx]] = clusters[first]; - } else { - ++bin_info[bin_id].num_combine_failures; - } - } - } - } - if (low_effort) { - // for low_effort case, update the final cost when everything is merged - for (idx = 0; idx < image_histo->size; ++idx) { - if (histograms[idx] == NULL) continue; - UpdateHistogramCost(histograms[idx]); - } - } -} - -// Implement a Lehmer random number generator with a multiplicative constant of -// 48271 and a modulo constant of 2^31 - 1. -static uint32_t MyRand(uint32_t* const seed) { - *seed = (uint32_t)(((uint64_t)(*seed) * 48271u) % 2147483647u); - assert(*seed > 0); - return *seed; -} - -// ----------------------------------------------------------------------------- -// Histogram pairs priority queue - -// Pair of histograms. Negative idx1 value means that pair is out-of-date. -typedef struct { - int idx1; - int idx2; - float cost_diff; - float cost_combo; -} HistogramPair; - -typedef struct { - HistogramPair* queue; - int size; - int max_size; -} HistoQueue; - -static int HistoQueueInit(HistoQueue* const histo_queue, const int max_size) { - histo_queue->size = 0; - histo_queue->max_size = max_size; - // We allocate max_size + 1 because the last element at index "size" is - // used as temporary data (and it could be up to max_size). - histo_queue->queue = (HistogramPair*)WebPSafeMalloc( - histo_queue->max_size + 1, sizeof(*histo_queue->queue)); - return histo_queue->queue != NULL; -} - -static void HistoQueueClear(HistoQueue* const histo_queue) { - assert(histo_queue != NULL); - WebPSafeFree(histo_queue->queue); - histo_queue->size = 0; - histo_queue->max_size = 0; -} - -// Pop a specific pair in the queue by replacing it with the last one -// and shrinking the queue. -static void HistoQueuePopPair(HistoQueue* const histo_queue, - HistogramPair* const pair) { - assert(pair >= histo_queue->queue && - pair < (histo_queue->queue + histo_queue->size)); - assert(histo_queue->size > 0); - *pair = histo_queue->queue[histo_queue->size - 1]; - --histo_queue->size; -} - -// Check whether a pair in the queue should be updated as head or not. -static void HistoQueueUpdateHead(HistoQueue* const histo_queue, - HistogramPair* const pair) { - assert(pair->cost_diff < 0.); - assert(pair >= histo_queue->queue && - pair < (histo_queue->queue + histo_queue->size)); - assert(histo_queue->size > 0); - if (pair->cost_diff < histo_queue->queue[0].cost_diff) { - // Replace the best pair. - const HistogramPair tmp = histo_queue->queue[0]; - histo_queue->queue[0] = *pair; - *pair = tmp; - } -} - -// Update the cost diff and combo of a pair of histograms. This needs to be -// called when the the histograms have been merged with a third one. -static void HistoQueueUpdatePair(const VP8LHistogram* const h1, - const VP8LHistogram* const h2, float threshold, - HistogramPair* const pair) { - const float sum_cost = h1->bit_cost_ + h2->bit_cost_; - pair->cost_combo = 0.; - GetCombinedHistogramEntropy(h1, h2, sum_cost + threshold, &pair->cost_combo); - pair->cost_diff = pair->cost_combo - sum_cost; -} - -// Create a pair from indices "idx1" and "idx2" provided its cost -// is inferior to "threshold", a negative entropy. -// It returns the cost of the pair, or 0. if it superior to threshold. -static float HistoQueuePush(HistoQueue* const histo_queue, - VP8LHistogram** const histograms, int idx1, - int idx2, float threshold) { - const VP8LHistogram* h1; - const VP8LHistogram* h2; - HistogramPair pair; - - // Stop here if the queue is full. - if (histo_queue->size == histo_queue->max_size) return 0.; - assert(threshold <= 0.); - if (idx1 > idx2) { - const int tmp = idx2; - idx2 = idx1; - idx1 = tmp; - } - pair.idx1 = idx1; - pair.idx2 = idx2; - h1 = histograms[idx1]; - h2 = histograms[idx2]; - - HistoQueueUpdatePair(h1, h2, threshold, &pair); - - // Do not even consider the pair if it does not improve the entropy. - if (pair.cost_diff >= threshold) return 0.; - - histo_queue->queue[histo_queue->size++] = pair; - HistoQueueUpdateHead(histo_queue, &histo_queue->queue[histo_queue->size - 1]); - - return pair.cost_diff; -} - -// ----------------------------------------------------------------------------- - -// Combines histograms by continuously choosing the one with the highest cost -// reduction. -static int HistogramCombineGreedy(VP8LHistogramSet* const image_histo, - int* const num_used) { - int ok = 0; - const int image_histo_size = image_histo->size; - int i, j; - VP8LHistogram** const histograms = image_histo->histograms; - // Priority queue of histogram pairs. - HistoQueue histo_queue; - - // image_histo_size^2 for the queue size is safe. If you look at - // HistogramCombineGreedy, and imagine that UpdateQueueFront always pushes - // data to the queue, you insert at most: - // - image_histo_size*(image_histo_size-1)/2 (the first two for loops) - // - image_histo_size - 1 in the last for loop at the first iteration of - // the while loop, image_histo_size - 2 at the second iteration ... - // therefore image_histo_size*(image_histo_size-1)/2 overall too - if (!HistoQueueInit(&histo_queue, image_histo_size * image_histo_size)) { - goto End; - } - - for (i = 0; i < image_histo_size; ++i) { - if (image_histo->histograms[i] == NULL) continue; - for (j = i + 1; j < image_histo_size; ++j) { - // Initialize queue. - if (image_histo->histograms[j] == NULL) continue; - HistoQueuePush(&histo_queue, histograms, i, j, 0.); - } - } - - while (histo_queue.size > 0) { - const int idx1 = histo_queue.queue[0].idx1; - const int idx2 = histo_queue.queue[0].idx2; - HistogramAdd(histograms[idx2], histograms[idx1], histograms[idx1]); - histograms[idx1]->bit_cost_ = histo_queue.queue[0].cost_combo; - - // Remove merged histogram. - HistogramSetRemoveHistogram(image_histo, idx2, num_used); - - // Remove pairs intersecting the just combined best pair. - for (i = 0; i < histo_queue.size;) { - HistogramPair* const p = histo_queue.queue + i; - if (p->idx1 == idx1 || p->idx2 == idx1 || - p->idx1 == idx2 || p->idx2 == idx2) { - HistoQueuePopPair(&histo_queue, p); - } else { - HistoQueueUpdateHead(&histo_queue, p); - ++i; - } - } - - // Push new pairs formed with combined histogram to the queue. - for (i = 0; i < image_histo->size; ++i) { - if (i == idx1 || image_histo->histograms[i] == NULL) continue; - HistoQueuePush(&histo_queue, image_histo->histograms, idx1, i, 0.); - } - } - - ok = 1; - - End: - HistoQueueClear(&histo_queue); - return ok; -} - -// Perform histogram aggregation using a stochastic approach. -// 'do_greedy' is set to 1 if a greedy approach needs to be performed -// afterwards, 0 otherwise. -static int PairComparison(const void* idx1, const void* idx2) { - // To be used with bsearch: <0 when *idx1<*idx2, >0 if >, 0 when ==. - return (*(int*) idx1 - *(int*) idx2); -} -static int HistogramCombineStochastic(VP8LHistogramSet* const image_histo, - int* const num_used, int min_cluster_size, - int* const do_greedy) { - int j, iter; - uint32_t seed = 1; - int tries_with_no_success = 0; - const int outer_iters = *num_used; - const int num_tries_no_success = outer_iters / 2; - VP8LHistogram** const histograms = image_histo->histograms; - // Priority queue of histogram pairs. Its size of 'kHistoQueueSize' - // impacts the quality of the compression and the speed: the smaller the - // faster but the worse for the compression. - HistoQueue histo_queue; - const int kHistoQueueSize = 9; - int ok = 0; - // mapping from an index in image_histo with no NULL histogram to the full - // blown image_histo. - int* mappings; - - if (*num_used < min_cluster_size) { - *do_greedy = 1; - return 1; - } - - mappings = (int*) WebPSafeMalloc(*num_used, sizeof(*mappings)); - if (mappings == NULL) return 0; - if (!HistoQueueInit(&histo_queue, kHistoQueueSize)) goto End; - // Fill the initial mapping. - for (j = 0, iter = 0; iter < image_histo->size; ++iter) { - if (histograms[iter] == NULL) continue; - mappings[j++] = iter; - } - assert(j == *num_used); - - // Collapse similar histograms in 'image_histo'. - for (iter = 0; - iter < outer_iters && *num_used >= min_cluster_size && - ++tries_with_no_success < num_tries_no_success; - ++iter) { - int* mapping_index; - float best_cost = - (histo_queue.size == 0) ? 0.f : histo_queue.queue[0].cost_diff; - int best_idx1 = -1, best_idx2 = 1; - const uint32_t rand_range = (*num_used - 1) * (*num_used); - // (*num_used) / 2 was chosen empirically. Less means faster but worse - // compression. - const int num_tries = (*num_used) / 2; - - // Pick random samples. - for (j = 0; *num_used >= 2 && j < num_tries; ++j) { - float curr_cost; - // Choose two different histograms at random and try to combine them. - const uint32_t tmp = MyRand(&seed) % rand_range; - uint32_t idx1 = tmp / (*num_used - 1); - uint32_t idx2 = tmp % (*num_used - 1); - if (idx2 >= idx1) ++idx2; - idx1 = mappings[idx1]; - idx2 = mappings[idx2]; - - // Calculate cost reduction on combination. - curr_cost = - HistoQueuePush(&histo_queue, histograms, idx1, idx2, best_cost); - if (curr_cost < 0) { // found a better pair? - best_cost = curr_cost; - // Empty the queue if we reached full capacity. - if (histo_queue.size == histo_queue.max_size) break; - } - } - if (histo_queue.size == 0) continue; - - // Get the best histograms. - best_idx1 = histo_queue.queue[0].idx1; - best_idx2 = histo_queue.queue[0].idx2; - assert(best_idx1 < best_idx2); - // Pop best_idx2 from mappings. - mapping_index = (int*) bsearch(&best_idx2, mappings, *num_used, - sizeof(best_idx2), &PairComparison); - assert(mapping_index != NULL); - memmove(mapping_index, mapping_index + 1, sizeof(*mapping_index) * - ((*num_used) - (mapping_index - mappings) - 1)); - // Merge the histograms and remove best_idx2 from the queue. - HistogramAdd(histograms[best_idx2], histograms[best_idx1], - histograms[best_idx1]); - histograms[best_idx1]->bit_cost_ = histo_queue.queue[0].cost_combo; - HistogramSetRemoveHistogram(image_histo, best_idx2, num_used); - // Parse the queue and update each pair that deals with best_idx1, - // best_idx2 or image_histo_size. - for (j = 0; j < histo_queue.size;) { - HistogramPair* const p = histo_queue.queue + j; - const int is_idx1_best = p->idx1 == best_idx1 || p->idx1 == best_idx2; - const int is_idx2_best = p->idx2 == best_idx1 || p->idx2 == best_idx2; - int do_eval = 0; - // The front pair could have been duplicated by a random pick so - // check for it all the time nevertheless. - if (is_idx1_best && is_idx2_best) { - HistoQueuePopPair(&histo_queue, p); - continue; - } - // Any pair containing one of the two best indices should only refer to - // best_idx1. Its cost should also be updated. - if (is_idx1_best) { - p->idx1 = best_idx1; - do_eval = 1; - } else if (is_idx2_best) { - p->idx2 = best_idx1; - do_eval = 1; - } - // Make sure the index order is respected. - if (p->idx1 > p->idx2) { - const int tmp = p->idx2; - p->idx2 = p->idx1; - p->idx1 = tmp; - } - if (do_eval) { - // Re-evaluate the cost of an updated pair. - HistoQueueUpdatePair(histograms[p->idx1], histograms[p->idx2], 0., p); - if (p->cost_diff >= 0.) { - HistoQueuePopPair(&histo_queue, p); - continue; - } - } - HistoQueueUpdateHead(&histo_queue, p); - ++j; - } - tries_with_no_success = 0; - } - *do_greedy = (*num_used <= min_cluster_size); - ok = 1; - - End: - HistoQueueClear(&histo_queue); - WebPSafeFree(mappings); - return ok; -} - -// ----------------------------------------------------------------------------- -// Histogram refinement - -// Find the best 'out' histogram for each of the 'in' histograms. -// At call-time, 'out' contains the histograms of the clusters. -// Note: we assume that out[]->bit_cost_ is already up-to-date. -static void HistogramRemap(const VP8LHistogramSet* const in, - VP8LHistogramSet* const out, - uint16_t* const symbols) { - int i; - VP8LHistogram** const in_histo = in->histograms; - VP8LHistogram** const out_histo = out->histograms; - const int in_size = out->max_size; - const int out_size = out->size; - if (out_size > 1) { - for (i = 0; i < in_size; ++i) { - int best_out = 0; - float best_bits = MAX_BIT_COST; - int k; - if (in_histo[i] == NULL) { - // Arbitrarily set to the previous value if unused to help future LZ77. - symbols[i] = symbols[i - 1]; - continue; - } - for (k = 0; k < out_size; ++k) { - float cur_bits; - cur_bits = HistogramAddThresh(out_histo[k], in_histo[i], best_bits); - if (k == 0 || cur_bits < best_bits) { - best_bits = cur_bits; - best_out = k; - } - } - symbols[i] = best_out; - } - } else { - assert(out_size == 1); - for (i = 0; i < in_size; ++i) { - symbols[i] = 0; - } - } - - // Recompute each out based on raw and symbols. - VP8LHistogramSetClear(out); - out->size = out_size; - - for (i = 0; i < in_size; ++i) { - int idx; - if (in_histo[i] == NULL) continue; - idx = symbols[i]; - HistogramAdd(in_histo[i], out_histo[idx], out_histo[idx]); - } -} - -static float GetCombineCostFactor(int histo_size, int quality) { - float combine_cost_factor = 0.16f; - if (quality < 90) { - if (histo_size > 256) combine_cost_factor /= 2.f; - if (histo_size > 512) combine_cost_factor /= 2.f; - if (histo_size > 1024) combine_cost_factor /= 2.f; - if (quality <= 50) combine_cost_factor /= 2.f; - } - return combine_cost_factor; -} - -// Given a HistogramSet 'set', the mapping of clusters 'cluster_mapping' and the -// current assignment of the cells in 'symbols', merge the clusters and -// assign the smallest possible clusters values. -static void OptimizeHistogramSymbols(const VP8LHistogramSet* const set, - uint16_t* const cluster_mappings, - int num_clusters, - uint16_t* const cluster_mappings_tmp, - uint16_t* const symbols) { - int i, cluster_max; - int do_continue = 1; - // First, assign the lowest cluster to each pixel. - while (do_continue) { - do_continue = 0; - for (i = 0; i < num_clusters; ++i) { - int k; - k = cluster_mappings[i]; - while (k != cluster_mappings[k]) { - cluster_mappings[k] = cluster_mappings[cluster_mappings[k]]; - k = cluster_mappings[k]; - } - if (k != cluster_mappings[i]) { - do_continue = 1; - cluster_mappings[i] = k; - } - } - } - // Create a mapping from a cluster id to its minimal version. - cluster_max = 0; - memset(cluster_mappings_tmp, 0, - set->max_size * sizeof(*cluster_mappings_tmp)); - assert(cluster_mappings[0] == 0); - // Re-map the ids. - for (i = 0; i < set->max_size; ++i) { - int cluster; - if (symbols[i] == kInvalidHistogramSymbol) continue; - cluster = cluster_mappings[symbols[i]]; - assert(symbols[i] < num_clusters); - if (cluster > 0 && cluster_mappings_tmp[cluster] == 0) { - ++cluster_max; - cluster_mappings_tmp[cluster] = cluster_max; - } - symbols[i] = cluster_mappings_tmp[cluster]; - } - - // Make sure all cluster values are used. - cluster_max = 0; - for (i = 0; i < set->max_size; ++i) { - if (symbols[i] == kInvalidHistogramSymbol) continue; - if (symbols[i] <= cluster_max) continue; - ++cluster_max; - assert(symbols[i] == cluster_max); - } -} - -static void RemoveEmptyHistograms(VP8LHistogramSet* const image_histo) { - uint32_t size; - int i; - for (i = 0, size = 0; i < image_histo->size; ++i) { - if (image_histo->histograms[i] == NULL) continue; - image_histo->histograms[size++] = image_histo->histograms[i]; - } - image_histo->size = size; -} - -int VP8LGetHistoImageSymbols(int xsize, int ysize, - const VP8LBackwardRefs* const refs, int quality, - int low_effort, int histogram_bits, int cache_bits, - VP8LHistogramSet* const image_histo, - VP8LHistogram* const tmp_histo, - uint16_t* const histogram_symbols, - const WebPPicture* const pic, int percent_range, - int* const percent) { - const int histo_xsize = - histogram_bits ? VP8LSubSampleSize(xsize, histogram_bits) : 1; - const int histo_ysize = - histogram_bits ? VP8LSubSampleSize(ysize, histogram_bits) : 1; - const int image_histo_raw_size = histo_xsize * histo_ysize; - VP8LHistogramSet* const orig_histo = - VP8LAllocateHistogramSet(image_histo_raw_size, cache_bits); - // Don't attempt linear bin-partition heuristic for - // histograms of small sizes (as bin_map will be very sparse) and - // maximum quality q==100 (to preserve the compression gains at that level). - const int entropy_combine_num_bins = low_effort ? NUM_PARTITIONS : BIN_SIZE; - int entropy_combine; - uint16_t* const map_tmp = - WebPSafeMalloc(2 * image_histo_raw_size, sizeof(*map_tmp)); - uint16_t* const cluster_mappings = map_tmp + image_histo_raw_size; - int num_used = image_histo_raw_size; - if (orig_histo == NULL || map_tmp == NULL) { - WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); - goto Error; - } - - // Construct the histograms from backward references. - HistogramBuild(xsize, histogram_bits, refs, orig_histo); - // Copies the histograms and computes its bit_cost. - // histogram_symbols is optimized - HistogramCopyAndAnalyze(orig_histo, image_histo, &num_used, - histogram_symbols); - - entropy_combine = - (num_used > entropy_combine_num_bins * 2) && (quality < 100); - - if (entropy_combine) { - uint16_t* const bin_map = map_tmp; - const float combine_cost_factor = - GetCombineCostFactor(image_histo_raw_size, quality); - const uint32_t num_clusters = num_used; - - HistogramAnalyzeEntropyBin(image_histo, bin_map, low_effort); - // Collapse histograms with similar entropy. - HistogramCombineEntropyBin( - image_histo, &num_used, histogram_symbols, cluster_mappings, tmp_histo, - bin_map, entropy_combine_num_bins, combine_cost_factor, low_effort); - OptimizeHistogramSymbols(image_histo, cluster_mappings, num_clusters, - map_tmp, histogram_symbols); - } - - // Don't combine the histograms using stochastic and greedy heuristics for - // low-effort compression mode. - if (!low_effort || !entropy_combine) { - const float x = quality / 100.f; - // cubic ramp between 1 and MAX_HISTO_GREEDY: - const int threshold_size = (int)(1 + (x * x * x) * (MAX_HISTO_GREEDY - 1)); - int do_greedy; - if (!HistogramCombineStochastic(image_histo, &num_used, threshold_size, - &do_greedy)) { - WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); - goto Error; - } - if (do_greedy) { - RemoveEmptyHistograms(image_histo); - if (!HistogramCombineGreedy(image_histo, &num_used)) { - WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); - goto Error; - } - } - } - - // Find the optimal map from original histograms to the final ones. - RemoveEmptyHistograms(image_histo); - HistogramRemap(orig_histo, image_histo, histogram_symbols); - - if (!WebPReportProgress(pic, *percent + percent_range, percent)) { - goto Error; - } - - Error: - VP8LFreeHistogramSet(orig_histo); - WebPSafeFree(map_tmp); - return (pic->error_code == VP8_ENC_OK); -} diff --git a/libwebp/src/enc/histogram_enc.h b/libwebp/src/enc/histogram_enc.h deleted file mode 100644 index 4c0bb974..00000000 --- a/libwebp/src/enc/histogram_enc.h +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright 2012 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Author: Jyrki Alakuijala (jyrki@google.com) -// -// Models the histograms of literal and distance codes. - -#ifndef WEBP_ENC_HISTOGRAM_ENC_H_ -#define WEBP_ENC_HISTOGRAM_ENC_H_ - -#include - -#include "src/enc/backward_references_enc.h" -#include "src/webp/format_constants.h" -#include "src/webp/types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -// Not a trivial literal symbol. -#define VP8L_NON_TRIVIAL_SYM (0xffffffff) - -// A simple container for histograms of data. -typedef struct { - // literal_ contains green literal, palette-code and - // copy-length-prefix histogram - uint32_t* literal_; // Pointer to the allocated buffer for literal. - uint32_t red_[NUM_LITERAL_CODES]; - uint32_t blue_[NUM_LITERAL_CODES]; - uint32_t alpha_[NUM_LITERAL_CODES]; - // Backward reference prefix-code histogram. - uint32_t distance_[NUM_DISTANCE_CODES]; - int palette_code_bits_; - uint32_t trivial_symbol_; // True, if histograms for Red, Blue & Alpha - // literal symbols are single valued. - float bit_cost_; // cached value of bit cost. - float literal_cost_; // Cached values of dominant entropy costs: - float red_cost_; // literal, red & blue. - float blue_cost_; - uint8_t is_used_[5]; // 5 for literal, red, blue, alpha, distance -} VP8LHistogram; - -// Collection of histograms with fixed capacity, allocated as one -// big memory chunk. Can be destroyed by calling WebPSafeFree(). -typedef struct { - int size; // number of slots currently in use - int max_size; // maximum capacity - VP8LHistogram** histograms; -} VP8LHistogramSet; - -// Create the histogram. -// -// The input data is the PixOrCopy data, which models the literals, stop -// codes and backward references (both distances and lengths). Also: if -// palette_code_bits is >= 0, initialize the histogram with this value. -void VP8LHistogramCreate(VP8LHistogram* const p, - const VP8LBackwardRefs* const refs, - int palette_code_bits); - -// Return the size of the histogram for a given cache_bits. -int VP8LGetHistogramSize(int cache_bits); - -// Set the palette_code_bits and reset the stats. -// If init_arrays is true, the arrays are also filled with 0's. -void VP8LHistogramInit(VP8LHistogram* const p, int palette_code_bits, - int init_arrays); - -// Collect all the references into a histogram (without reset) -void VP8LHistogramStoreRefs(const VP8LBackwardRefs* const refs, - VP8LHistogram* const histo); - -// Free the memory allocated for the histogram. -void VP8LFreeHistogram(VP8LHistogram* const histo); - -// Free the memory allocated for the histogram set. -void VP8LFreeHistogramSet(VP8LHistogramSet* const histo); - -// Allocate an array of pointer to histograms, allocated and initialized -// using 'cache_bits'. Return NULL in case of memory error. -VP8LHistogramSet* VP8LAllocateHistogramSet(int size, int cache_bits); - -// Set the histograms in set to 0. -void VP8LHistogramSetClear(VP8LHistogramSet* const set); - -// Allocate and initialize histogram object with specified 'cache_bits'. -// Returns NULL in case of memory error. -// Special case of VP8LAllocateHistogramSet, with size equals 1. -VP8LHistogram* VP8LAllocateHistogram(int cache_bits); - -// Accumulate a token 'v' into a histogram. -void VP8LHistogramAddSinglePixOrCopy(VP8LHistogram* const histo, - const PixOrCopy* const v, - int (*const distance_modifier)(int, int), - int distance_modifier_arg0); - -static WEBP_INLINE int VP8LHistogramNumCodes(int palette_code_bits) { - return NUM_LITERAL_CODES + NUM_LENGTH_CODES + - ((palette_code_bits > 0) ? (1 << palette_code_bits) : 0); -} - -// Builds the histogram image. pic and percent are for progress. -// Returns false in case of error (stored in pic->error_code). -int VP8LGetHistoImageSymbols(int xsize, int ysize, - const VP8LBackwardRefs* const refs, int quality, - int low_effort, int histogram_bits, int cache_bits, - VP8LHistogramSet* const image_histo, - VP8LHistogram* const tmp_histo, - uint16_t* const histogram_symbols, - const WebPPicture* const pic, int percent_range, - int* const percent); - -// Returns the entropy for the symbols in the input array. -float VP8LBitsEntropy(const uint32_t* const array, int n); - -// Estimate how many bits the combined entropy of literals and distance -// approximately maps to. -float VP8LHistogramEstimateBits(VP8LHistogram* const p); - -#ifdef __cplusplus -} -#endif - -#endif // WEBP_ENC_HISTOGRAM_ENC_H_ diff --git a/libwebp/src/enc/iterator_enc.c b/libwebp/src/enc/iterator_enc.c deleted file mode 100644 index 29f91d83..00000000 --- a/libwebp/src/enc/iterator_enc.c +++ /dev/null @@ -1,459 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// VP8Iterator: block iterator -// -// Author: Skal (pascal.massimino@gmail.com) - -#include - -#include "src/enc/vp8i_enc.h" - -//------------------------------------------------------------------------------ -// VP8Iterator -//------------------------------------------------------------------------------ - -static void InitLeft(VP8EncIterator* const it) { - it->y_left_[-1] = it->u_left_[-1] = it->v_left_[-1] = - (it->y_ > 0) ? 129 : 127; - memset(it->y_left_, 129, 16); - memset(it->u_left_, 129, 8); - memset(it->v_left_, 129, 8); - it->left_nz_[8] = 0; - if (it->top_derr_ != NULL) { - memset(&it->left_derr_, 0, sizeof(it->left_derr_)); - } -} - -static void InitTop(VP8EncIterator* const it) { - const VP8Encoder* const enc = it->enc_; - const size_t top_size = enc->mb_w_ * 16; - memset(enc->y_top_, 127, 2 * top_size); - memset(enc->nz_, 0, enc->mb_w_ * sizeof(*enc->nz_)); - if (enc->top_derr_ != NULL) { - memset(enc->top_derr_, 0, enc->mb_w_ * sizeof(*enc->top_derr_)); - } -} - -void VP8IteratorSetRow(VP8EncIterator* const it, int y) { - VP8Encoder* const enc = it->enc_; - it->x_ = 0; - it->y_ = y; - it->bw_ = &enc->parts_[y & (enc->num_parts_ - 1)]; - it->preds_ = enc->preds_ + y * 4 * enc->preds_w_; - it->nz_ = enc->nz_; - it->mb_ = enc->mb_info_ + y * enc->mb_w_; - it->y_top_ = enc->y_top_; - it->uv_top_ = enc->uv_top_; - InitLeft(it); -} - -void VP8IteratorReset(VP8EncIterator* const it) { - VP8Encoder* const enc = it->enc_; - VP8IteratorSetRow(it, 0); - VP8IteratorSetCountDown(it, enc->mb_w_ * enc->mb_h_); // default - InitTop(it); - memset(it->bit_count_, 0, sizeof(it->bit_count_)); - it->do_trellis_ = 0; -} - -void VP8IteratorSetCountDown(VP8EncIterator* const it, int count_down) { - it->count_down_ = it->count_down0_ = count_down; -} - -int VP8IteratorIsDone(const VP8EncIterator* const it) { - return (it->count_down_ <= 0); -} - -void VP8IteratorInit(VP8Encoder* const enc, VP8EncIterator* const it) { - it->enc_ = enc; - it->yuv_in_ = (uint8_t*)WEBP_ALIGN(it->yuv_mem_); - it->yuv_out_ = it->yuv_in_ + YUV_SIZE_ENC; - it->yuv_out2_ = it->yuv_out_ + YUV_SIZE_ENC; - it->yuv_p_ = it->yuv_out2_ + YUV_SIZE_ENC; - it->lf_stats_ = enc->lf_stats_; - it->percent0_ = enc->percent_; - it->y_left_ = (uint8_t*)WEBP_ALIGN(it->yuv_left_mem_ + 1); - it->u_left_ = it->y_left_ + 16 + 16; - it->v_left_ = it->u_left_ + 16; - it->top_derr_ = enc->top_derr_; - VP8IteratorReset(it); -} - -int VP8IteratorProgress(const VP8EncIterator* const it, int delta) { - VP8Encoder* const enc = it->enc_; - if (delta && enc->pic_->progress_hook != NULL) { - const int done = it->count_down0_ - it->count_down_; - const int percent = (it->count_down0_ <= 0) - ? it->percent0_ - : it->percent0_ + delta * done / it->count_down0_; - return WebPReportProgress(enc->pic_, percent, &enc->percent_); - } - return 1; -} - -//------------------------------------------------------------------------------ -// Import the source samples into the cache. Takes care of replicating -// boundary pixels if necessary. - -static WEBP_INLINE int MinSize(int a, int b) { return (a < b) ? a : b; } - -static void ImportBlock(const uint8_t* src, int src_stride, - uint8_t* dst, int w, int h, int size) { - int i; - for (i = 0; i < h; ++i) { - memcpy(dst, src, w); - if (w < size) { - memset(dst + w, dst[w - 1], size - w); - } - dst += BPS; - src += src_stride; - } - for (i = h; i < size; ++i) { - memcpy(dst, dst - BPS, size); - dst += BPS; - } -} - -static void ImportLine(const uint8_t* src, int src_stride, - uint8_t* dst, int len, int total_len) { - int i; - for (i = 0; i < len; ++i, src += src_stride) dst[i] = *src; - for (; i < total_len; ++i) dst[i] = dst[len - 1]; -} - -void VP8IteratorImport(VP8EncIterator* const it, uint8_t* const tmp_32) { - const VP8Encoder* const enc = it->enc_; - const int x = it->x_, y = it->y_; - const WebPPicture* const pic = enc->pic_; - const uint8_t* const ysrc = pic->y + (y * pic->y_stride + x) * 16; - const uint8_t* const usrc = pic->u + (y * pic->uv_stride + x) * 8; - const uint8_t* const vsrc = pic->v + (y * pic->uv_stride + x) * 8; - const int w = MinSize(pic->width - x * 16, 16); - const int h = MinSize(pic->height - y * 16, 16); - const int uv_w = (w + 1) >> 1; - const int uv_h = (h + 1) >> 1; - - ImportBlock(ysrc, pic->y_stride, it->yuv_in_ + Y_OFF_ENC, w, h, 16); - ImportBlock(usrc, pic->uv_stride, it->yuv_in_ + U_OFF_ENC, uv_w, uv_h, 8); - ImportBlock(vsrc, pic->uv_stride, it->yuv_in_ + V_OFF_ENC, uv_w, uv_h, 8); - - if (tmp_32 == NULL) return; - - // Import source (uncompressed) samples into boundary. - if (x == 0) { - InitLeft(it); - } else { - if (y == 0) { - it->y_left_[-1] = it->u_left_[-1] = it->v_left_[-1] = 127; - } else { - it->y_left_[-1] = ysrc[- 1 - pic->y_stride]; - it->u_left_[-1] = usrc[- 1 - pic->uv_stride]; - it->v_left_[-1] = vsrc[- 1 - pic->uv_stride]; - } - ImportLine(ysrc - 1, pic->y_stride, it->y_left_, h, 16); - ImportLine(usrc - 1, pic->uv_stride, it->u_left_, uv_h, 8); - ImportLine(vsrc - 1, pic->uv_stride, it->v_left_, uv_h, 8); - } - - it->y_top_ = tmp_32 + 0; - it->uv_top_ = tmp_32 + 16; - if (y == 0) { - memset(tmp_32, 127, 32 * sizeof(*tmp_32)); - } else { - ImportLine(ysrc - pic->y_stride, 1, tmp_32, w, 16); - ImportLine(usrc - pic->uv_stride, 1, tmp_32 + 16, uv_w, 8); - ImportLine(vsrc - pic->uv_stride, 1, tmp_32 + 16 + 8, uv_w, 8); - } -} - -//------------------------------------------------------------------------------ -// Copy back the compressed samples into user space if requested. - -static void ExportBlock(const uint8_t* src, uint8_t* dst, int dst_stride, - int w, int h) { - while (h-- > 0) { - memcpy(dst, src, w); - dst += dst_stride; - src += BPS; - } -} - -void VP8IteratorExport(const VP8EncIterator* const it) { - const VP8Encoder* const enc = it->enc_; - if (enc->config_->show_compressed) { - const int x = it->x_, y = it->y_; - const uint8_t* const ysrc = it->yuv_out_ + Y_OFF_ENC; - const uint8_t* const usrc = it->yuv_out_ + U_OFF_ENC; - const uint8_t* const vsrc = it->yuv_out_ + V_OFF_ENC; - const WebPPicture* const pic = enc->pic_; - uint8_t* const ydst = pic->y + (y * pic->y_stride + x) * 16; - uint8_t* const udst = pic->u + (y * pic->uv_stride + x) * 8; - uint8_t* const vdst = pic->v + (y * pic->uv_stride + x) * 8; - int w = (pic->width - x * 16); - int h = (pic->height - y * 16); - - if (w > 16) w = 16; - if (h > 16) h = 16; - - // Luma plane - ExportBlock(ysrc, ydst, pic->y_stride, w, h); - - { // U/V planes - const int uv_w = (w + 1) >> 1; - const int uv_h = (h + 1) >> 1; - ExportBlock(usrc, udst, pic->uv_stride, uv_w, uv_h); - ExportBlock(vsrc, vdst, pic->uv_stride, uv_w, uv_h); - } - } -} - -//------------------------------------------------------------------------------ -// Non-zero contexts setup/teardown - -// Nz bits: -// 0 1 2 3 Y -// 4 5 6 7 -// 8 9 10 11 -// 12 13 14 15 -// 16 17 U -// 18 19 -// 20 21 V -// 22 23 -// 24 DC-intra16 - -// Convert packed context to byte array -#define BIT(nz, n) (!!((nz) & (1 << (n)))) - -void VP8IteratorNzToBytes(VP8EncIterator* const it) { - const int tnz = it->nz_[0], lnz = it->nz_[-1]; - int* const top_nz = it->top_nz_; - int* const left_nz = it->left_nz_; - - // Top-Y - top_nz[0] = BIT(tnz, 12); - top_nz[1] = BIT(tnz, 13); - top_nz[2] = BIT(tnz, 14); - top_nz[3] = BIT(tnz, 15); - // Top-U - top_nz[4] = BIT(tnz, 18); - top_nz[5] = BIT(tnz, 19); - // Top-V - top_nz[6] = BIT(tnz, 22); - top_nz[7] = BIT(tnz, 23); - // DC - top_nz[8] = BIT(tnz, 24); - - // left-Y - left_nz[0] = BIT(lnz, 3); - left_nz[1] = BIT(lnz, 7); - left_nz[2] = BIT(lnz, 11); - left_nz[3] = BIT(lnz, 15); - // left-U - left_nz[4] = BIT(lnz, 17); - left_nz[5] = BIT(lnz, 19); - // left-V - left_nz[6] = BIT(lnz, 21); - left_nz[7] = BIT(lnz, 23); - // left-DC is special, iterated separately -} - -void VP8IteratorBytesToNz(VP8EncIterator* const it) { - uint32_t nz = 0; - const int* const top_nz = it->top_nz_; - const int* const left_nz = it->left_nz_; - // top - nz |= (top_nz[0] << 12) | (top_nz[1] << 13); - nz |= (top_nz[2] << 14) | (top_nz[3] << 15); - nz |= (top_nz[4] << 18) | (top_nz[5] << 19); - nz |= (top_nz[6] << 22) | (top_nz[7] << 23); - nz |= (top_nz[8] << 24); // we propagate the _top_ bit, esp. for intra4 - // left - nz |= (left_nz[0] << 3) | (left_nz[1] << 7); - nz |= (left_nz[2] << 11); - nz |= (left_nz[4] << 17) | (left_nz[6] << 21); - - *it->nz_ = nz; -} - -#undef BIT - -//------------------------------------------------------------------------------ -// Advance to the next position, doing the bookkeeping. - -void VP8IteratorSaveBoundary(VP8EncIterator* const it) { - VP8Encoder* const enc = it->enc_; - const int x = it->x_, y = it->y_; - const uint8_t* const ysrc = it->yuv_out_ + Y_OFF_ENC; - const uint8_t* const uvsrc = it->yuv_out_ + U_OFF_ENC; - if (x < enc->mb_w_ - 1) { // left - int i; - for (i = 0; i < 16; ++i) { - it->y_left_[i] = ysrc[15 + i * BPS]; - } - for (i = 0; i < 8; ++i) { - it->u_left_[i] = uvsrc[7 + i * BPS]; - it->v_left_[i] = uvsrc[15 + i * BPS]; - } - // top-left (before 'top'!) - it->y_left_[-1] = it->y_top_[15]; - it->u_left_[-1] = it->uv_top_[0 + 7]; - it->v_left_[-1] = it->uv_top_[8 + 7]; - } - if (y < enc->mb_h_ - 1) { // top - memcpy(it->y_top_, ysrc + 15 * BPS, 16); - memcpy(it->uv_top_, uvsrc + 7 * BPS, 8 + 8); - } -} - -int VP8IteratorNext(VP8EncIterator* const it) { - if (++it->x_ == it->enc_->mb_w_) { - VP8IteratorSetRow(it, ++it->y_); - } else { - it->preds_ += 4; - it->mb_ += 1; - it->nz_ += 1; - it->y_top_ += 16; - it->uv_top_ += 16; - } - return (0 < --it->count_down_); -} - -//------------------------------------------------------------------------------ -// Helper function to set mode properties - -void VP8SetIntra16Mode(const VP8EncIterator* const it, int mode) { - uint8_t* preds = it->preds_; - int y; - for (y = 0; y < 4; ++y) { - memset(preds, mode, 4); - preds += it->enc_->preds_w_; - } - it->mb_->type_ = 1; -} - -void VP8SetIntra4Mode(const VP8EncIterator* const it, const uint8_t* modes) { - uint8_t* preds = it->preds_; - int y; - for (y = 4; y > 0; --y) { - memcpy(preds, modes, 4 * sizeof(*modes)); - preds += it->enc_->preds_w_; - modes += 4; - } - it->mb_->type_ = 0; -} - -void VP8SetIntraUVMode(const VP8EncIterator* const it, int mode) { - it->mb_->uv_mode_ = mode; -} - -void VP8SetSkip(const VP8EncIterator* const it, int skip) { - it->mb_->skip_ = skip; -} - -void VP8SetSegment(const VP8EncIterator* const it, int segment) { - it->mb_->segment_ = segment; -} - -//------------------------------------------------------------------------------ -// Intra4x4 sub-blocks iteration -// -// We store and update the boundary samples into an array of 37 pixels. They -// are updated as we iterate and reconstructs each intra4x4 blocks in turn. -// The position of the samples has the following snake pattern: -// -// 16|17 18 19 20|21 22 23 24|25 26 27 28|29 30 31 32|33 34 35 36 <- Top-right -// --+-----------+-----------+-----------+-----------+ -// 15| 19| 23| 27| 31| -// 14| 18| 22| 26| 30| -// 13| 17| 21| 25| 29| -// 12|13 14 15 16|17 18 19 20|21 22 23 24|25 26 27 28| -// --+-----------+-----------+-----------+-----------+ -// 11| 15| 19| 23| 27| -// 10| 14| 18| 22| 26| -// 9| 13| 17| 21| 25| -// 8| 9 10 11 12|13 14 15 16|17 18 19 20|21 22 23 24| -// --+-----------+-----------+-----------+-----------+ -// 7| 11| 15| 19| 23| -// 6| 10| 14| 18| 22| -// 5| 9| 13| 17| 21| -// 4| 5 6 7 8| 9 10 11 12|13 14 15 16|17 18 19 20| -// --+-----------+-----------+-----------+-----------+ -// 3| 7| 11| 15| 19| -// 2| 6| 10| 14| 18| -// 1| 5| 9| 13| 17| -// 0| 1 2 3 4| 5 6 7 8| 9 10 11 12|13 14 15 16| -// --+-----------+-----------+-----------+-----------+ - -// Array to record the position of the top sample to pass to the prediction -// functions in dsp.c. -static const uint8_t VP8TopLeftI4[16] = { - 17, 21, 25, 29, - 13, 17, 21, 25, - 9, 13, 17, 21, - 5, 9, 13, 17 -}; - -void VP8IteratorStartI4(VP8EncIterator* const it) { - const VP8Encoder* const enc = it->enc_; - int i; - - it->i4_ = 0; // first 4x4 sub-block - it->i4_top_ = it->i4_boundary_ + VP8TopLeftI4[0]; - - // Import the boundary samples - for (i = 0; i < 17; ++i) { // left - it->i4_boundary_[i] = it->y_left_[15 - i]; - } - for (i = 0; i < 16; ++i) { // top - it->i4_boundary_[17 + i] = it->y_top_[i]; - } - // top-right samples have a special case on the far right of the picture - if (it->x_ < enc->mb_w_ - 1) { - for (i = 16; i < 16 + 4; ++i) { - it->i4_boundary_[17 + i] = it->y_top_[i]; - } - } else { // else, replicate the last valid pixel four times - for (i = 16; i < 16 + 4; ++i) { - it->i4_boundary_[17 + i] = it->i4_boundary_[17 + 15]; - } - } - VP8IteratorNzToBytes(it); // import the non-zero context -} - -int VP8IteratorRotateI4(VP8EncIterator* const it, - const uint8_t* const yuv_out) { - const uint8_t* const blk = yuv_out + VP8Scan[it->i4_]; - uint8_t* const top = it->i4_top_; - int i; - - // Update the cache with 7 fresh samples - for (i = 0; i <= 3; ++i) { - top[-4 + i] = blk[i + 3 * BPS]; // store future top samples - } - if ((it->i4_ & 3) != 3) { // if not on the right sub-blocks #3, #7, #11, #15 - for (i = 0; i <= 2; ++i) { // store future left samples - top[i] = blk[3 + (2 - i) * BPS]; - } - } else { // else replicate top-right samples, as says the specs. - for (i = 0; i <= 3; ++i) { - top[i] = top[i + 4]; - } - } - // move pointers to next sub-block - ++it->i4_; - if (it->i4_ == 16) { // we're done - return 0; - } - - it->i4_top_ = it->i4_boundary_ + VP8TopLeftI4[it->i4_]; - return 1; -} - -//------------------------------------------------------------------------------ diff --git a/libwebp/src/enc/near_lossless_enc.c b/libwebp/src/enc/near_lossless_enc.c deleted file mode 100644 index 5517a7e2..00000000 --- a/libwebp/src/enc/near_lossless_enc.c +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright 2014 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Near-lossless image preprocessing adjusts pixel values to help -// compressibility with a guarantee of maximum deviation between original and -// resulting pixel values. -// -// Author: Jyrki Alakuijala (jyrki@google.com) -// Converted to C by Aleksander Kramarz (akramarz@google.com) - -#include -#include - -#include "src/dsp/lossless_common.h" -#include "src/utils/utils.h" -#include "src/enc/vp8li_enc.h" - -#if (WEBP_NEAR_LOSSLESS == 1) - -#define MIN_DIM_FOR_NEAR_LOSSLESS 64 -#define MAX_LIMIT_BITS 5 - -// Quantizes the value up or down to a multiple of 1<> 1) + ((a >> bits) & 1); - assert(bits > 0); - if (biased > 0xff) return 0xff; - return biased & ~mask; -} - -// Applies FindClosestDiscretized to all channels of pixel. -static uint32_t ClosestDiscretizedArgb(uint32_t a, int bits) { - return - (FindClosestDiscretized(a >> 24, bits) << 24) | - (FindClosestDiscretized((a >> 16) & 0xff, bits) << 16) | - (FindClosestDiscretized((a >> 8) & 0xff, bits) << 8) | - (FindClosestDiscretized(a & 0xff, bits)); -} - -// Checks if distance between corresponding channel values of pixels a and b -// is within the given limit. -static int IsNear(uint32_t a, uint32_t b, int limit) { - int k; - for (k = 0; k < 4; ++k) { - const int delta = - (int)((a >> (k * 8)) & 0xff) - (int)((b >> (k * 8)) & 0xff); - if (delta >= limit || delta <= -limit) { - return 0; - } - } - return 1; -} - -static int IsSmooth(const uint32_t* const prev_row, - const uint32_t* const curr_row, - const uint32_t* const next_row, - int ix, int limit) { - // Check that all pixels in 4-connected neighborhood are smooth. - return (IsNear(curr_row[ix], curr_row[ix - 1], limit) && - IsNear(curr_row[ix], curr_row[ix + 1], limit) && - IsNear(curr_row[ix], prev_row[ix], limit) && - IsNear(curr_row[ix], next_row[ix], limit)); -} - -// Adjusts pixel values of image with given maximum error. -static void NearLossless(int xsize, int ysize, const uint32_t* argb_src, - int stride, int limit_bits, uint32_t* copy_buffer, - uint32_t* argb_dst) { - int x, y; - const int limit = 1 << limit_bits; - uint32_t* prev_row = copy_buffer; - uint32_t* curr_row = prev_row + xsize; - uint32_t* next_row = curr_row + xsize; - memcpy(curr_row, argb_src, xsize * sizeof(argb_src[0])); - memcpy(next_row, argb_src + stride, xsize * sizeof(argb_src[0])); - - for (y = 0; y < ysize; ++y, argb_src += stride, argb_dst += xsize) { - if (y == 0 || y == ysize - 1) { - memcpy(argb_dst, argb_src, xsize * sizeof(argb_src[0])); - } else { - memcpy(next_row, argb_src + stride, xsize * sizeof(argb_src[0])); - argb_dst[0] = argb_src[0]; - argb_dst[xsize - 1] = argb_src[xsize - 1]; - for (x = 1; x < xsize - 1; ++x) { - if (IsSmooth(prev_row, curr_row, next_row, x, limit)) { - argb_dst[x] = curr_row[x]; - } else { - argb_dst[x] = ClosestDiscretizedArgb(curr_row[x], limit_bits); - } - } - } - { - // Three-way swap. - uint32_t* const temp = prev_row; - prev_row = curr_row; - curr_row = next_row; - next_row = temp; - } - } -} - -int VP8ApplyNearLossless(const WebPPicture* const picture, int quality, - uint32_t* const argb_dst) { - int i; - const int xsize = picture->width; - const int ysize = picture->height; - const int stride = picture->argb_stride; - uint32_t* const copy_buffer = - (uint32_t*)WebPSafeMalloc(xsize * 3, sizeof(*copy_buffer)); - const int limit_bits = VP8LNearLosslessBits(quality); - assert(argb_dst != NULL); - assert(limit_bits > 0); - assert(limit_bits <= MAX_LIMIT_BITS); - if (copy_buffer == NULL) { - return 0; - } - // For small icon images, don't attempt to apply near-lossless compression. - if ((xsize < MIN_DIM_FOR_NEAR_LOSSLESS && - ysize < MIN_DIM_FOR_NEAR_LOSSLESS) || - ysize < 3) { - for (i = 0; i < ysize; ++i) { - memcpy(argb_dst + i * xsize, picture->argb + i * picture->argb_stride, - xsize * sizeof(*argb_dst)); - } - WebPSafeFree(copy_buffer); - return 1; - } - - NearLossless(xsize, ysize, picture->argb, stride, limit_bits, copy_buffer, - argb_dst); - for (i = limit_bits - 1; i != 0; --i) { - NearLossless(xsize, ysize, argb_dst, xsize, i, copy_buffer, argb_dst); - } - WebPSafeFree(copy_buffer); - return 1; -} -#else // (WEBP_NEAR_LOSSLESS == 1) - -// Define a stub to suppress compiler warnings. -extern void VP8LNearLosslessStub(void); -void VP8LNearLosslessStub(void) {} - -#endif // (WEBP_NEAR_LOSSLESS == 1) diff --git a/libwebp/src/enc/picture_csp_enc.c b/libwebp/src/enc/picture_csp_enc.c deleted file mode 100644 index a9280e6c..00000000 --- a/libwebp/src/enc/picture_csp_enc.c +++ /dev/null @@ -1,846 +0,0 @@ -// Copyright 2014 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// WebPPicture utils for colorspace conversion -// -// Author: Skal (pascal.massimino@gmail.com) - -#include -#include -#include - -#include "sharpyuv/sharpyuv.h" -#include "sharpyuv/sharpyuv_csp.h" -#include "src/enc/vp8i_enc.h" -#include "src/utils/random_utils.h" -#include "src/utils/utils.h" -#include "src/dsp/dsp.h" -#include "src/dsp/lossless.h" -#include "src/dsp/yuv.h" -#include "src/dsp/cpu.h" - -#if defined(WEBP_USE_THREAD) && !defined(_WIN32) -#include -#endif - -// Uncomment to disable gamma-compression during RGB->U/V averaging -#define USE_GAMMA_COMPRESSION - -// If defined, use table to compute x / alpha. -#define USE_INVERSE_ALPHA_TABLE - -#ifdef WORDS_BIGENDIAN -// uint32_t 0xff000000 is 0xff,00,00,00 in memory -#define CHANNEL_OFFSET(i) (i) -#else -// uint32_t 0xff000000 is 0x00,00,00,ff in memory -#define CHANNEL_OFFSET(i) (3-(i)) -#endif - -#define ALPHA_OFFSET CHANNEL_OFFSET(0) - -//------------------------------------------------------------------------------ -// Detection of non-trivial transparency - -// Returns true if alpha[] has non-0xff values. -static int CheckNonOpaque(const uint8_t* alpha, int width, int height, - int x_step, int y_step) { - if (alpha == NULL) return 0; - WebPInitAlphaProcessing(); - if (x_step == 1) { - for (; height-- > 0; alpha += y_step) { - if (WebPHasAlpha8b(alpha, width)) return 1; - } - } else { - for (; height-- > 0; alpha += y_step) { - if (WebPHasAlpha32b(alpha, width)) return 1; - } - } - return 0; -} - -// Checking for the presence of non-opaque alpha. -int WebPPictureHasTransparency(const WebPPicture* picture) { - if (picture == NULL) return 0; - if (picture->use_argb) { - if (picture->argb != NULL) { - return CheckNonOpaque((const uint8_t*)picture->argb + ALPHA_OFFSET, - picture->width, picture->height, - 4, picture->argb_stride * sizeof(*picture->argb)); - } - return 0; - } - return CheckNonOpaque(picture->a, picture->width, picture->height, - 1, picture->a_stride); -} - -//------------------------------------------------------------------------------ -// Code for gamma correction - -#if defined(USE_GAMMA_COMPRESSION) - -// Gamma correction compensates loss of resolution during chroma subsampling. -#define GAMMA_FIX 12 // fixed-point precision for linear values -#define GAMMA_TAB_FIX 7 // fixed-point fractional bits precision -#define GAMMA_TAB_SIZE (1 << (GAMMA_FIX - GAMMA_TAB_FIX)) -static const double kGamma = 0.80; -static const int kGammaScale = ((1 << GAMMA_FIX) - 1); -static const int kGammaTabScale = (1 << GAMMA_TAB_FIX); -static const int kGammaTabRounder = (1 << GAMMA_TAB_FIX >> 1); - -static int kLinearToGammaTab[GAMMA_TAB_SIZE + 1]; -static uint16_t kGammaToLinearTab[256]; -static volatile int kGammaTablesOk = 0; -static void InitGammaTables(void); -extern VP8CPUInfo VP8GetCPUInfo; - -WEBP_DSP_INIT_FUNC(InitGammaTables) { - if (!kGammaTablesOk) { - int v; - const double scale = (double)(1 << GAMMA_TAB_FIX) / kGammaScale; - const double norm = 1. / 255.; - for (v = 0; v <= 255; ++v) { - kGammaToLinearTab[v] = - (uint16_t)(pow(norm * v, kGamma) * kGammaScale + .5); - } - for (v = 0; v <= GAMMA_TAB_SIZE; ++v) { - kLinearToGammaTab[v] = (int)(255. * pow(scale * v, 1. / kGamma) + .5); - } - kGammaTablesOk = 1; - } -} - -static WEBP_INLINE uint32_t GammaToLinear(uint8_t v) { - return kGammaToLinearTab[v]; -} - -static WEBP_INLINE int Interpolate(int v) { - const int tab_pos = v >> (GAMMA_TAB_FIX + 2); // integer part - const int x = v & ((kGammaTabScale << 2) - 1); // fractional part - const int v0 = kLinearToGammaTab[tab_pos]; - const int v1 = kLinearToGammaTab[tab_pos + 1]; - const int y = v1 * x + v0 * ((kGammaTabScale << 2) - x); // interpolate - assert(tab_pos + 1 < GAMMA_TAB_SIZE + 1); - return y; -} - -// Convert a linear value 'v' to YUV_FIX+2 fixed-point precision -// U/V value, suitable for RGBToU/V calls. -static WEBP_INLINE int LinearToGamma(uint32_t base_value, int shift) { - const int y = Interpolate(base_value << shift); // final uplifted value - return (y + kGammaTabRounder) >> GAMMA_TAB_FIX; // descale -} - -#else - -static void InitGammaTables(void) {} -static WEBP_INLINE uint32_t GammaToLinear(uint8_t v) { return v; } -static WEBP_INLINE int LinearToGamma(uint32_t base_value, int shift) { - return (int)(base_value << shift); -} - -#endif // USE_GAMMA_COMPRESSION - -//------------------------------------------------------------------------------ -// RGB -> YUV conversion - -static int RGBToY(int r, int g, int b, VP8Random* const rg) { - return (rg == NULL) ? VP8RGBToY(r, g, b, YUV_HALF) - : VP8RGBToY(r, g, b, VP8RandomBits(rg, YUV_FIX)); -} - -static int RGBToU(int r, int g, int b, VP8Random* const rg) { - return (rg == NULL) ? VP8RGBToU(r, g, b, YUV_HALF << 2) - : VP8RGBToU(r, g, b, VP8RandomBits(rg, YUV_FIX + 2)); -} - -static int RGBToV(int r, int g, int b, VP8Random* const rg) { - return (rg == NULL) ? VP8RGBToV(r, g, b, YUV_HALF << 2) - : VP8RGBToV(r, g, b, VP8RandomBits(rg, YUV_FIX + 2)); -} - -//------------------------------------------------------------------------------ -// Sharp RGB->YUV conversion - -static const int kMinDimensionIterativeConversion = 4; - -//------------------------------------------------------------------------------ -// Main function - -static int PreprocessARGB(const uint8_t* r_ptr, - const uint8_t* g_ptr, - const uint8_t* b_ptr, - int step, int rgb_stride, - WebPPicture* const picture) { - const int ok = SharpYuvConvert( - r_ptr, g_ptr, b_ptr, step, rgb_stride, /*rgb_bit_depth=*/8, - picture->y, picture->y_stride, picture->u, picture->uv_stride, picture->v, - picture->uv_stride, /*yuv_bit_depth=*/8, picture->width, - picture->height, SharpYuvGetConversionMatrix(kSharpYuvMatrixWebp)); - if (!ok) { - return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); - } - return ok; -} - -//------------------------------------------------------------------------------ -// "Fast" regular RGB->YUV - -#define SUM4(ptr, step) LinearToGamma( \ - GammaToLinear((ptr)[0]) + \ - GammaToLinear((ptr)[(step)]) + \ - GammaToLinear((ptr)[rgb_stride]) + \ - GammaToLinear((ptr)[rgb_stride + (step)]), 0) \ - -#define SUM2(ptr) \ - LinearToGamma(GammaToLinear((ptr)[0]) + GammaToLinear((ptr)[rgb_stride]), 1) - -#define SUM2ALPHA(ptr) ((ptr)[0] + (ptr)[rgb_stride]) -#define SUM4ALPHA(ptr) (SUM2ALPHA(ptr) + SUM2ALPHA((ptr) + 4)) - -#if defined(USE_INVERSE_ALPHA_TABLE) - -static const int kAlphaFix = 19; -// Following table is (1 << kAlphaFix) / a. The (v * kInvAlpha[a]) >> kAlphaFix -// formula is then equal to v / a in most (99.6%) cases. Note that this table -// and constant are adjusted very tightly to fit 32b arithmetic. -// In particular, they use the fact that the operands for 'v / a' are actually -// derived as v = (a0.p0 + a1.p1 + a2.p2 + a3.p3) and a = a0 + a1 + a2 + a3 -// with ai in [0..255] and pi in [0..1<> (kAlphaFix - 2)) - -#else - -#define DIVIDE_BY_ALPHA(sum, a) (4 * (sum) / (a)) - -#endif // USE_INVERSE_ALPHA_TABLE - -static WEBP_INLINE int LinearToGammaWeighted(const uint8_t* src, - const uint8_t* a_ptr, - uint32_t total_a, int step, - int rgb_stride) { - const uint32_t sum = - a_ptr[0] * GammaToLinear(src[0]) + - a_ptr[step] * GammaToLinear(src[step]) + - a_ptr[rgb_stride] * GammaToLinear(src[rgb_stride]) + - a_ptr[rgb_stride + step] * GammaToLinear(src[rgb_stride + step]); - assert(total_a > 0 && total_a <= 4 * 0xff); -#if defined(USE_INVERSE_ALPHA_TABLE) - assert((uint64_t)sum * kInvAlpha[total_a] < ((uint64_t)1 << 32)); -#endif - return LinearToGamma(DIVIDE_BY_ALPHA(sum, total_a), 0); -} - -static WEBP_INLINE void ConvertRowToY(const uint8_t* const r_ptr, - const uint8_t* const g_ptr, - const uint8_t* const b_ptr, - int step, - uint8_t* const dst_y, - int width, - VP8Random* const rg) { - int i, j; - for (i = 0, j = 0; i < width; i += 1, j += step) { - dst_y[i] = RGBToY(r_ptr[j], g_ptr[j], b_ptr[j], rg); - } -} - -static WEBP_INLINE void AccumulateRGBA(const uint8_t* const r_ptr, - const uint8_t* const g_ptr, - const uint8_t* const b_ptr, - const uint8_t* const a_ptr, - int rgb_stride, - uint16_t* dst, int width) { - int i, j; - // we loop over 2x2 blocks and produce one R/G/B/A value for each. - for (i = 0, j = 0; i < (width >> 1); i += 1, j += 2 * 4, dst += 4) { - const uint32_t a = SUM4ALPHA(a_ptr + j); - int r, g, b; - if (a == 4 * 0xff || a == 0) { - r = SUM4(r_ptr + j, 4); - g = SUM4(g_ptr + j, 4); - b = SUM4(b_ptr + j, 4); - } else { - r = LinearToGammaWeighted(r_ptr + j, a_ptr + j, a, 4, rgb_stride); - g = LinearToGammaWeighted(g_ptr + j, a_ptr + j, a, 4, rgb_stride); - b = LinearToGammaWeighted(b_ptr + j, a_ptr + j, a, 4, rgb_stride); - } - dst[0] = r; - dst[1] = g; - dst[2] = b; - dst[3] = a; - } - if (width & 1) { - const uint32_t a = 2u * SUM2ALPHA(a_ptr + j); - int r, g, b; - if (a == 4 * 0xff || a == 0) { - r = SUM2(r_ptr + j); - g = SUM2(g_ptr + j); - b = SUM2(b_ptr + j); - } else { - r = LinearToGammaWeighted(r_ptr + j, a_ptr + j, a, 0, rgb_stride); - g = LinearToGammaWeighted(g_ptr + j, a_ptr + j, a, 0, rgb_stride); - b = LinearToGammaWeighted(b_ptr + j, a_ptr + j, a, 0, rgb_stride); - } - dst[0] = r; - dst[1] = g; - dst[2] = b; - dst[3] = a; - } -} - -static WEBP_INLINE void AccumulateRGB(const uint8_t* const r_ptr, - const uint8_t* const g_ptr, - const uint8_t* const b_ptr, - int step, int rgb_stride, - uint16_t* dst, int width) { - int i, j; - for (i = 0, j = 0; i < (width >> 1); i += 1, j += 2 * step, dst += 4) { - dst[0] = SUM4(r_ptr + j, step); - dst[1] = SUM4(g_ptr + j, step); - dst[2] = SUM4(b_ptr + j, step); - // MemorySanitizer may raise false positives with data that passes through - // RGBA32PackedToPlanar_16b_SSE41() due to incorrect modeling of shuffles. - // See https://crbug.com/webp/573. -#ifdef WEBP_MSAN - dst[3] = 0; -#endif - } - if (width & 1) { - dst[0] = SUM2(r_ptr + j); - dst[1] = SUM2(g_ptr + j); - dst[2] = SUM2(b_ptr + j); -#ifdef WEBP_MSAN - dst[3] = 0; -#endif - } -} - -static WEBP_INLINE void ConvertRowsToUV(const uint16_t* rgb, - uint8_t* const dst_u, - uint8_t* const dst_v, - int width, - VP8Random* const rg) { - int i; - for (i = 0; i < width; i += 1, rgb += 4) { - const int r = rgb[0], g = rgb[1], b = rgb[2]; - dst_u[i] = RGBToU(r, g, b, rg); - dst_v[i] = RGBToV(r, g, b, rg); - } -} - -extern void SharpYuvInit(VP8CPUInfo cpu_info_func); - -static int ImportYUVAFromRGBA(const uint8_t* r_ptr, - const uint8_t* g_ptr, - const uint8_t* b_ptr, - const uint8_t* a_ptr, - int step, // bytes per pixel - int rgb_stride, // bytes per scanline - float dithering, - int use_iterative_conversion, - WebPPicture* const picture) { - int y; - const int width = picture->width; - const int height = picture->height; - const int has_alpha = CheckNonOpaque(a_ptr, width, height, step, rgb_stride); - const int is_rgb = (r_ptr < b_ptr); // otherwise it's bgr - - picture->colorspace = has_alpha ? WEBP_YUV420A : WEBP_YUV420; - picture->use_argb = 0; - - // disable smart conversion if source is too small (overkill). - if (width < kMinDimensionIterativeConversion || - height < kMinDimensionIterativeConversion) { - use_iterative_conversion = 0; - } - - if (!WebPPictureAllocYUVA(picture)) { - return 0; - } - if (has_alpha) { - assert(step == 4); -#if defined(USE_GAMMA_COMPRESSION) && defined(USE_INVERSE_ALPHA_TABLE) - assert(kAlphaFix + GAMMA_FIX <= 31); -#endif - } - - if (use_iterative_conversion) { - SharpYuvInit(VP8GetCPUInfo); - if (!PreprocessARGB(r_ptr, g_ptr, b_ptr, step, rgb_stride, picture)) { - return 0; - } - if (has_alpha) { - WebPExtractAlpha(a_ptr, rgb_stride, width, height, - picture->a, picture->a_stride); - } - } else { - const int uv_width = (width + 1) >> 1; - int use_dsp = (step == 3); // use special function in this case - // temporary storage for accumulated R/G/B values during conversion to U/V - uint16_t* const tmp_rgb = - (uint16_t*)WebPSafeMalloc(4 * uv_width, sizeof(*tmp_rgb)); - uint8_t* dst_y = picture->y; - uint8_t* dst_u = picture->u; - uint8_t* dst_v = picture->v; - uint8_t* dst_a = picture->a; - - VP8Random base_rg; - VP8Random* rg = NULL; - if (dithering > 0.) { - VP8InitRandom(&base_rg, dithering); - rg = &base_rg; - use_dsp = 0; // can't use dsp in this case - } - WebPInitConvertARGBToYUV(); - InitGammaTables(); - - if (tmp_rgb == NULL) { - return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); - } - - // Downsample Y/U/V planes, two rows at a time - for (y = 0; y < (height >> 1); ++y) { - int rows_have_alpha = has_alpha; - if (use_dsp) { - if (is_rgb) { - WebPConvertRGB24ToY(r_ptr, dst_y, width); - WebPConvertRGB24ToY(r_ptr + rgb_stride, - dst_y + picture->y_stride, width); - } else { - WebPConvertBGR24ToY(b_ptr, dst_y, width); - WebPConvertBGR24ToY(b_ptr + rgb_stride, - dst_y + picture->y_stride, width); - } - } else { - ConvertRowToY(r_ptr, g_ptr, b_ptr, step, dst_y, width, rg); - ConvertRowToY(r_ptr + rgb_stride, - g_ptr + rgb_stride, - b_ptr + rgb_stride, step, - dst_y + picture->y_stride, width, rg); - } - dst_y += 2 * picture->y_stride; - if (has_alpha) { - rows_have_alpha &= !WebPExtractAlpha(a_ptr, rgb_stride, width, 2, - dst_a, picture->a_stride); - dst_a += 2 * picture->a_stride; - } - // Collect averaged R/G/B(/A) - if (!rows_have_alpha) { - AccumulateRGB(r_ptr, g_ptr, b_ptr, step, rgb_stride, tmp_rgb, width); - } else { - AccumulateRGBA(r_ptr, g_ptr, b_ptr, a_ptr, rgb_stride, tmp_rgb, width); - } - // Convert to U/V - if (rg == NULL) { - WebPConvertRGBA32ToUV(tmp_rgb, dst_u, dst_v, uv_width); - } else { - ConvertRowsToUV(tmp_rgb, dst_u, dst_v, uv_width, rg); - } - dst_u += picture->uv_stride; - dst_v += picture->uv_stride; - r_ptr += 2 * rgb_stride; - b_ptr += 2 * rgb_stride; - g_ptr += 2 * rgb_stride; - if (has_alpha) a_ptr += 2 * rgb_stride; - } - if (height & 1) { // extra last row - int row_has_alpha = has_alpha; - if (use_dsp) { - if (r_ptr < b_ptr) { - WebPConvertRGB24ToY(r_ptr, dst_y, width); - } else { - WebPConvertBGR24ToY(b_ptr, dst_y, width); - } - } else { - ConvertRowToY(r_ptr, g_ptr, b_ptr, step, dst_y, width, rg); - } - if (row_has_alpha) { - row_has_alpha &= !WebPExtractAlpha(a_ptr, 0, width, 1, dst_a, 0); - } - // Collect averaged R/G/B(/A) - if (!row_has_alpha) { - // Collect averaged R/G/B - AccumulateRGB(r_ptr, g_ptr, b_ptr, step, /* rgb_stride = */ 0, - tmp_rgb, width); - } else { - AccumulateRGBA(r_ptr, g_ptr, b_ptr, a_ptr, /* rgb_stride = */ 0, - tmp_rgb, width); - } - if (rg == NULL) { - WebPConvertRGBA32ToUV(tmp_rgb, dst_u, dst_v, uv_width); - } else { - ConvertRowsToUV(tmp_rgb, dst_u, dst_v, uv_width, rg); - } - } - WebPSafeFree(tmp_rgb); - } - return 1; -} - -#undef SUM4 -#undef SUM2 -#undef SUM4ALPHA -#undef SUM2ALPHA - -//------------------------------------------------------------------------------ -// call for ARGB->YUVA conversion - -static int PictureARGBToYUVA(WebPPicture* picture, WebPEncCSP colorspace, - float dithering, int use_iterative_conversion) { - if (picture == NULL) return 0; - if (picture->argb == NULL) { - return WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER); - } else if ((colorspace & WEBP_CSP_UV_MASK) != WEBP_YUV420) { - return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION); - } else { - const uint8_t* const argb = (const uint8_t*)picture->argb; - const uint8_t* const a = argb + CHANNEL_OFFSET(0); - const uint8_t* const r = argb + CHANNEL_OFFSET(1); - const uint8_t* const g = argb + CHANNEL_OFFSET(2); - const uint8_t* const b = argb + CHANNEL_OFFSET(3); - - picture->colorspace = WEBP_YUV420; - return ImportYUVAFromRGBA(r, g, b, a, 4, 4 * picture->argb_stride, - dithering, use_iterative_conversion, picture); - } -} - -int WebPPictureARGBToYUVADithered(WebPPicture* picture, WebPEncCSP colorspace, - float dithering) { - return PictureARGBToYUVA(picture, colorspace, dithering, 0); -} - -int WebPPictureARGBToYUVA(WebPPicture* picture, WebPEncCSP colorspace) { - return PictureARGBToYUVA(picture, colorspace, 0.f, 0); -} - -int WebPPictureSharpARGBToYUVA(WebPPicture* picture) { - return PictureARGBToYUVA(picture, WEBP_YUV420, 0.f, 1); -} -// for backward compatibility -int WebPPictureSmartARGBToYUVA(WebPPicture* picture) { - return WebPPictureSharpARGBToYUVA(picture); -} - -//------------------------------------------------------------------------------ -// call for YUVA -> ARGB conversion - -int WebPPictureYUVAToARGB(WebPPicture* picture) { - if (picture == NULL) return 0; - if (picture->y == NULL || picture->u == NULL || picture->v == NULL) { - return WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER); - } - if ((picture->colorspace & WEBP_CSP_ALPHA_BIT) && picture->a == NULL) { - return WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER); - } - if ((picture->colorspace & WEBP_CSP_UV_MASK) != WEBP_YUV420) { - return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION); - } - // Allocate a new argb buffer (discarding the previous one). - if (!WebPPictureAllocARGB(picture)) return 0; - picture->use_argb = 1; - - // Convert - { - int y; - const int width = picture->width; - const int height = picture->height; - const int argb_stride = 4 * picture->argb_stride; - uint8_t* dst = (uint8_t*)picture->argb; - const uint8_t* cur_u = picture->u, *cur_v = picture->v, *cur_y = picture->y; - WebPUpsampleLinePairFunc upsample = - WebPGetLinePairConverter(ALPHA_OFFSET > 0); - - // First row, with replicated top samples. - upsample(cur_y, NULL, cur_u, cur_v, cur_u, cur_v, dst, NULL, width); - cur_y += picture->y_stride; - dst += argb_stride; - // Center rows. - for (y = 1; y + 1 < height; y += 2) { - const uint8_t* const top_u = cur_u; - const uint8_t* const top_v = cur_v; - cur_u += picture->uv_stride; - cur_v += picture->uv_stride; - upsample(cur_y, cur_y + picture->y_stride, top_u, top_v, cur_u, cur_v, - dst, dst + argb_stride, width); - cur_y += 2 * picture->y_stride; - dst += 2 * argb_stride; - } - // Last row (if needed), with replicated bottom samples. - if (height > 1 && !(height & 1)) { - upsample(cur_y, NULL, cur_u, cur_v, cur_u, cur_v, dst, NULL, width); - } - // Insert alpha values if needed, in replacement for the default 0xff ones. - if (picture->colorspace & WEBP_CSP_ALPHA_BIT) { - for (y = 0; y < height; ++y) { - uint32_t* const argb_dst = picture->argb + y * picture->argb_stride; - const uint8_t* const src = picture->a + y * picture->a_stride; - int x; - for (x = 0; x < width; ++x) { - argb_dst[x] = (argb_dst[x] & 0x00ffffffu) | ((uint32_t)src[x] << 24); - } - } - } - } - return 1; -} - -//------------------------------------------------------------------------------ -// automatic import / conversion - -static int Import(WebPPicture* const picture, - const uint8_t* rgb, int rgb_stride, - int step, int swap_rb, int import_alpha) { - int y; - // swap_rb -> b,g,r,a , !swap_rb -> r,g,b,a - const uint8_t* r_ptr = rgb + (swap_rb ? 2 : 0); - const uint8_t* g_ptr = rgb + 1; - const uint8_t* b_ptr = rgb + (swap_rb ? 0 : 2); - const int width = picture->width; - const int height = picture->height; - - if (abs(rgb_stride) < (import_alpha ? 4 : 3) * width) return 0; - - if (!picture->use_argb) { - const uint8_t* a_ptr = import_alpha ? rgb + 3 : NULL; - return ImportYUVAFromRGBA(r_ptr, g_ptr, b_ptr, a_ptr, step, rgb_stride, - 0.f /* no dithering */, 0, picture); - } - if (!WebPPictureAlloc(picture)) return 0; - - VP8LDspInit(); - WebPInitAlphaProcessing(); - - if (import_alpha) { - // dst[] byte order is {a,r,g,b} for big-endian, {b,g,r,a} for little endian - uint32_t* dst = picture->argb; - const int do_copy = (ALPHA_OFFSET == 3) && swap_rb; - assert(step == 4); - if (do_copy) { - for (y = 0; y < height; ++y) { - memcpy(dst, rgb, width * 4); - rgb += rgb_stride; - dst += picture->argb_stride; - } - } else { - for (y = 0; y < height; ++y) { -#ifdef WORDS_BIGENDIAN - // BGRA or RGBA input order. - const uint8_t* a_ptr = rgb + 3; - WebPPackARGB(a_ptr, r_ptr, g_ptr, b_ptr, width, dst); - r_ptr += rgb_stride; - g_ptr += rgb_stride; - b_ptr += rgb_stride; -#else - // RGBA input order. Need to swap R and B. - VP8LConvertBGRAToRGBA((const uint32_t*)rgb, width, (uint8_t*)dst); -#endif - rgb += rgb_stride; - dst += picture->argb_stride; - } - } - } else { - uint32_t* dst = picture->argb; - assert(step >= 3); - for (y = 0; y < height; ++y) { - WebPPackRGB(r_ptr, g_ptr, b_ptr, width, step, dst); - r_ptr += rgb_stride; - g_ptr += rgb_stride; - b_ptr += rgb_stride; - dst += picture->argb_stride; - } - } - return 1; -} - -// Public API - -#if !defined(WEBP_REDUCE_CSP) - -int WebPPictureImportBGR(WebPPicture* picture, - const uint8_t* bgr, int bgr_stride) { - return (picture != NULL && bgr != NULL) - ? Import(picture, bgr, bgr_stride, 3, 1, 0) - : 0; -} - -int WebPPictureImportBGRA(WebPPicture* picture, - const uint8_t* bgra, int bgra_stride) { - return (picture != NULL && bgra != NULL) - ? Import(picture, bgra, bgra_stride, 4, 1, 1) - : 0; -} - - -int WebPPictureImportBGRX(WebPPicture* picture, - const uint8_t* bgrx, int bgrx_stride) { - return (picture != NULL && bgrx != NULL) - ? Import(picture, bgrx, bgrx_stride, 4, 1, 0) - : 0; -} - -#endif // WEBP_REDUCE_CSP - -int WebPPictureImportRGB(WebPPicture* picture, - const uint8_t* rgb, int rgb_stride) { - return (picture != NULL && rgb != NULL) - ? Import(picture, rgb, rgb_stride, 3, 0, 0) - : 0; -} - -int WebPPictureImportRGBA(WebPPicture* picture, - const uint8_t* rgba, int rgba_stride) { - return (picture != NULL && rgba != NULL) - ? Import(picture, rgba, rgba_stride, 4, 0, 1) - : 0; -} - -int WebPPictureImportRGBX(WebPPicture* picture, - const uint8_t* rgbx, int rgbx_stride) { - return (picture != NULL && rgbx != NULL) - ? Import(picture, rgbx, rgbx_stride, 4, 0, 0) - : 0; -} - -//------------------------------------------------------------------------------ diff --git a/libwebp/src/enc/picture_enc.c b/libwebp/src/enc/picture_enc.c deleted file mode 100644 index 5a270354..00000000 --- a/libwebp/src/enc/picture_enc.c +++ /dev/null @@ -1,304 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// WebPPicture class basis -// -// Author: Skal (pascal.massimino@gmail.com) - -#include -#include -#include - -#include "src/enc/vp8i_enc.h" -#include "src/utils/utils.h" - -//------------------------------------------------------------------------------ -// WebPPicture -//------------------------------------------------------------------------------ - -static int DummyWriter(const uint8_t* data, size_t data_size, - const WebPPicture* const picture) { - // The following are to prevent 'unused variable' error message. - (void)data; - (void)data_size; - (void)picture; - return 1; -} - -int WebPPictureInitInternal(WebPPicture* picture, int version) { - if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_ENCODER_ABI_VERSION)) { - return 0; // caller/system version mismatch! - } - if (picture != NULL) { - memset(picture, 0, sizeof(*picture)); - picture->writer = DummyWriter; - WebPEncodingSetError(picture, VP8_ENC_OK); - } - return 1; -} - -//------------------------------------------------------------------------------ - -int WebPValidatePicture(const WebPPicture* const picture) { - if (picture == NULL) return 0; - if (picture->width <= 0 || picture->height <= 0) { - return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION); - } - if (picture->width <= 0 || picture->width / 4 > INT_MAX / 4 || - picture->height <= 0 || picture->height / 4 > INT_MAX / 4) { - return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION); - } - if (picture->colorspace != WEBP_YUV420 && - picture->colorspace != WEBP_YUV420A) { - return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION); - } - return 1; -} - -static void WebPPictureResetBufferARGB(WebPPicture* const picture) { - picture->memory_argb_ = NULL; - picture->argb = NULL; - picture->argb_stride = 0; -} - -static void WebPPictureResetBufferYUVA(WebPPicture* const picture) { - picture->memory_ = NULL; - picture->y = picture->u = picture->v = picture->a = NULL; - picture->y_stride = picture->uv_stride = 0; - picture->a_stride = 0; -} - -void WebPPictureResetBuffers(WebPPicture* const picture) { - WebPPictureResetBufferARGB(picture); - WebPPictureResetBufferYUVA(picture); -} - -int WebPPictureAllocARGB(WebPPicture* const picture) { - void* memory; - const int width = picture->width; - const int height = picture->height; - const uint64_t argb_size = (uint64_t)width * height; - - if (!WebPValidatePicture(picture)) return 0; - - WebPSafeFree(picture->memory_argb_); - WebPPictureResetBufferARGB(picture); - - // allocate a new buffer. - memory = WebPSafeMalloc(argb_size + WEBP_ALIGN_CST, sizeof(*picture->argb)); - if (memory == NULL) { - return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); - } - picture->memory_argb_ = memory; - picture->argb = (uint32_t*)WEBP_ALIGN(memory); - picture->argb_stride = width; - return 1; -} - -int WebPPictureAllocYUVA(WebPPicture* const picture) { - const int has_alpha = (int)picture->colorspace & WEBP_CSP_ALPHA_BIT; - const int width = picture->width; - const int height = picture->height; - const int y_stride = width; - const int uv_width = (int)(((int64_t)width + 1) >> 1); - const int uv_height = (int)(((int64_t)height + 1) >> 1); - const int uv_stride = uv_width; - int a_width, a_stride; - uint64_t y_size, uv_size, a_size, total_size; - uint8_t* mem; - - if (!WebPValidatePicture(picture)) return 0; - - WebPSafeFree(picture->memory_); - WebPPictureResetBufferYUVA(picture); - - // alpha - a_width = has_alpha ? width : 0; - a_stride = a_width; - y_size = (uint64_t)y_stride * height; - uv_size = (uint64_t)uv_stride * uv_height; - a_size = (uint64_t)a_stride * height; - - total_size = y_size + a_size + 2 * uv_size; - - // Security and validation checks - if (width <= 0 || height <= 0 || // luma/alpha param error - uv_width <= 0 || uv_height <= 0) { // u/v param error - return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION); - } - // allocate a new buffer. - mem = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*mem)); - if (mem == NULL) { - return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); - } - - // From now on, we're in the clear, we can no longer fail... - picture->memory_ = (void*)mem; - picture->y_stride = y_stride; - picture->uv_stride = uv_stride; - picture->a_stride = a_stride; - - // TODO(skal): we could align the y/u/v planes and adjust stride. - picture->y = mem; - mem += y_size; - - picture->u = mem; - mem += uv_size; - picture->v = mem; - mem += uv_size; - - if (a_size > 0) { - picture->a = mem; - mem += a_size; - } - (void)mem; // makes the static analyzer happy - return 1; -} - -int WebPPictureAlloc(WebPPicture* picture) { - if (picture != NULL) { - WebPPictureFree(picture); // erase previous buffer - - if (!picture->use_argb) { - return WebPPictureAllocYUVA(picture); - } else { - return WebPPictureAllocARGB(picture); - } - } - return 1; -} - -void WebPPictureFree(WebPPicture* picture) { - if (picture != NULL) { - WebPSafeFree(picture->memory_); - WebPSafeFree(picture->memory_argb_); - WebPPictureResetBuffers(picture); - } -} - -//------------------------------------------------------------------------------ -// WebPMemoryWriter: Write-to-memory - -void WebPMemoryWriterInit(WebPMemoryWriter* writer) { - writer->mem = NULL; - writer->size = 0; - writer->max_size = 0; -} - -int WebPMemoryWrite(const uint8_t* data, size_t data_size, - const WebPPicture* picture) { - WebPMemoryWriter* const w = (WebPMemoryWriter*)picture->custom_ptr; - uint64_t next_size; - if (w == NULL) { - return 1; - } - next_size = (uint64_t)w->size + data_size; - if (next_size > w->max_size) { - uint8_t* new_mem; - uint64_t next_max_size = 2ULL * w->max_size; - if (next_max_size < next_size) next_max_size = next_size; - if (next_max_size < 8192ULL) next_max_size = 8192ULL; - new_mem = (uint8_t*)WebPSafeMalloc(next_max_size, 1); - if (new_mem == NULL) { - return 0; - } - if (w->size > 0) { - memcpy(new_mem, w->mem, w->size); - } - WebPSafeFree(w->mem); - w->mem = new_mem; - // down-cast is ok, thanks to WebPSafeMalloc - w->max_size = (size_t)next_max_size; - } - if (data_size > 0) { - memcpy(w->mem + w->size, data, data_size); - w->size += data_size; - } - return 1; -} - -void WebPMemoryWriterClear(WebPMemoryWriter* writer) { - if (writer != NULL) { - WebPSafeFree(writer->mem); - writer->mem = NULL; - writer->size = 0; - writer->max_size = 0; - } -} - -//------------------------------------------------------------------------------ -// Simplest high-level calls: - -typedef int (*Importer)(WebPPicture* const, const uint8_t* const, int); - -static size_t Encode(const uint8_t* rgba, int width, int height, int stride, - Importer import, float quality_factor, int lossless, - uint8_t** output) { - WebPPicture pic; - WebPConfig config; - WebPMemoryWriter wrt; - int ok; - - if (output == NULL) return 0; - - if (!WebPConfigPreset(&config, WEBP_PRESET_DEFAULT, quality_factor) || - !WebPPictureInit(&pic)) { - return 0; // shouldn't happen, except if system installation is broken - } - - config.lossless = !!lossless; - pic.use_argb = !!lossless; - pic.width = width; - pic.height = height; - pic.writer = WebPMemoryWrite; - pic.custom_ptr = &wrt; - WebPMemoryWriterInit(&wrt); - - ok = import(&pic, rgba, stride) && WebPEncode(&config, &pic); - WebPPictureFree(&pic); - if (!ok) { - WebPMemoryWriterClear(&wrt); - *output = NULL; - return 0; - } - *output = wrt.mem; - return wrt.size; -} - -#define ENCODE_FUNC(NAME, IMPORTER) \ -size_t NAME(const uint8_t* in, int w, int h, int bps, float q, \ - uint8_t** out) { \ - return Encode(in, w, h, bps, IMPORTER, q, 0, out); \ -} - -ENCODE_FUNC(WebPEncodeRGB, WebPPictureImportRGB) -ENCODE_FUNC(WebPEncodeRGBA, WebPPictureImportRGBA) -#if !defined(WEBP_REDUCE_CSP) -ENCODE_FUNC(WebPEncodeBGR, WebPPictureImportBGR) -ENCODE_FUNC(WebPEncodeBGRA, WebPPictureImportBGRA) -#endif // WEBP_REDUCE_CSP - -#undef ENCODE_FUNC - -#define LOSSLESS_DEFAULT_QUALITY 70. -#define LOSSLESS_ENCODE_FUNC(NAME, IMPORTER) \ -size_t NAME(const uint8_t* in, int w, int h, int bps, uint8_t** out) { \ - return Encode(in, w, h, bps, IMPORTER, LOSSLESS_DEFAULT_QUALITY, 1, out); \ -} - -LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessRGB, WebPPictureImportRGB) -LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessRGBA, WebPPictureImportRGBA) -#if !defined(WEBP_REDUCE_CSP) -LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessBGR, WebPPictureImportBGR) -LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessBGRA, WebPPictureImportBGRA) -#endif // WEBP_REDUCE_CSP - -#undef LOSSLESS_ENCODE_FUNC - -//------------------------------------------------------------------------------ diff --git a/libwebp/src/enc/picture_psnr_enc.c b/libwebp/src/enc/picture_psnr_enc.c deleted file mode 100644 index 1a2f0bef..00000000 --- a/libwebp/src/enc/picture_psnr_enc.c +++ /dev/null @@ -1,258 +0,0 @@ -// Copyright 2014 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// WebPPicture tools for measuring distortion -// -// Author: Skal (pascal.massimino@gmail.com) - -#include "src/webp/encode.h" - -#if !(defined(WEBP_DISABLE_STATS) || defined(WEBP_REDUCE_SIZE)) - -#include -#include - -#include "src/dsp/dsp.h" -#include "src/enc/vp8i_enc.h" -#include "src/utils/utils.h" - -typedef double (*AccumulateFunc)(const uint8_t* src, int src_stride, - const uint8_t* ref, int ref_stride, - int w, int h); - -//------------------------------------------------------------------------------ -// local-min distortion -// -// For every pixel in the *reference* picture, we search for the local best -// match in the compressed image. This is not a symmetrical measure. - -#define RADIUS 2 // search radius. Shouldn't be too large. - -static double AccumulateLSIM(const uint8_t* src, int src_stride, - const uint8_t* ref, int ref_stride, - int w, int h) { - int x, y; - double total_sse = 0.; - for (y = 0; y < h; ++y) { - const int y_0 = (y - RADIUS < 0) ? 0 : y - RADIUS; - const int y_1 = (y + RADIUS + 1 >= h) ? h : y + RADIUS + 1; - for (x = 0; x < w; ++x) { - const int x_0 = (x - RADIUS < 0) ? 0 : x - RADIUS; - const int x_1 = (x + RADIUS + 1 >= w) ? w : x + RADIUS + 1; - double best_sse = 255. * 255.; - const double value = (double)ref[y * ref_stride + x]; - int i, j; - for (j = y_0; j < y_1; ++j) { - const uint8_t* const s = src + j * src_stride; - for (i = x_0; i < x_1; ++i) { - const double diff = s[i] - value; - const double sse = diff * diff; - if (sse < best_sse) best_sse = sse; - } - } - total_sse += best_sse; - } - } - return total_sse; -} -#undef RADIUS - -static double AccumulateSSE(const uint8_t* src, int src_stride, - const uint8_t* ref, int ref_stride, - int w, int h) { - int y; - double total_sse = 0.; - for (y = 0; y < h; ++y) { - total_sse += VP8AccumulateSSE(src, ref, w); - src += src_stride; - ref += ref_stride; - } - return total_sse; -} - -//------------------------------------------------------------------------------ - -static double AccumulateSSIM(const uint8_t* src, int src_stride, - const uint8_t* ref, int ref_stride, - int w, int h) { - const int w0 = (w < VP8_SSIM_KERNEL) ? w : VP8_SSIM_KERNEL; - const int w1 = w - VP8_SSIM_KERNEL - 1; - const int h0 = (h < VP8_SSIM_KERNEL) ? h : VP8_SSIM_KERNEL; - const int h1 = h - VP8_SSIM_KERNEL - 1; - int x, y; - double sum = 0.; - for (y = 0; y < h0; ++y) { - for (x = 0; x < w; ++x) { - sum += VP8SSIMGetClipped(src, src_stride, ref, ref_stride, x, y, w, h); - } - } - for (; y < h1; ++y) { - for (x = 0; x < w0; ++x) { - sum += VP8SSIMGetClipped(src, src_stride, ref, ref_stride, x, y, w, h); - } - for (; x < w1; ++x) { - const int off1 = x - VP8_SSIM_KERNEL + (y - VP8_SSIM_KERNEL) * src_stride; - const int off2 = x - VP8_SSIM_KERNEL + (y - VP8_SSIM_KERNEL) * ref_stride; - sum += VP8SSIMGet(src + off1, src_stride, ref + off2, ref_stride); - } - for (; x < w; ++x) { - sum += VP8SSIMGetClipped(src, src_stride, ref, ref_stride, x, y, w, h); - } - } - for (; y < h; ++y) { - for (x = 0; x < w; ++x) { - sum += VP8SSIMGetClipped(src, src_stride, ref, ref_stride, x, y, w, h); - } - } - return sum; -} - -//------------------------------------------------------------------------------ -// Distortion - -// Max value returned in case of exact similarity. -static const double kMinDistortion_dB = 99.; - -static double GetPSNR(double v, double size) { - return (v > 0. && size > 0.) ? -4.3429448 * log(v / (size * 255 * 255.)) - : kMinDistortion_dB; -} - -static double GetLogSSIM(double v, double size) { - v = (size > 0.) ? v / size : 1.; - return (v < 1.) ? -10.0 * log10(1. - v) : kMinDistortion_dB; -} - -int WebPPlaneDistortion(const uint8_t* src, size_t src_stride, - const uint8_t* ref, size_t ref_stride, - int width, int height, size_t x_step, - int type, float* distortion, float* result) { - uint8_t* allocated = NULL; - const AccumulateFunc metric = (type == 0) ? AccumulateSSE : - (type == 1) ? AccumulateSSIM : - AccumulateLSIM; - if (src == NULL || ref == NULL || - src_stride < x_step * width || ref_stride < x_step * width || - result == NULL || distortion == NULL) { - return 0; - } - - VP8SSIMDspInit(); - if (x_step != 1) { // extract a packed plane if needed - int x, y; - uint8_t* tmp1; - uint8_t* tmp2; - allocated = - (uint8_t*)WebPSafeMalloc(2ULL * width * height, sizeof(*allocated)); - if (allocated == NULL) return 0; - tmp1 = allocated; - tmp2 = tmp1 + (size_t)width * height; - for (y = 0; y < height; ++y) { - for (x = 0; x < width; ++x) { - tmp1[x + y * width] = src[x * x_step + y * src_stride]; - tmp2[x + y * width] = ref[x * x_step + y * ref_stride]; - } - } - src = tmp1; - ref = tmp2; - } - *distortion = (float)metric(src, width, ref, width, width, height); - WebPSafeFree(allocated); - - *result = (type == 1) ? (float)GetLogSSIM(*distortion, (double)width * height) - : (float)GetPSNR(*distortion, (double)width * height); - return 1; -} - -#ifdef WORDS_BIGENDIAN -#define BLUE_OFFSET 3 // uint32_t 0x000000ff is 0x00,00,00,ff in memory -#else -#define BLUE_OFFSET 0 // uint32_t 0x000000ff is 0xff,00,00,00 in memory -#endif - -int WebPPictureDistortion(const WebPPicture* src, const WebPPicture* ref, - int type, float results[5]) { - int w, h, c; - int ok = 0; - WebPPicture p0, p1; - double total_size = 0., total_distortion = 0.; - if (src == NULL || ref == NULL || - src->width != ref->width || src->height != ref->height || - results == NULL) { - return 0; - } - - VP8SSIMDspInit(); - if (!WebPPictureInit(&p0) || !WebPPictureInit(&p1)) return 0; - w = src->width; - h = src->height; - if (!WebPPictureView(src, 0, 0, w, h, &p0)) goto Error; - if (!WebPPictureView(ref, 0, 0, w, h, &p1)) goto Error; - - // We always measure distortion in ARGB space. - if (p0.use_argb == 0 && !WebPPictureYUVAToARGB(&p0)) goto Error; - if (p1.use_argb == 0 && !WebPPictureYUVAToARGB(&p1)) goto Error; - for (c = 0; c < 4; ++c) { - float distortion; - const size_t stride0 = 4 * (size_t)p0.argb_stride; - const size_t stride1 = 4 * (size_t)p1.argb_stride; - // results are reported as BGRA - const int offset = c ^ BLUE_OFFSET; - if (!WebPPlaneDistortion((const uint8_t*)p0.argb + offset, stride0, - (const uint8_t*)p1.argb + offset, stride1, - w, h, 4, type, &distortion, results + c)) { - goto Error; - } - total_distortion += distortion; - total_size += w * h; - } - - results[4] = (type == 1) ? (float)GetLogSSIM(total_distortion, total_size) - : (float)GetPSNR(total_distortion, total_size); - ok = 1; - - Error: - WebPPictureFree(&p0); - WebPPictureFree(&p1); - return ok; -} - -#undef BLUE_OFFSET - -#else // defined(WEBP_DISABLE_STATS) -int WebPPlaneDistortion(const uint8_t* src, size_t src_stride, - const uint8_t* ref, size_t ref_stride, - int width, int height, size_t x_step, - int type, float* distortion, float* result) { - (void)src; - (void)src_stride; - (void)ref; - (void)ref_stride; - (void)width; - (void)height; - (void)x_step; - (void)type; - if (distortion == NULL || result == NULL) return 0; - *distortion = 0.f; - *result = 0.f; - return 1; -} - -int WebPPictureDistortion(const WebPPicture* src, const WebPPicture* ref, - int type, float results[5]) { - int i; - (void)src; - (void)ref; - (void)type; - if (results == NULL) return 0; - for (i = 0; i < 5; ++i) results[i] = 0.f; - return 1; -} - -#endif // !defined(WEBP_DISABLE_STATS) diff --git a/libwebp/src/enc/picture_rescale_enc.c b/libwebp/src/enc/picture_rescale_enc.c deleted file mode 100644 index ea90d825..00000000 --- a/libwebp/src/enc/picture_rescale_enc.c +++ /dev/null @@ -1,304 +0,0 @@ -// Copyright 2014 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// WebPPicture tools: copy, crop, rescaling and view. -// -// Author: Skal (pascal.massimino@gmail.com) - -#include "src/webp/encode.h" - -#include -#include - -#include "src/enc/vp8i_enc.h" - -#if !defined(WEBP_REDUCE_SIZE) -#include "src/utils/rescaler_utils.h" -#include "src/utils/utils.h" -#endif // !defined(WEBP_REDUCE_SIZE) - -#define HALVE(x) (((x) + 1) >> 1) - -// Grab the 'specs' (writer, *opaque, width, height...) from 'src' and copy them -// into 'dst'. Mark 'dst' as not owning any memory. -static void PictureGrabSpecs(const WebPPicture* const src, - WebPPicture* const dst) { - assert(src != NULL && dst != NULL); - *dst = *src; - WebPPictureResetBuffers(dst); -} - -//------------------------------------------------------------------------------ - -// Adjust top-left corner to chroma sample position. -static void SnapTopLeftPosition(const WebPPicture* const pic, - int* const left, int* const top) { - if (!pic->use_argb) { - *left &= ~1; - *top &= ~1; - } -} - -// Adjust top-left corner and verify that the sub-rectangle is valid. -static int AdjustAndCheckRectangle(const WebPPicture* const pic, - int* const left, int* const top, - int width, int height) { - SnapTopLeftPosition(pic, left, top); - if ((*left) < 0 || (*top) < 0) return 0; - if (width <= 0 || height <= 0) return 0; - if ((*left) + width > pic->width) return 0; - if ((*top) + height > pic->height) return 0; - return 1; -} - -#if !defined(WEBP_REDUCE_SIZE) -int WebPPictureCopy(const WebPPicture* src, WebPPicture* dst) { - if (src == NULL || dst == NULL) return 0; - if (src == dst) return 1; - - PictureGrabSpecs(src, dst); - if (!WebPPictureAlloc(dst)) return 0; - - if (!src->use_argb) { - WebPCopyPlane(src->y, src->y_stride, - dst->y, dst->y_stride, dst->width, dst->height); - WebPCopyPlane(src->u, src->uv_stride, dst->u, dst->uv_stride, - HALVE(dst->width), HALVE(dst->height)); - WebPCopyPlane(src->v, src->uv_stride, dst->v, dst->uv_stride, - HALVE(dst->width), HALVE(dst->height)); - if (dst->a != NULL) { - WebPCopyPlane(src->a, src->a_stride, - dst->a, dst->a_stride, dst->width, dst->height); - } - } else { - WebPCopyPlane((const uint8_t*)src->argb, 4 * src->argb_stride, - (uint8_t*)dst->argb, 4 * dst->argb_stride, - 4 * dst->width, dst->height); - } - return 1; -} -#endif // !defined(WEBP_REDUCE_SIZE) - -int WebPPictureIsView(const WebPPicture* picture) { - if (picture == NULL) return 0; - if (picture->use_argb) { - return (picture->memory_argb_ == NULL); - } - return (picture->memory_ == NULL); -} - -int WebPPictureView(const WebPPicture* src, - int left, int top, int width, int height, - WebPPicture* dst) { - if (src == NULL || dst == NULL) return 0; - - // verify rectangle position. - if (!AdjustAndCheckRectangle(src, &left, &top, width, height)) return 0; - - if (src != dst) { // beware of aliasing! We don't want to leak 'memory_'. - PictureGrabSpecs(src, dst); - } - dst->width = width; - dst->height = height; - if (!src->use_argb) { - dst->y = src->y + top * src->y_stride + left; - dst->u = src->u + (top >> 1) * src->uv_stride + (left >> 1); - dst->v = src->v + (top >> 1) * src->uv_stride + (left >> 1); - dst->y_stride = src->y_stride; - dst->uv_stride = src->uv_stride; - if (src->a != NULL) { - dst->a = src->a + top * src->a_stride + left; - dst->a_stride = src->a_stride; - } - } else { - dst->argb = src->argb + top * src->argb_stride + left; - dst->argb_stride = src->argb_stride; - } - return 1; -} - -#if !defined(WEBP_REDUCE_SIZE) -//------------------------------------------------------------------------------ -// Picture cropping - -int WebPPictureCrop(WebPPicture* pic, - int left, int top, int width, int height) { - WebPPicture tmp; - - if (pic == NULL) return 0; - if (!AdjustAndCheckRectangle(pic, &left, &top, width, height)) return 0; - - PictureGrabSpecs(pic, &tmp); - tmp.width = width; - tmp.height = height; - if (!WebPPictureAlloc(&tmp)) { - return WebPEncodingSetError(pic, tmp.error_code); - } - - if (!pic->use_argb) { - const int y_offset = top * pic->y_stride + left; - const int uv_offset = (top / 2) * pic->uv_stride + left / 2; - WebPCopyPlane(pic->y + y_offset, pic->y_stride, - tmp.y, tmp.y_stride, width, height); - WebPCopyPlane(pic->u + uv_offset, pic->uv_stride, - tmp.u, tmp.uv_stride, HALVE(width), HALVE(height)); - WebPCopyPlane(pic->v + uv_offset, pic->uv_stride, - tmp.v, tmp.uv_stride, HALVE(width), HALVE(height)); - - if (tmp.a != NULL) { - const int a_offset = top * pic->a_stride + left; - WebPCopyPlane(pic->a + a_offset, pic->a_stride, - tmp.a, tmp.a_stride, width, height); - } - } else { - const uint8_t* const src = - (const uint8_t*)(pic->argb + top * pic->argb_stride + left); - WebPCopyPlane(src, pic->argb_stride * 4, (uint8_t*)tmp.argb, - tmp.argb_stride * 4, width * 4, height); - } - WebPPictureFree(pic); - *pic = tmp; - return 1; -} - -//------------------------------------------------------------------------------ -// Simple picture rescaler - -static int RescalePlane(const uint8_t* src, - int src_width, int src_height, int src_stride, - uint8_t* dst, - int dst_width, int dst_height, int dst_stride, - rescaler_t* const work, - int num_channels) { - WebPRescaler rescaler; - int y = 0; - if (!WebPRescalerInit(&rescaler, src_width, src_height, - dst, dst_width, dst_height, dst_stride, - num_channels, work)) { - return 0; - } - while (y < src_height) { - y += WebPRescalerImport(&rescaler, src_height - y, - src + y * src_stride, src_stride); - WebPRescalerExport(&rescaler); - } - return 1; -} - -static void AlphaMultiplyARGB(WebPPicture* const pic, int inverse) { - assert(pic->argb != NULL); - WebPMultARGBRows((uint8_t*)pic->argb, pic->argb_stride * sizeof(*pic->argb), - pic->width, pic->height, inverse); -} - -static void AlphaMultiplyY(WebPPicture* const pic, int inverse) { - if (pic->a != NULL) { - WebPMultRows(pic->y, pic->y_stride, pic->a, pic->a_stride, - pic->width, pic->height, inverse); - } -} - -int WebPPictureRescale(WebPPicture* picture, int width, int height) { - WebPPicture tmp; - int prev_width, prev_height; - rescaler_t* work; - - if (picture == NULL) return 0; - prev_width = picture->width; - prev_height = picture->height; - if (!WebPRescalerGetScaledDimensions( - prev_width, prev_height, &width, &height)) { - return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION); - } - - PictureGrabSpecs(picture, &tmp); - tmp.width = width; - tmp.height = height; - if (!WebPPictureAlloc(&tmp)) { - return WebPEncodingSetError(picture, tmp.error_code); - } - - if (!picture->use_argb) { - work = (rescaler_t*)WebPSafeMalloc(2ULL * width, sizeof(*work)); - if (work == NULL) { - WebPPictureFree(&tmp); - return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); - } - // If present, we need to rescale alpha first (for AlphaMultiplyY). - if (picture->a != NULL) { - WebPInitAlphaProcessing(); - if (!RescalePlane(picture->a, prev_width, prev_height, picture->a_stride, - tmp.a, width, height, tmp.a_stride, work, 1)) { - return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION); - } - } - - // We take transparency into account on the luma plane only. That's not - // totally exact blending, but still is a good approximation. - AlphaMultiplyY(picture, 0); - if (!RescalePlane(picture->y, prev_width, prev_height, picture->y_stride, - tmp.y, width, height, tmp.y_stride, work, 1) || - !RescalePlane(picture->u, HALVE(prev_width), HALVE(prev_height), - picture->uv_stride, tmp.u, HALVE(width), HALVE(height), - tmp.uv_stride, work, 1) || - !RescalePlane(picture->v, HALVE(prev_width), HALVE(prev_height), - picture->uv_stride, tmp.v, HALVE(width), HALVE(height), - tmp.uv_stride, work, 1)) { - return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION); - } - AlphaMultiplyY(&tmp, 1); - } else { - work = (rescaler_t*)WebPSafeMalloc(2ULL * width * 4, sizeof(*work)); - if (work == NULL) { - WebPPictureFree(&tmp); - return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); - } - // In order to correctly interpolate colors, we need to apply the alpha - // weighting first (black-matting), scale the RGB values, and remove - // the premultiplication afterward (while preserving the alpha channel). - WebPInitAlphaProcessing(); - AlphaMultiplyARGB(picture, 0); - if (!RescalePlane((const uint8_t*)picture->argb, prev_width, prev_height, - picture->argb_stride * 4, (uint8_t*)tmp.argb, width, - height, tmp.argb_stride * 4, work, 4)) { - return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION); - } - AlphaMultiplyARGB(&tmp, 1); - } - WebPPictureFree(picture); - WebPSafeFree(work); - *picture = tmp; - return 1; -} - -#else // defined(WEBP_REDUCE_SIZE) - -int WebPPictureCopy(const WebPPicture* src, WebPPicture* dst) { - (void)src; - (void)dst; - return 0; -} - -int WebPPictureCrop(WebPPicture* pic, - int left, int top, int width, int height) { - (void)pic; - (void)left; - (void)top; - (void)width; - (void)height; - return 0; -} - -int WebPPictureRescale(WebPPicture* pic, int width, int height) { - (void)pic; - (void)width; - (void)height; - return 0; -} -#endif // !defined(WEBP_REDUCE_SIZE) diff --git a/libwebp/src/enc/picture_tools_enc.c b/libwebp/src/enc/picture_tools_enc.c deleted file mode 100644 index 147cc186..00000000 --- a/libwebp/src/enc/picture_tools_enc.c +++ /dev/null @@ -1,274 +0,0 @@ -// Copyright 2014 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// WebPPicture tools: alpha handling, etc. -// -// Author: Skal (pascal.massimino@gmail.com) - -#include - -#include "src/enc/vp8i_enc.h" -#include "src/dsp/yuv.h" - -//------------------------------------------------------------------------------ -// Helper: clean up fully transparent area to help compressibility. - -#define SIZE 8 -#define SIZE2 (SIZE / 2) -static int IsTransparentARGBArea(const uint32_t* ptr, int stride, int size) { - int y, x; - for (y = 0; y < size; ++y) { - for (x = 0; x < size; ++x) { - if (ptr[x] & 0xff000000u) { - return 0; - } - } - ptr += stride; - } - return 1; -} - -static void Flatten(uint8_t* ptr, int v, int stride, int size) { - int y; - for (y = 0; y < size; ++y) { - memset(ptr, v, size); - ptr += stride; - } -} - -static void FlattenARGB(uint32_t* ptr, uint32_t v, int stride, int size) { - int x, y; - for (y = 0; y < size; ++y) { - for (x = 0; x < size; ++x) ptr[x] = v; - ptr += stride; - } -} - -// Smoothen the luma components of transparent pixels. Return true if the whole -// block is transparent. -static int SmoothenBlock(const uint8_t* a_ptr, int a_stride, uint8_t* y_ptr, - int y_stride, int width, int height) { - int sum = 0, count = 0; - int x, y; - const uint8_t* alpha_ptr = a_ptr; - uint8_t* luma_ptr = y_ptr; - for (y = 0; y < height; ++y) { - for (x = 0; x < width; ++x) { - if (alpha_ptr[x] != 0) { - ++count; - sum += luma_ptr[x]; - } - } - alpha_ptr += a_stride; - luma_ptr += y_stride; - } - if (count > 0 && count < width * height) { - const uint8_t avg_u8 = (uint8_t)(sum / count); - alpha_ptr = a_ptr; - luma_ptr = y_ptr; - for (y = 0; y < height; ++y) { - for (x = 0; x < width; ++x) { - if (alpha_ptr[x] == 0) luma_ptr[x] = avg_u8; - } - alpha_ptr += a_stride; - luma_ptr += y_stride; - } - } - return (count == 0); -} - -void WebPReplaceTransparentPixels(WebPPicture* const pic, uint32_t color) { - if (pic != NULL && pic->use_argb) { - int y = pic->height; - uint32_t* argb = pic->argb; - color &= 0xffffffu; // force alpha=0 - WebPInitAlphaProcessing(); - while (y-- > 0) { - WebPAlphaReplace(argb, pic->width, color); - argb += pic->argb_stride; - } - } -} - -void WebPCleanupTransparentArea(WebPPicture* pic) { - int x, y, w, h; - if (pic == NULL) return; - w = pic->width / SIZE; - h = pic->height / SIZE; - - // note: we ignore the left-overs on right/bottom, except for SmoothenBlock(). - if (pic->use_argb) { - uint32_t argb_value = 0; - for (y = 0; y < h; ++y) { - int need_reset = 1; - for (x = 0; x < w; ++x) { - const int off = (y * pic->argb_stride + x) * SIZE; - if (IsTransparentARGBArea(pic->argb + off, pic->argb_stride, SIZE)) { - if (need_reset) { - argb_value = pic->argb[off]; - need_reset = 0; - } - FlattenARGB(pic->argb + off, argb_value, pic->argb_stride, SIZE); - } else { - need_reset = 1; - } - } - } - } else { - const int width = pic->width; - const int height = pic->height; - const int y_stride = pic->y_stride; - const int uv_stride = pic->uv_stride; - const int a_stride = pic->a_stride; - uint8_t* y_ptr = pic->y; - uint8_t* u_ptr = pic->u; - uint8_t* v_ptr = pic->v; - const uint8_t* a_ptr = pic->a; - int values[3] = { 0 }; - if (a_ptr == NULL || y_ptr == NULL || u_ptr == NULL || v_ptr == NULL) { - return; - } - for (y = 0; y + SIZE <= height; y += SIZE) { - int need_reset = 1; - for (x = 0; x + SIZE <= width; x += SIZE) { - if (SmoothenBlock(a_ptr + x, a_stride, y_ptr + x, y_stride, - SIZE, SIZE)) { - if (need_reset) { - values[0] = y_ptr[x]; - values[1] = u_ptr[x >> 1]; - values[2] = v_ptr[x >> 1]; - need_reset = 0; - } - Flatten(y_ptr + x, values[0], y_stride, SIZE); - Flatten(u_ptr + (x >> 1), values[1], uv_stride, SIZE2); - Flatten(v_ptr + (x >> 1), values[2], uv_stride, SIZE2); - } else { - need_reset = 1; - } - } - if (x < width) { - SmoothenBlock(a_ptr + x, a_stride, y_ptr + x, y_stride, - width - x, SIZE); - } - a_ptr += SIZE * a_stride; - y_ptr += SIZE * y_stride; - u_ptr += SIZE2 * uv_stride; - v_ptr += SIZE2 * uv_stride; - } - if (y < height) { - const int sub_height = height - y; - for (x = 0; x + SIZE <= width; x += SIZE) { - SmoothenBlock(a_ptr + x, a_stride, y_ptr + x, y_stride, - SIZE, sub_height); - } - if (x < width) { - SmoothenBlock(a_ptr + x, a_stride, y_ptr + x, y_stride, - width - x, sub_height); - } - } - } -} - -#undef SIZE -#undef SIZE2 - -//------------------------------------------------------------------------------ -// Blend color and remove transparency info - -#define BLEND(V0, V1, ALPHA) \ - ((((V0) * (255 - (ALPHA)) + (V1) * (ALPHA)) * 0x101 + 256) >> 16) -#define BLEND_10BIT(V0, V1, ALPHA) \ - ((((V0) * (1020 - (ALPHA)) + (V1) * (ALPHA)) * 0x101 + 1024) >> 18) - -static WEBP_INLINE uint32_t MakeARGB32(int r, int g, int b) { - return (0xff000000u | (r << 16) | (g << 8) | b); -} - -void WebPBlendAlpha(WebPPicture* picture, uint32_t background_rgb) { - const int red = (background_rgb >> 16) & 0xff; - const int green = (background_rgb >> 8) & 0xff; - const int blue = (background_rgb >> 0) & 0xff; - int x, y; - if (picture == NULL) return; - if (!picture->use_argb) { - // omit last pixel during u/v loop - const int uv_width = (picture->width >> 1); - const int Y0 = VP8RGBToY(red, green, blue, YUV_HALF); - // VP8RGBToU/V expects the u/v values summed over four pixels - const int U0 = VP8RGBToU(4 * red, 4 * green, 4 * blue, 4 * YUV_HALF); - const int V0 = VP8RGBToV(4 * red, 4 * green, 4 * blue, 4 * YUV_HALF); - const int has_alpha = picture->colorspace & WEBP_CSP_ALPHA_BIT; - uint8_t* y_ptr = picture->y; - uint8_t* u_ptr = picture->u; - uint8_t* v_ptr = picture->v; - uint8_t* a_ptr = picture->a; - if (!has_alpha || a_ptr == NULL) return; // nothing to do - for (y = 0; y < picture->height; ++y) { - // Luma blending - for (x = 0; x < picture->width; ++x) { - const uint8_t alpha = a_ptr[x]; - if (alpha < 0xff) { - y_ptr[x] = BLEND(Y0, y_ptr[x], alpha); - } - } - // Chroma blending every even line - if ((y & 1) == 0) { - uint8_t* const a_ptr2 = - (y + 1 == picture->height) ? a_ptr : a_ptr + picture->a_stride; - for (x = 0; x < uv_width; ++x) { - // Average four alpha values into a single blending weight. - // TODO(skal): might lead to visible contouring. Can we do better? - const uint32_t alpha = - a_ptr[2 * x + 0] + a_ptr[2 * x + 1] + - a_ptr2[2 * x + 0] + a_ptr2[2 * x + 1]; - u_ptr[x] = BLEND_10BIT(U0, u_ptr[x], alpha); - v_ptr[x] = BLEND_10BIT(V0, v_ptr[x], alpha); - } - if (picture->width & 1) { // rightmost pixel - const uint32_t alpha = 2 * (a_ptr[2 * x + 0] + a_ptr2[2 * x + 0]); - u_ptr[x] = BLEND_10BIT(U0, u_ptr[x], alpha); - v_ptr[x] = BLEND_10BIT(V0, v_ptr[x], alpha); - } - } else { - u_ptr += picture->uv_stride; - v_ptr += picture->uv_stride; - } - memset(a_ptr, 0xff, picture->width); // reset alpha value to opaque - a_ptr += picture->a_stride; - y_ptr += picture->y_stride; - } - } else { - uint32_t* argb = picture->argb; - const uint32_t background = MakeARGB32(red, green, blue); - for (y = 0; y < picture->height; ++y) { - for (x = 0; x < picture->width; ++x) { - const int alpha = (argb[x] >> 24) & 0xff; - if (alpha != 0xff) { - if (alpha > 0) { - int r = (argb[x] >> 16) & 0xff; - int g = (argb[x] >> 8) & 0xff; - int b = (argb[x] >> 0) & 0xff; - r = BLEND(red, r, alpha); - g = BLEND(green, g, alpha); - b = BLEND(blue, b, alpha); - argb[x] = MakeARGB32(r, g, b); - } else { - argb[x] = background; - } - } - } - argb += picture->argb_stride; - } - } -} - -#undef BLEND -#undef BLEND_10BIT - -//------------------------------------------------------------------------------ diff --git a/libwebp/src/enc/predictor_enc.c b/libwebp/src/enc/predictor_enc.c deleted file mode 100644 index b3d44b59..00000000 --- a/libwebp/src/enc/predictor_enc.c +++ /dev/null @@ -1,792 +0,0 @@ -// Copyright 2016 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Image transform methods for lossless encoder. -// -// Authors: Vikas Arora (vikaas.arora@gmail.com) -// Jyrki Alakuijala (jyrki@google.com) -// Urvang Joshi (urvang@google.com) -// Vincent Rabaud (vrabaud@google.com) - -#include "src/dsp/lossless.h" -#include "src/dsp/lossless_common.h" -#include "src/enc/vp8i_enc.h" -#include "src/enc/vp8li_enc.h" - -#define MAX_DIFF_COST (1e30f) - -static const float kSpatialPredictorBias = 15.f; -static const int kPredLowEffort = 11; -static const uint32_t kMaskAlpha = 0xff000000; - -// Mostly used to reduce code size + readability -static WEBP_INLINE int GetMin(int a, int b) { return (a > b) ? b : a; } - -//------------------------------------------------------------------------------ -// Methods to calculate Entropy (Shannon). - -static float PredictionCostSpatial(const int counts[256], int weight_0, - float exp_val) { - const int significant_symbols = 256 >> 4; - const float exp_decay_factor = 0.6f; - float bits = (float)weight_0 * counts[0]; - int i; - for (i = 1; i < significant_symbols; ++i) { - bits += exp_val * (counts[i] + counts[256 - i]); - exp_val *= exp_decay_factor; - } - return (float)(-0.1 * bits); -} - -static float PredictionCostSpatialHistogram(const int accumulated[4][256], - const int tile[4][256]) { - int i; - float retval = 0.f; - for (i = 0; i < 4; ++i) { - const float kExpValue = 0.94f; - retval += PredictionCostSpatial(tile[i], 1, kExpValue); - retval += VP8LCombinedShannonEntropy(tile[i], accumulated[i]); - } - return (float)retval; -} - -static WEBP_INLINE void UpdateHisto(int histo_argb[4][256], uint32_t argb) { - ++histo_argb[0][argb >> 24]; - ++histo_argb[1][(argb >> 16) & 0xff]; - ++histo_argb[2][(argb >> 8) & 0xff]; - ++histo_argb[3][argb & 0xff]; -} - -//------------------------------------------------------------------------------ -// Spatial transform functions. - -static WEBP_INLINE void PredictBatch(int mode, int x_start, int y, - int num_pixels, const uint32_t* current, - const uint32_t* upper, uint32_t* out) { - if (x_start == 0) { - if (y == 0) { - // ARGB_BLACK. - VP8LPredictorsSub[0](current, NULL, 1, out); - } else { - // Top one. - VP8LPredictorsSub[2](current, upper, 1, out); - } - ++x_start; - ++out; - --num_pixels; - } - if (y == 0) { - // Left one. - VP8LPredictorsSub[1](current + x_start, NULL, num_pixels, out); - } else { - VP8LPredictorsSub[mode](current + x_start, upper + x_start, num_pixels, - out); - } -} - -#if (WEBP_NEAR_LOSSLESS == 1) -static WEBP_INLINE int GetMax(int a, int b) { return (a < b) ? b : a; } - -static int MaxDiffBetweenPixels(uint32_t p1, uint32_t p2) { - const int diff_a = abs((int)(p1 >> 24) - (int)(p2 >> 24)); - const int diff_r = abs((int)((p1 >> 16) & 0xff) - (int)((p2 >> 16) & 0xff)); - const int diff_g = abs((int)((p1 >> 8) & 0xff) - (int)((p2 >> 8) & 0xff)); - const int diff_b = abs((int)(p1 & 0xff) - (int)(p2 & 0xff)); - return GetMax(GetMax(diff_a, diff_r), GetMax(diff_g, diff_b)); -} - -static int MaxDiffAroundPixel(uint32_t current, uint32_t up, uint32_t down, - uint32_t left, uint32_t right) { - const int diff_up = MaxDiffBetweenPixels(current, up); - const int diff_down = MaxDiffBetweenPixels(current, down); - const int diff_left = MaxDiffBetweenPixels(current, left); - const int diff_right = MaxDiffBetweenPixels(current, right); - return GetMax(GetMax(diff_up, diff_down), GetMax(diff_left, diff_right)); -} - -static uint32_t AddGreenToBlueAndRed(uint32_t argb) { - const uint32_t green = (argb >> 8) & 0xff; - uint32_t red_blue = argb & 0x00ff00ffu; - red_blue += (green << 16) | green; - red_blue &= 0x00ff00ffu; - return (argb & 0xff00ff00u) | red_blue; -} - -static void MaxDiffsForRow(int width, int stride, const uint32_t* const argb, - uint8_t* const max_diffs, int used_subtract_green) { - uint32_t current, up, down, left, right; - int x; - if (width <= 2) return; - current = argb[0]; - right = argb[1]; - if (used_subtract_green) { - current = AddGreenToBlueAndRed(current); - right = AddGreenToBlueAndRed(right); - } - // max_diffs[0] and max_diffs[width - 1] are never used. - for (x = 1; x < width - 1; ++x) { - up = argb[-stride + x]; - down = argb[stride + x]; - left = current; - current = right; - right = argb[x + 1]; - if (used_subtract_green) { - up = AddGreenToBlueAndRed(up); - down = AddGreenToBlueAndRed(down); - right = AddGreenToBlueAndRed(right); - } - max_diffs[x] = MaxDiffAroundPixel(current, up, down, left, right); - } -} - -// Quantize the difference between the actual component value and its prediction -// to a multiple of quantization, working modulo 256, taking care not to cross -// a boundary (inclusive upper limit). -static uint8_t NearLosslessComponent(uint8_t value, uint8_t predict, - uint8_t boundary, int quantization) { - const int residual = (value - predict) & 0xff; - const int boundary_residual = (boundary - predict) & 0xff; - const int lower = residual & ~(quantization - 1); - const int upper = lower + quantization; - // Resolve ties towards a value closer to the prediction (i.e. towards lower - // if value comes after prediction and towards upper otherwise). - const int bias = ((boundary - value) & 0xff) < boundary_residual; - if (residual - lower < upper - residual + bias) { - // lower is closer to residual than upper. - if (residual > boundary_residual && lower <= boundary_residual) { - // Halve quantization step to avoid crossing boundary. This midpoint is - // on the same side of boundary as residual because midpoint >= residual - // (since lower is closer than upper) and residual is above the boundary. - return lower + (quantization >> 1); - } - return lower; - } else { - // upper is closer to residual than lower. - if (residual <= boundary_residual && upper > boundary_residual) { - // Halve quantization step to avoid crossing boundary. This midpoint is - // on the same side of boundary as residual because midpoint <= residual - // (since upper is closer than lower) and residual is below the boundary. - return lower + (quantization >> 1); - } - return upper & 0xff; - } -} - -static WEBP_INLINE uint8_t NearLosslessDiff(uint8_t a, uint8_t b) { - return (uint8_t)((((int)(a) - (int)(b))) & 0xff); -} - -// Quantize every component of the difference between the actual pixel value and -// its prediction to a multiple of a quantization (a power of 2, not larger than -// max_quantization which is a power of 2, smaller than max_diff). Take care if -// value and predict have undergone subtract green, which means that red and -// blue are represented as offsets from green. -static uint32_t NearLossless(uint32_t value, uint32_t predict, - int max_quantization, int max_diff, - int used_subtract_green) { - int quantization; - uint8_t new_green = 0; - uint8_t green_diff = 0; - uint8_t a, r, g, b; - if (max_diff <= 2) { - return VP8LSubPixels(value, predict); - } - quantization = max_quantization; - while (quantization >= max_diff) { - quantization >>= 1; - } - if ((value >> 24) == 0 || (value >> 24) == 0xff) { - // Preserve transparency of fully transparent or fully opaque pixels. - a = NearLosslessDiff((value >> 24) & 0xff, (predict >> 24) & 0xff); - } else { - a = NearLosslessComponent(value >> 24, predict >> 24, 0xff, quantization); - } - g = NearLosslessComponent((value >> 8) & 0xff, (predict >> 8) & 0xff, 0xff, - quantization); - if (used_subtract_green) { - // The green offset will be added to red and blue components during decoding - // to obtain the actual red and blue values. - new_green = ((predict >> 8) + g) & 0xff; - // The amount by which green has been adjusted during quantization. It is - // subtracted from red and blue for compensation, to avoid accumulating two - // quantization errors in them. - green_diff = NearLosslessDiff(new_green, (value >> 8) & 0xff); - } - r = NearLosslessComponent(NearLosslessDiff((value >> 16) & 0xff, green_diff), - (predict >> 16) & 0xff, 0xff - new_green, - quantization); - b = NearLosslessComponent(NearLosslessDiff(value & 0xff, green_diff), - predict & 0xff, 0xff - new_green, quantization); - return ((uint32_t)a << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; -} -#endif // (WEBP_NEAR_LOSSLESS == 1) - -// Stores the difference between the pixel and its prediction in "out". -// In case of a lossy encoding, updates the source image to avoid propagating -// the deviation further to pixels which depend on the current pixel for their -// predictions. -static WEBP_INLINE void GetResidual( - int width, int height, uint32_t* const upper_row, - uint32_t* const current_row, const uint8_t* const max_diffs, int mode, - int x_start, int x_end, int y, int max_quantization, int exact, - int used_subtract_green, uint32_t* const out) { - if (exact) { - PredictBatch(mode, x_start, y, x_end - x_start, current_row, upper_row, - out); - } else { - const VP8LPredictorFunc pred_func = VP8LPredictors[mode]; - int x; - for (x = x_start; x < x_end; ++x) { - uint32_t predict; - uint32_t residual; - if (y == 0) { - predict = (x == 0) ? ARGB_BLACK : current_row[x - 1]; // Left. - } else if (x == 0) { - predict = upper_row[x]; // Top. - } else { - predict = pred_func(¤t_row[x - 1], upper_row + x); - } -#if (WEBP_NEAR_LOSSLESS == 1) - if (max_quantization == 1 || mode == 0 || y == 0 || y == height - 1 || - x == 0 || x == width - 1) { - residual = VP8LSubPixels(current_row[x], predict); - } else { - residual = NearLossless(current_row[x], predict, max_quantization, - max_diffs[x], used_subtract_green); - // Update the source image. - current_row[x] = VP8LAddPixels(predict, residual); - // x is never 0 here so we do not need to update upper_row like below. - } -#else - (void)max_diffs; - (void)height; - (void)max_quantization; - (void)used_subtract_green; - residual = VP8LSubPixels(current_row[x], predict); -#endif - if ((current_row[x] & kMaskAlpha) == 0) { - // If alpha is 0, cleanup RGB. We can choose the RGB values of the - // residual for best compression. The prediction of alpha itself can be - // non-zero and must be kept though. We choose RGB of the residual to be - // 0. - residual &= kMaskAlpha; - // Update the source image. - current_row[x] = predict & ~kMaskAlpha; - // The prediction for the rightmost pixel in a row uses the leftmost - // pixel - // in that row as its top-right context pixel. Hence if we change the - // leftmost pixel of current_row, the corresponding change must be - // applied - // to upper_row as well where top-right context is being read from. - if (x == 0 && y != 0) upper_row[width] = current_row[0]; - } - out[x - x_start] = residual; - } - } -} - -// Returns best predictor and updates the accumulated histogram. -// If max_quantization > 1, assumes that near lossless processing will be -// applied, quantizing residuals to multiples of quantization levels up to -// max_quantization (the actual quantization level depends on smoothness near -// the given pixel). -static int GetBestPredictorForTile(int width, int height, - int tile_x, int tile_y, int bits, - int accumulated[4][256], - uint32_t* const argb_scratch, - const uint32_t* const argb, - int max_quantization, - int exact, int used_subtract_green, - const uint32_t* const modes) { - const int kNumPredModes = 14; - const int start_x = tile_x << bits; - const int start_y = tile_y << bits; - const int tile_size = 1 << bits; - const int max_y = GetMin(tile_size, height - start_y); - const int max_x = GetMin(tile_size, width - start_x); - // Whether there exist columns just outside the tile. - const int have_left = (start_x > 0); - // Position and size of the strip covering the tile and adjacent columns if - // they exist. - const int context_start_x = start_x - have_left; -#if (WEBP_NEAR_LOSSLESS == 1) - const int context_width = max_x + have_left + (max_x < width - start_x); -#endif - const int tiles_per_row = VP8LSubSampleSize(width, bits); - // Prediction modes of the left and above neighbor tiles. - const int left_mode = (tile_x > 0) ? - (modes[tile_y * tiles_per_row + tile_x - 1] >> 8) & 0xff : 0xff; - const int above_mode = (tile_y > 0) ? - (modes[(tile_y - 1) * tiles_per_row + tile_x] >> 8) & 0xff : 0xff; - // The width of upper_row and current_row is one pixel larger than image width - // to allow the top right pixel to point to the leftmost pixel of the next row - // when at the right edge. - uint32_t* upper_row = argb_scratch; - uint32_t* current_row = upper_row + width + 1; - uint8_t* const max_diffs = (uint8_t*)(current_row + width + 1); - float best_diff = MAX_DIFF_COST; - int best_mode = 0; - int mode; - int histo_stack_1[4][256]; - int histo_stack_2[4][256]; - // Need pointers to be able to swap arrays. - int (*histo_argb)[256] = histo_stack_1; - int (*best_histo)[256] = histo_stack_2; - int i, j; - uint32_t residuals[1 << MAX_TRANSFORM_BITS]; - assert(bits <= MAX_TRANSFORM_BITS); - assert(max_x <= (1 << MAX_TRANSFORM_BITS)); - - for (mode = 0; mode < kNumPredModes; ++mode) { - float cur_diff; - int relative_y; - memset(histo_argb, 0, sizeof(histo_stack_1)); - if (start_y > 0) { - // Read the row above the tile which will become the first upper_row. - // Include a pixel to the left if it exists; include a pixel to the right - // in all cases (wrapping to the leftmost pixel of the next row if it does - // not exist). - memcpy(current_row + context_start_x, - argb + (start_y - 1) * width + context_start_x, - sizeof(*argb) * (max_x + have_left + 1)); - } - for (relative_y = 0; relative_y < max_y; ++relative_y) { - const int y = start_y + relative_y; - int relative_x; - uint32_t* tmp = upper_row; - upper_row = current_row; - current_row = tmp; - // Read current_row. Include a pixel to the left if it exists; include a - // pixel to the right in all cases except at the bottom right corner of - // the image (wrapping to the leftmost pixel of the next row if it does - // not exist in the current row). - memcpy(current_row + context_start_x, - argb + y * width + context_start_x, - sizeof(*argb) * (max_x + have_left + (y + 1 < height))); -#if (WEBP_NEAR_LOSSLESS == 1) - if (max_quantization > 1 && y >= 1 && y + 1 < height) { - MaxDiffsForRow(context_width, width, argb + y * width + context_start_x, - max_diffs + context_start_x, used_subtract_green); - } -#endif - - GetResidual(width, height, upper_row, current_row, max_diffs, mode, - start_x, start_x + max_x, y, max_quantization, exact, - used_subtract_green, residuals); - for (relative_x = 0; relative_x < max_x; ++relative_x) { - UpdateHisto(histo_argb, residuals[relative_x]); - } - } - cur_diff = PredictionCostSpatialHistogram( - (const int (*)[256])accumulated, (const int (*)[256])histo_argb); - // Favor keeping the areas locally similar. - if (mode == left_mode) cur_diff -= kSpatialPredictorBias; - if (mode == above_mode) cur_diff -= kSpatialPredictorBias; - - if (cur_diff < best_diff) { - int (*tmp)[256] = histo_argb; - histo_argb = best_histo; - best_histo = tmp; - best_diff = cur_diff; - best_mode = mode; - } - } - - for (i = 0; i < 4; i++) { - for (j = 0; j < 256; j++) { - accumulated[i][j] += best_histo[i][j]; - } - } - - return best_mode; -} - -// Converts pixels of the image to residuals with respect to predictions. -// If max_quantization > 1, applies near lossless processing, quantizing -// residuals to multiples of quantization levels up to max_quantization -// (the actual quantization level depends on smoothness near the given pixel). -static void CopyImageWithPrediction(int width, int height, - int bits, uint32_t* const modes, - uint32_t* const argb_scratch, - uint32_t* const argb, - int low_effort, int max_quantization, - int exact, int used_subtract_green) { - const int tiles_per_row = VP8LSubSampleSize(width, bits); - // The width of upper_row and current_row is one pixel larger than image width - // to allow the top right pixel to point to the leftmost pixel of the next row - // when at the right edge. - uint32_t* upper_row = argb_scratch; - uint32_t* current_row = upper_row + width + 1; - uint8_t* current_max_diffs = (uint8_t*)(current_row + width + 1); -#if (WEBP_NEAR_LOSSLESS == 1) - uint8_t* lower_max_diffs = current_max_diffs + width; -#endif - int y; - - for (y = 0; y < height; ++y) { - int x; - uint32_t* const tmp32 = upper_row; - upper_row = current_row; - current_row = tmp32; - memcpy(current_row, argb + y * width, - sizeof(*argb) * (width + (y + 1 < height))); - - if (low_effort) { - PredictBatch(kPredLowEffort, 0, y, width, current_row, upper_row, - argb + y * width); - } else { -#if (WEBP_NEAR_LOSSLESS == 1) - if (max_quantization > 1) { - // Compute max_diffs for the lower row now, because that needs the - // contents of argb for the current row, which we will overwrite with - // residuals before proceeding with the next row. - uint8_t* const tmp8 = current_max_diffs; - current_max_diffs = lower_max_diffs; - lower_max_diffs = tmp8; - if (y + 2 < height) { - MaxDiffsForRow(width, width, argb + (y + 1) * width, lower_max_diffs, - used_subtract_green); - } - } -#endif - for (x = 0; x < width;) { - const int mode = - (modes[(y >> bits) * tiles_per_row + (x >> bits)] >> 8) & 0xff; - int x_end = x + (1 << bits); - if (x_end > width) x_end = width; - GetResidual(width, height, upper_row, current_row, current_max_diffs, - mode, x, x_end, y, max_quantization, exact, - used_subtract_green, argb + y * width + x); - x = x_end; - } - } - } -} - -// Finds the best predictor for each tile, and converts the image to residuals -// with respect to predictions. If near_lossless_quality < 100, applies -// near lossless processing, shaving off more bits of residuals for lower -// qualities. -int VP8LResidualImage(int width, int height, int bits, int low_effort, - uint32_t* const argb, uint32_t* const argb_scratch, - uint32_t* const image, int near_lossless_quality, - int exact, int used_subtract_green, - const WebPPicture* const pic, int percent_range, - int* const percent) { - const int tiles_per_row = VP8LSubSampleSize(width, bits); - const int tiles_per_col = VP8LSubSampleSize(height, bits); - int percent_start = *percent; - int tile_y; - int histo[4][256]; - const int max_quantization = 1 << VP8LNearLosslessBits(near_lossless_quality); - if (low_effort) { - int i; - for (i = 0; i < tiles_per_row * tiles_per_col; ++i) { - image[i] = ARGB_BLACK | (kPredLowEffort << 8); - } - } else { - memset(histo, 0, sizeof(histo)); - for (tile_y = 0; tile_y < tiles_per_col; ++tile_y) { - int tile_x; - for (tile_x = 0; tile_x < tiles_per_row; ++tile_x) { - const int pred = GetBestPredictorForTile( - width, height, tile_x, tile_y, bits, histo, argb_scratch, argb, - max_quantization, exact, used_subtract_green, image); - image[tile_y * tiles_per_row + tile_x] = ARGB_BLACK | (pred << 8); - } - - if (!WebPReportProgress( - pic, percent_start + percent_range * tile_y / tiles_per_col, - percent)) { - return 0; - } - } - } - - CopyImageWithPrediction(width, height, bits, image, argb_scratch, argb, - low_effort, max_quantization, exact, - used_subtract_green); - return WebPReportProgress(pic, percent_start + percent_range, percent); -} - -//------------------------------------------------------------------------------ -// Color transform functions. - -static WEBP_INLINE void MultipliersClear(VP8LMultipliers* const m) { - m->green_to_red_ = 0; - m->green_to_blue_ = 0; - m->red_to_blue_ = 0; -} - -static WEBP_INLINE void ColorCodeToMultipliers(uint32_t color_code, - VP8LMultipliers* const m) { - m->green_to_red_ = (color_code >> 0) & 0xff; - m->green_to_blue_ = (color_code >> 8) & 0xff; - m->red_to_blue_ = (color_code >> 16) & 0xff; -} - -static WEBP_INLINE uint32_t MultipliersToColorCode( - const VP8LMultipliers* const m) { - return 0xff000000u | - ((uint32_t)(m->red_to_blue_) << 16) | - ((uint32_t)(m->green_to_blue_) << 8) | - m->green_to_red_; -} - -static float PredictionCostCrossColor(const int accumulated[256], - const int counts[256]) { - // Favor low entropy, locally and globally. - // Favor small absolute values for PredictionCostSpatial - static const float kExpValue = 2.4f; - return VP8LCombinedShannonEntropy(counts, accumulated) + - PredictionCostSpatial(counts, 3, kExpValue); -} - -static float GetPredictionCostCrossColorRed( - const uint32_t* argb, int stride, int tile_width, int tile_height, - VP8LMultipliers prev_x, VP8LMultipliers prev_y, int green_to_red, - const int accumulated_red_histo[256]) { - int histo[256] = { 0 }; - float cur_diff; - - VP8LCollectColorRedTransforms(argb, stride, tile_width, tile_height, - green_to_red, histo); - - cur_diff = PredictionCostCrossColor(accumulated_red_histo, histo); - if ((uint8_t)green_to_red == prev_x.green_to_red_) { - cur_diff -= 3; // favor keeping the areas locally similar - } - if ((uint8_t)green_to_red == prev_y.green_to_red_) { - cur_diff -= 3; // favor keeping the areas locally similar - } - if (green_to_red == 0) { - cur_diff -= 3; - } - return cur_diff; -} - -static void GetBestGreenToRed( - const uint32_t* argb, int stride, int tile_width, int tile_height, - VP8LMultipliers prev_x, VP8LMultipliers prev_y, int quality, - const int accumulated_red_histo[256], VP8LMultipliers* const best_tx) { - const int kMaxIters = 4 + ((7 * quality) >> 8); // in range [4..6] - int green_to_red_best = 0; - int iter, offset; - float best_diff = GetPredictionCostCrossColorRed( - argb, stride, tile_width, tile_height, prev_x, prev_y, - green_to_red_best, accumulated_red_histo); - for (iter = 0; iter < kMaxIters; ++iter) { - // ColorTransformDelta is a 3.5 bit fixed point, so 32 is equal to - // one in color computation. Having initial delta here as 1 is sufficient - // to explore the range of (-2, 2). - const int delta = 32 >> iter; - // Try a negative and a positive delta from the best known value. - for (offset = -delta; offset <= delta; offset += 2 * delta) { - const int green_to_red_cur = offset + green_to_red_best; - const float cur_diff = GetPredictionCostCrossColorRed( - argb, stride, tile_width, tile_height, prev_x, prev_y, - green_to_red_cur, accumulated_red_histo); - if (cur_diff < best_diff) { - best_diff = cur_diff; - green_to_red_best = green_to_red_cur; - } - } - } - best_tx->green_to_red_ = (green_to_red_best & 0xff); -} - -static float GetPredictionCostCrossColorBlue( - const uint32_t* argb, int stride, int tile_width, int tile_height, - VP8LMultipliers prev_x, VP8LMultipliers prev_y, - int green_to_blue, int red_to_blue, const int accumulated_blue_histo[256]) { - int histo[256] = { 0 }; - float cur_diff; - - VP8LCollectColorBlueTransforms(argb, stride, tile_width, tile_height, - green_to_blue, red_to_blue, histo); - - cur_diff = PredictionCostCrossColor(accumulated_blue_histo, histo); - if ((uint8_t)green_to_blue == prev_x.green_to_blue_) { - cur_diff -= 3; // favor keeping the areas locally similar - } - if ((uint8_t)green_to_blue == prev_y.green_to_blue_) { - cur_diff -= 3; // favor keeping the areas locally similar - } - if ((uint8_t)red_to_blue == prev_x.red_to_blue_) { - cur_diff -= 3; // favor keeping the areas locally similar - } - if ((uint8_t)red_to_blue == prev_y.red_to_blue_) { - cur_diff -= 3; // favor keeping the areas locally similar - } - if (green_to_blue == 0) { - cur_diff -= 3; - } - if (red_to_blue == 0) { - cur_diff -= 3; - } - return cur_diff; -} - -#define kGreenRedToBlueNumAxis 8 -#define kGreenRedToBlueMaxIters 7 -static void GetBestGreenRedToBlue( - const uint32_t* argb, int stride, int tile_width, int tile_height, - VP8LMultipliers prev_x, VP8LMultipliers prev_y, int quality, - const int accumulated_blue_histo[256], - VP8LMultipliers* const best_tx) { - const int8_t offset[kGreenRedToBlueNumAxis][2] = - {{0, -1}, {0, 1}, {-1, 0}, {1, 0}, {-1, -1}, {-1, 1}, {1, -1}, {1, 1}}; - const int8_t delta_lut[kGreenRedToBlueMaxIters] = { 16, 16, 8, 4, 2, 2, 2 }; - const int iters = - (quality < 25) ? 1 : (quality > 50) ? kGreenRedToBlueMaxIters : 4; - int green_to_blue_best = 0; - int red_to_blue_best = 0; - int iter; - // Initial value at origin: - float best_diff = GetPredictionCostCrossColorBlue( - argb, stride, tile_width, tile_height, prev_x, prev_y, - green_to_blue_best, red_to_blue_best, accumulated_blue_histo); - for (iter = 0; iter < iters; ++iter) { - const int delta = delta_lut[iter]; - int axis; - for (axis = 0; axis < kGreenRedToBlueNumAxis; ++axis) { - const int green_to_blue_cur = - offset[axis][0] * delta + green_to_blue_best; - const int red_to_blue_cur = offset[axis][1] * delta + red_to_blue_best; - const float cur_diff = GetPredictionCostCrossColorBlue( - argb, stride, tile_width, tile_height, prev_x, prev_y, - green_to_blue_cur, red_to_blue_cur, accumulated_blue_histo); - if (cur_diff < best_diff) { - best_diff = cur_diff; - green_to_blue_best = green_to_blue_cur; - red_to_blue_best = red_to_blue_cur; - } - if (quality < 25 && iter == 4) { - // Only axis aligned diffs for lower quality. - break; // next iter. - } - } - if (delta == 2 && green_to_blue_best == 0 && red_to_blue_best == 0) { - // Further iterations would not help. - break; // out of iter-loop. - } - } - best_tx->green_to_blue_ = green_to_blue_best & 0xff; - best_tx->red_to_blue_ = red_to_blue_best & 0xff; -} -#undef kGreenRedToBlueMaxIters -#undef kGreenRedToBlueNumAxis - -static VP8LMultipliers GetBestColorTransformForTile( - int tile_x, int tile_y, int bits, - VP8LMultipliers prev_x, - VP8LMultipliers prev_y, - int quality, int xsize, int ysize, - const int accumulated_red_histo[256], - const int accumulated_blue_histo[256], - const uint32_t* const argb) { - const int max_tile_size = 1 << bits; - const int tile_y_offset = tile_y * max_tile_size; - const int tile_x_offset = tile_x * max_tile_size; - const int all_x_max = GetMin(tile_x_offset + max_tile_size, xsize); - const int all_y_max = GetMin(tile_y_offset + max_tile_size, ysize); - const int tile_width = all_x_max - tile_x_offset; - const int tile_height = all_y_max - tile_y_offset; - const uint32_t* const tile_argb = argb + tile_y_offset * xsize - + tile_x_offset; - VP8LMultipliers best_tx; - MultipliersClear(&best_tx); - - GetBestGreenToRed(tile_argb, xsize, tile_width, tile_height, - prev_x, prev_y, quality, accumulated_red_histo, &best_tx); - GetBestGreenRedToBlue(tile_argb, xsize, tile_width, tile_height, - prev_x, prev_y, quality, accumulated_blue_histo, - &best_tx); - return best_tx; -} - -static void CopyTileWithColorTransform(int xsize, int ysize, - int tile_x, int tile_y, - int max_tile_size, - VP8LMultipliers color_transform, - uint32_t* argb) { - const int xscan = GetMin(max_tile_size, xsize - tile_x); - int yscan = GetMin(max_tile_size, ysize - tile_y); - argb += tile_y * xsize + tile_x; - while (yscan-- > 0) { - VP8LTransformColor(&color_transform, argb, xscan); - argb += xsize; - } -} - -int VP8LColorSpaceTransform(int width, int height, int bits, int quality, - uint32_t* const argb, uint32_t* image, - const WebPPicture* const pic, int percent_range, - int* const percent) { - const int max_tile_size = 1 << bits; - const int tile_xsize = VP8LSubSampleSize(width, bits); - const int tile_ysize = VP8LSubSampleSize(height, bits); - int percent_start = *percent; - int accumulated_red_histo[256] = { 0 }; - int accumulated_blue_histo[256] = { 0 }; - int tile_x, tile_y; - VP8LMultipliers prev_x, prev_y; - MultipliersClear(&prev_y); - MultipliersClear(&prev_x); - for (tile_y = 0; tile_y < tile_ysize; ++tile_y) { - for (tile_x = 0; tile_x < tile_xsize; ++tile_x) { - int y; - const int tile_x_offset = tile_x * max_tile_size; - const int tile_y_offset = tile_y * max_tile_size; - const int all_x_max = GetMin(tile_x_offset + max_tile_size, width); - const int all_y_max = GetMin(tile_y_offset + max_tile_size, height); - const int offset = tile_y * tile_xsize + tile_x; - if (tile_y != 0) { - ColorCodeToMultipliers(image[offset - tile_xsize], &prev_y); - } - prev_x = GetBestColorTransformForTile(tile_x, tile_y, bits, - prev_x, prev_y, - quality, width, height, - accumulated_red_histo, - accumulated_blue_histo, - argb); - image[offset] = MultipliersToColorCode(&prev_x); - CopyTileWithColorTransform(width, height, tile_x_offset, tile_y_offset, - max_tile_size, prev_x, argb); - - // Gather accumulated histogram data. - for (y = tile_y_offset; y < all_y_max; ++y) { - int ix = y * width + tile_x_offset; - const int ix_end = ix + all_x_max - tile_x_offset; - for (; ix < ix_end; ++ix) { - const uint32_t pix = argb[ix]; - if (ix >= 2 && - pix == argb[ix - 2] && - pix == argb[ix - 1]) { - continue; // repeated pixels are handled by backward references - } - if (ix >= width + 2 && - argb[ix - 2] == argb[ix - width - 2] && - argb[ix - 1] == argb[ix - width - 1] && - pix == argb[ix - width]) { - continue; // repeated pixels are handled by backward references - } - ++accumulated_red_histo[(pix >> 16) & 0xff]; - ++accumulated_blue_histo[(pix >> 0) & 0xff]; - } - } - } - if (!WebPReportProgress( - pic, percent_start + percent_range * tile_y / tile_ysize, - percent)) { - return 0; - } - } - return 1; -} diff --git a/libwebp/src/enc/quant_enc.c b/libwebp/src/enc/quant_enc.c deleted file mode 100644 index 6d8202d2..00000000 --- a/libwebp/src/enc/quant_enc.c +++ /dev/null @@ -1,1398 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Quantization -// -// Author: Skal (pascal.massimino@gmail.com) - -#include -#include -#include // for abs() - -#include "src/dsp/quant.h" -#include "src/enc/vp8i_enc.h" -#include "src/enc/cost_enc.h" - -#define DO_TRELLIS_I4 1 -#define DO_TRELLIS_I16 1 // not a huge gain, but ok at low bitrate. -#define DO_TRELLIS_UV 0 // disable trellis for UV. Risky. Not worth. -#define USE_TDISTO 1 - -#define MID_ALPHA 64 // neutral value for susceptibility -#define MIN_ALPHA 30 // lowest usable value for susceptibility -#define MAX_ALPHA 100 // higher meaningful value for susceptibility - -#define SNS_TO_DQ 0.9 // Scaling constant between the sns value and the QP - // power-law modulation. Must be strictly less than 1. - -// number of non-zero coeffs below which we consider the block very flat -// (and apply a penalty to complex predictions) -#define FLATNESS_LIMIT_I16 0 // I16 mode (special case) -#define FLATNESS_LIMIT_I4 3 // I4 mode -#define FLATNESS_LIMIT_UV 2 // UV mode -#define FLATNESS_PENALTY 140 // roughly ~1bit per block - -#define MULT_8B(a, b) (((a) * (b) + 128) >> 8) - -#define RD_DISTO_MULT 256 // distortion multiplier (equivalent of lambda) - -// #define DEBUG_BLOCK - -//------------------------------------------------------------------------------ - -#if defined(DEBUG_BLOCK) - -#include -#include - -static void PrintBlockInfo(const VP8EncIterator* const it, - const VP8ModeScore* const rd) { - int i, j; - const int is_i16 = (it->mb_->type_ == 1); - const uint8_t* const y_in = it->yuv_in_ + Y_OFF_ENC; - const uint8_t* const y_out = it->yuv_out_ + Y_OFF_ENC; - const uint8_t* const uv_in = it->yuv_in_ + U_OFF_ENC; - const uint8_t* const uv_out = it->yuv_out_ + U_OFF_ENC; - printf("SOURCE / OUTPUT / ABS DELTA\n"); - for (j = 0; j < 16; ++j) { - for (i = 0; i < 16; ++i) printf("%3d ", y_in[i + j * BPS]); - printf(" "); - for (i = 0; i < 16; ++i) printf("%3d ", y_out[i + j * BPS]); - printf(" "); - for (i = 0; i < 16; ++i) { - printf("%1d ", abs(y_in[i + j * BPS] - y_out[i + j * BPS])); - } - printf("\n"); - } - printf("\n"); // newline before the U/V block - for (j = 0; j < 8; ++j) { - for (i = 0; i < 8; ++i) printf("%3d ", uv_in[i + j * BPS]); - printf(" "); - for (i = 8; i < 16; ++i) printf("%3d ", uv_in[i + j * BPS]); - printf(" "); - for (i = 0; i < 8; ++i) printf("%3d ", uv_out[i + j * BPS]); - printf(" "); - for (i = 8; i < 16; ++i) printf("%3d ", uv_out[i + j * BPS]); - printf(" "); - for (i = 0; i < 8; ++i) { - printf("%1d ", abs(uv_out[i + j * BPS] - uv_in[i + j * BPS])); - } - printf(" "); - for (i = 8; i < 16; ++i) { - printf("%1d ", abs(uv_out[i + j * BPS] - uv_in[i + j * BPS])); - } - printf("\n"); - } - printf("\nD:%d SD:%d R:%d H:%d nz:0x%x score:%d\n", - (int)rd->D, (int)rd->SD, (int)rd->R, (int)rd->H, (int)rd->nz, - (int)rd->score); - if (is_i16) { - printf("Mode: %d\n", rd->mode_i16); - printf("y_dc_levels:"); - for (i = 0; i < 16; ++i) printf("%3d ", rd->y_dc_levels[i]); - printf("\n"); - } else { - printf("Modes[16]: "); - for (i = 0; i < 16; ++i) printf("%d ", rd->modes_i4[i]); - printf("\n"); - } - printf("y_ac_levels:\n"); - for (j = 0; j < 16; ++j) { - for (i = is_i16 ? 1 : 0; i < 16; ++i) { - printf("%4d ", rd->y_ac_levels[j][i]); - } - printf("\n"); - } - printf("\n"); - printf("uv_levels (mode=%d):\n", rd->mode_uv); - for (j = 0; j < 8; ++j) { - for (i = 0; i < 16; ++i) { - printf("%4d ", rd->uv_levels[j][i]); - } - printf("\n"); - } -} - -#endif // DEBUG_BLOCK - -//------------------------------------------------------------------------------ - -static WEBP_INLINE int clip(int v, int m, int M) { - return v < m ? m : v > M ? M : v; -} - -static const uint8_t kZigzag[16] = { - 0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15 -}; - -static const uint8_t kDcTable[128] = { - 4, 5, 6, 7, 8, 9, 10, 10, - 11, 12, 13, 14, 15, 16, 17, 17, - 18, 19, 20, 20, 21, 21, 22, 22, - 23, 23, 24, 25, 25, 26, 27, 28, - 29, 30, 31, 32, 33, 34, 35, 36, - 37, 37, 38, 39, 40, 41, 42, 43, - 44, 45, 46, 46, 47, 48, 49, 50, - 51, 52, 53, 54, 55, 56, 57, 58, - 59, 60, 61, 62, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 72, 73, 74, - 75, 76, 76, 77, 78, 79, 80, 81, - 82, 83, 84, 85, 86, 87, 88, 89, - 91, 93, 95, 96, 98, 100, 101, 102, - 104, 106, 108, 110, 112, 114, 116, 118, - 122, 124, 126, 128, 130, 132, 134, 136, - 138, 140, 143, 145, 148, 151, 154, 157 -}; - -static const uint16_t kAcTable[128] = { - 4, 5, 6, 7, 8, 9, 10, 11, - 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, - 28, 29, 30, 31, 32, 33, 34, 35, - 36, 37, 38, 39, 40, 41, 42, 43, - 44, 45, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, 57, 58, 60, - 62, 64, 66, 68, 70, 72, 74, 76, - 78, 80, 82, 84, 86, 88, 90, 92, - 94, 96, 98, 100, 102, 104, 106, 108, - 110, 112, 114, 116, 119, 122, 125, 128, - 131, 134, 137, 140, 143, 146, 149, 152, - 155, 158, 161, 164, 167, 170, 173, 177, - 181, 185, 189, 193, 197, 201, 205, 209, - 213, 217, 221, 225, 229, 234, 239, 245, - 249, 254, 259, 264, 269, 274, 279, 284 -}; - -static const uint16_t kAcTable2[128] = { - 8, 8, 9, 10, 12, 13, 15, 17, - 18, 20, 21, 23, 24, 26, 27, 29, - 31, 32, 34, 35, 37, 38, 40, 41, - 43, 44, 46, 48, 49, 51, 52, 54, - 55, 57, 58, 60, 62, 63, 65, 66, - 68, 69, 71, 72, 74, 75, 77, 79, - 80, 82, 83, 85, 86, 88, 89, 93, - 96, 99, 102, 105, 108, 111, 114, 117, - 120, 124, 127, 130, 133, 136, 139, 142, - 145, 148, 151, 155, 158, 161, 164, 167, - 170, 173, 176, 179, 184, 189, 193, 198, - 203, 207, 212, 217, 221, 226, 230, 235, - 240, 244, 249, 254, 258, 263, 268, 274, - 280, 286, 292, 299, 305, 311, 317, 323, - 330, 336, 342, 348, 354, 362, 370, 379, - 385, 393, 401, 409, 416, 424, 432, 440 -}; - -static const uint8_t kBiasMatrices[3][2] = { // [luma-ac,luma-dc,chroma][dc,ac] - { 96, 110 }, { 96, 108 }, { 110, 115 } -}; - -// Sharpening by (slightly) raising the hi-frequency coeffs. -// Hack-ish but helpful for mid-bitrate range. Use with care. -#define SHARPEN_BITS 11 // number of descaling bits for sharpening bias -static const uint8_t kFreqSharpening[16] = { - 0, 30, 60, 90, - 30, 60, 90, 90, - 60, 90, 90, 90, - 90, 90, 90, 90 -}; - -//------------------------------------------------------------------------------ -// Initialize quantization parameters in VP8Matrix - -// Returns the average quantizer -static int ExpandMatrix(VP8Matrix* const m, int type) { - int i, sum; - for (i = 0; i < 2; ++i) { - const int is_ac_coeff = (i > 0); - const int bias = kBiasMatrices[type][is_ac_coeff]; - m->iq_[i] = (1 << QFIX) / m->q_[i]; - m->bias_[i] = BIAS(bias); - // zthresh_ is the exact value such that QUANTDIV(coeff, iQ, B) is: - // * zero if coeff <= zthresh - // * non-zero if coeff > zthresh - m->zthresh_[i] = ((1 << QFIX) - 1 - m->bias_[i]) / m->iq_[i]; - } - for (i = 2; i < 16; ++i) { - m->q_[i] = m->q_[1]; - m->iq_[i] = m->iq_[1]; - m->bias_[i] = m->bias_[1]; - m->zthresh_[i] = m->zthresh_[1]; - } - for (sum = 0, i = 0; i < 16; ++i) { - if (type == 0) { // we only use sharpening for AC luma coeffs - m->sharpen_[i] = (kFreqSharpening[i] * m->q_[i]) >> SHARPEN_BITS; - } else { - m->sharpen_[i] = 0; - } - sum += m->q_[i]; - } - return (sum + 8) >> 4; -} - -static void CheckLambdaValue(int* const v) { if (*v < 1) *v = 1; } - -static void SetupMatrices(VP8Encoder* enc) { - int i; - const int tlambda_scale = - (enc->method_ >= 4) ? enc->config_->sns_strength - : 0; - const int num_segments = enc->segment_hdr_.num_segments_; - for (i = 0; i < num_segments; ++i) { - VP8SegmentInfo* const m = &enc->dqm_[i]; - const int q = m->quant_; - int q_i4, q_i16, q_uv; - m->y1_.q_[0] = kDcTable[clip(q + enc->dq_y1_dc_, 0, 127)]; - m->y1_.q_[1] = kAcTable[clip(q, 0, 127)]; - - m->y2_.q_[0] = kDcTable[ clip(q + enc->dq_y2_dc_, 0, 127)] * 2; - m->y2_.q_[1] = kAcTable2[clip(q + enc->dq_y2_ac_, 0, 127)]; - - m->uv_.q_[0] = kDcTable[clip(q + enc->dq_uv_dc_, 0, 117)]; - m->uv_.q_[1] = kAcTable[clip(q + enc->dq_uv_ac_, 0, 127)]; - - q_i4 = ExpandMatrix(&m->y1_, 0); - q_i16 = ExpandMatrix(&m->y2_, 1); - q_uv = ExpandMatrix(&m->uv_, 2); - - m->lambda_i4_ = (3 * q_i4 * q_i4) >> 7; - m->lambda_i16_ = (3 * q_i16 * q_i16); - m->lambda_uv_ = (3 * q_uv * q_uv) >> 6; - m->lambda_mode_ = (1 * q_i4 * q_i4) >> 7; - m->lambda_trellis_i4_ = (7 * q_i4 * q_i4) >> 3; - m->lambda_trellis_i16_ = (q_i16 * q_i16) >> 2; - m->lambda_trellis_uv_ = (q_uv * q_uv) << 1; - m->tlambda_ = (tlambda_scale * q_i4) >> 5; - - // none of these constants should be < 1 - CheckLambdaValue(&m->lambda_i4_); - CheckLambdaValue(&m->lambda_i16_); - CheckLambdaValue(&m->lambda_uv_); - CheckLambdaValue(&m->lambda_mode_); - CheckLambdaValue(&m->lambda_trellis_i4_); - CheckLambdaValue(&m->lambda_trellis_i16_); - CheckLambdaValue(&m->lambda_trellis_uv_); - CheckLambdaValue(&m->tlambda_); - - m->min_disto_ = 20 * m->y1_.q_[0]; // quantization-aware min disto - m->max_edge_ = 0; - - m->i4_penalty_ = 1000 * q_i4 * q_i4; - } -} - -//------------------------------------------------------------------------------ -// Initialize filtering parameters - -// Very small filter-strength values have close to no visual effect. So we can -// save a little decoding-CPU by turning filtering off for these. -#define FSTRENGTH_CUTOFF 2 - -static void SetupFilterStrength(VP8Encoder* const enc) { - int i; - // level0 is in [0..500]. Using '-f 50' as filter_strength is mid-filtering. - const int level0 = 5 * enc->config_->filter_strength; - for (i = 0; i < NUM_MB_SEGMENTS; ++i) { - VP8SegmentInfo* const m = &enc->dqm_[i]; - // We focus on the quantization of AC coeffs. - const int qstep = kAcTable[clip(m->quant_, 0, 127)] >> 2; - const int base_strength = - VP8FilterStrengthFromDelta(enc->filter_hdr_.sharpness_, qstep); - // Segments with lower complexity ('beta') will be less filtered. - const int f = base_strength * level0 / (256 + m->beta_); - m->fstrength_ = (f < FSTRENGTH_CUTOFF) ? 0 : (f > 63) ? 63 : f; - } - // We record the initial strength (mainly for the case of 1-segment only). - enc->filter_hdr_.level_ = enc->dqm_[0].fstrength_; - enc->filter_hdr_.simple_ = (enc->config_->filter_type == 0); - enc->filter_hdr_.sharpness_ = enc->config_->filter_sharpness; -} - -//------------------------------------------------------------------------------ - -// Note: if you change the values below, remember that the max range -// allowed by the syntax for DQ_UV is [-16,16]. -#define MAX_DQ_UV (6) -#define MIN_DQ_UV (-4) - -// We want to emulate jpeg-like behaviour where the expected "good" quality -// is around q=75. Internally, our "good" middle is around c=50. So we -// map accordingly using linear piece-wise function -static double QualityToCompression(double c) { - const double linear_c = (c < 0.75) ? c * (2. / 3.) : 2. * c - 1.; - // The file size roughly scales as pow(quantizer, 3.). Actually, the - // exponent is somewhere between 2.8 and 3.2, but we're mostly interested - // in the mid-quant range. So we scale the compressibility inversely to - // this power-law: quant ~= compression ^ 1/3. This law holds well for - // low quant. Finer modeling for high-quant would make use of kAcTable[] - // more explicitly. - const double v = pow(linear_c, 1 / 3.); - return v; -} - -static double QualityToJPEGCompression(double c, double alpha) { - // We map the complexity 'alpha' and quality setting 'c' to a compression - // exponent empirically matched to the compression curve of libjpeg6b. - // On average, the WebP output size will be roughly similar to that of a - // JPEG file compressed with same quality factor. - const double amin = 0.30; - const double amax = 0.85; - const double exp_min = 0.4; - const double exp_max = 0.9; - const double slope = (exp_min - exp_max) / (amax - amin); - // Linearly interpolate 'expn' from exp_min to exp_max - // in the [amin, amax] range. - const double expn = (alpha > amax) ? exp_min - : (alpha < amin) ? exp_max - : exp_max + slope * (alpha - amin); - const double v = pow(c, expn); - return v; -} - -static int SegmentsAreEquivalent(const VP8SegmentInfo* const S1, - const VP8SegmentInfo* const S2) { - return (S1->quant_ == S2->quant_) && (S1->fstrength_ == S2->fstrength_); -} - -static void SimplifySegments(VP8Encoder* const enc) { - int map[NUM_MB_SEGMENTS] = { 0, 1, 2, 3 }; - // 'num_segments_' is previously validated and <= NUM_MB_SEGMENTS, but an - // explicit check is needed to avoid a spurious warning about 'i' exceeding - // array bounds of 'dqm_' with some compilers (noticed with gcc-4.9). - const int num_segments = (enc->segment_hdr_.num_segments_ < NUM_MB_SEGMENTS) - ? enc->segment_hdr_.num_segments_ - : NUM_MB_SEGMENTS; - int num_final_segments = 1; - int s1, s2; - for (s1 = 1; s1 < num_segments; ++s1) { // find similar segments - const VP8SegmentInfo* const S1 = &enc->dqm_[s1]; - int found = 0; - // check if we already have similar segment - for (s2 = 0; s2 < num_final_segments; ++s2) { - const VP8SegmentInfo* const S2 = &enc->dqm_[s2]; - if (SegmentsAreEquivalent(S1, S2)) { - found = 1; - break; - } - } - map[s1] = s2; - if (!found) { - if (num_final_segments != s1) { - enc->dqm_[num_final_segments] = enc->dqm_[s1]; - } - ++num_final_segments; - } - } - if (num_final_segments < num_segments) { // Remap - int i = enc->mb_w_ * enc->mb_h_; - while (i-- > 0) enc->mb_info_[i].segment_ = map[enc->mb_info_[i].segment_]; - enc->segment_hdr_.num_segments_ = num_final_segments; - // Replicate the trailing segment infos (it's mostly cosmetics) - for (i = num_final_segments; i < num_segments; ++i) { - enc->dqm_[i] = enc->dqm_[num_final_segments - 1]; - } - } -} - -void VP8SetSegmentParams(VP8Encoder* const enc, float quality) { - int i; - int dq_uv_ac, dq_uv_dc; - const int num_segments = enc->segment_hdr_.num_segments_; - const double amp = SNS_TO_DQ * enc->config_->sns_strength / 100. / 128.; - const double Q = quality / 100.; - const double c_base = enc->config_->emulate_jpeg_size ? - QualityToJPEGCompression(Q, enc->alpha_ / 255.) : - QualityToCompression(Q); - for (i = 0; i < num_segments; ++i) { - // We modulate the base coefficient to accommodate for the quantization - // susceptibility and allow denser segments to be quantized more. - const double expn = 1. - amp * enc->dqm_[i].alpha_; - const double c = pow(c_base, expn); - const int q = (int)(127. * (1. - c)); - assert(expn > 0.); - enc->dqm_[i].quant_ = clip(q, 0, 127); - } - - // purely indicative in the bitstream (except for the 1-segment case) - enc->base_quant_ = enc->dqm_[0].quant_; - - // fill-in values for the unused segments (required by the syntax) - for (i = num_segments; i < NUM_MB_SEGMENTS; ++i) { - enc->dqm_[i].quant_ = enc->base_quant_; - } - - // uv_alpha_ is normally spread around ~60. The useful range is - // typically ~30 (quite bad) to ~100 (ok to decimate UV more). - // We map it to the safe maximal range of MAX/MIN_DQ_UV for dq_uv. - dq_uv_ac = (enc->uv_alpha_ - MID_ALPHA) * (MAX_DQ_UV - MIN_DQ_UV) - / (MAX_ALPHA - MIN_ALPHA); - // we rescale by the user-defined strength of adaptation - dq_uv_ac = dq_uv_ac * enc->config_->sns_strength / 100; - // and make it safe. - dq_uv_ac = clip(dq_uv_ac, MIN_DQ_UV, MAX_DQ_UV); - // We also boost the dc-uv-quant a little, based on sns-strength, since - // U/V channels are quite more reactive to high quants (flat DC-blocks - // tend to appear, and are unpleasant). - dq_uv_dc = -4 * enc->config_->sns_strength / 100; - dq_uv_dc = clip(dq_uv_dc, -15, 15); // 4bit-signed max allowed - - enc->dq_y1_dc_ = 0; // TODO(skal): dq-lum - enc->dq_y2_dc_ = 0; - enc->dq_y2_ac_ = 0; - enc->dq_uv_dc_ = dq_uv_dc; - enc->dq_uv_ac_ = dq_uv_ac; - - SetupFilterStrength(enc); // initialize segments' filtering, eventually - - if (num_segments > 1) SimplifySegments(enc); - - SetupMatrices(enc); // finalize quantization matrices -} - -//------------------------------------------------------------------------------ -// Form the predictions in cache - -// Must be ordered using {DC_PRED, TM_PRED, V_PRED, H_PRED} as index -const uint16_t VP8I16ModeOffsets[4] = { I16DC16, I16TM16, I16VE16, I16HE16 }; -const uint16_t VP8UVModeOffsets[4] = { C8DC8, C8TM8, C8VE8, C8HE8 }; - -// Must be indexed using {B_DC_PRED -> B_HU_PRED} as index -const uint16_t VP8I4ModeOffsets[NUM_BMODES] = { - I4DC4, I4TM4, I4VE4, I4HE4, I4RD4, I4VR4, I4LD4, I4VL4, I4HD4, I4HU4 -}; - -void VP8MakeLuma16Preds(const VP8EncIterator* const it) { - const uint8_t* const left = it->x_ ? it->y_left_ : NULL; - const uint8_t* const top = it->y_ ? it->y_top_ : NULL; - VP8EncPredLuma16(it->yuv_p_, left, top); -} - -void VP8MakeChroma8Preds(const VP8EncIterator* const it) { - const uint8_t* const left = it->x_ ? it->u_left_ : NULL; - const uint8_t* const top = it->y_ ? it->uv_top_ : NULL; - VP8EncPredChroma8(it->yuv_p_, left, top); -} - -void VP8MakeIntra4Preds(const VP8EncIterator* const it) { - VP8EncPredLuma4(it->yuv_p_, it->i4_top_); -} - -//------------------------------------------------------------------------------ -// Quantize - -// Layout: -// +----+----+ -// |YYYY|UUVV| 0 -// |YYYY|UUVV| 4 -// |YYYY|....| 8 -// |YYYY|....| 12 -// +----+----+ - -const uint16_t VP8Scan[16] = { // Luma - 0 + 0 * BPS, 4 + 0 * BPS, 8 + 0 * BPS, 12 + 0 * BPS, - 0 + 4 * BPS, 4 + 4 * BPS, 8 + 4 * BPS, 12 + 4 * BPS, - 0 + 8 * BPS, 4 + 8 * BPS, 8 + 8 * BPS, 12 + 8 * BPS, - 0 + 12 * BPS, 4 + 12 * BPS, 8 + 12 * BPS, 12 + 12 * BPS, -}; - -static const uint16_t VP8ScanUV[4 + 4] = { - 0 + 0 * BPS, 4 + 0 * BPS, 0 + 4 * BPS, 4 + 4 * BPS, // U - 8 + 0 * BPS, 12 + 0 * BPS, 8 + 4 * BPS, 12 + 4 * BPS // V -}; - -//------------------------------------------------------------------------------ -// Distortion measurement - -static const uint16_t kWeightY[16] = { - 38, 32, 20, 9, 32, 28, 17, 7, 20, 17, 10, 4, 9, 7, 4, 2 -}; - -static const uint16_t kWeightTrellis[16] = { -#if USE_TDISTO == 0 - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 -#else - 30, 27, 19, 11, - 27, 24, 17, 10, - 19, 17, 12, 8, - 11, 10, 8, 6 -#endif -}; - -// Init/Copy the common fields in score. -static void InitScore(VP8ModeScore* const rd) { - rd->D = 0; - rd->SD = 0; - rd->R = 0; - rd->H = 0; - rd->nz = 0; - rd->score = MAX_COST; -} - -static void CopyScore(VP8ModeScore* WEBP_RESTRICT const dst, - const VP8ModeScore* WEBP_RESTRICT const src) { - dst->D = src->D; - dst->SD = src->SD; - dst->R = src->R; - dst->H = src->H; - dst->nz = src->nz; // note that nz is not accumulated, but just copied. - dst->score = src->score; -} - -static void AddScore(VP8ModeScore* WEBP_RESTRICT const dst, - const VP8ModeScore* WEBP_RESTRICT const src) { - dst->D += src->D; - dst->SD += src->SD; - dst->R += src->R; - dst->H += src->H; - dst->nz |= src->nz; // here, new nz bits are accumulated. - dst->score += src->score; -} - -//------------------------------------------------------------------------------ -// Performs trellis-optimized quantization. - -// Trellis node -typedef struct { - int8_t prev; // best previous node - int8_t sign; // sign of coeff_i - int16_t level; // level -} Node; - -// Score state -typedef struct { - score_t score; // partial RD score - const uint16_t* costs; // shortcut to cost tables -} ScoreState; - -// If a coefficient was quantized to a value Q (using a neutral bias), -// we test all alternate possibilities between [Q-MIN_DELTA, Q+MAX_DELTA] -// We don't test negative values though. -#define MIN_DELTA 0 // how much lower level to try -#define MAX_DELTA 1 // how much higher -#define NUM_NODES (MIN_DELTA + 1 + MAX_DELTA) -#define NODE(n, l) (nodes[(n)][(l) + MIN_DELTA]) -#define SCORE_STATE(n, l) (score_states[n][(l) + MIN_DELTA]) - -static WEBP_INLINE void SetRDScore(int lambda, VP8ModeScore* const rd) { - rd->score = (rd->R + rd->H) * lambda + RD_DISTO_MULT * (rd->D + rd->SD); -} - -static WEBP_INLINE score_t RDScoreTrellis(int lambda, score_t rate, - score_t distortion) { - return rate * lambda + RD_DISTO_MULT * distortion; -} - -// Coefficient type. -enum { TYPE_I16_AC = 0, TYPE_I16_DC = 1, TYPE_CHROMA_A = 2, TYPE_I4_AC = 3 }; - -static int TrellisQuantizeBlock(const VP8Encoder* WEBP_RESTRICT const enc, - int16_t in[16], int16_t out[16], - int ctx0, int coeff_type, - const VP8Matrix* WEBP_RESTRICT const mtx, - int lambda) { - const ProbaArray* const probas = enc->proba_.coeffs_[coeff_type]; - CostArrayPtr const costs = - (CostArrayPtr)enc->proba_.remapped_costs_[coeff_type]; - const int first = (coeff_type == TYPE_I16_AC) ? 1 : 0; - Node nodes[16][NUM_NODES]; - ScoreState score_states[2][NUM_NODES]; - ScoreState* ss_cur = &SCORE_STATE(0, MIN_DELTA); - ScoreState* ss_prev = &SCORE_STATE(1, MIN_DELTA); - int best_path[3] = {-1, -1, -1}; // store best-last/best-level/best-previous - score_t best_score; - int n, m, p, last; - - { - score_t cost; - const int thresh = mtx->q_[1] * mtx->q_[1] / 4; - const int last_proba = probas[VP8EncBands[first]][ctx0][0]; - - // compute the position of the last interesting coefficient - last = first - 1; - for (n = 15; n >= first; --n) { - const int j = kZigzag[n]; - const int err = in[j] * in[j]; - if (err > thresh) { - last = n; - break; - } - } - // we don't need to go inspect up to n = 16 coeffs. We can just go up - // to last + 1 (inclusive) without losing much. - if (last < 15) ++last; - - // compute 'skip' score. This is the max score one can do. - cost = VP8BitCost(0, last_proba); - best_score = RDScoreTrellis(lambda, cost, 0); - - // initialize source node. - for (m = -MIN_DELTA; m <= MAX_DELTA; ++m) { - const score_t rate = (ctx0 == 0) ? VP8BitCost(1, last_proba) : 0; - ss_cur[m].score = RDScoreTrellis(lambda, rate, 0); - ss_cur[m].costs = costs[first][ctx0]; - } - } - - // traverse trellis. - for (n = first; n <= last; ++n) { - const int j = kZigzag[n]; - const uint32_t Q = mtx->q_[j]; - const uint32_t iQ = mtx->iq_[j]; - const uint32_t B = BIAS(0x00); // neutral bias - // note: it's important to take sign of the _original_ coeff, - // so we don't have to consider level < 0 afterward. - const int sign = (in[j] < 0); - const uint32_t coeff0 = (sign ? -in[j] : in[j]) + mtx->sharpen_[j]; - int level0 = QUANTDIV(coeff0, iQ, B); - int thresh_level = QUANTDIV(coeff0, iQ, BIAS(0x80)); - if (thresh_level > MAX_LEVEL) thresh_level = MAX_LEVEL; - if (level0 > MAX_LEVEL) level0 = MAX_LEVEL; - - { // Swap current and previous score states - ScoreState* const tmp = ss_cur; - ss_cur = ss_prev; - ss_prev = tmp; - } - - // test all alternate level values around level0. - for (m = -MIN_DELTA; m <= MAX_DELTA; ++m) { - Node* const cur = &NODE(n, m); - const int level = level0 + m; - const int ctx = (level > 2) ? 2 : level; - const int band = VP8EncBands[n + 1]; - score_t base_score; - score_t best_cur_score; - int best_prev; - score_t cost, score; - - ss_cur[m].costs = costs[n + 1][ctx]; - if (level < 0 || level > thresh_level) { - ss_cur[m].score = MAX_COST; - // Node is dead. - continue; - } - - { - // Compute delta_error = how much coding this level will - // subtract to max_error as distortion. - // Here, distortion = sum of (|coeff_i| - level_i * Q_i)^2 - const int new_error = coeff0 - level * Q; - const int delta_error = - kWeightTrellis[j] * (new_error * new_error - coeff0 * coeff0); - base_score = RDScoreTrellis(lambda, 0, delta_error); - } - - // Inspect all possible non-dead predecessors. Retain only the best one. - // The base_score is added to all scores so it is only added for the final - // value after the loop. - cost = VP8LevelCost(ss_prev[-MIN_DELTA].costs, level); - best_cur_score = - ss_prev[-MIN_DELTA].score + RDScoreTrellis(lambda, cost, 0); - best_prev = -MIN_DELTA; - for (p = -MIN_DELTA + 1; p <= MAX_DELTA; ++p) { - // Dead nodes (with ss_prev[p].score >= MAX_COST) are automatically - // eliminated since their score can't be better than the current best. - cost = VP8LevelCost(ss_prev[p].costs, level); - // Examine node assuming it's a non-terminal one. - score = ss_prev[p].score + RDScoreTrellis(lambda, cost, 0); - if (score < best_cur_score) { - best_cur_score = score; - best_prev = p; - } - } - best_cur_score += base_score; - // Store best finding in current node. - cur->sign = sign; - cur->level = level; - cur->prev = best_prev; - ss_cur[m].score = best_cur_score; - - // Now, record best terminal node (and thus best entry in the graph). - if (level != 0 && best_cur_score < best_score) { - const score_t last_pos_cost = - (n < 15) ? VP8BitCost(0, probas[band][ctx][0]) : 0; - const score_t last_pos_score = RDScoreTrellis(lambda, last_pos_cost, 0); - score = best_cur_score + last_pos_score; - if (score < best_score) { - best_score = score; - best_path[0] = n; // best eob position - best_path[1] = m; // best node index - best_path[2] = best_prev; // best predecessor - } - } - } - } - - // Fresh start - // Beware! We must preserve in[0]/out[0] value for TYPE_I16_AC case. - if (coeff_type == TYPE_I16_AC) { - memset(in + 1, 0, 15 * sizeof(*in)); - memset(out + 1, 0, 15 * sizeof(*out)); - } else { - memset(in, 0, 16 * sizeof(*in)); - memset(out, 0, 16 * sizeof(*out)); - } - if (best_path[0] == -1) { - return 0; // skip! - } - - { - // Unwind the best path. - // Note: best-prev on terminal node is not necessarily equal to the - // best_prev for non-terminal. So we patch best_path[2] in. - int nz = 0; - int best_node = best_path[1]; - n = best_path[0]; - NODE(n, best_node).prev = best_path[2]; // force best-prev for terminal - - for (; n >= first; --n) { - const Node* const node = &NODE(n, best_node); - const int j = kZigzag[n]; - out[n] = node->sign ? -node->level : node->level; - nz |= node->level; - in[j] = out[n] * mtx->q_[j]; - best_node = node->prev; - } - return (nz != 0); - } -} - -#undef NODE - -//------------------------------------------------------------------------------ -// Performs: difference, transform, quantize, back-transform, add -// all at once. Output is the reconstructed block in *yuv_out, and the -// quantized levels in *levels. - -static int ReconstructIntra16(VP8EncIterator* WEBP_RESTRICT const it, - VP8ModeScore* WEBP_RESTRICT const rd, - uint8_t* WEBP_RESTRICT const yuv_out, - int mode) { - const VP8Encoder* const enc = it->enc_; - const uint8_t* const ref = it->yuv_p_ + VP8I16ModeOffsets[mode]; - const uint8_t* const src = it->yuv_in_ + Y_OFF_ENC; - const VP8SegmentInfo* const dqm = &enc->dqm_[it->mb_->segment_]; - int nz = 0; - int n; - int16_t tmp[16][16], dc_tmp[16]; - - for (n = 0; n < 16; n += 2) { - VP8FTransform2(src + VP8Scan[n], ref + VP8Scan[n], tmp[n]); - } - VP8FTransformWHT(tmp[0], dc_tmp); - nz |= VP8EncQuantizeBlockWHT(dc_tmp, rd->y_dc_levels, &dqm->y2_) << 24; - - if (DO_TRELLIS_I16 && it->do_trellis_) { - int x, y; - VP8IteratorNzToBytes(it); - for (y = 0, n = 0; y < 4; ++y) { - for (x = 0; x < 4; ++x, ++n) { - const int ctx = it->top_nz_[x] + it->left_nz_[y]; - const int non_zero = TrellisQuantizeBlock( - enc, tmp[n], rd->y_ac_levels[n], ctx, TYPE_I16_AC, &dqm->y1_, - dqm->lambda_trellis_i16_); - it->top_nz_[x] = it->left_nz_[y] = non_zero; - rd->y_ac_levels[n][0] = 0; - nz |= non_zero << n; - } - } - } else { - for (n = 0; n < 16; n += 2) { - // Zero-out the first coeff, so that: a) nz is correct below, and - // b) finding 'last' non-zero coeffs in SetResidualCoeffs() is simplified. - tmp[n][0] = tmp[n + 1][0] = 0; - nz |= VP8EncQuantize2Blocks(tmp[n], rd->y_ac_levels[n], &dqm->y1_) << n; - assert(rd->y_ac_levels[n + 0][0] == 0); - assert(rd->y_ac_levels[n + 1][0] == 0); - } - } - - // Transform back - VP8TransformWHT(dc_tmp, tmp[0]); - for (n = 0; n < 16; n += 2) { - VP8ITransform(ref + VP8Scan[n], tmp[n], yuv_out + VP8Scan[n], 1); - } - - return nz; -} - -static int ReconstructIntra4(VP8EncIterator* WEBP_RESTRICT const it, - int16_t levels[16], - const uint8_t* WEBP_RESTRICT const src, - uint8_t* WEBP_RESTRICT const yuv_out, - int mode) { - const VP8Encoder* const enc = it->enc_; - const uint8_t* const ref = it->yuv_p_ + VP8I4ModeOffsets[mode]; - const VP8SegmentInfo* const dqm = &enc->dqm_[it->mb_->segment_]; - int nz = 0; - int16_t tmp[16]; - - VP8FTransform(src, ref, tmp); - if (DO_TRELLIS_I4 && it->do_trellis_) { - const int x = it->i4_ & 3, y = it->i4_ >> 2; - const int ctx = it->top_nz_[x] + it->left_nz_[y]; - nz = TrellisQuantizeBlock(enc, tmp, levels, ctx, TYPE_I4_AC, &dqm->y1_, - dqm->lambda_trellis_i4_); - } else { - nz = VP8EncQuantizeBlock(tmp, levels, &dqm->y1_); - } - VP8ITransform(ref, tmp, yuv_out, 0); - return nz; -} - -//------------------------------------------------------------------------------ -// DC-error diffusion - -// Diffusion weights. We under-correct a bit (15/16th of the error is actually -// diffused) to avoid 'rainbow' chessboard pattern of blocks at q~=0. -#define C1 7 // fraction of error sent to the 4x4 block below -#define C2 8 // fraction of error sent to the 4x4 block on the right -#define DSHIFT 4 -#define DSCALE 1 // storage descaling, needed to make the error fit int8_t - -// Quantize as usual, but also compute and return the quantization error. -// Error is already divided by DSHIFT. -static int QuantizeSingle(int16_t* WEBP_RESTRICT const v, - const VP8Matrix* WEBP_RESTRICT const mtx) { - int V = *v; - const int sign = (V < 0); - if (sign) V = -V; - if (V > (int)mtx->zthresh_[0]) { - const int qV = QUANTDIV(V, mtx->iq_[0], mtx->bias_[0]) * mtx->q_[0]; - const int err = (V - qV); - *v = sign ? -qV : qV; - return (sign ? -err : err) >> DSCALE; - } - *v = 0; - return (sign ? -V : V) >> DSCALE; -} - -static void CorrectDCValues(const VP8EncIterator* WEBP_RESTRICT const it, - const VP8Matrix* WEBP_RESTRICT const mtx, - int16_t tmp[][16], - VP8ModeScore* WEBP_RESTRICT const rd) { - // | top[0] | top[1] - // --------+--------+--------- - // left[0] | tmp[0] tmp[1] <-> err0 err1 - // left[1] | tmp[2] tmp[3] err2 err3 - // - // Final errors {err1,err2,err3} are preserved and later restored - // as top[]/left[] on the next block. - int ch; - for (ch = 0; ch <= 1; ++ch) { - const int8_t* const top = it->top_derr_[it->x_][ch]; - const int8_t* const left = it->left_derr_[ch]; - int16_t (* const c)[16] = &tmp[ch * 4]; - int err0, err1, err2, err3; - c[0][0] += (C1 * top[0] + C2 * left[0]) >> (DSHIFT - DSCALE); - err0 = QuantizeSingle(&c[0][0], mtx); - c[1][0] += (C1 * top[1] + C2 * err0) >> (DSHIFT - DSCALE); - err1 = QuantizeSingle(&c[1][0], mtx); - c[2][0] += (C1 * err0 + C2 * left[1]) >> (DSHIFT - DSCALE); - err2 = QuantizeSingle(&c[2][0], mtx); - c[3][0] += (C1 * err1 + C2 * err2) >> (DSHIFT - DSCALE); - err3 = QuantizeSingle(&c[3][0], mtx); - // error 'err' is bounded by mtx->q_[0] which is 132 at max. Hence - // err >> DSCALE will fit in an int8_t type if DSCALE>=1. - assert(abs(err1) <= 127 && abs(err2) <= 127 && abs(err3) <= 127); - rd->derr[ch][0] = (int8_t)err1; - rd->derr[ch][1] = (int8_t)err2; - rd->derr[ch][2] = (int8_t)err3; - } -} - -static void StoreDiffusionErrors(VP8EncIterator* WEBP_RESTRICT const it, - const VP8ModeScore* WEBP_RESTRICT const rd) { - int ch; - for (ch = 0; ch <= 1; ++ch) { - int8_t* const top = it->top_derr_[it->x_][ch]; - int8_t* const left = it->left_derr_[ch]; - left[0] = rd->derr[ch][0]; // restore err1 - left[1] = 3 * rd->derr[ch][2] >> 2; // ... 3/4th of err3 - top[0] = rd->derr[ch][1]; // ... err2 - top[1] = rd->derr[ch][2] - left[1]; // ... 1/4th of err3. - } -} - -#undef C1 -#undef C2 -#undef DSHIFT -#undef DSCALE - -//------------------------------------------------------------------------------ - -static int ReconstructUV(VP8EncIterator* WEBP_RESTRICT const it, - VP8ModeScore* WEBP_RESTRICT const rd, - uint8_t* WEBP_RESTRICT const yuv_out, int mode) { - const VP8Encoder* const enc = it->enc_; - const uint8_t* const ref = it->yuv_p_ + VP8UVModeOffsets[mode]; - const uint8_t* const src = it->yuv_in_ + U_OFF_ENC; - const VP8SegmentInfo* const dqm = &enc->dqm_[it->mb_->segment_]; - int nz = 0; - int n; - int16_t tmp[8][16]; - - for (n = 0; n < 8; n += 2) { - VP8FTransform2(src + VP8ScanUV[n], ref + VP8ScanUV[n], tmp[n]); - } - if (it->top_derr_ != NULL) CorrectDCValues(it, &dqm->uv_, tmp, rd); - - if (DO_TRELLIS_UV && it->do_trellis_) { - int ch, x, y; - for (ch = 0, n = 0; ch <= 2; ch += 2) { - for (y = 0; y < 2; ++y) { - for (x = 0; x < 2; ++x, ++n) { - const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y]; - const int non_zero = TrellisQuantizeBlock( - enc, tmp[n], rd->uv_levels[n], ctx, TYPE_CHROMA_A, &dqm->uv_, - dqm->lambda_trellis_uv_); - it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] = non_zero; - nz |= non_zero << n; - } - } - } - } else { - for (n = 0; n < 8; n += 2) { - nz |= VP8EncQuantize2Blocks(tmp[n], rd->uv_levels[n], &dqm->uv_) << n; - } - } - - for (n = 0; n < 8; n += 2) { - VP8ITransform(ref + VP8ScanUV[n], tmp[n], yuv_out + VP8ScanUV[n], 1); - } - return (nz << 16); -} - -//------------------------------------------------------------------------------ -// RD-opt decision. Reconstruct each modes, evalue distortion and bit-cost. -// Pick the mode is lower RD-cost = Rate + lambda * Distortion. - -static void StoreMaxDelta(VP8SegmentInfo* const dqm, const int16_t DCs[16]) { - // We look at the first three AC coefficients to determine what is the average - // delta between each sub-4x4 block. - const int v0 = abs(DCs[1]); - const int v1 = abs(DCs[2]); - const int v2 = abs(DCs[4]); - int max_v = (v1 > v0) ? v1 : v0; - max_v = (v2 > max_v) ? v2 : max_v; - if (max_v > dqm->max_edge_) dqm->max_edge_ = max_v; -} - -static void SwapModeScore(VP8ModeScore** a, VP8ModeScore** b) { - VP8ModeScore* const tmp = *a; - *a = *b; - *b = tmp; -} - -static void SwapPtr(uint8_t** a, uint8_t** b) { - uint8_t* const tmp = *a; - *a = *b; - *b = tmp; -} - -static void SwapOut(VP8EncIterator* const it) { - SwapPtr(&it->yuv_out_, &it->yuv_out2_); -} - -static void PickBestIntra16(VP8EncIterator* WEBP_RESTRICT const it, - VP8ModeScore* WEBP_RESTRICT rd) { - const int kNumBlocks = 16; - VP8SegmentInfo* const dqm = &it->enc_->dqm_[it->mb_->segment_]; - const int lambda = dqm->lambda_i16_; - const int tlambda = dqm->tlambda_; - const uint8_t* const src = it->yuv_in_ + Y_OFF_ENC; - VP8ModeScore rd_tmp; - VP8ModeScore* rd_cur = &rd_tmp; - VP8ModeScore* rd_best = rd; - int mode; - int is_flat = IsFlatSource16(it->yuv_in_ + Y_OFF_ENC); - - rd->mode_i16 = -1; - for (mode = 0; mode < NUM_PRED_MODES; ++mode) { - uint8_t* const tmp_dst = it->yuv_out2_ + Y_OFF_ENC; // scratch buffer - rd_cur->mode_i16 = mode; - - // Reconstruct - rd_cur->nz = ReconstructIntra16(it, rd_cur, tmp_dst, mode); - - // Measure RD-score - rd_cur->D = VP8SSE16x16(src, tmp_dst); - rd_cur->SD = - tlambda ? MULT_8B(tlambda, VP8TDisto16x16(src, tmp_dst, kWeightY)) : 0; - rd_cur->H = VP8FixedCostsI16[mode]; - rd_cur->R = VP8GetCostLuma16(it, rd_cur); - if (is_flat) { - // refine the first impression (which was in pixel space) - is_flat = IsFlat(rd_cur->y_ac_levels[0], kNumBlocks, FLATNESS_LIMIT_I16); - if (is_flat) { - // Block is very flat. We put emphasis on the distortion being very low! - rd_cur->D *= 2; - rd_cur->SD *= 2; - } - } - - // Since we always examine Intra16 first, we can overwrite *rd directly. - SetRDScore(lambda, rd_cur); - if (mode == 0 || rd_cur->score < rd_best->score) { - SwapModeScore(&rd_cur, &rd_best); - SwapOut(it); - } - } - if (rd_best != rd) { - memcpy(rd, rd_best, sizeof(*rd)); - } - SetRDScore(dqm->lambda_mode_, rd); // finalize score for mode decision. - VP8SetIntra16Mode(it, rd->mode_i16); - - // we have a blocky macroblock (only DCs are non-zero) with fairly high - // distortion, record max delta so we can later adjust the minimal filtering - // strength needed to smooth these blocks out. - if ((rd->nz & 0x100ffff) == 0x1000000 && rd->D > dqm->min_disto_) { - StoreMaxDelta(dqm, rd->y_dc_levels); - } -} - -//------------------------------------------------------------------------------ - -// return the cost array corresponding to the surrounding prediction modes. -static const uint16_t* GetCostModeI4(VP8EncIterator* WEBP_RESTRICT const it, - const uint8_t modes[16]) { - const int preds_w = it->enc_->preds_w_; - const int x = (it->i4_ & 3), y = it->i4_ >> 2; - const int left = (x == 0) ? it->preds_[y * preds_w - 1] : modes[it->i4_ - 1]; - const int top = (y == 0) ? it->preds_[-preds_w + x] : modes[it->i4_ - 4]; - return VP8FixedCostsI4[top][left]; -} - -static int PickBestIntra4(VP8EncIterator* WEBP_RESTRICT const it, - VP8ModeScore* WEBP_RESTRICT const rd) { - const VP8Encoder* const enc = it->enc_; - const VP8SegmentInfo* const dqm = &enc->dqm_[it->mb_->segment_]; - const int lambda = dqm->lambda_i4_; - const int tlambda = dqm->tlambda_; - const uint8_t* const src0 = it->yuv_in_ + Y_OFF_ENC; - uint8_t* const best_blocks = it->yuv_out2_ + Y_OFF_ENC; - int total_header_bits = 0; - VP8ModeScore rd_best; - - if (enc->max_i4_header_bits_ == 0) { - return 0; - } - - InitScore(&rd_best); - rd_best.H = 211; // '211' is the value of VP8BitCost(0, 145) - SetRDScore(dqm->lambda_mode_, &rd_best); - VP8IteratorStartI4(it); - do { - const int kNumBlocks = 1; - VP8ModeScore rd_i4; - int mode; - int best_mode = -1; - const uint8_t* const src = src0 + VP8Scan[it->i4_]; - const uint16_t* const mode_costs = GetCostModeI4(it, rd->modes_i4); - uint8_t* best_block = best_blocks + VP8Scan[it->i4_]; - uint8_t* tmp_dst = it->yuv_p_ + I4TMP; // scratch buffer. - - InitScore(&rd_i4); - VP8MakeIntra4Preds(it); - for (mode = 0; mode < NUM_BMODES; ++mode) { - VP8ModeScore rd_tmp; - int16_t tmp_levels[16]; - - // Reconstruct - rd_tmp.nz = - ReconstructIntra4(it, tmp_levels, src, tmp_dst, mode) << it->i4_; - - // Compute RD-score - rd_tmp.D = VP8SSE4x4(src, tmp_dst); - rd_tmp.SD = - tlambda ? MULT_8B(tlambda, VP8TDisto4x4(src, tmp_dst, kWeightY)) - : 0; - rd_tmp.H = mode_costs[mode]; - - // Add flatness penalty, to avoid flat area to be mispredicted - // by a complex mode. - if (mode > 0 && IsFlat(tmp_levels, kNumBlocks, FLATNESS_LIMIT_I4)) { - rd_tmp.R = FLATNESS_PENALTY * kNumBlocks; - } else { - rd_tmp.R = 0; - } - - // early-out check - SetRDScore(lambda, &rd_tmp); - if (best_mode >= 0 && rd_tmp.score >= rd_i4.score) continue; - - // finish computing score - rd_tmp.R += VP8GetCostLuma4(it, tmp_levels); - SetRDScore(lambda, &rd_tmp); - - if (best_mode < 0 || rd_tmp.score < rd_i4.score) { - CopyScore(&rd_i4, &rd_tmp); - best_mode = mode; - SwapPtr(&tmp_dst, &best_block); - memcpy(rd_best.y_ac_levels[it->i4_], tmp_levels, - sizeof(rd_best.y_ac_levels[it->i4_])); - } - } - SetRDScore(dqm->lambda_mode_, &rd_i4); - AddScore(&rd_best, &rd_i4); - if (rd_best.score >= rd->score) { - return 0; - } - total_header_bits += (int)rd_i4.H; // <- equal to mode_costs[best_mode]; - if (total_header_bits > enc->max_i4_header_bits_) { - return 0; - } - // Copy selected samples if not in the right place already. - if (best_block != best_blocks + VP8Scan[it->i4_]) { - VP8Copy4x4(best_block, best_blocks + VP8Scan[it->i4_]); - } - rd->modes_i4[it->i4_] = best_mode; - it->top_nz_[it->i4_ & 3] = it->left_nz_[it->i4_ >> 2] = (rd_i4.nz ? 1 : 0); - } while (VP8IteratorRotateI4(it, best_blocks)); - - // finalize state - CopyScore(rd, &rd_best); - VP8SetIntra4Mode(it, rd->modes_i4); - SwapOut(it); - memcpy(rd->y_ac_levels, rd_best.y_ac_levels, sizeof(rd->y_ac_levels)); - return 1; // select intra4x4 over intra16x16 -} - -//------------------------------------------------------------------------------ - -static void PickBestUV(VP8EncIterator* WEBP_RESTRICT const it, - VP8ModeScore* WEBP_RESTRICT const rd) { - const int kNumBlocks = 8; - const VP8SegmentInfo* const dqm = &it->enc_->dqm_[it->mb_->segment_]; - const int lambda = dqm->lambda_uv_; - const uint8_t* const src = it->yuv_in_ + U_OFF_ENC; - uint8_t* tmp_dst = it->yuv_out2_ + U_OFF_ENC; // scratch buffer - uint8_t* dst0 = it->yuv_out_ + U_OFF_ENC; - uint8_t* dst = dst0; - VP8ModeScore rd_best; - int mode; - - rd->mode_uv = -1; - InitScore(&rd_best); - for (mode = 0; mode < NUM_PRED_MODES; ++mode) { - VP8ModeScore rd_uv; - - // Reconstruct - rd_uv.nz = ReconstructUV(it, &rd_uv, tmp_dst, mode); - - // Compute RD-score - rd_uv.D = VP8SSE16x8(src, tmp_dst); - rd_uv.SD = 0; // not calling TDisto here: it tends to flatten areas. - rd_uv.H = VP8FixedCostsUV[mode]; - rd_uv.R = VP8GetCostUV(it, &rd_uv); - if (mode > 0 && IsFlat(rd_uv.uv_levels[0], kNumBlocks, FLATNESS_LIMIT_UV)) { - rd_uv.R += FLATNESS_PENALTY * kNumBlocks; - } - - SetRDScore(lambda, &rd_uv); - if (mode == 0 || rd_uv.score < rd_best.score) { - CopyScore(&rd_best, &rd_uv); - rd->mode_uv = mode; - memcpy(rd->uv_levels, rd_uv.uv_levels, sizeof(rd->uv_levels)); - if (it->top_derr_ != NULL) { - memcpy(rd->derr, rd_uv.derr, sizeof(rd_uv.derr)); - } - SwapPtr(&dst, &tmp_dst); - } - } - VP8SetIntraUVMode(it, rd->mode_uv); - AddScore(rd, &rd_best); - if (dst != dst0) { // copy 16x8 block if needed - VP8Copy16x8(dst, dst0); - } - if (it->top_derr_ != NULL) { // store diffusion errors for next block - StoreDiffusionErrors(it, rd); - } -} - -//------------------------------------------------------------------------------ -// Final reconstruction and quantization. - -static void SimpleQuantize(VP8EncIterator* WEBP_RESTRICT const it, - VP8ModeScore* WEBP_RESTRICT const rd) { - const VP8Encoder* const enc = it->enc_; - const int is_i16 = (it->mb_->type_ == 1); - int nz = 0; - - if (is_i16) { - nz = ReconstructIntra16(it, rd, it->yuv_out_ + Y_OFF_ENC, it->preds_[0]); - } else { - VP8IteratorStartI4(it); - do { - const int mode = - it->preds_[(it->i4_ & 3) + (it->i4_ >> 2) * enc->preds_w_]; - const uint8_t* const src = it->yuv_in_ + Y_OFF_ENC + VP8Scan[it->i4_]; - uint8_t* const dst = it->yuv_out_ + Y_OFF_ENC + VP8Scan[it->i4_]; - VP8MakeIntra4Preds(it); - nz |= ReconstructIntra4(it, rd->y_ac_levels[it->i4_], - src, dst, mode) << it->i4_; - } while (VP8IteratorRotateI4(it, it->yuv_out_ + Y_OFF_ENC)); - } - - nz |= ReconstructUV(it, rd, it->yuv_out_ + U_OFF_ENC, it->mb_->uv_mode_); - rd->nz = nz; -} - -// Refine intra16/intra4 sub-modes based on distortion only (not rate). -static void RefineUsingDistortion(VP8EncIterator* WEBP_RESTRICT const it, - int try_both_modes, int refine_uv_mode, - VP8ModeScore* WEBP_RESTRICT const rd) { - score_t best_score = MAX_COST; - int nz = 0; - int mode; - int is_i16 = try_both_modes || (it->mb_->type_ == 1); - - const VP8SegmentInfo* const dqm = &it->enc_->dqm_[it->mb_->segment_]; - // Some empiric constants, of approximate order of magnitude. - const int lambda_d_i16 = 106; - const int lambda_d_i4 = 11; - const int lambda_d_uv = 120; - score_t score_i4 = dqm->i4_penalty_; - score_t i4_bit_sum = 0; - const score_t bit_limit = try_both_modes ? it->enc_->mb_header_limit_ - : MAX_COST; // no early-out allowed - - if (is_i16) { // First, evaluate Intra16 distortion - int best_mode = -1; - const uint8_t* const src = it->yuv_in_ + Y_OFF_ENC; - for (mode = 0; mode < NUM_PRED_MODES; ++mode) { - const uint8_t* const ref = it->yuv_p_ + VP8I16ModeOffsets[mode]; - const score_t score = (score_t)VP8SSE16x16(src, ref) * RD_DISTO_MULT - + VP8FixedCostsI16[mode] * lambda_d_i16; - if (mode > 0 && VP8FixedCostsI16[mode] > bit_limit) { - continue; - } - - if (score < best_score) { - best_mode = mode; - best_score = score; - } - } - if (it->x_ == 0 || it->y_ == 0) { - // avoid starting a checkerboard resonance from the border. See bug #432. - if (IsFlatSource16(src)) { - best_mode = (it->x_ == 0) ? 0 : 2; - try_both_modes = 0; // stick to i16 - } - } - VP8SetIntra16Mode(it, best_mode); - // we'll reconstruct later, if i16 mode actually gets selected - } - - // Next, evaluate Intra4 - if (try_both_modes || !is_i16) { - // We don't evaluate the rate here, but just account for it through a - // constant penalty (i4 mode usually needs more bits compared to i16). - is_i16 = 0; - VP8IteratorStartI4(it); - do { - int best_i4_mode = -1; - score_t best_i4_score = MAX_COST; - const uint8_t* const src = it->yuv_in_ + Y_OFF_ENC + VP8Scan[it->i4_]; - const uint16_t* const mode_costs = GetCostModeI4(it, rd->modes_i4); - - VP8MakeIntra4Preds(it); - for (mode = 0; mode < NUM_BMODES; ++mode) { - const uint8_t* const ref = it->yuv_p_ + VP8I4ModeOffsets[mode]; - const score_t score = VP8SSE4x4(src, ref) * RD_DISTO_MULT - + mode_costs[mode] * lambda_d_i4; - if (score < best_i4_score) { - best_i4_mode = mode; - best_i4_score = score; - } - } - i4_bit_sum += mode_costs[best_i4_mode]; - rd->modes_i4[it->i4_] = best_i4_mode; - score_i4 += best_i4_score; - if (score_i4 >= best_score || i4_bit_sum > bit_limit) { - // Intra4 won't be better than Intra16. Bail out and pick Intra16. - is_i16 = 1; - break; - } else { // reconstruct partial block inside yuv_out2_ buffer - uint8_t* const tmp_dst = it->yuv_out2_ + Y_OFF_ENC + VP8Scan[it->i4_]; - nz |= ReconstructIntra4(it, rd->y_ac_levels[it->i4_], - src, tmp_dst, best_i4_mode) << it->i4_; - } - } while (VP8IteratorRotateI4(it, it->yuv_out2_ + Y_OFF_ENC)); - } - - // Final reconstruction, depending on which mode is selected. - if (!is_i16) { - VP8SetIntra4Mode(it, rd->modes_i4); - SwapOut(it); - best_score = score_i4; - } else { - nz = ReconstructIntra16(it, rd, it->yuv_out_ + Y_OFF_ENC, it->preds_[0]); - } - - // ... and UV! - if (refine_uv_mode) { - int best_mode = -1; - score_t best_uv_score = MAX_COST; - const uint8_t* const src = it->yuv_in_ + U_OFF_ENC; - for (mode = 0; mode < NUM_PRED_MODES; ++mode) { - const uint8_t* const ref = it->yuv_p_ + VP8UVModeOffsets[mode]; - const score_t score = VP8SSE16x8(src, ref) * RD_DISTO_MULT - + VP8FixedCostsUV[mode] * lambda_d_uv; - if (score < best_uv_score) { - best_mode = mode; - best_uv_score = score; - } - } - VP8SetIntraUVMode(it, best_mode); - } - nz |= ReconstructUV(it, rd, it->yuv_out_ + U_OFF_ENC, it->mb_->uv_mode_); - - rd->nz = nz; - rd->score = best_score; -} - -//------------------------------------------------------------------------------ -// Entry point - -int VP8Decimate(VP8EncIterator* WEBP_RESTRICT const it, - VP8ModeScore* WEBP_RESTRICT const rd, - VP8RDLevel rd_opt) { - int is_skipped; - const int method = it->enc_->method_; - - InitScore(rd); - - // We can perform predictions for Luma16x16 and Chroma8x8 already. - // Luma4x4 predictions needs to be done as-we-go. - VP8MakeLuma16Preds(it); - VP8MakeChroma8Preds(it); - - if (rd_opt > RD_OPT_NONE) { - it->do_trellis_ = (rd_opt >= RD_OPT_TRELLIS_ALL); - PickBestIntra16(it, rd); - if (method >= 2) { - PickBestIntra4(it, rd); - } - PickBestUV(it, rd); - if (rd_opt == RD_OPT_TRELLIS) { // finish off with trellis-optim now - it->do_trellis_ = 1; - SimpleQuantize(it, rd); - } - } else { - // At this point we have heuristically decided intra16 / intra4. - // For method >= 2, pick the best intra4/intra16 based on SSE (~tad slower). - // For method <= 1, we don't re-examine the decision but just go ahead with - // quantization/reconstruction. - RefineUsingDistortion(it, (method >= 2), (method >= 1), rd); - } - is_skipped = (rd->nz == 0); - VP8SetSkip(it, is_skipped); - return is_skipped; -} diff --git a/libwebp/src/enc/syntax_enc.c b/libwebp/src/enc/syntax_enc.c deleted file mode 100644 index 9b8f524d..00000000 --- a/libwebp/src/enc/syntax_enc.c +++ /dev/null @@ -1,392 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Header syntax writing -// -// Author: Skal (pascal.massimino@gmail.com) - -#include - -#include "src/utils/utils.h" -#include "src/webp/format_constants.h" // RIFF constants -#include "src/webp/mux_types.h" // ALPHA_FLAG -#include "src/enc/vp8i_enc.h" - -//------------------------------------------------------------------------------ -// Helper functions - -static int IsVP8XNeeded(const VP8Encoder* const enc) { - return !!enc->has_alpha_; // Currently the only case when VP8X is needed. - // This could change in the future. -} - -static int PutPaddingByte(const WebPPicture* const pic) { - const uint8_t pad_byte[1] = { 0 }; - return !!pic->writer(pad_byte, 1, pic); -} - -//------------------------------------------------------------------------------ -// Writers for header's various pieces (in order of appearance) - -static WebPEncodingError PutRIFFHeader(const VP8Encoder* const enc, - size_t riff_size) { - const WebPPicture* const pic = enc->pic_; - uint8_t riff[RIFF_HEADER_SIZE] = { - 'R', 'I', 'F', 'F', 0, 0, 0, 0, 'W', 'E', 'B', 'P' - }; - assert(riff_size == (uint32_t)riff_size); - PutLE32(riff + TAG_SIZE, (uint32_t)riff_size); - if (!pic->writer(riff, sizeof(riff), pic)) { - return VP8_ENC_ERROR_BAD_WRITE; - } - return VP8_ENC_OK; -} - -static WebPEncodingError PutVP8XHeader(const VP8Encoder* const enc) { - const WebPPicture* const pic = enc->pic_; - uint8_t vp8x[CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE] = { - 'V', 'P', '8', 'X' - }; - uint32_t flags = 0; - - assert(IsVP8XNeeded(enc)); - assert(pic->width >= 1 && pic->height >= 1); - assert(pic->width <= MAX_CANVAS_SIZE && pic->height <= MAX_CANVAS_SIZE); - - if (enc->has_alpha_) { - flags |= ALPHA_FLAG; - } - - PutLE32(vp8x + TAG_SIZE, VP8X_CHUNK_SIZE); - PutLE32(vp8x + CHUNK_HEADER_SIZE, flags); - PutLE24(vp8x + CHUNK_HEADER_SIZE + 4, pic->width - 1); - PutLE24(vp8x + CHUNK_HEADER_SIZE + 7, pic->height - 1); - if (!pic->writer(vp8x, sizeof(vp8x), pic)) { - return VP8_ENC_ERROR_BAD_WRITE; - } - return VP8_ENC_OK; -} - -static WebPEncodingError PutAlphaChunk(const VP8Encoder* const enc) { - const WebPPicture* const pic = enc->pic_; - uint8_t alpha_chunk_hdr[CHUNK_HEADER_SIZE] = { - 'A', 'L', 'P', 'H' - }; - - assert(enc->has_alpha_); - - // Alpha chunk header. - PutLE32(alpha_chunk_hdr + TAG_SIZE, enc->alpha_data_size_); - if (!pic->writer(alpha_chunk_hdr, sizeof(alpha_chunk_hdr), pic)) { - return VP8_ENC_ERROR_BAD_WRITE; - } - - // Alpha chunk data. - if (!pic->writer(enc->alpha_data_, enc->alpha_data_size_, pic)) { - return VP8_ENC_ERROR_BAD_WRITE; - } - - // Padding. - if ((enc->alpha_data_size_ & 1) && !PutPaddingByte(pic)) { - return VP8_ENC_ERROR_BAD_WRITE; - } - return VP8_ENC_OK; -} - -static WebPEncodingError PutVP8Header(const WebPPicture* const pic, - size_t vp8_size) { - uint8_t vp8_chunk_hdr[CHUNK_HEADER_SIZE] = { - 'V', 'P', '8', ' ' - }; - assert(vp8_size == (uint32_t)vp8_size); - PutLE32(vp8_chunk_hdr + TAG_SIZE, (uint32_t)vp8_size); - if (!pic->writer(vp8_chunk_hdr, sizeof(vp8_chunk_hdr), pic)) { - return VP8_ENC_ERROR_BAD_WRITE; - } - return VP8_ENC_OK; -} - -static WebPEncodingError PutVP8FrameHeader(const WebPPicture* const pic, - int profile, size_t size0) { - uint8_t vp8_frm_hdr[VP8_FRAME_HEADER_SIZE]; - uint32_t bits; - - if (size0 >= VP8_MAX_PARTITION0_SIZE) { // partition #0 is too big to fit - return VP8_ENC_ERROR_PARTITION0_OVERFLOW; - } - - // Paragraph 9.1. - bits = 0 // keyframe (1b) - | (profile << 1) // profile (3b) - | (1 << 4) // visible (1b) - | ((uint32_t)size0 << 5); // partition length (19b) - vp8_frm_hdr[0] = (bits >> 0) & 0xff; - vp8_frm_hdr[1] = (bits >> 8) & 0xff; - vp8_frm_hdr[2] = (bits >> 16) & 0xff; - // signature - vp8_frm_hdr[3] = (VP8_SIGNATURE >> 16) & 0xff; - vp8_frm_hdr[4] = (VP8_SIGNATURE >> 8) & 0xff; - vp8_frm_hdr[5] = (VP8_SIGNATURE >> 0) & 0xff; - // dimensions - vp8_frm_hdr[6] = pic->width & 0xff; - vp8_frm_hdr[7] = pic->width >> 8; - vp8_frm_hdr[8] = pic->height & 0xff; - vp8_frm_hdr[9] = pic->height >> 8; - - if (!pic->writer(vp8_frm_hdr, sizeof(vp8_frm_hdr), pic)) { - return VP8_ENC_ERROR_BAD_WRITE; - } - return VP8_ENC_OK; -} - -// WebP Headers. -static int PutWebPHeaders(const VP8Encoder* const enc, size_t size0, - size_t vp8_size, size_t riff_size) { - WebPPicture* const pic = enc->pic_; - WebPEncodingError err = VP8_ENC_OK; - - // RIFF header. - err = PutRIFFHeader(enc, riff_size); - if (err != VP8_ENC_OK) goto Error; - - // VP8X. - if (IsVP8XNeeded(enc)) { - err = PutVP8XHeader(enc); - if (err != VP8_ENC_OK) goto Error; - } - - // Alpha. - if (enc->has_alpha_) { - err = PutAlphaChunk(enc); - if (err != VP8_ENC_OK) goto Error; - } - - // VP8 header. - err = PutVP8Header(pic, vp8_size); - if (err != VP8_ENC_OK) goto Error; - - // VP8 frame header. - err = PutVP8FrameHeader(pic, enc->profile_, size0); - if (err != VP8_ENC_OK) goto Error; - - // All OK. - return 1; - - // Error. - Error: - return WebPEncodingSetError(pic, err); -} - -// Segmentation header -static void PutSegmentHeader(VP8BitWriter* const bw, - const VP8Encoder* const enc) { - const VP8EncSegmentHeader* const hdr = &enc->segment_hdr_; - const VP8EncProba* const proba = &enc->proba_; - if (VP8PutBitUniform(bw, (hdr->num_segments_ > 1))) { - // We always 'update' the quant and filter strength values - const int update_data = 1; - int s; - VP8PutBitUniform(bw, hdr->update_map_); - if (VP8PutBitUniform(bw, update_data)) { - // we always use absolute values, not relative ones - VP8PutBitUniform(bw, 1); // (segment_feature_mode = 1. Paragraph 9.3.) - for (s = 0; s < NUM_MB_SEGMENTS; ++s) { - VP8PutSignedBits(bw, enc->dqm_[s].quant_, 7); - } - for (s = 0; s < NUM_MB_SEGMENTS; ++s) { - VP8PutSignedBits(bw, enc->dqm_[s].fstrength_, 6); - } - } - if (hdr->update_map_) { - for (s = 0; s < 3; ++s) { - if (VP8PutBitUniform(bw, (proba->segments_[s] != 255u))) { - VP8PutBits(bw, proba->segments_[s], 8); - } - } - } - } -} - -// Filtering parameters header -static void PutFilterHeader(VP8BitWriter* const bw, - const VP8EncFilterHeader* const hdr) { - const int use_lf_delta = (hdr->i4x4_lf_delta_ != 0); - VP8PutBitUniform(bw, hdr->simple_); - VP8PutBits(bw, hdr->level_, 6); - VP8PutBits(bw, hdr->sharpness_, 3); - if (VP8PutBitUniform(bw, use_lf_delta)) { - // '0' is the default value for i4x4_lf_delta_ at frame #0. - const int need_update = (hdr->i4x4_lf_delta_ != 0); - if (VP8PutBitUniform(bw, need_update)) { - // we don't use ref_lf_delta => emit four 0 bits - VP8PutBits(bw, 0, 4); - // we use mode_lf_delta for i4x4 - VP8PutSignedBits(bw, hdr->i4x4_lf_delta_, 6); - VP8PutBits(bw, 0, 3); // all others unused - } - } -} - -// Nominal quantization parameters -static void PutQuant(VP8BitWriter* const bw, - const VP8Encoder* const enc) { - VP8PutBits(bw, enc->base_quant_, 7); - VP8PutSignedBits(bw, enc->dq_y1_dc_, 4); - VP8PutSignedBits(bw, enc->dq_y2_dc_, 4); - VP8PutSignedBits(bw, enc->dq_y2_ac_, 4); - VP8PutSignedBits(bw, enc->dq_uv_dc_, 4); - VP8PutSignedBits(bw, enc->dq_uv_ac_, 4); -} - -// Partition sizes -static int EmitPartitionsSize(const VP8Encoder* const enc, - WebPPicture* const pic) { - uint8_t buf[3 * (MAX_NUM_PARTITIONS - 1)]; - int p; - for (p = 0; p < enc->num_parts_ - 1; ++p) { - const size_t part_size = VP8BitWriterSize(enc->parts_ + p); - if (part_size >= VP8_MAX_PARTITION_SIZE) { - return WebPEncodingSetError(pic, VP8_ENC_ERROR_PARTITION_OVERFLOW); - } - buf[3 * p + 0] = (part_size >> 0) & 0xff; - buf[3 * p + 1] = (part_size >> 8) & 0xff; - buf[3 * p + 2] = (part_size >> 16) & 0xff; - } - if (p && !pic->writer(buf, 3 * p, pic)) { - return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_WRITE); - } - return 1; -} - -//------------------------------------------------------------------------------ - -static int GeneratePartition0(VP8Encoder* const enc) { - VP8BitWriter* const bw = &enc->bw_; - const int mb_size = enc->mb_w_ * enc->mb_h_; - uint64_t pos1, pos2, pos3; - - pos1 = VP8BitWriterPos(bw); - if (!VP8BitWriterInit(bw, mb_size * 7 / 8)) { // ~7 bits per macroblock - return WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY); - } - VP8PutBitUniform(bw, 0); // colorspace - VP8PutBitUniform(bw, 0); // clamp type - - PutSegmentHeader(bw, enc); - PutFilterHeader(bw, &enc->filter_hdr_); - VP8PutBits(bw, enc->num_parts_ == 8 ? 3 : - enc->num_parts_ == 4 ? 2 : - enc->num_parts_ == 2 ? 1 : 0, 2); - PutQuant(bw, enc); - VP8PutBitUniform(bw, 0); // no proba update - VP8WriteProbas(bw, &enc->proba_); - pos2 = VP8BitWriterPos(bw); - VP8CodeIntraModes(enc); - VP8BitWriterFinish(bw); - - pos3 = VP8BitWriterPos(bw); - -#if !defined(WEBP_DISABLE_STATS) - if (enc->pic_->stats) { - enc->pic_->stats->header_bytes[0] = (int)((pos2 - pos1 + 7) >> 3); - enc->pic_->stats->header_bytes[1] = (int)((pos3 - pos2 + 7) >> 3); - enc->pic_->stats->alpha_data_size = (int)enc->alpha_data_size_; - } -#else - (void)pos1; - (void)pos2; - (void)pos3; -#endif - if (bw->error_) { - return WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY); - } - return 1; -} - -void VP8EncFreeBitWriters(VP8Encoder* const enc) { - int p; - VP8BitWriterWipeOut(&enc->bw_); - for (p = 0; p < enc->num_parts_; ++p) { - VP8BitWriterWipeOut(enc->parts_ + p); - } -} - -int VP8EncWrite(VP8Encoder* const enc) { - WebPPicture* const pic = enc->pic_; - VP8BitWriter* const bw = &enc->bw_; - const int task_percent = 19; - const int percent_per_part = task_percent / enc->num_parts_; - const int final_percent = enc->percent_ + task_percent; - int ok = 0; - size_t vp8_size, pad, riff_size; - int p; - - // Partition #0 with header and partition sizes - ok = GeneratePartition0(enc); - if (!ok) return 0; - - // Compute VP8 size - vp8_size = VP8_FRAME_HEADER_SIZE + - VP8BitWriterSize(bw) + - 3 * (enc->num_parts_ - 1); - for (p = 0; p < enc->num_parts_; ++p) { - vp8_size += VP8BitWriterSize(enc->parts_ + p); - } - pad = vp8_size & 1; - vp8_size += pad; - - // Compute RIFF size - // At the minimum it is: "WEBPVP8 nnnn" + VP8 data size. - riff_size = TAG_SIZE + CHUNK_HEADER_SIZE + vp8_size; - if (IsVP8XNeeded(enc)) { // Add size for: VP8X header + data. - riff_size += CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE; - } - if (enc->has_alpha_) { // Add size for: ALPH header + data. - const uint32_t padded_alpha_size = enc->alpha_data_size_ + - (enc->alpha_data_size_ & 1); - riff_size += CHUNK_HEADER_SIZE + padded_alpha_size; - } - // RIFF size should fit in 32-bits. - if (riff_size > 0xfffffffeU) { - return WebPEncodingSetError(pic, VP8_ENC_ERROR_FILE_TOO_BIG); - } - - // Emit headers and partition #0 - { - const uint8_t* const part0 = VP8BitWriterBuf(bw); - const size_t size0 = VP8BitWriterSize(bw); - ok = ok && PutWebPHeaders(enc, size0, vp8_size, riff_size) - && pic->writer(part0, size0, pic) - && EmitPartitionsSize(enc, pic); - VP8BitWriterWipeOut(bw); // will free the internal buffer. - } - - // Token partitions - for (p = 0; p < enc->num_parts_; ++p) { - const uint8_t* const buf = VP8BitWriterBuf(enc->parts_ + p); - const size_t size = VP8BitWriterSize(enc->parts_ + p); - if (size) ok = ok && pic->writer(buf, size, pic); - VP8BitWriterWipeOut(enc->parts_ + p); // will free the internal buffer. - ok = ok && WebPReportProgress(pic, enc->percent_ + percent_per_part, - &enc->percent_); - } - - // Padding byte - if (ok && pad) { - ok = PutPaddingByte(pic); - } - - enc->coded_size_ = (int)(CHUNK_HEADER_SIZE + riff_size); - ok = ok && WebPReportProgress(pic, final_percent, &enc->percent_); - if (!ok) WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_WRITE); - return ok; -} - -//------------------------------------------------------------------------------ - diff --git a/libwebp/src/enc/token_enc.c b/libwebp/src/enc/token_enc.c deleted file mode 100644 index 3a2192ac..00000000 --- a/libwebp/src/enc/token_enc.c +++ /dev/null @@ -1,262 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Paginated token buffer -// -// A 'token' is a bit value associated with a probability, either fixed -// or a later-to-be-determined after statistics have been collected. -// For dynamic probability, we just record the slot id (idx) for the probability -// value in the final probability array (uint8_t* probas in VP8EmitTokens). -// -// Author: Skal (pascal.massimino@gmail.com) - -#include -#include -#include - -#include "src/enc/cost_enc.h" -#include "src/enc/vp8i_enc.h" -#include "src/utils/utils.h" - -#if !defined(DISABLE_TOKEN_BUFFER) - -// we use pages to reduce the number of memcpy() -#define MIN_PAGE_SIZE 8192 // minimum number of token per page -#define FIXED_PROBA_BIT (1u << 14) - -typedef uint16_t token_t; // bit #15: bit value - // bit #14: flags for constant proba or idx - // bits #0..13: slot or constant proba -struct VP8Tokens { - VP8Tokens* next_; // pointer to next page -}; -// Token data is located in memory just after the next_ field. -// This macro is used to return their address and hide the trick. -#define TOKEN_DATA(p) ((const token_t*)&(p)[1]) - -//------------------------------------------------------------------------------ - -void VP8TBufferInit(VP8TBuffer* const b, int page_size) { - b->tokens_ = NULL; - b->pages_ = NULL; - b->last_page_ = &b->pages_; - b->left_ = 0; - b->page_size_ = (page_size < MIN_PAGE_SIZE) ? MIN_PAGE_SIZE : page_size; - b->error_ = 0; -} - -void VP8TBufferClear(VP8TBuffer* const b) { - if (b != NULL) { - VP8Tokens* p = b->pages_; - while (p != NULL) { - VP8Tokens* const next = p->next_; - WebPSafeFree(p); - p = next; - } - VP8TBufferInit(b, b->page_size_); - } -} - -static int TBufferNewPage(VP8TBuffer* const b) { - VP8Tokens* page = NULL; - if (!b->error_) { - const size_t size = sizeof(*page) + b->page_size_ * sizeof(token_t); - page = (VP8Tokens*)WebPSafeMalloc(1ULL, size); - } - if (page == NULL) { - b->error_ = 1; - return 0; - } - page->next_ = NULL; - - *b->last_page_ = page; - b->last_page_ = &page->next_; - b->left_ = b->page_size_; - b->tokens_ = (token_t*)TOKEN_DATA(page); - return 1; -} - -//------------------------------------------------------------------------------ - -#define TOKEN_ID(t, b, ctx) \ - (NUM_PROBAS * ((ctx) + NUM_CTX * ((b) + NUM_BANDS * (t)))) - -static WEBP_INLINE uint32_t AddToken(VP8TBuffer* const b, uint32_t bit, - uint32_t proba_idx, - proba_t* const stats) { - assert(proba_idx < FIXED_PROBA_BIT); - assert(bit <= 1); - if (b->left_ > 0 || TBufferNewPage(b)) { - const int slot = --b->left_; - b->tokens_[slot] = (bit << 15) | proba_idx; - } - VP8RecordStats(bit, stats); - return bit; -} - -static WEBP_INLINE void AddConstantToken(VP8TBuffer* const b, - uint32_t bit, uint32_t proba) { - assert(proba < 256); - assert(bit <= 1); - if (b->left_ > 0 || TBufferNewPage(b)) { - const int slot = --b->left_; - b->tokens_[slot] = (bit << 15) | FIXED_PROBA_BIT | proba; - } -} - -int VP8RecordCoeffTokens(int ctx, const struct VP8Residual* const res, - VP8TBuffer* const tokens) { - const int16_t* const coeffs = res->coeffs; - const int coeff_type = res->coeff_type; - const int last = res->last; - int n = res->first; - uint32_t base_id = TOKEN_ID(coeff_type, n, ctx); - // should be stats[VP8EncBands[n]], but it's equivalent for n=0 or 1 - proba_t* s = res->stats[n][ctx]; - if (!AddToken(tokens, last >= 0, base_id + 0, s + 0)) { - return 0; - } - - while (n < 16) { - const int c = coeffs[n++]; - const int sign = c < 0; - const uint32_t v = sign ? -c : c; - if (!AddToken(tokens, v != 0, base_id + 1, s + 1)) { - base_id = TOKEN_ID(coeff_type, VP8EncBands[n], 0); // ctx=0 - s = res->stats[VP8EncBands[n]][0]; - continue; - } - if (!AddToken(tokens, v > 1, base_id + 2, s + 2)) { - base_id = TOKEN_ID(coeff_type, VP8EncBands[n], 1); // ctx=1 - s = res->stats[VP8EncBands[n]][1]; - } else { - if (!AddToken(tokens, v > 4, base_id + 3, s + 3)) { - if (AddToken(tokens, v != 2, base_id + 4, s + 4)) { - AddToken(tokens, v == 4, base_id + 5, s + 5); - } - } else if (!AddToken(tokens, v > 10, base_id + 6, s + 6)) { - if (!AddToken(tokens, v > 6, base_id + 7, s + 7)) { - AddConstantToken(tokens, v == 6, 159); - } else { - AddConstantToken(tokens, v >= 9, 165); - AddConstantToken(tokens, !(v & 1), 145); - } - } else { - int mask; - const uint8_t* tab; - uint32_t residue = v - 3; - if (residue < (8 << 1)) { // VP8Cat3 (3b) - AddToken(tokens, 0, base_id + 8, s + 8); - AddToken(tokens, 0, base_id + 9, s + 9); - residue -= (8 << 0); - mask = 1 << 2; - tab = VP8Cat3; - } else if (residue < (8 << 2)) { // VP8Cat4 (4b) - AddToken(tokens, 0, base_id + 8, s + 8); - AddToken(tokens, 1, base_id + 9, s + 9); - residue -= (8 << 1); - mask = 1 << 3; - tab = VP8Cat4; - } else if (residue < (8 << 3)) { // VP8Cat5 (5b) - AddToken(tokens, 1, base_id + 8, s + 8); - AddToken(tokens, 0, base_id + 10, s + 9); - residue -= (8 << 2); - mask = 1 << 4; - tab = VP8Cat5; - } else { // VP8Cat6 (11b) - AddToken(tokens, 1, base_id + 8, s + 8); - AddToken(tokens, 1, base_id + 10, s + 9); - residue -= (8 << 3); - mask = 1 << 10; - tab = VP8Cat6; - } - while (mask) { - AddConstantToken(tokens, !!(residue & mask), *tab++); - mask >>= 1; - } - } - base_id = TOKEN_ID(coeff_type, VP8EncBands[n], 2); // ctx=2 - s = res->stats[VP8EncBands[n]][2]; - } - AddConstantToken(tokens, sign, 128); - if (n == 16 || !AddToken(tokens, n <= last, base_id + 0, s + 0)) { - return 1; // EOB - } - } - return 1; -} - -#undef TOKEN_ID - -//------------------------------------------------------------------------------ -// Final coding pass, with known probabilities - -int VP8EmitTokens(VP8TBuffer* const b, VP8BitWriter* const bw, - const uint8_t* const probas, int final_pass) { - const VP8Tokens* p = b->pages_; - assert(!b->error_); - while (p != NULL) { - const VP8Tokens* const next = p->next_; - const int N = (next == NULL) ? b->left_ : 0; - int n = b->page_size_; - const token_t* const tokens = TOKEN_DATA(p); - while (n-- > N) { - const token_t token = tokens[n]; - const int bit = (token >> 15) & 1; - if (token & FIXED_PROBA_BIT) { - VP8PutBit(bw, bit, token & 0xffu); // constant proba - } else { - VP8PutBit(bw, bit, probas[token & 0x3fffu]); - } - } - if (final_pass) WebPSafeFree((void*)p); - p = next; - } - if (final_pass) b->pages_ = NULL; - return 1; -} - -// Size estimation -size_t VP8EstimateTokenSize(VP8TBuffer* const b, const uint8_t* const probas) { - size_t size = 0; - const VP8Tokens* p = b->pages_; - assert(!b->error_); - while (p != NULL) { - const VP8Tokens* const next = p->next_; - const int N = (next == NULL) ? b->left_ : 0; - int n = b->page_size_; - const token_t* const tokens = TOKEN_DATA(p); - while (n-- > N) { - const token_t token = tokens[n]; - const int bit = token & (1 << 15); - if (token & FIXED_PROBA_BIT) { - size += VP8BitCost(bit, token & 0xffu); - } else { - size += VP8BitCost(bit, probas[token & 0x3fffu]); - } - } - p = next; - } - return size; -} - -//------------------------------------------------------------------------------ - -#else // DISABLE_TOKEN_BUFFER - -void VP8TBufferInit(VP8TBuffer* const b, int page_size) { - (void)b; - (void)page_size; -} -void VP8TBufferClear(VP8TBuffer* const b) { - (void)b; -} - -#endif // !DISABLE_TOKEN_BUFFER - diff --git a/libwebp/src/enc/tree_enc.c b/libwebp/src/enc/tree_enc.c deleted file mode 100644 index 64ed2836..00000000 --- a/libwebp/src/enc/tree_enc.c +++ /dev/null @@ -1,504 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Coding of token probabilities, intra modes and segments. -// -// Author: Skal (pascal.massimino@gmail.com) - -#include "src/enc/vp8i_enc.h" - -//------------------------------------------------------------------------------ -// Default probabilities - -// Paragraph 13.5 -const uint8_t - VP8CoeffsProba0[NUM_TYPES][NUM_BANDS][NUM_CTX][NUM_PROBAS] = { - { { { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }, - { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }, - { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 } - }, - { { 253, 136, 254, 255, 228, 219, 128, 128, 128, 128, 128 }, - { 189, 129, 242, 255, 227, 213, 255, 219, 128, 128, 128 }, - { 106, 126, 227, 252, 214, 209, 255, 255, 128, 128, 128 } - }, - { { 1, 98, 248, 255, 236, 226, 255, 255, 128, 128, 128 }, - { 181, 133, 238, 254, 221, 234, 255, 154, 128, 128, 128 }, - { 78, 134, 202, 247, 198, 180, 255, 219, 128, 128, 128 }, - }, - { { 1, 185, 249, 255, 243, 255, 128, 128, 128, 128, 128 }, - { 184, 150, 247, 255, 236, 224, 128, 128, 128, 128, 128 }, - { 77, 110, 216, 255, 236, 230, 128, 128, 128, 128, 128 }, - }, - { { 1, 101, 251, 255, 241, 255, 128, 128, 128, 128, 128 }, - { 170, 139, 241, 252, 236, 209, 255, 255, 128, 128, 128 }, - { 37, 116, 196, 243, 228, 255, 255, 255, 128, 128, 128 } - }, - { { 1, 204, 254, 255, 245, 255, 128, 128, 128, 128, 128 }, - { 207, 160, 250, 255, 238, 128, 128, 128, 128, 128, 128 }, - { 102, 103, 231, 255, 211, 171, 128, 128, 128, 128, 128 } - }, - { { 1, 152, 252, 255, 240, 255, 128, 128, 128, 128, 128 }, - { 177, 135, 243, 255, 234, 225, 128, 128, 128, 128, 128 }, - { 80, 129, 211, 255, 194, 224, 128, 128, 128, 128, 128 } - }, - { { 1, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 }, - { 246, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 }, - { 255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 } - } - }, - { { { 198, 35, 237, 223, 193, 187, 162, 160, 145, 155, 62 }, - { 131, 45, 198, 221, 172, 176, 220, 157, 252, 221, 1 }, - { 68, 47, 146, 208, 149, 167, 221, 162, 255, 223, 128 } - }, - { { 1, 149, 241, 255, 221, 224, 255, 255, 128, 128, 128 }, - { 184, 141, 234, 253, 222, 220, 255, 199, 128, 128, 128 }, - { 81, 99, 181, 242, 176, 190, 249, 202, 255, 255, 128 } - }, - { { 1, 129, 232, 253, 214, 197, 242, 196, 255, 255, 128 }, - { 99, 121, 210, 250, 201, 198, 255, 202, 128, 128, 128 }, - { 23, 91, 163, 242, 170, 187, 247, 210, 255, 255, 128 } - }, - { { 1, 200, 246, 255, 234, 255, 128, 128, 128, 128, 128 }, - { 109, 178, 241, 255, 231, 245, 255, 255, 128, 128, 128 }, - { 44, 130, 201, 253, 205, 192, 255, 255, 128, 128, 128 } - }, - { { 1, 132, 239, 251, 219, 209, 255, 165, 128, 128, 128 }, - { 94, 136, 225, 251, 218, 190, 255, 255, 128, 128, 128 }, - { 22, 100, 174, 245, 186, 161, 255, 199, 128, 128, 128 } - }, - { { 1, 182, 249, 255, 232, 235, 128, 128, 128, 128, 128 }, - { 124, 143, 241, 255, 227, 234, 128, 128, 128, 128, 128 }, - { 35, 77, 181, 251, 193, 211, 255, 205, 128, 128, 128 } - }, - { { 1, 157, 247, 255, 236, 231, 255, 255, 128, 128, 128 }, - { 121, 141, 235, 255, 225, 227, 255, 255, 128, 128, 128 }, - { 45, 99, 188, 251, 195, 217, 255, 224, 128, 128, 128 } - }, - { { 1, 1, 251, 255, 213, 255, 128, 128, 128, 128, 128 }, - { 203, 1, 248, 255, 255, 128, 128, 128, 128, 128, 128 }, - { 137, 1, 177, 255, 224, 255, 128, 128, 128, 128, 128 } - } - }, - { { { 253, 9, 248, 251, 207, 208, 255, 192, 128, 128, 128 }, - { 175, 13, 224, 243, 193, 185, 249, 198, 255, 255, 128 }, - { 73, 17, 171, 221, 161, 179, 236, 167, 255, 234, 128 } - }, - { { 1, 95, 247, 253, 212, 183, 255, 255, 128, 128, 128 }, - { 239, 90, 244, 250, 211, 209, 255, 255, 128, 128, 128 }, - { 155, 77, 195, 248, 188, 195, 255, 255, 128, 128, 128 } - }, - { { 1, 24, 239, 251, 218, 219, 255, 205, 128, 128, 128 }, - { 201, 51, 219, 255, 196, 186, 128, 128, 128, 128, 128 }, - { 69, 46, 190, 239, 201, 218, 255, 228, 128, 128, 128 } - }, - { { 1, 191, 251, 255, 255, 128, 128, 128, 128, 128, 128 }, - { 223, 165, 249, 255, 213, 255, 128, 128, 128, 128, 128 }, - { 141, 124, 248, 255, 255, 128, 128, 128, 128, 128, 128 } - }, - { { 1, 16, 248, 255, 255, 128, 128, 128, 128, 128, 128 }, - { 190, 36, 230, 255, 236, 255, 128, 128, 128, 128, 128 }, - { 149, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 } - }, - { { 1, 226, 255, 128, 128, 128, 128, 128, 128, 128, 128 }, - { 247, 192, 255, 128, 128, 128, 128, 128, 128, 128, 128 }, - { 240, 128, 255, 128, 128, 128, 128, 128, 128, 128, 128 } - }, - { { 1, 134, 252, 255, 255, 128, 128, 128, 128, 128, 128 }, - { 213, 62, 250, 255, 255, 128, 128, 128, 128, 128, 128 }, - { 55, 93, 255, 128, 128, 128, 128, 128, 128, 128, 128 } - }, - { { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }, - { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }, - { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 } - } - }, - { { { 202, 24, 213, 235, 186, 191, 220, 160, 240, 175, 255 }, - { 126, 38, 182, 232, 169, 184, 228, 174, 255, 187, 128 }, - { 61, 46, 138, 219, 151, 178, 240, 170, 255, 216, 128 } - }, - { { 1, 112, 230, 250, 199, 191, 247, 159, 255, 255, 128 }, - { 166, 109, 228, 252, 211, 215, 255, 174, 128, 128, 128 }, - { 39, 77, 162, 232, 172, 180, 245, 178, 255, 255, 128 } - }, - { { 1, 52, 220, 246, 198, 199, 249, 220, 255, 255, 128 }, - { 124, 74, 191, 243, 183, 193, 250, 221, 255, 255, 128 }, - { 24, 71, 130, 219, 154, 170, 243, 182, 255, 255, 128 } - }, - { { 1, 182, 225, 249, 219, 240, 255, 224, 128, 128, 128 }, - { 149, 150, 226, 252, 216, 205, 255, 171, 128, 128, 128 }, - { 28, 108, 170, 242, 183, 194, 254, 223, 255, 255, 128 } - }, - { { 1, 81, 230, 252, 204, 203, 255, 192, 128, 128, 128 }, - { 123, 102, 209, 247, 188, 196, 255, 233, 128, 128, 128 }, - { 20, 95, 153, 243, 164, 173, 255, 203, 128, 128, 128 } - }, - { { 1, 222, 248, 255, 216, 213, 128, 128, 128, 128, 128 }, - { 168, 175, 246, 252, 235, 205, 255, 255, 128, 128, 128 }, - { 47, 116, 215, 255, 211, 212, 255, 255, 128, 128, 128 } - }, - { { 1, 121, 236, 253, 212, 214, 255, 255, 128, 128, 128 }, - { 141, 84, 213, 252, 201, 202, 255, 219, 128, 128, 128 }, - { 42, 80, 160, 240, 162, 185, 255, 205, 128, 128, 128 } - }, - { { 1, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 }, - { 244, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 }, - { 238, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 } - } - } -}; - -void VP8DefaultProbas(VP8Encoder* const enc) { - VP8EncProba* const probas = &enc->proba_; - probas->use_skip_proba_ = 0; - memset(probas->segments_, 255u, sizeof(probas->segments_)); - memcpy(probas->coeffs_, VP8CoeffsProba0, sizeof(VP8CoeffsProba0)); - // Note: we could hard-code the level_costs_ corresponding to VP8CoeffsProba0, - // but that's ~11k of static data. Better call VP8CalculateLevelCosts() later. - probas->dirty_ = 1; -} - -// Paragraph 11.5. 900bytes. -static const uint8_t kBModesProba[NUM_BMODES][NUM_BMODES][NUM_BMODES - 1] = { - { { 231, 120, 48, 89, 115, 113, 120, 152, 112 }, - { 152, 179, 64, 126, 170, 118, 46, 70, 95 }, - { 175, 69, 143, 80, 85, 82, 72, 155, 103 }, - { 56, 58, 10, 171, 218, 189, 17, 13, 152 }, - { 114, 26, 17, 163, 44, 195, 21, 10, 173 }, - { 121, 24, 80, 195, 26, 62, 44, 64, 85 }, - { 144, 71, 10, 38, 171, 213, 144, 34, 26 }, - { 170, 46, 55, 19, 136, 160, 33, 206, 71 }, - { 63, 20, 8, 114, 114, 208, 12, 9, 226 }, - { 81, 40, 11, 96, 182, 84, 29, 16, 36 } }, - { { 134, 183, 89, 137, 98, 101, 106, 165, 148 }, - { 72, 187, 100, 130, 157, 111, 32, 75, 80 }, - { 66, 102, 167, 99, 74, 62, 40, 234, 128 }, - { 41, 53, 9, 178, 241, 141, 26, 8, 107 }, - { 74, 43, 26, 146, 73, 166, 49, 23, 157 }, - { 65, 38, 105, 160, 51, 52, 31, 115, 128 }, - { 104, 79, 12, 27, 217, 255, 87, 17, 7 }, - { 87, 68, 71, 44, 114, 51, 15, 186, 23 }, - { 47, 41, 14, 110, 182, 183, 21, 17, 194 }, - { 66, 45, 25, 102, 197, 189, 23, 18, 22 } }, - { { 88, 88, 147, 150, 42, 46, 45, 196, 205 }, - { 43, 97, 183, 117, 85, 38, 35, 179, 61 }, - { 39, 53, 200, 87, 26, 21, 43, 232, 171 }, - { 56, 34, 51, 104, 114, 102, 29, 93, 77 }, - { 39, 28, 85, 171, 58, 165, 90, 98, 64 }, - { 34, 22, 116, 206, 23, 34, 43, 166, 73 }, - { 107, 54, 32, 26, 51, 1, 81, 43, 31 }, - { 68, 25, 106, 22, 64, 171, 36, 225, 114 }, - { 34, 19, 21, 102, 132, 188, 16, 76, 124 }, - { 62, 18, 78, 95, 85, 57, 50, 48, 51 } }, - { { 193, 101, 35, 159, 215, 111, 89, 46, 111 }, - { 60, 148, 31, 172, 219, 228, 21, 18, 111 }, - { 112, 113, 77, 85, 179, 255, 38, 120, 114 }, - { 40, 42, 1, 196, 245, 209, 10, 25, 109 }, - { 88, 43, 29, 140, 166, 213, 37, 43, 154 }, - { 61, 63, 30, 155, 67, 45, 68, 1, 209 }, - { 100, 80, 8, 43, 154, 1, 51, 26, 71 }, - { 142, 78, 78, 16, 255, 128, 34, 197, 171 }, - { 41, 40, 5, 102, 211, 183, 4, 1, 221 }, - { 51, 50, 17, 168, 209, 192, 23, 25, 82 } }, - { { 138, 31, 36, 171, 27, 166, 38, 44, 229 }, - { 67, 87, 58, 169, 82, 115, 26, 59, 179 }, - { 63, 59, 90, 180, 59, 166, 93, 73, 154 }, - { 40, 40, 21, 116, 143, 209, 34, 39, 175 }, - { 47, 15, 16, 183, 34, 223, 49, 45, 183 }, - { 46, 17, 33, 183, 6, 98, 15, 32, 183 }, - { 57, 46, 22, 24, 128, 1, 54, 17, 37 }, - { 65, 32, 73, 115, 28, 128, 23, 128, 205 }, - { 40, 3, 9, 115, 51, 192, 18, 6, 223 }, - { 87, 37, 9, 115, 59, 77, 64, 21, 47 } }, - { { 104, 55, 44, 218, 9, 54, 53, 130, 226 }, - { 64, 90, 70, 205, 40, 41, 23, 26, 57 }, - { 54, 57, 112, 184, 5, 41, 38, 166, 213 }, - { 30, 34, 26, 133, 152, 116, 10, 32, 134 }, - { 39, 19, 53, 221, 26, 114, 32, 73, 255 }, - { 31, 9, 65, 234, 2, 15, 1, 118, 73 }, - { 75, 32, 12, 51, 192, 255, 160, 43, 51 }, - { 88, 31, 35, 67, 102, 85, 55, 186, 85 }, - { 56, 21, 23, 111, 59, 205, 45, 37, 192 }, - { 55, 38, 70, 124, 73, 102, 1, 34, 98 } }, - { { 125, 98, 42, 88, 104, 85, 117, 175, 82 }, - { 95, 84, 53, 89, 128, 100, 113, 101, 45 }, - { 75, 79, 123, 47, 51, 128, 81, 171, 1 }, - { 57, 17, 5, 71, 102, 57, 53, 41, 49 }, - { 38, 33, 13, 121, 57, 73, 26, 1, 85 }, - { 41, 10, 67, 138, 77, 110, 90, 47, 114 }, - { 115, 21, 2, 10, 102, 255, 166, 23, 6 }, - { 101, 29, 16, 10, 85, 128, 101, 196, 26 }, - { 57, 18, 10, 102, 102, 213, 34, 20, 43 }, - { 117, 20, 15, 36, 163, 128, 68, 1, 26 } }, - { { 102, 61, 71, 37, 34, 53, 31, 243, 192 }, - { 69, 60, 71, 38, 73, 119, 28, 222, 37 }, - { 68, 45, 128, 34, 1, 47, 11, 245, 171 }, - { 62, 17, 19, 70, 146, 85, 55, 62, 70 }, - { 37, 43, 37, 154, 100, 163, 85, 160, 1 }, - { 63, 9, 92, 136, 28, 64, 32, 201, 85 }, - { 75, 15, 9, 9, 64, 255, 184, 119, 16 }, - { 86, 6, 28, 5, 64, 255, 25, 248, 1 }, - { 56, 8, 17, 132, 137, 255, 55, 116, 128 }, - { 58, 15, 20, 82, 135, 57, 26, 121, 40 } }, - { { 164, 50, 31, 137, 154, 133, 25, 35, 218 }, - { 51, 103, 44, 131, 131, 123, 31, 6, 158 }, - { 86, 40, 64, 135, 148, 224, 45, 183, 128 }, - { 22, 26, 17, 131, 240, 154, 14, 1, 209 }, - { 45, 16, 21, 91, 64, 222, 7, 1, 197 }, - { 56, 21, 39, 155, 60, 138, 23, 102, 213 }, - { 83, 12, 13, 54, 192, 255, 68, 47, 28 }, - { 85, 26, 85, 85, 128, 128, 32, 146, 171 }, - { 18, 11, 7, 63, 144, 171, 4, 4, 246 }, - { 35, 27, 10, 146, 174, 171, 12, 26, 128 } }, - { { 190, 80, 35, 99, 180, 80, 126, 54, 45 }, - { 85, 126, 47, 87, 176, 51, 41, 20, 32 }, - { 101, 75, 128, 139, 118, 146, 116, 128, 85 }, - { 56, 41, 15, 176, 236, 85, 37, 9, 62 }, - { 71, 30, 17, 119, 118, 255, 17, 18, 138 }, - { 101, 38, 60, 138, 55, 70, 43, 26, 142 }, - { 146, 36, 19, 30, 171, 255, 97, 27, 20 }, - { 138, 45, 61, 62, 219, 1, 81, 188, 64 }, - { 32, 41, 20, 117, 151, 142, 20, 21, 163 }, - { 112, 19, 12, 61, 195, 128, 48, 4, 24 } } -}; - -static int PutI4Mode(VP8BitWriter* const bw, int mode, - const uint8_t* const prob) { - if (VP8PutBit(bw, mode != B_DC_PRED, prob[0])) { - if (VP8PutBit(bw, mode != B_TM_PRED, prob[1])) { - if (VP8PutBit(bw, mode != B_VE_PRED, prob[2])) { - if (!VP8PutBit(bw, mode >= B_LD_PRED, prob[3])) { - if (VP8PutBit(bw, mode != B_HE_PRED, prob[4])) { - VP8PutBit(bw, mode != B_RD_PRED, prob[5]); - } - } else { - if (VP8PutBit(bw, mode != B_LD_PRED, prob[6])) { - if (VP8PutBit(bw, mode != B_VL_PRED, prob[7])) { - VP8PutBit(bw, mode != B_HD_PRED, prob[8]); - } - } - } - } - } - } - return mode; -} - -static void PutI16Mode(VP8BitWriter* const bw, int mode) { - if (VP8PutBit(bw, (mode == TM_PRED || mode == H_PRED), 156)) { - VP8PutBit(bw, mode == TM_PRED, 128); // TM or HE - } else { - VP8PutBit(bw, mode == V_PRED, 163); // VE or DC - } -} - -static void PutUVMode(VP8BitWriter* const bw, int uv_mode) { - if (VP8PutBit(bw, uv_mode != DC_PRED, 142)) { - if (VP8PutBit(bw, uv_mode != V_PRED, 114)) { - VP8PutBit(bw, uv_mode != H_PRED, 183); // else: TM_PRED - } - } -} - -static void PutSegment(VP8BitWriter* const bw, int s, const uint8_t* p) { - if (VP8PutBit(bw, s >= 2, p[0])) p += 1; - VP8PutBit(bw, s & 1, p[1]); -} - -void VP8CodeIntraModes(VP8Encoder* const enc) { - VP8BitWriter* const bw = &enc->bw_; - VP8EncIterator it; - VP8IteratorInit(enc, &it); - do { - const VP8MBInfo* const mb = it.mb_; - const uint8_t* preds = it.preds_; - if (enc->segment_hdr_.update_map_) { - PutSegment(bw, mb->segment_, enc->proba_.segments_); - } - if (enc->proba_.use_skip_proba_) { - VP8PutBit(bw, mb->skip_, enc->proba_.skip_proba_); - } - if (VP8PutBit(bw, (mb->type_ != 0), 145)) { // i16x16 - PutI16Mode(bw, preds[0]); - } else { - const int preds_w = enc->preds_w_; - const uint8_t* top_pred = preds - preds_w; - int x, y; - for (y = 0; y < 4; ++y) { - int left = preds[-1]; - for (x = 0; x < 4; ++x) { - const uint8_t* const probas = kBModesProba[top_pred[x]][left]; - left = PutI4Mode(bw, preds[x], probas); - } - top_pred = preds; - preds += preds_w; - } - } - PutUVMode(bw, mb->uv_mode_); - } while (VP8IteratorNext(&it)); -} - -//------------------------------------------------------------------------------ -// Paragraph 13 - -const uint8_t - VP8CoeffsUpdateProba[NUM_TYPES][NUM_BANDS][NUM_CTX][NUM_PROBAS] = { - { { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } - }, - { { 176, 246, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 223, 241, 252, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 249, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255 } - }, - { { 255, 244, 252, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 234, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } - }, - { { 255, 246, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 239, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 } - }, - { { 255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 251, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } - }, - { { 255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 251, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 } - }, - { { 255, 254, 253, 255, 254, 255, 255, 255, 255, 255, 255 }, - { 250, 255, 254, 255, 254, 255, 255, 255, 255, 255, 255 }, - { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } - }, - { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } - } - }, - { { { 217, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 225, 252, 241, 253, 255, 255, 254, 255, 255, 255, 255 }, - { 234, 250, 241, 250, 253, 255, 253, 254, 255, 255, 255 } - }, - { { 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 223, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 238, 253, 254, 254, 255, 255, 255, 255, 255, 255, 255 } - }, - { { 255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 249, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } - }, - { { 255, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 247, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } - }, - { { 255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 252, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } - }, - { { 255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } - }, - { { 255, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } - }, - { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } - } - }, - { { { 186, 251, 250, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 234, 251, 244, 254, 255, 255, 255, 255, 255, 255, 255 }, - { 251, 251, 243, 253, 254, 255, 254, 255, 255, 255, 255 } - }, - { { 255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 236, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 251, 253, 253, 254, 254, 255, 255, 255, 255, 255, 255 } - }, - { { 255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } - }, - { { 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } - }, - { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } - }, - { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } - }, - { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } - }, - { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } - } - }, - { { { 248, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 250, 254, 252, 254, 255, 255, 255, 255, 255, 255, 255 }, - { 248, 254, 249, 253, 255, 255, 255, 255, 255, 255, 255 } - }, - { { 255, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 246, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 252, 254, 251, 254, 254, 255, 255, 255, 255, 255, 255 } - }, - { { 255, 254, 252, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 248, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 253, 255, 254, 254, 255, 255, 255, 255, 255, 255, 255 } - }, - { { 255, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 245, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 253, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 } - }, - { { 255, 251, 253, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 252, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 } - }, - { { 255, 252, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 249, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 } - }, - { { 255, 255, 253, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } - }, - { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, - { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } - } - } -}; - -void VP8WriteProbas(VP8BitWriter* const bw, const VP8EncProba* const probas) { - int t, b, c, p; - for (t = 0; t < NUM_TYPES; ++t) { - for (b = 0; b < NUM_BANDS; ++b) { - for (c = 0; c < NUM_CTX; ++c) { - for (p = 0; p < NUM_PROBAS; ++p) { - const uint8_t p0 = probas->coeffs_[t][b][c][p]; - const int update = (p0 != VP8CoeffsProba0[t][b][c][p]); - if (VP8PutBit(bw, update, VP8CoeffsUpdateProba[t][b][c][p])) { - VP8PutBits(bw, p0, 8); - } - } - } - } - } - if (VP8PutBitUniform(bw, probas->use_skip_proba_)) { - VP8PutBits(bw, probas->skip_proba_, 8); - } -} - diff --git a/libwebp/src/enc/vp8i_enc.h b/libwebp/src/enc/vp8i_enc.h deleted file mode 100644 index 0864fbf1..00000000 --- a/libwebp/src/enc/vp8i_enc.h +++ /dev/null @@ -1,523 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// WebP encoder: internal header. -// -// Author: Skal (pascal.massimino@gmail.com) - -#ifndef WEBP_ENC_VP8I_ENC_H_ -#define WEBP_ENC_VP8I_ENC_H_ - -#include // for memcpy() -#include "src/dec/common_dec.h" -#include "src/dsp/dsp.h" -#include "src/utils/bit_writer_utils.h" -#include "src/utils/thread_utils.h" -#include "src/utils/utils.h" -#include "src/webp/encode.h" - -#ifdef __cplusplus -extern "C" { -#endif - -//------------------------------------------------------------------------------ -// Various defines and enums - -// version numbers -#define ENC_MAJ_VERSION 1 -#define ENC_MIN_VERSION 3 -#define ENC_REV_VERSION 2 - -enum { MAX_LF_LEVELS = 64, // Maximum loop filter level - MAX_VARIABLE_LEVEL = 67, // last (inclusive) level with variable cost - MAX_LEVEL = 2047 // max level (note: max codable is 2047 + 67) - }; - -typedef enum { // Rate-distortion optimization levels - RD_OPT_NONE = 0, // no rd-opt - RD_OPT_BASIC = 1, // basic scoring (no trellis) - RD_OPT_TRELLIS = 2, // perform trellis-quant on the final decision only - RD_OPT_TRELLIS_ALL = 3 // trellis-quant for every scoring (much slower) -} VP8RDLevel; - -// YUV-cache parameters. Cache is 32-bytes wide (= one cacheline). -// The original or reconstructed samples can be accessed using VP8Scan[]. -// The predicted blocks can be accessed using offsets to yuv_p_ and -// the arrays VP8*ModeOffsets[]. -// * YUV Samples area (yuv_in_/yuv_out_/yuv_out2_) -// (see VP8Scan[] for accessing the blocks, along with -// Y_OFF_ENC/U_OFF_ENC/V_OFF_ENC): -// +----+----+ -// Y_OFF_ENC |YYYY|UUVV| -// U_OFF_ENC |YYYY|UUVV| -// V_OFF_ENC |YYYY|....| <- 25% wasted U/V area -// |YYYY|....| -// +----+----+ -// * Prediction area ('yuv_p_', size = PRED_SIZE_ENC) -// Intra16 predictions (16x16 block each, two per row): -// |I16DC16|I16TM16| -// |I16VE16|I16HE16| -// Chroma U/V predictions (16x8 block each, two per row): -// |C8DC8|C8TM8| -// |C8VE8|C8HE8| -// Intra 4x4 predictions (4x4 block each) -// |I4DC4 I4TM4 I4VE4 I4HE4|I4RD4 I4VR4 I4LD4 I4VL4| -// |I4HD4 I4HU4 I4TMP .....|.......................| <- ~31% wasted -#define YUV_SIZE_ENC (BPS * 16) -#define PRED_SIZE_ENC (32 * BPS + 16 * BPS + 8 * BPS) // I16+Chroma+I4 preds -#define Y_OFF_ENC (0) -#define U_OFF_ENC (16) -#define V_OFF_ENC (16 + 8) - -extern const uint16_t VP8Scan[16]; -extern const uint16_t VP8UVModeOffsets[4]; -extern const uint16_t VP8I16ModeOffsets[4]; -extern const uint16_t VP8I4ModeOffsets[NUM_BMODES]; - -// Layout of prediction blocks -// intra 16x16 -#define I16DC16 (0 * 16 * BPS) -#define I16TM16 (I16DC16 + 16) -#define I16VE16 (1 * 16 * BPS) -#define I16HE16 (I16VE16 + 16) -// chroma 8x8, two U/V blocks side by side (hence: 16x8 each) -#define C8DC8 (2 * 16 * BPS) -#define C8TM8 (C8DC8 + 1 * 16) -#define C8VE8 (2 * 16 * BPS + 8 * BPS) -#define C8HE8 (C8VE8 + 1 * 16) -// intra 4x4 -#define I4DC4 (3 * 16 * BPS + 0) -#define I4TM4 (I4DC4 + 4) -#define I4VE4 (I4DC4 + 8) -#define I4HE4 (I4DC4 + 12) -#define I4RD4 (I4DC4 + 16) -#define I4VR4 (I4DC4 + 20) -#define I4LD4 (I4DC4 + 24) -#define I4VL4 (I4DC4 + 28) -#define I4HD4 (3 * 16 * BPS + 4 * BPS) -#define I4HU4 (I4HD4 + 4) -#define I4TMP (I4HD4 + 8) - -typedef int64_t score_t; // type used for scores, rate, distortion -// Note that MAX_COST is not the maximum allowed by sizeof(score_t), -// in order to allow overflowing computations. -#define MAX_COST ((score_t)0x7fffffffffffffLL) - -#define QFIX 17 -#define BIAS(b) ((b) << (QFIX - 8)) -// Fun fact: this is the _only_ line where we're actually being lossy and -// discarding bits. -static WEBP_INLINE int QUANTDIV(uint32_t n, uint32_t iQ, uint32_t B) { - return (int)((n * iQ + B) >> QFIX); -} - -// Uncomment the following to remove token-buffer code: -// #define DISABLE_TOKEN_BUFFER - -// quality below which error-diffusion is enabled -#define ERROR_DIFFUSION_QUALITY 98 - -//------------------------------------------------------------------------------ -// Headers - -typedef uint32_t proba_t; // 16b + 16b -typedef uint8_t ProbaArray[NUM_CTX][NUM_PROBAS]; -typedef proba_t StatsArray[NUM_CTX][NUM_PROBAS]; -typedef uint16_t CostArray[NUM_CTX][MAX_VARIABLE_LEVEL + 1]; -typedef const uint16_t* (*CostArrayPtr)[NUM_CTX]; // for easy casting -typedef const uint16_t* CostArrayMap[16][NUM_CTX]; -typedef double LFStats[NUM_MB_SEGMENTS][MAX_LF_LEVELS]; // filter stats - -typedef struct VP8Encoder VP8Encoder; - -// segment features -typedef struct { - int num_segments_; // Actual number of segments. 1 segment only = unused. - int update_map_; // whether to update the segment map or not. - // must be 0 if there's only 1 segment. - int size_; // bit-cost for transmitting the segment map -} VP8EncSegmentHeader; - -// Struct collecting all frame-persistent probabilities. -typedef struct { - uint8_t segments_[3]; // probabilities for segment tree - uint8_t skip_proba_; // final probability of being skipped. - ProbaArray coeffs_[NUM_TYPES][NUM_BANDS]; // 1056 bytes - StatsArray stats_[NUM_TYPES][NUM_BANDS]; // 4224 bytes - CostArray level_cost_[NUM_TYPES][NUM_BANDS]; // 13056 bytes - CostArrayMap remapped_costs_[NUM_TYPES]; // 1536 bytes - int dirty_; // if true, need to call VP8CalculateLevelCosts() - int use_skip_proba_; // Note: we always use skip_proba for now. - int nb_skip_; // number of skipped blocks -} VP8EncProba; - -// Filter parameters. Not actually used in the code (we don't perform -// the in-loop filtering), but filled from user's config -typedef struct { - int simple_; // filtering type: 0=complex, 1=simple - int level_; // base filter level [0..63] - int sharpness_; // [0..7] - int i4x4_lf_delta_; // delta filter level for i4x4 relative to i16x16 -} VP8EncFilterHeader; - -//------------------------------------------------------------------------------ -// Informations about the macroblocks. - -typedef struct { - // block type - unsigned int type_:2; // 0=i4x4, 1=i16x16 - unsigned int uv_mode_:2; - unsigned int skip_:1; - unsigned int segment_:2; - uint8_t alpha_; // quantization-susceptibility -} VP8MBInfo; - -typedef struct VP8Matrix { - uint16_t q_[16]; // quantizer steps - uint16_t iq_[16]; // reciprocals, fixed point. - uint32_t bias_[16]; // rounding bias - uint32_t zthresh_[16]; // value below which a coefficient is zeroed - uint16_t sharpen_[16]; // frequency boosters for slight sharpening -} VP8Matrix; - -typedef struct { - VP8Matrix y1_, y2_, uv_; // quantization matrices - int alpha_; // quant-susceptibility, range [-127,127]. Zero is neutral. - // Lower values indicate a lower risk of blurriness. - int beta_; // filter-susceptibility, range [0,255]. - int quant_; // final segment quantizer. - int fstrength_; // final in-loop filtering strength - int max_edge_; // max edge delta (for filtering strength) - int min_disto_; // minimum distortion required to trigger filtering record - // reactivities - int lambda_i16_, lambda_i4_, lambda_uv_; - int lambda_mode_, lambda_trellis_, tlambda_; - int lambda_trellis_i16_, lambda_trellis_i4_, lambda_trellis_uv_; - - // lambda values for distortion-based evaluation - score_t i4_penalty_; // penalty for using Intra4 -} VP8SegmentInfo; - -typedef int8_t DError[2 /* u/v */][2 /* top or left */]; - -// Handy transient struct to accumulate score and info during RD-optimization -// and mode evaluation. -typedef struct { - score_t D, SD; // Distortion, spectral distortion - score_t H, R, score; // header bits, rate, score. - int16_t y_dc_levels[16]; // Quantized levels for luma-DC, luma-AC, chroma. - int16_t y_ac_levels[16][16]; - int16_t uv_levels[4 + 4][16]; - int mode_i16; // mode number for intra16 prediction - uint8_t modes_i4[16]; // mode numbers for intra4 predictions - int mode_uv; // mode number of chroma prediction - uint32_t nz; // non-zero blocks - int8_t derr[2][3]; // DC diffusion errors for U/V for blocks #1/2/3 -} VP8ModeScore; - -// Iterator structure to iterate through macroblocks, pointing to the -// right neighbouring data (samples, predictions, contexts, ...) -typedef struct { - int x_, y_; // current macroblock - uint8_t* yuv_in_; // input samples - uint8_t* yuv_out_; // output samples - uint8_t* yuv_out2_; // secondary buffer swapped with yuv_out_. - uint8_t* yuv_p_; // scratch buffer for prediction - VP8Encoder* enc_; // back-pointer - VP8MBInfo* mb_; // current macroblock - VP8BitWriter* bw_; // current bit-writer - uint8_t* preds_; // intra mode predictors (4x4 blocks) - uint32_t* nz_; // non-zero pattern - uint8_t i4_boundary_[37]; // 32+5 boundary samples needed by intra4x4 - uint8_t* i4_top_; // pointer to the current top boundary sample - int i4_; // current intra4x4 mode being tested - int top_nz_[9]; // top-non-zero context. - int left_nz_[9]; // left-non-zero. left_nz[8] is independent. - uint64_t bit_count_[4][3]; // bit counters for coded levels. - uint64_t luma_bits_; // macroblock bit-cost for luma - uint64_t uv_bits_; // macroblock bit-cost for chroma - LFStats* lf_stats_; // filter stats (borrowed from enc_) - int do_trellis_; // if true, perform extra level optimisation - int count_down_; // number of mb still to be processed - int count_down0_; // starting counter value (for progress) - int percent0_; // saved initial progress percent - - DError left_derr_; // left error diffusion (u/v) - DError* top_derr_; // top diffusion error - NULL if disabled - - uint8_t* y_left_; // left luma samples (addressable from index -1 to 15). - uint8_t* u_left_; // left u samples (addressable from index -1 to 7) - uint8_t* v_left_; // left v samples (addressable from index -1 to 7) - - uint8_t* y_top_; // top luma samples at position 'x_' - uint8_t* uv_top_; // top u/v samples at position 'x_', packed as 16 bytes - - // memory for storing y/u/v_left_ - uint8_t yuv_left_mem_[17 + 16 + 16 + 8 + WEBP_ALIGN_CST]; - // memory for yuv_* - uint8_t yuv_mem_[3 * YUV_SIZE_ENC + PRED_SIZE_ENC + WEBP_ALIGN_CST]; -} VP8EncIterator; - - // in iterator.c -// must be called first -void VP8IteratorInit(VP8Encoder* const enc, VP8EncIterator* const it); -// restart a scan -void VP8IteratorReset(VP8EncIterator* const it); -// reset iterator position to row 'y' -void VP8IteratorSetRow(VP8EncIterator* const it, int y); -// set count down (=number of iterations to go) -void VP8IteratorSetCountDown(VP8EncIterator* const it, int count_down); -// return true if iteration is finished -int VP8IteratorIsDone(const VP8EncIterator* const it); -// Import uncompressed samples from source. -// If tmp_32 is not NULL, import boundary samples too. -// tmp_32 is a 32-bytes scratch buffer that must be aligned in memory. -void VP8IteratorImport(VP8EncIterator* const it, uint8_t* const tmp_32); -// export decimated samples -void VP8IteratorExport(const VP8EncIterator* const it); -// go to next macroblock. Returns false if not finished. -int VP8IteratorNext(VP8EncIterator* const it); -// save the yuv_out_ boundary values to top_/left_ arrays for next iterations. -void VP8IteratorSaveBoundary(VP8EncIterator* const it); -// Report progression based on macroblock rows. Return 0 for user-abort request. -int VP8IteratorProgress(const VP8EncIterator* const it, int delta); -// Intra4x4 iterations -void VP8IteratorStartI4(VP8EncIterator* const it); -// returns true if not done. -int VP8IteratorRotateI4(VP8EncIterator* const it, - const uint8_t* const yuv_out); - -// Non-zero context setup/teardown -void VP8IteratorNzToBytes(VP8EncIterator* const it); -void VP8IteratorBytesToNz(VP8EncIterator* const it); - -// Helper functions to set mode properties -void VP8SetIntra16Mode(const VP8EncIterator* const it, int mode); -void VP8SetIntra4Mode(const VP8EncIterator* const it, const uint8_t* modes); -void VP8SetIntraUVMode(const VP8EncIterator* const it, int mode); -void VP8SetSkip(const VP8EncIterator* const it, int skip); -void VP8SetSegment(const VP8EncIterator* const it, int segment); - -//------------------------------------------------------------------------------ -// Paginated token buffer - -typedef struct VP8Tokens VP8Tokens; // struct details in token.c - -typedef struct { -#if !defined(DISABLE_TOKEN_BUFFER) - VP8Tokens* pages_; // first page - VP8Tokens** last_page_; // last page - uint16_t* tokens_; // set to (*last_page_)->tokens_ - int left_; // how many free tokens left before the page is full - int page_size_; // number of tokens per page -#endif - int error_; // true in case of malloc error -} VP8TBuffer; - -// initialize an empty buffer -void VP8TBufferInit(VP8TBuffer* const b, int page_size); -void VP8TBufferClear(VP8TBuffer* const b); // de-allocate pages memory - -#if !defined(DISABLE_TOKEN_BUFFER) - -// Finalizes bitstream when probabilities are known. -// Deletes the allocated token memory if final_pass is true. -int VP8EmitTokens(VP8TBuffer* const b, VP8BitWriter* const bw, - const uint8_t* const probas, int final_pass); - -// record the coding of coefficients without knowing the probabilities yet -int VP8RecordCoeffTokens(int ctx, const struct VP8Residual* const res, - VP8TBuffer* const tokens); - -// Estimate the final coded size given a set of 'probas'. -size_t VP8EstimateTokenSize(VP8TBuffer* const b, const uint8_t* const probas); - -#endif // !DISABLE_TOKEN_BUFFER - -//------------------------------------------------------------------------------ -// VP8Encoder - -struct VP8Encoder { - const WebPConfig* config_; // user configuration and parameters - WebPPicture* pic_; // input / output picture - - // headers - VP8EncFilterHeader filter_hdr_; // filtering information - VP8EncSegmentHeader segment_hdr_; // segment information - - int profile_; // VP8's profile, deduced from Config. - - // dimension, in macroblock units. - int mb_w_, mb_h_; - int preds_w_; // stride of the *preds_ prediction plane (=4*mb_w + 1) - - // number of partitions (1, 2, 4 or 8 = MAX_NUM_PARTITIONS) - int num_parts_; - - // per-partition boolean decoders. - VP8BitWriter bw_; // part0 - VP8BitWriter parts_[MAX_NUM_PARTITIONS]; // token partitions - VP8TBuffer tokens_; // token buffer - - int percent_; // for progress - - // transparency blob - int has_alpha_; - uint8_t* alpha_data_; // non-NULL if transparency is present - uint32_t alpha_data_size_; - WebPWorker alpha_worker_; - - // quantization info (one set of DC/AC dequant factor per segment) - VP8SegmentInfo dqm_[NUM_MB_SEGMENTS]; - int base_quant_; // nominal quantizer value. Only used - // for relative coding of segments' quant. - int alpha_; // global susceptibility (<=> complexity) - int uv_alpha_; // U/V quantization susceptibility - // global offset of quantizers, shared by all segments - int dq_y1_dc_; - int dq_y2_dc_, dq_y2_ac_; - int dq_uv_dc_, dq_uv_ac_; - - // probabilities and statistics - VP8EncProba proba_; - uint64_t sse_[4]; // sum of Y/U/V/A squared errors for all macroblocks - uint64_t sse_count_; // pixel count for the sse_[] stats - int coded_size_; - int residual_bytes_[3][4]; - int block_count_[3]; - - // quality/speed settings - int method_; // 0=fastest, 6=best/slowest. - VP8RDLevel rd_opt_level_; // Deduced from method_. - int max_i4_header_bits_; // partition #0 safeness factor - int mb_header_limit_; // rough limit for header bits per MB - int thread_level_; // derived from config->thread_level - int do_search_; // derived from config->target_XXX - int use_tokens_; // if true, use token buffer - - // Memory - VP8MBInfo* mb_info_; // contextual macroblock infos (mb_w_ + 1) - uint8_t* preds_; // predictions modes: (4*mb_w+1) * (4*mb_h+1) - uint32_t* nz_; // non-zero bit context: mb_w+1 - uint8_t* y_top_; // top luma samples. - uint8_t* uv_top_; // top u/v samples. - // U and V are packed into 16 bytes (8 U + 8 V) - LFStats* lf_stats_; // autofilter stats (if NULL, autofilter is off) - DError* top_derr_; // diffusion error (NULL if disabled) -}; - -//------------------------------------------------------------------------------ -// internal functions. Not public. - - // in tree.c -extern const uint8_t VP8CoeffsProba0[NUM_TYPES][NUM_BANDS][NUM_CTX][NUM_PROBAS]; -extern const uint8_t - VP8CoeffsUpdateProba[NUM_TYPES][NUM_BANDS][NUM_CTX][NUM_PROBAS]; -// Reset the token probabilities to their initial (default) values -void VP8DefaultProbas(VP8Encoder* const enc); -// Write the token probabilities -void VP8WriteProbas(VP8BitWriter* const bw, const VP8EncProba* const probas); -// Writes the partition #0 modes (that is: all intra modes) -void VP8CodeIntraModes(VP8Encoder* const enc); - - // in syntax.c -// Generates the final bitstream by coding the partition0 and headers, -// and appending an assembly of all the pre-coded token partitions. -// Return true if everything is ok. -int VP8EncWrite(VP8Encoder* const enc); -// Release memory allocated for bit-writing in VP8EncLoop & seq. -void VP8EncFreeBitWriters(VP8Encoder* const enc); - - // in frame.c -extern const uint8_t VP8Cat3[]; -extern const uint8_t VP8Cat4[]; -extern const uint8_t VP8Cat5[]; -extern const uint8_t VP8Cat6[]; - -// Form all the four Intra16x16 predictions in the yuv_p_ cache -void VP8MakeLuma16Preds(const VP8EncIterator* const it); -// Form all the four Chroma8x8 predictions in the yuv_p_ cache -void VP8MakeChroma8Preds(const VP8EncIterator* const it); -// Form all the ten Intra4x4 predictions in the yuv_p_ cache -// for the 4x4 block it->i4_ -void VP8MakeIntra4Preds(const VP8EncIterator* const it); -// Rate calculation -int VP8GetCostLuma16(VP8EncIterator* const it, const VP8ModeScore* const rd); -int VP8GetCostLuma4(VP8EncIterator* const it, const int16_t levels[16]); -int VP8GetCostUV(VP8EncIterator* const it, const VP8ModeScore* const rd); -// Main coding calls -int VP8EncLoop(VP8Encoder* const enc); -int VP8EncTokenLoop(VP8Encoder* const enc); - - // in webpenc.c -// Assign an error code to a picture. Return false for convenience. -int WebPEncodingSetError(const WebPPicture* const pic, WebPEncodingError error); -int WebPReportProgress(const WebPPicture* const pic, - int percent, int* const percent_store); - - // in analysis.c -// Main analysis loop. Decides the segmentations and complexity. -// Assigns a first guess for Intra16 and uvmode_ prediction modes. -int VP8EncAnalyze(VP8Encoder* const enc); - - // in quant.c -// Sets up segment's quantization values, base_quant_ and filter strengths. -void VP8SetSegmentParams(VP8Encoder* const enc, float quality); -// Pick best modes and fills the levels. Returns true if skipped. -int VP8Decimate(VP8EncIterator* WEBP_RESTRICT const it, - VP8ModeScore* WEBP_RESTRICT const rd, - VP8RDLevel rd_opt); - - // in alpha.c -void VP8EncInitAlpha(VP8Encoder* const enc); // initialize alpha compression -int VP8EncStartAlpha(VP8Encoder* const enc); // start alpha coding process -int VP8EncFinishAlpha(VP8Encoder* const enc); // finalize compressed data -int VP8EncDeleteAlpha(VP8Encoder* const enc); // delete compressed data - -// autofilter -void VP8InitFilter(VP8EncIterator* const it); -void VP8StoreFilterStats(VP8EncIterator* const it); -void VP8AdjustFilterStrength(VP8EncIterator* const it); - -// returns the approximate filtering strength needed to smooth a edge -// step of 'delta', given a sharpness parameter 'sharpness'. -int VP8FilterStrengthFromDelta(int sharpness, int delta); - - // misc utils for picture_*.c: - -// Returns true if 'picture' is non-NULL and dimensions/colorspace are within -// their valid ranges. If returning false, the 'error_code' in 'picture' is -// updated. -int WebPValidatePicture(const WebPPicture* const picture); - -// Remove reference to the ARGB/YUVA buffer (doesn't free anything). -void WebPPictureResetBuffers(WebPPicture* const picture); - -// Allocates ARGB buffer according to set width/height (previous one is -// always free'd). Preserves the YUV(A) buffer. Returns false in case of error -// (invalid param, out-of-memory). -int WebPPictureAllocARGB(WebPPicture* const picture); - -// Allocates YUVA buffer according to set width/height (previous one is always -// free'd). Uses picture->csp to determine whether an alpha buffer is needed. -// Preserves the ARGB buffer. -// Returns false in case of error (invalid param, out-of-memory). -int WebPPictureAllocYUVA(WebPPicture* const picture); - -// Replace samples that are fully transparent by 'color' to help compressibility -// (no guarantee, though). Assumes pic->use_argb is true. -void WebPReplaceTransparentPixels(WebPPicture* const pic, uint32_t color); - -//------------------------------------------------------------------------------ - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // WEBP_ENC_VP8I_ENC_H_ diff --git a/libwebp/src/enc/vp8l_enc.c b/libwebp/src/enc/vp8l_enc.c deleted file mode 100644 index 40eafa41..00000000 --- a/libwebp/src/enc/vp8l_enc.c +++ /dev/null @@ -1,1893 +0,0 @@ -// Copyright 2012 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// main entry for the lossless encoder. -// -// Author: Vikas Arora (vikaas.arora@gmail.com) -// - -#include -#include - -#include "src/dsp/lossless.h" -#include "src/dsp/lossless_common.h" -#include "src/enc/backward_references_enc.h" -#include "src/enc/histogram_enc.h" -#include "src/enc/vp8i_enc.h" -#include "src/enc/vp8li_enc.h" -#include "src/utils/bit_writer_utils.h" -#include "src/utils/huffman_encode_utils.h" -#include "src/utils/palette.h" -#include "src/utils/utils.h" -#include "src/webp/encode.h" -#include "src/webp/format_constants.h" - -// Maximum number of histogram images (sub-blocks). -#define MAX_HUFF_IMAGE_SIZE 2600 - -// ----------------------------------------------------------------------------- -// Palette - -// These five modes are evaluated and their respective entropy is computed. -typedef enum { - kDirect = 0, - kSpatial = 1, - kSubGreen = 2, - kSpatialSubGreen = 3, - kPalette = 4, - kPaletteAndSpatial = 5, - kNumEntropyIx = 6 -} EntropyIx; - -typedef enum { - kHistoAlpha = 0, - kHistoAlphaPred, - kHistoGreen, - kHistoGreenPred, - kHistoRed, - kHistoRedPred, - kHistoBlue, - kHistoBluePred, - kHistoRedSubGreen, - kHistoRedPredSubGreen, - kHistoBlueSubGreen, - kHistoBluePredSubGreen, - kHistoPalette, - kHistoTotal // Must be last. -} HistoIx; - -static void AddSingleSubGreen(uint32_t p, - uint32_t* const r, uint32_t* const b) { - const int green = (int)p >> 8; // The upper bits are masked away later. - ++r[(((int)p >> 16) - green) & 0xff]; - ++b[(((int)p >> 0) - green) & 0xff]; -} - -static void AddSingle(uint32_t p, - uint32_t* const a, uint32_t* const r, - uint32_t* const g, uint32_t* const b) { - ++a[(p >> 24) & 0xff]; - ++r[(p >> 16) & 0xff]; - ++g[(p >> 8) & 0xff]; - ++b[(p >> 0) & 0xff]; -} - -static WEBP_INLINE uint32_t HashPix(uint32_t pix) { - // Note that masking with 0xffffffffu is for preventing an - // 'unsigned int overflow' warning. Doesn't impact the compiled code. - return ((((uint64_t)pix + (pix >> 19)) * 0x39c5fba7ull) & 0xffffffffu) >> 24; -} - -static int AnalyzeEntropy(const uint32_t* argb, - int width, int height, int argb_stride, - int use_palette, - int palette_size, int transform_bits, - EntropyIx* const min_entropy_ix, - int* const red_and_blue_always_zero) { - // Allocate histogram set with cache_bits = 0. - uint32_t* histo; - - if (use_palette && palette_size <= 16) { - // In the case of small palettes, we pack 2, 4 or 8 pixels together. In - // practice, small palettes are better than any other transform. - *min_entropy_ix = kPalette; - *red_and_blue_always_zero = 1; - return 1; - } - histo = (uint32_t*)WebPSafeCalloc(kHistoTotal, sizeof(*histo) * 256); - if (histo != NULL) { - int i, x, y; - const uint32_t* prev_row = NULL; - const uint32_t* curr_row = argb; - uint32_t pix_prev = argb[0]; // Skip the first pixel. - for (y = 0; y < height; ++y) { - for (x = 0; x < width; ++x) { - const uint32_t pix = curr_row[x]; - const uint32_t pix_diff = VP8LSubPixels(pix, pix_prev); - pix_prev = pix; - if ((pix_diff == 0) || (prev_row != NULL && pix == prev_row[x])) { - continue; - } - AddSingle(pix, - &histo[kHistoAlpha * 256], - &histo[kHistoRed * 256], - &histo[kHistoGreen * 256], - &histo[kHistoBlue * 256]); - AddSingle(pix_diff, - &histo[kHistoAlphaPred * 256], - &histo[kHistoRedPred * 256], - &histo[kHistoGreenPred * 256], - &histo[kHistoBluePred * 256]); - AddSingleSubGreen(pix, - &histo[kHistoRedSubGreen * 256], - &histo[kHistoBlueSubGreen * 256]); - AddSingleSubGreen(pix_diff, - &histo[kHistoRedPredSubGreen * 256], - &histo[kHistoBluePredSubGreen * 256]); - { - // Approximate the palette by the entropy of the multiplicative hash. - const uint32_t hash = HashPix(pix); - ++histo[kHistoPalette * 256 + hash]; - } - } - prev_row = curr_row; - curr_row += argb_stride; - } - { - float entropy_comp[kHistoTotal]; - float entropy[kNumEntropyIx]; - int k; - int last_mode_to_analyze = use_palette ? kPalette : kSpatialSubGreen; - int j; - // Let's add one zero to the predicted histograms. The zeros are removed - // too efficiently by the pix_diff == 0 comparison, at least one of the - // zeros is likely to exist. - ++histo[kHistoRedPredSubGreen * 256]; - ++histo[kHistoBluePredSubGreen * 256]; - ++histo[kHistoRedPred * 256]; - ++histo[kHistoGreenPred * 256]; - ++histo[kHistoBluePred * 256]; - ++histo[kHistoAlphaPred * 256]; - - for (j = 0; j < kHistoTotal; ++j) { - entropy_comp[j] = VP8LBitsEntropy(&histo[j * 256], 256); - } - entropy[kDirect] = entropy_comp[kHistoAlpha] + - entropy_comp[kHistoRed] + - entropy_comp[kHistoGreen] + - entropy_comp[kHistoBlue]; - entropy[kSpatial] = entropy_comp[kHistoAlphaPred] + - entropy_comp[kHistoRedPred] + - entropy_comp[kHistoGreenPred] + - entropy_comp[kHistoBluePred]; - entropy[kSubGreen] = entropy_comp[kHistoAlpha] + - entropy_comp[kHistoRedSubGreen] + - entropy_comp[kHistoGreen] + - entropy_comp[kHistoBlueSubGreen]; - entropy[kSpatialSubGreen] = entropy_comp[kHistoAlphaPred] + - entropy_comp[kHistoRedPredSubGreen] + - entropy_comp[kHistoGreenPred] + - entropy_comp[kHistoBluePredSubGreen]; - entropy[kPalette] = entropy_comp[kHistoPalette]; - - // When including transforms, there is an overhead in bits from - // storing them. This overhead is small but matters for small images. - // For spatial, there are 14 transformations. - entropy[kSpatial] += VP8LSubSampleSize(width, transform_bits) * - VP8LSubSampleSize(height, transform_bits) * - VP8LFastLog2(14); - // For color transforms: 24 as only 3 channels are considered in a - // ColorTransformElement. - entropy[kSpatialSubGreen] += VP8LSubSampleSize(width, transform_bits) * - VP8LSubSampleSize(height, transform_bits) * - VP8LFastLog2(24); - // For palettes, add the cost of storing the palette. - // We empirically estimate the cost of a compressed entry as 8 bits. - // The palette is differential-coded when compressed hence a much - // lower cost than sizeof(uint32_t)*8. - entropy[kPalette] += palette_size * 8; - - *min_entropy_ix = kDirect; - for (k = kDirect + 1; k <= last_mode_to_analyze; ++k) { - if (entropy[*min_entropy_ix] > entropy[k]) { - *min_entropy_ix = (EntropyIx)k; - } - } - assert((int)*min_entropy_ix <= last_mode_to_analyze); - *red_and_blue_always_zero = 1; - // Let's check if the histogram of the chosen entropy mode has - // non-zero red and blue values. If all are zero, we can later skip - // the cross color optimization. - { - static const uint8_t kHistoPairs[5][2] = { - { kHistoRed, kHistoBlue }, - { kHistoRedPred, kHistoBluePred }, - { kHistoRedSubGreen, kHistoBlueSubGreen }, - { kHistoRedPredSubGreen, kHistoBluePredSubGreen }, - { kHistoRed, kHistoBlue } - }; - const uint32_t* const red_histo = - &histo[256 * kHistoPairs[*min_entropy_ix][0]]; - const uint32_t* const blue_histo = - &histo[256 * kHistoPairs[*min_entropy_ix][1]]; - for (i = 1; i < 256; ++i) { - if ((red_histo[i] | blue_histo[i]) != 0) { - *red_and_blue_always_zero = 0; - break; - } - } - } - } - WebPSafeFree(histo); - return 1; - } else { - return 0; - } -} - -static int GetHistoBits(int method, int use_palette, int width, int height) { - // Make tile size a function of encoding method (Range: 0 to 6). - int histo_bits = (use_palette ? 9 : 7) - method; - while (1) { - const int huff_image_size = VP8LSubSampleSize(width, histo_bits) * - VP8LSubSampleSize(height, histo_bits); - if (huff_image_size <= MAX_HUFF_IMAGE_SIZE) break; - ++histo_bits; - } - return (histo_bits < MIN_HUFFMAN_BITS) ? MIN_HUFFMAN_BITS : - (histo_bits > MAX_HUFFMAN_BITS) ? MAX_HUFFMAN_BITS : histo_bits; -} - -static int GetTransformBits(int method, int histo_bits) { - const int max_transform_bits = (method < 4) ? 6 : (method > 4) ? 4 : 5; - const int res = - (histo_bits > max_transform_bits) ? max_transform_bits : histo_bits; - assert(res <= MAX_TRANSFORM_BITS); - return res; -} - -// Set of parameters to be used in each iteration of the cruncher. -#define CRUNCH_SUBCONFIGS_MAX 2 -typedef struct { - int lz77_; - int do_no_cache_; -} CrunchSubConfig; -typedef struct { - int entropy_idx_; - PaletteSorting palette_sorting_type_; - CrunchSubConfig sub_configs_[CRUNCH_SUBCONFIGS_MAX]; - int sub_configs_size_; -} CrunchConfig; - -// +2 because we add a palette sorting configuration for kPalette and -// kPaletteAndSpatial. -#define CRUNCH_CONFIGS_MAX (kNumEntropyIx + 2 * kPaletteSortingNum) - -static int EncoderAnalyze(VP8LEncoder* const enc, - CrunchConfig crunch_configs[CRUNCH_CONFIGS_MAX], - int* const crunch_configs_size, - int* const red_and_blue_always_zero) { - const WebPPicture* const pic = enc->pic_; - const int width = pic->width; - const int height = pic->height; - const WebPConfig* const config = enc->config_; - const int method = config->method; - const int low_effort = (config->method == 0); - int i; - int use_palette; - int n_lz77s; - // If set to 0, analyze the cache with the computed cache value. If 1, also - // analyze with no-cache. - int do_no_cache = 0; - assert(pic != NULL && pic->argb != NULL); - - // Check whether a palette is possible. - enc->palette_size_ = GetColorPalette(pic, enc->palette_sorted_); - use_palette = (enc->palette_size_ <= MAX_PALETTE_SIZE); - if (!use_palette) { - enc->palette_size_ = 0; - } - - // Empirical bit sizes. - enc->histo_bits_ = GetHistoBits(method, use_palette, - pic->width, pic->height); - enc->transform_bits_ = GetTransformBits(method, enc->histo_bits_); - - if (low_effort) { - // AnalyzeEntropy is somewhat slow. - crunch_configs[0].entropy_idx_ = use_palette ? kPalette : kSpatialSubGreen; - crunch_configs[0].palette_sorting_type_ = - use_palette ? kSortedDefault : kUnusedPalette; - n_lz77s = 1; - *crunch_configs_size = 1; - } else { - EntropyIx min_entropy_ix; - // Try out multiple LZ77 on images with few colors. - n_lz77s = (enc->palette_size_ > 0 && enc->palette_size_ <= 16) ? 2 : 1; - if (!AnalyzeEntropy(pic->argb, width, height, pic->argb_stride, use_palette, - enc->palette_size_, enc->transform_bits_, - &min_entropy_ix, red_and_blue_always_zero)) { - return 0; - } - if (method == 6 && config->quality == 100) { - do_no_cache = 1; - // Go brute force on all transforms. - *crunch_configs_size = 0; - for (i = 0; i < kNumEntropyIx; ++i) { - // We can only apply kPalette or kPaletteAndSpatial if we can indeed use - // a palette. - if ((i != kPalette && i != kPaletteAndSpatial) || use_palette) { - assert(*crunch_configs_size < CRUNCH_CONFIGS_MAX); - if (use_palette && (i == kPalette || i == kPaletteAndSpatial)) { - int sorting_method; - for (sorting_method = 0; sorting_method < kPaletteSortingNum; - ++sorting_method) { - const PaletteSorting typed_sorting_method = - (PaletteSorting)sorting_method; - // TODO(vrabaud) kSortedDefault should be tested. It is omitted - // for now for backward compatibility. - if (typed_sorting_method == kUnusedPalette || - typed_sorting_method == kSortedDefault) { - continue; - } - crunch_configs[(*crunch_configs_size)].entropy_idx_ = i; - crunch_configs[(*crunch_configs_size)].palette_sorting_type_ = - typed_sorting_method; - ++*crunch_configs_size; - } - } else { - crunch_configs[(*crunch_configs_size)].entropy_idx_ = i; - crunch_configs[(*crunch_configs_size)].palette_sorting_type_ = - kUnusedPalette; - ++*crunch_configs_size; - } - } - } - } else { - // Only choose the guessed best transform. - *crunch_configs_size = 1; - crunch_configs[0].entropy_idx_ = min_entropy_ix; - crunch_configs[0].palette_sorting_type_ = - use_palette ? kMinimizeDelta : kUnusedPalette; - if (config->quality >= 75 && method == 5) { - // Test with and without color cache. - do_no_cache = 1; - // If we have a palette, also check in combination with spatial. - if (min_entropy_ix == kPalette) { - *crunch_configs_size = 2; - crunch_configs[1].entropy_idx_ = kPaletteAndSpatial; - crunch_configs[1].palette_sorting_type_ = kMinimizeDelta; - } - } - } - } - // Fill in the different LZ77s. - assert(n_lz77s <= CRUNCH_SUBCONFIGS_MAX); - for (i = 0; i < *crunch_configs_size; ++i) { - int j; - for (j = 0; j < n_lz77s; ++j) { - assert(j < CRUNCH_SUBCONFIGS_MAX); - crunch_configs[i].sub_configs_[j].lz77_ = - (j == 0) ? kLZ77Standard | kLZ77RLE : kLZ77Box; - crunch_configs[i].sub_configs_[j].do_no_cache_ = do_no_cache; - } - crunch_configs[i].sub_configs_size_ = n_lz77s; - } - return 1; -} - -static int EncoderInit(VP8LEncoder* const enc) { - const WebPPicture* const pic = enc->pic_; - const int width = pic->width; - const int height = pic->height; - const int pix_cnt = width * height; - // we round the block size up, so we're guaranteed to have - // at most MAX_REFS_BLOCK_PER_IMAGE blocks used: - const int refs_block_size = (pix_cnt - 1) / MAX_REFS_BLOCK_PER_IMAGE + 1; - int i; - if (!VP8LHashChainInit(&enc->hash_chain_, pix_cnt)) return 0; - - for (i = 0; i < 4; ++i) VP8LBackwardRefsInit(&enc->refs_[i], refs_block_size); - - return 1; -} - -// Returns false in case of memory error. -static int GetHuffBitLengthsAndCodes( - const VP8LHistogramSet* const histogram_image, - HuffmanTreeCode* const huffman_codes) { - int i, k; - int ok = 0; - uint64_t total_length_size = 0; - uint8_t* mem_buf = NULL; - const int histogram_image_size = histogram_image->size; - int max_num_symbols = 0; - uint8_t* buf_rle = NULL; - HuffmanTree* huff_tree = NULL; - - // Iterate over all histograms and get the aggregate number of codes used. - for (i = 0; i < histogram_image_size; ++i) { - const VP8LHistogram* const histo = histogram_image->histograms[i]; - HuffmanTreeCode* const codes = &huffman_codes[5 * i]; - assert(histo != NULL); - for (k = 0; k < 5; ++k) { - const int num_symbols = - (k == 0) ? VP8LHistogramNumCodes(histo->palette_code_bits_) : - (k == 4) ? NUM_DISTANCE_CODES : 256; - codes[k].num_symbols = num_symbols; - total_length_size += num_symbols; - } - } - - // Allocate and Set Huffman codes. - { - uint16_t* codes; - uint8_t* lengths; - mem_buf = (uint8_t*)WebPSafeCalloc(total_length_size, - sizeof(*lengths) + sizeof(*codes)); - if (mem_buf == NULL) goto End; - - codes = (uint16_t*)mem_buf; - lengths = (uint8_t*)&codes[total_length_size]; - for (i = 0; i < 5 * histogram_image_size; ++i) { - const int bit_length = huffman_codes[i].num_symbols; - huffman_codes[i].codes = codes; - huffman_codes[i].code_lengths = lengths; - codes += bit_length; - lengths += bit_length; - if (max_num_symbols < bit_length) { - max_num_symbols = bit_length; - } - } - } - - buf_rle = (uint8_t*)WebPSafeMalloc(1ULL, max_num_symbols); - huff_tree = (HuffmanTree*)WebPSafeMalloc(3ULL * max_num_symbols, - sizeof(*huff_tree)); - if (buf_rle == NULL || huff_tree == NULL) goto End; - - // Create Huffman trees. - for (i = 0; i < histogram_image_size; ++i) { - HuffmanTreeCode* const codes = &huffman_codes[5 * i]; - VP8LHistogram* const histo = histogram_image->histograms[i]; - VP8LCreateHuffmanTree(histo->literal_, 15, buf_rle, huff_tree, codes + 0); - VP8LCreateHuffmanTree(histo->red_, 15, buf_rle, huff_tree, codes + 1); - VP8LCreateHuffmanTree(histo->blue_, 15, buf_rle, huff_tree, codes + 2); - VP8LCreateHuffmanTree(histo->alpha_, 15, buf_rle, huff_tree, codes + 3); - VP8LCreateHuffmanTree(histo->distance_, 15, buf_rle, huff_tree, codes + 4); - } - ok = 1; - End: - WebPSafeFree(huff_tree); - WebPSafeFree(buf_rle); - if (!ok) { - WebPSafeFree(mem_buf); - memset(huffman_codes, 0, 5 * histogram_image_size * sizeof(*huffman_codes)); - } - return ok; -} - -static void StoreHuffmanTreeOfHuffmanTreeToBitMask( - VP8LBitWriter* const bw, const uint8_t* code_length_bitdepth) { - // RFC 1951 will calm you down if you are worried about this funny sequence. - // This sequence is tuned from that, but more weighted for lower symbol count, - // and more spiking histograms. - static const uint8_t kStorageOrder[CODE_LENGTH_CODES] = { - 17, 18, 0, 1, 2, 3, 4, 5, 16, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 - }; - int i; - // Throw away trailing zeros: - int codes_to_store = CODE_LENGTH_CODES; - for (; codes_to_store > 4; --codes_to_store) { - if (code_length_bitdepth[kStorageOrder[codes_to_store - 1]] != 0) { - break; - } - } - VP8LPutBits(bw, codes_to_store - 4, 4); - for (i = 0; i < codes_to_store; ++i) { - VP8LPutBits(bw, code_length_bitdepth[kStorageOrder[i]], 3); - } -} - -static void ClearHuffmanTreeIfOnlyOneSymbol( - HuffmanTreeCode* const huffman_code) { - int k; - int count = 0; - for (k = 0; k < huffman_code->num_symbols; ++k) { - if (huffman_code->code_lengths[k] != 0) { - ++count; - if (count > 1) return; - } - } - for (k = 0; k < huffman_code->num_symbols; ++k) { - huffman_code->code_lengths[k] = 0; - huffman_code->codes[k] = 0; - } -} - -static void StoreHuffmanTreeToBitMask( - VP8LBitWriter* const bw, - const HuffmanTreeToken* const tokens, const int num_tokens, - const HuffmanTreeCode* const huffman_code) { - int i; - for (i = 0; i < num_tokens; ++i) { - const int ix = tokens[i].code; - const int extra_bits = tokens[i].extra_bits; - VP8LPutBits(bw, huffman_code->codes[ix], huffman_code->code_lengths[ix]); - switch (ix) { - case 16: - VP8LPutBits(bw, extra_bits, 2); - break; - case 17: - VP8LPutBits(bw, extra_bits, 3); - break; - case 18: - VP8LPutBits(bw, extra_bits, 7); - break; - } - } -} - -// 'huff_tree' and 'tokens' are pre-alloacted buffers. -static void StoreFullHuffmanCode(VP8LBitWriter* const bw, - HuffmanTree* const huff_tree, - HuffmanTreeToken* const tokens, - const HuffmanTreeCode* const tree) { - uint8_t code_length_bitdepth[CODE_LENGTH_CODES] = { 0 }; - uint16_t code_length_bitdepth_symbols[CODE_LENGTH_CODES] = { 0 }; - const int max_tokens = tree->num_symbols; - int num_tokens; - HuffmanTreeCode huffman_code; - huffman_code.num_symbols = CODE_LENGTH_CODES; - huffman_code.code_lengths = code_length_bitdepth; - huffman_code.codes = code_length_bitdepth_symbols; - - VP8LPutBits(bw, 0, 1); - num_tokens = VP8LCreateCompressedHuffmanTree(tree, tokens, max_tokens); - { - uint32_t histogram[CODE_LENGTH_CODES] = { 0 }; - uint8_t buf_rle[CODE_LENGTH_CODES] = { 0 }; - int i; - for (i = 0; i < num_tokens; ++i) { - ++histogram[tokens[i].code]; - } - - VP8LCreateHuffmanTree(histogram, 7, buf_rle, huff_tree, &huffman_code); - } - - StoreHuffmanTreeOfHuffmanTreeToBitMask(bw, code_length_bitdepth); - ClearHuffmanTreeIfOnlyOneSymbol(&huffman_code); - { - int trailing_zero_bits = 0; - int trimmed_length = num_tokens; - int write_trimmed_length; - int length; - int i = num_tokens; - while (i-- > 0) { - const int ix = tokens[i].code; - if (ix == 0 || ix == 17 || ix == 18) { - --trimmed_length; // discount trailing zeros - trailing_zero_bits += code_length_bitdepth[ix]; - if (ix == 17) { - trailing_zero_bits += 3; - } else if (ix == 18) { - trailing_zero_bits += 7; - } - } else { - break; - } - } - write_trimmed_length = (trimmed_length > 1 && trailing_zero_bits > 12); - length = write_trimmed_length ? trimmed_length : num_tokens; - VP8LPutBits(bw, write_trimmed_length, 1); - if (write_trimmed_length) { - if (trimmed_length == 2) { - VP8LPutBits(bw, 0, 3 + 2); // nbitpairs=1, trimmed_length=2 - } else { - const int nbits = BitsLog2Floor(trimmed_length - 2); - const int nbitpairs = nbits / 2 + 1; - assert(trimmed_length > 2); - assert(nbitpairs - 1 < 8); - VP8LPutBits(bw, nbitpairs - 1, 3); - VP8LPutBits(bw, trimmed_length - 2, nbitpairs * 2); - } - } - StoreHuffmanTreeToBitMask(bw, tokens, length, &huffman_code); - } -} - -// 'huff_tree' and 'tokens' are pre-alloacted buffers. -static void StoreHuffmanCode(VP8LBitWriter* const bw, - HuffmanTree* const huff_tree, - HuffmanTreeToken* const tokens, - const HuffmanTreeCode* const huffman_code) { - int i; - int count = 0; - int symbols[2] = { 0, 0 }; - const int kMaxBits = 8; - const int kMaxSymbol = 1 << kMaxBits; - - // Check whether it's a small tree. - for (i = 0; i < huffman_code->num_symbols && count < 3; ++i) { - if (huffman_code->code_lengths[i] != 0) { - if (count < 2) symbols[count] = i; - ++count; - } - } - - if (count == 0) { // emit minimal tree for empty cases - // bits: small tree marker: 1, count-1: 0, large 8-bit code: 0, code: 0 - VP8LPutBits(bw, 0x01, 4); - } else if (count <= 2 && symbols[0] < kMaxSymbol && symbols[1] < kMaxSymbol) { - VP8LPutBits(bw, 1, 1); // Small tree marker to encode 1 or 2 symbols. - VP8LPutBits(bw, count - 1, 1); - if (symbols[0] <= 1) { - VP8LPutBits(bw, 0, 1); // Code bit for small (1 bit) symbol value. - VP8LPutBits(bw, symbols[0], 1); - } else { - VP8LPutBits(bw, 1, 1); - VP8LPutBits(bw, symbols[0], 8); - } - if (count == 2) { - VP8LPutBits(bw, symbols[1], 8); - } - } else { - StoreFullHuffmanCode(bw, huff_tree, tokens, huffman_code); - } -} - -static WEBP_INLINE void WriteHuffmanCode(VP8LBitWriter* const bw, - const HuffmanTreeCode* const code, - int code_index) { - const int depth = code->code_lengths[code_index]; - const int symbol = code->codes[code_index]; - VP8LPutBits(bw, symbol, depth); -} - -static WEBP_INLINE void WriteHuffmanCodeWithExtraBits( - VP8LBitWriter* const bw, - const HuffmanTreeCode* const code, - int code_index, - int bits, - int n_bits) { - const int depth = code->code_lengths[code_index]; - const int symbol = code->codes[code_index]; - VP8LPutBits(bw, (bits << depth) | symbol, depth + n_bits); -} - -static int StoreImageToBitMask( - VP8LBitWriter* const bw, int width, int histo_bits, - const VP8LBackwardRefs* const refs, - const uint16_t* histogram_symbols, - const HuffmanTreeCode* const huffman_codes, const WebPPicture* const pic) { - const int histo_xsize = histo_bits ? VP8LSubSampleSize(width, histo_bits) : 1; - const int tile_mask = (histo_bits == 0) ? 0 : -(1 << histo_bits); - // x and y trace the position in the image. - int x = 0; - int y = 0; - int tile_x = x & tile_mask; - int tile_y = y & tile_mask; - int histogram_ix = histogram_symbols[0]; - const HuffmanTreeCode* codes = huffman_codes + 5 * histogram_ix; - VP8LRefsCursor c = VP8LRefsCursorInit(refs); - while (VP8LRefsCursorOk(&c)) { - const PixOrCopy* const v = c.cur_pos; - if ((tile_x != (x & tile_mask)) || (tile_y != (y & tile_mask))) { - tile_x = x & tile_mask; - tile_y = y & tile_mask; - histogram_ix = histogram_symbols[(y >> histo_bits) * histo_xsize + - (x >> histo_bits)]; - codes = huffman_codes + 5 * histogram_ix; - } - if (PixOrCopyIsLiteral(v)) { - static const uint8_t order[] = { 1, 2, 0, 3 }; - int k; - for (k = 0; k < 4; ++k) { - const int code = PixOrCopyLiteral(v, order[k]); - WriteHuffmanCode(bw, codes + k, code); - } - } else if (PixOrCopyIsCacheIdx(v)) { - const int code = PixOrCopyCacheIdx(v); - const int literal_ix = 256 + NUM_LENGTH_CODES + code; - WriteHuffmanCode(bw, codes, literal_ix); - } else { - int bits, n_bits; - int code; - - const int distance = PixOrCopyDistance(v); - VP8LPrefixEncode(v->len, &code, &n_bits, &bits); - WriteHuffmanCodeWithExtraBits(bw, codes, 256 + code, bits, n_bits); - - // Don't write the distance with the extra bits code since - // the distance can be up to 18 bits of extra bits, and the prefix - // 15 bits, totaling to 33, and our PutBits only supports up to 32 bits. - VP8LPrefixEncode(distance, &code, &n_bits, &bits); - WriteHuffmanCode(bw, codes + 4, code); - VP8LPutBits(bw, bits, n_bits); - } - x += PixOrCopyLength(v); - while (x >= width) { - x -= width; - ++y; - } - VP8LRefsCursorNext(&c); - } - if (bw->error_) { - return WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); - } - return 1; -} - -// Special case of EncodeImageInternal() for cache-bits=0, histo_bits=31. -// pic and percent are for progress. -static int EncodeImageNoHuffman(VP8LBitWriter* const bw, - const uint32_t* const argb, - VP8LHashChain* const hash_chain, - VP8LBackwardRefs* const refs_array, int width, - int height, int quality, int low_effort, - const WebPPicture* const pic, int percent_range, - int* const percent) { - int i; - int max_tokens = 0; - VP8LBackwardRefs* refs; - HuffmanTreeToken* tokens = NULL; - HuffmanTreeCode huffman_codes[5] = {{0, NULL, NULL}}; - const uint16_t histogram_symbols[1] = {0}; // only one tree, one symbol - int cache_bits = 0; - VP8LHistogramSet* histogram_image = NULL; - HuffmanTree* const huff_tree = (HuffmanTree*)WebPSafeMalloc( - 3ULL * CODE_LENGTH_CODES, sizeof(*huff_tree)); - if (huff_tree == NULL) { - WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); - goto Error; - } - - // Calculate backward references from ARGB image. - if (!VP8LHashChainFill(hash_chain, quality, argb, width, height, low_effort, - pic, percent_range / 2, percent)) { - goto Error; - } - if (!VP8LGetBackwardReferences(width, height, argb, quality, /*low_effort=*/0, - kLZ77Standard | kLZ77RLE, cache_bits, - /*do_no_cache=*/0, hash_chain, refs_array, - &cache_bits, pic, - percent_range - percent_range / 2, percent)) { - goto Error; - } - refs = &refs_array[0]; - histogram_image = VP8LAllocateHistogramSet(1, cache_bits); - if (histogram_image == NULL) { - WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); - goto Error; - } - VP8LHistogramSetClear(histogram_image); - - // Build histogram image and symbols from backward references. - VP8LHistogramStoreRefs(refs, histogram_image->histograms[0]); - - // Create Huffman bit lengths and codes for each histogram image. - assert(histogram_image->size == 1); - if (!GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) { - WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); - goto Error; - } - - // No color cache, no Huffman image. - VP8LPutBits(bw, 0, 1); - - // Find maximum number of symbols for the huffman tree-set. - for (i = 0; i < 5; ++i) { - HuffmanTreeCode* const codes = &huffman_codes[i]; - if (max_tokens < codes->num_symbols) { - max_tokens = codes->num_symbols; - } - } - - tokens = (HuffmanTreeToken*)WebPSafeMalloc(max_tokens, sizeof(*tokens)); - if (tokens == NULL) { - WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); - goto Error; - } - - // Store Huffman codes. - for (i = 0; i < 5; ++i) { - HuffmanTreeCode* const codes = &huffman_codes[i]; - StoreHuffmanCode(bw, huff_tree, tokens, codes); - ClearHuffmanTreeIfOnlyOneSymbol(codes); - } - - // Store actual literals. - if (!StoreImageToBitMask(bw, width, 0, refs, histogram_symbols, huffman_codes, - pic)) { - goto Error; - } - - Error: - WebPSafeFree(tokens); - WebPSafeFree(huff_tree); - VP8LFreeHistogramSet(histogram_image); - WebPSafeFree(huffman_codes[0].codes); - return (pic->error_code == VP8_ENC_OK); -} - -// pic and percent are for progress. -static int EncodeImageInternal( - VP8LBitWriter* const bw, const uint32_t* const argb, - VP8LHashChain* const hash_chain, VP8LBackwardRefs refs_array[4], int width, - int height, int quality, int low_effort, const CrunchConfig* const config, - int* cache_bits, int histogram_bits, size_t init_byte_position, - int* const hdr_size, int* const data_size, const WebPPicture* const pic, - int percent_range, int* const percent) { - const uint32_t histogram_image_xysize = - VP8LSubSampleSize(width, histogram_bits) * - VP8LSubSampleSize(height, histogram_bits); - int remaining_percent = percent_range; - int percent_start = *percent; - VP8LHistogramSet* histogram_image = NULL; - VP8LHistogram* tmp_histo = NULL; - int histogram_image_size = 0; - size_t bit_array_size = 0; - HuffmanTree* const huff_tree = (HuffmanTree*)WebPSafeMalloc( - 3ULL * CODE_LENGTH_CODES, sizeof(*huff_tree)); - HuffmanTreeToken* tokens = NULL; - HuffmanTreeCode* huffman_codes = NULL; - uint16_t* const histogram_symbols = (uint16_t*)WebPSafeMalloc( - histogram_image_xysize, sizeof(*histogram_symbols)); - int sub_configs_idx; - int cache_bits_init, write_histogram_image; - VP8LBitWriter bw_init = *bw, bw_best; - int hdr_size_tmp; - VP8LHashChain hash_chain_histogram; // histogram image hash chain - size_t bw_size_best = ~(size_t)0; - assert(histogram_bits >= MIN_HUFFMAN_BITS); - assert(histogram_bits <= MAX_HUFFMAN_BITS); - assert(hdr_size != NULL); - assert(data_size != NULL); - - memset(&hash_chain_histogram, 0, sizeof(hash_chain_histogram)); - if (!VP8LBitWriterInit(&bw_best, 0)) { - WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); - goto Error; - } - - // Make sure we can allocate the different objects. - if (huff_tree == NULL || histogram_symbols == NULL || - !VP8LHashChainInit(&hash_chain_histogram, histogram_image_xysize)) { - WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); - goto Error; - } - - percent_range = remaining_percent / 5; - if (!VP8LHashChainFill(hash_chain, quality, argb, width, height, - low_effort, pic, percent_range, percent)) { - goto Error; - } - percent_start += percent_range; - remaining_percent -= percent_range; - - // If the value is different from zero, it has been set during the palette - // analysis. - cache_bits_init = (*cache_bits == 0) ? MAX_COLOR_CACHE_BITS : *cache_bits; - // If several iterations will happen, clone into bw_best. - if ((config->sub_configs_size_ > 1 || config->sub_configs_[0].do_no_cache_) && - !VP8LBitWriterClone(bw, &bw_best)) { - WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); - goto Error; - } - - for (sub_configs_idx = 0; sub_configs_idx < config->sub_configs_size_; - ++sub_configs_idx) { - const CrunchSubConfig* const sub_config = - &config->sub_configs_[sub_configs_idx]; - int cache_bits_best, i_cache; - int i_remaining_percent = remaining_percent / config->sub_configs_size_; - int i_percent_range = i_remaining_percent / 4; - i_remaining_percent -= i_percent_range; - - if (!VP8LGetBackwardReferences( - width, height, argb, quality, low_effort, sub_config->lz77_, - cache_bits_init, sub_config->do_no_cache_, hash_chain, - &refs_array[0], &cache_bits_best, pic, i_percent_range, percent)) { - goto Error; - } - - for (i_cache = 0; i_cache < (sub_config->do_no_cache_ ? 2 : 1); ++i_cache) { - const int cache_bits_tmp = (i_cache == 0) ? cache_bits_best : 0; - // Speed-up: no need to study the no-cache case if it was already studied - // in i_cache == 0. - if (i_cache == 1 && cache_bits_best == 0) break; - - // Reset the bit writer for this iteration. - VP8LBitWriterReset(&bw_init, bw); - - // Build histogram image and symbols from backward references. - histogram_image = - VP8LAllocateHistogramSet(histogram_image_xysize, cache_bits_tmp); - tmp_histo = VP8LAllocateHistogram(cache_bits_tmp); - if (histogram_image == NULL || tmp_histo == NULL) { - WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); - goto Error; - } - - i_percent_range = i_remaining_percent / 3; - i_remaining_percent -= i_percent_range; - if (!VP8LGetHistoImageSymbols( - width, height, &refs_array[i_cache], quality, low_effort, - histogram_bits, cache_bits_tmp, histogram_image, tmp_histo, - histogram_symbols, pic, i_percent_range, percent)) { - goto Error; - } - // Create Huffman bit lengths and codes for each histogram image. - histogram_image_size = histogram_image->size; - bit_array_size = 5 * histogram_image_size; - huffman_codes = (HuffmanTreeCode*)WebPSafeCalloc(bit_array_size, - sizeof(*huffman_codes)); - // Note: some histogram_image entries may point to tmp_histos[], so the - // latter need to outlive the following call to - // GetHuffBitLengthsAndCodes(). - if (huffman_codes == NULL || - !GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) { - WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); - goto Error; - } - // Free combined histograms. - VP8LFreeHistogramSet(histogram_image); - histogram_image = NULL; - - // Free scratch histograms. - VP8LFreeHistogram(tmp_histo); - tmp_histo = NULL; - - // Color Cache parameters. - if (cache_bits_tmp > 0) { - VP8LPutBits(bw, 1, 1); - VP8LPutBits(bw, cache_bits_tmp, 4); - } else { - VP8LPutBits(bw, 0, 1); - } - - // Huffman image + meta huffman. - write_histogram_image = (histogram_image_size > 1); - VP8LPutBits(bw, write_histogram_image, 1); - if (write_histogram_image) { - uint32_t* const histogram_argb = (uint32_t*)WebPSafeMalloc( - histogram_image_xysize, sizeof(*histogram_argb)); - int max_index = 0; - uint32_t i; - if (histogram_argb == NULL) { - WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); - goto Error; - } - for (i = 0; i < histogram_image_xysize; ++i) { - const int symbol_index = histogram_symbols[i] & 0xffff; - histogram_argb[i] = (symbol_index << 8); - if (symbol_index >= max_index) { - max_index = symbol_index + 1; - } - } - histogram_image_size = max_index; - - VP8LPutBits(bw, histogram_bits - 2, 3); - i_percent_range = i_remaining_percent / 2; - i_remaining_percent -= i_percent_range; - if (!EncodeImageNoHuffman( - bw, histogram_argb, &hash_chain_histogram, &refs_array[2], - VP8LSubSampleSize(width, histogram_bits), - VP8LSubSampleSize(height, histogram_bits), quality, low_effort, - pic, i_percent_range, percent)) { - WebPSafeFree(histogram_argb); - goto Error; - } - WebPSafeFree(histogram_argb); - } - - // Store Huffman codes. - { - int i; - int max_tokens = 0; - // Find maximum number of symbols for the huffman tree-set. - for (i = 0; i < 5 * histogram_image_size; ++i) { - HuffmanTreeCode* const codes = &huffman_codes[i]; - if (max_tokens < codes->num_symbols) { - max_tokens = codes->num_symbols; - } - } - tokens = (HuffmanTreeToken*)WebPSafeMalloc(max_tokens, sizeof(*tokens)); - if (tokens == NULL) { - WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); - goto Error; - } - for (i = 0; i < 5 * histogram_image_size; ++i) { - HuffmanTreeCode* const codes = &huffman_codes[i]; - StoreHuffmanCode(bw, huff_tree, tokens, codes); - ClearHuffmanTreeIfOnlyOneSymbol(codes); - } - } - // Store actual literals. - hdr_size_tmp = (int)(VP8LBitWriterNumBytes(bw) - init_byte_position); - if (!StoreImageToBitMask(bw, width, histogram_bits, &refs_array[i_cache], - histogram_symbols, huffman_codes, pic)) { - goto Error; - } - // Keep track of the smallest image so far. - if (VP8LBitWriterNumBytes(bw) < bw_size_best) { - bw_size_best = VP8LBitWriterNumBytes(bw); - *cache_bits = cache_bits_tmp; - *hdr_size = hdr_size_tmp; - *data_size = - (int)(VP8LBitWriterNumBytes(bw) - init_byte_position - *hdr_size); - VP8LBitWriterSwap(bw, &bw_best); - } - WebPSafeFree(tokens); - tokens = NULL; - if (huffman_codes != NULL) { - WebPSafeFree(huffman_codes->codes); - WebPSafeFree(huffman_codes); - huffman_codes = NULL; - } - } - } - VP8LBitWriterSwap(bw, &bw_best); - - if (!WebPReportProgress(pic, percent_start + remaining_percent, percent)) { - goto Error; - } - - Error: - WebPSafeFree(tokens); - WebPSafeFree(huff_tree); - VP8LFreeHistogramSet(histogram_image); - VP8LFreeHistogram(tmp_histo); - VP8LHashChainClear(&hash_chain_histogram); - if (huffman_codes != NULL) { - WebPSafeFree(huffman_codes->codes); - WebPSafeFree(huffman_codes); - } - WebPSafeFree(histogram_symbols); - VP8LBitWriterWipeOut(&bw_best); - return (pic->error_code == VP8_ENC_OK); -} - -// ----------------------------------------------------------------------------- -// Transforms - -static void ApplySubtractGreen(VP8LEncoder* const enc, int width, int height, - VP8LBitWriter* const bw) { - VP8LPutBits(bw, TRANSFORM_PRESENT, 1); - VP8LPutBits(bw, SUBTRACT_GREEN_TRANSFORM, 2); - VP8LSubtractGreenFromBlueAndRed(enc->argb_, width * height); -} - -static int ApplyPredictFilter(const VP8LEncoder* const enc, int width, - int height, int quality, int low_effort, - int used_subtract_green, VP8LBitWriter* const bw, - int percent_range, int* const percent) { - const int pred_bits = enc->transform_bits_; - const int transform_width = VP8LSubSampleSize(width, pred_bits); - const int transform_height = VP8LSubSampleSize(height, pred_bits); - // we disable near-lossless quantization if palette is used. - const int near_lossless_strength = - enc->use_palette_ ? 100 : enc->config_->near_lossless; - - if (!VP8LResidualImage( - width, height, pred_bits, low_effort, enc->argb_, enc->argb_scratch_, - enc->transform_data_, near_lossless_strength, enc->config_->exact, - used_subtract_green, enc->pic_, percent_range / 2, percent)) { - return 0; - } - VP8LPutBits(bw, TRANSFORM_PRESENT, 1); - VP8LPutBits(bw, PREDICTOR_TRANSFORM, 2); - assert(pred_bits >= 2); - VP8LPutBits(bw, pred_bits - 2, 3); - return EncodeImageNoHuffman( - bw, enc->transform_data_, (VP8LHashChain*)&enc->hash_chain_, - (VP8LBackwardRefs*)&enc->refs_[0], transform_width, transform_height, - quality, low_effort, enc->pic_, percent_range - percent_range / 2, - percent); -} - -static int ApplyCrossColorFilter(const VP8LEncoder* const enc, int width, - int height, int quality, int low_effort, - VP8LBitWriter* const bw, int percent_range, - int* const percent) { - const int ccolor_transform_bits = enc->transform_bits_; - const int transform_width = VP8LSubSampleSize(width, ccolor_transform_bits); - const int transform_height = VP8LSubSampleSize(height, ccolor_transform_bits); - - if (!VP8LColorSpaceTransform(width, height, ccolor_transform_bits, quality, - enc->argb_, enc->transform_data_, enc->pic_, - percent_range / 2, percent)) { - return 0; - } - VP8LPutBits(bw, TRANSFORM_PRESENT, 1); - VP8LPutBits(bw, CROSS_COLOR_TRANSFORM, 2); - assert(ccolor_transform_bits >= 2); - VP8LPutBits(bw, ccolor_transform_bits - 2, 3); - return EncodeImageNoHuffman( - bw, enc->transform_data_, (VP8LHashChain*)&enc->hash_chain_, - (VP8LBackwardRefs*)&enc->refs_[0], transform_width, transform_height, - quality, low_effort, enc->pic_, percent_range - percent_range / 2, - percent); -} - -// ----------------------------------------------------------------------------- - -static int WriteRiffHeader(const WebPPicture* const pic, size_t riff_size, - size_t vp8l_size) { - uint8_t riff[RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE + VP8L_SIGNATURE_SIZE] = { - 'R', 'I', 'F', 'F', 0, 0, 0, 0, 'W', 'E', 'B', 'P', - 'V', 'P', '8', 'L', 0, 0, 0, 0, VP8L_MAGIC_BYTE, - }; - PutLE32(riff + TAG_SIZE, (uint32_t)riff_size); - PutLE32(riff + RIFF_HEADER_SIZE + TAG_SIZE, (uint32_t)vp8l_size); - return pic->writer(riff, sizeof(riff), pic); -} - -static int WriteImageSize(const WebPPicture* const pic, - VP8LBitWriter* const bw) { - const int width = pic->width - 1; - const int height = pic->height - 1; - assert(width < WEBP_MAX_DIMENSION && height < WEBP_MAX_DIMENSION); - - VP8LPutBits(bw, width, VP8L_IMAGE_SIZE_BITS); - VP8LPutBits(bw, height, VP8L_IMAGE_SIZE_BITS); - return !bw->error_; -} - -static int WriteRealAlphaAndVersion(VP8LBitWriter* const bw, int has_alpha) { - VP8LPutBits(bw, has_alpha, 1); - VP8LPutBits(bw, VP8L_VERSION, VP8L_VERSION_BITS); - return !bw->error_; -} - -static int WriteImage(const WebPPicture* const pic, VP8LBitWriter* const bw, - size_t* const coded_size) { - const uint8_t* const webpll_data = VP8LBitWriterFinish(bw); - const size_t webpll_size = VP8LBitWriterNumBytes(bw); - const size_t vp8l_size = VP8L_SIGNATURE_SIZE + webpll_size; - const size_t pad = vp8l_size & 1; - const size_t riff_size = TAG_SIZE + CHUNK_HEADER_SIZE + vp8l_size + pad; - *coded_size = 0; - - if (bw->error_) { - return WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); - } - - if (!WriteRiffHeader(pic, riff_size, vp8l_size) || - !pic->writer(webpll_data, webpll_size, pic)) { - return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_WRITE); - } - - if (pad) { - const uint8_t pad_byte[1] = { 0 }; - if (!pic->writer(pad_byte, 1, pic)) { - return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_WRITE); - } - } - *coded_size = CHUNK_HEADER_SIZE + riff_size; - return 1; -} - -// ----------------------------------------------------------------------------- - -static void ClearTransformBuffer(VP8LEncoder* const enc) { - WebPSafeFree(enc->transform_mem_); - enc->transform_mem_ = NULL; - enc->transform_mem_size_ = 0; -} - -// Allocates the memory for argb (W x H) buffer, 2 rows of context for -// prediction and transform data. -// Flags influencing the memory allocated: -// enc->transform_bits_ -// enc->use_predict_, enc->use_cross_color_ -static int AllocateTransformBuffer(VP8LEncoder* const enc, int width, - int height) { - const uint64_t image_size = (uint64_t)width * height; - // VP8LResidualImage needs room for 2 scanlines of uint32 pixels with an extra - // pixel in each, plus 2 regular scanlines of bytes. - // TODO(skal): Clean up by using arithmetic in bytes instead of words. - const uint64_t argb_scratch_size = - enc->use_predict_ ? (width + 1) * 2 + (width * 2 + sizeof(uint32_t) - 1) / - sizeof(uint32_t) - : 0; - const uint64_t transform_data_size = - (enc->use_predict_ || enc->use_cross_color_) - ? (uint64_t)VP8LSubSampleSize(width, enc->transform_bits_) * - VP8LSubSampleSize(height, enc->transform_bits_) - : 0; - const uint64_t max_alignment_in_words = - (WEBP_ALIGN_CST + sizeof(uint32_t) - 1) / sizeof(uint32_t); - const uint64_t mem_size = image_size + max_alignment_in_words + - argb_scratch_size + max_alignment_in_words + - transform_data_size; - uint32_t* mem = enc->transform_mem_; - if (mem == NULL || mem_size > enc->transform_mem_size_) { - ClearTransformBuffer(enc); - mem = (uint32_t*)WebPSafeMalloc(mem_size, sizeof(*mem)); - if (mem == NULL) { - return WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY); - } - enc->transform_mem_ = mem; - enc->transform_mem_size_ = (size_t)mem_size; - enc->argb_content_ = kEncoderNone; - } - enc->argb_ = mem; - mem = (uint32_t*)WEBP_ALIGN(mem + image_size); - enc->argb_scratch_ = mem; - mem = (uint32_t*)WEBP_ALIGN(mem + argb_scratch_size); - enc->transform_data_ = mem; - - enc->current_width_ = width; - return 1; -} - -static int MakeInputImageCopy(VP8LEncoder* const enc) { - const WebPPicture* const picture = enc->pic_; - const int width = picture->width; - const int height = picture->height; - - if (!AllocateTransformBuffer(enc, width, height)) return 0; - if (enc->argb_content_ == kEncoderARGB) return 1; - - { - uint32_t* dst = enc->argb_; - const uint32_t* src = picture->argb; - int y; - for (y = 0; y < height; ++y) { - memcpy(dst, src, width * sizeof(*dst)); - dst += width; - src += picture->argb_stride; - } - } - enc->argb_content_ = kEncoderARGB; - assert(enc->current_width_ == width); - return 1; -} - -// ----------------------------------------------------------------------------- - -#define APPLY_PALETTE_GREEDY_MAX 4 - -static WEBP_INLINE uint32_t SearchColorGreedy(const uint32_t palette[], - int palette_size, - uint32_t color) { - (void)palette_size; - assert(palette_size < APPLY_PALETTE_GREEDY_MAX); - assert(3 == APPLY_PALETTE_GREEDY_MAX - 1); - if (color == palette[0]) return 0; - if (color == palette[1]) return 1; - if (color == palette[2]) return 2; - return 3; -} - -static WEBP_INLINE uint32_t ApplyPaletteHash0(uint32_t color) { - // Focus on the green color. - return (color >> 8) & 0xff; -} - -#define PALETTE_INV_SIZE_BITS 11 -#define PALETTE_INV_SIZE (1 << PALETTE_INV_SIZE_BITS) - -static WEBP_INLINE uint32_t ApplyPaletteHash1(uint32_t color) { - // Forget about alpha. - return ((uint32_t)((color & 0x00ffffffu) * 4222244071ull)) >> - (32 - PALETTE_INV_SIZE_BITS); -} - -static WEBP_INLINE uint32_t ApplyPaletteHash2(uint32_t color) { - // Forget about alpha. - return ((uint32_t)((color & 0x00ffffffu) * ((1ull << 31) - 1))) >> - (32 - PALETTE_INV_SIZE_BITS); -} - -// Use 1 pixel cache for ARGB pixels. -#define APPLY_PALETTE_FOR(COLOR_INDEX) do { \ - uint32_t prev_pix = palette[0]; \ - uint32_t prev_idx = 0; \ - for (y = 0; y < height; ++y) { \ - for (x = 0; x < width; ++x) { \ - const uint32_t pix = src[x]; \ - if (pix != prev_pix) { \ - prev_idx = COLOR_INDEX; \ - prev_pix = pix; \ - } \ - tmp_row[x] = prev_idx; \ - } \ - VP8LBundleColorMap(tmp_row, width, xbits, dst); \ - src += src_stride; \ - dst += dst_stride; \ - } \ -} while (0) - -// Remap argb values in src[] to packed palettes entries in dst[] -// using 'row' as a temporary buffer of size 'width'. -// We assume that all src[] values have a corresponding entry in the palette. -// Note: src[] can be the same as dst[] -static int ApplyPalette(const uint32_t* src, uint32_t src_stride, uint32_t* dst, - uint32_t dst_stride, const uint32_t* palette, - int palette_size, int width, int height, int xbits, - const WebPPicture* const pic) { - // TODO(skal): this tmp buffer is not needed if VP8LBundleColorMap() can be - // made to work in-place. - uint8_t* const tmp_row = (uint8_t*)WebPSafeMalloc(width, sizeof(*tmp_row)); - int x, y; - - if (tmp_row == NULL) { - return WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY); - } - - if (palette_size < APPLY_PALETTE_GREEDY_MAX) { - APPLY_PALETTE_FOR(SearchColorGreedy(palette, palette_size, pix)); - } else { - int i, j; - uint16_t buffer[PALETTE_INV_SIZE]; - uint32_t (*const hash_functions[])(uint32_t) = { - ApplyPaletteHash0, ApplyPaletteHash1, ApplyPaletteHash2 - }; - - // Try to find a perfect hash function able to go from a color to an index - // within 1 << PALETTE_INV_SIZE_BITS in order to build a hash map to go - // from color to index in palette. - for (i = 0; i < 3; ++i) { - int use_LUT = 1; - // Set each element in buffer to max uint16_t. - memset(buffer, 0xff, sizeof(buffer)); - for (j = 0; j < palette_size; ++j) { - const uint32_t ind = hash_functions[i](palette[j]); - if (buffer[ind] != 0xffffu) { - use_LUT = 0; - break; - } else { - buffer[ind] = j; - } - } - if (use_LUT) break; - } - - if (i == 0) { - APPLY_PALETTE_FOR(buffer[ApplyPaletteHash0(pix)]); - } else if (i == 1) { - APPLY_PALETTE_FOR(buffer[ApplyPaletteHash1(pix)]); - } else if (i == 2) { - APPLY_PALETTE_FOR(buffer[ApplyPaletteHash2(pix)]); - } else { - uint32_t idx_map[MAX_PALETTE_SIZE]; - uint32_t palette_sorted[MAX_PALETTE_SIZE]; - PrepareMapToPalette(palette, palette_size, palette_sorted, idx_map); - APPLY_PALETTE_FOR( - idx_map[SearchColorNoIdx(palette_sorted, pix, palette_size)]); - } - } - WebPSafeFree(tmp_row); - return 1; -} -#undef APPLY_PALETTE_FOR -#undef PALETTE_INV_SIZE_BITS -#undef PALETTE_INV_SIZE -#undef APPLY_PALETTE_GREEDY_MAX - -// Note: Expects "enc->palette_" to be set properly. -static int MapImageFromPalette(VP8LEncoder* const enc, int in_place) { - const WebPPicture* const pic = enc->pic_; - const int width = pic->width; - const int height = pic->height; - const uint32_t* const palette = enc->palette_; - const uint32_t* src = in_place ? enc->argb_ : pic->argb; - const int src_stride = in_place ? enc->current_width_ : pic->argb_stride; - const int palette_size = enc->palette_size_; - int xbits; - - // Replace each input pixel by corresponding palette index. - // This is done line by line. - if (palette_size <= 4) { - xbits = (palette_size <= 2) ? 3 : 2; - } else { - xbits = (palette_size <= 16) ? 1 : 0; - } - - if (!AllocateTransformBuffer(enc, VP8LSubSampleSize(width, xbits), height)) { - return 0; - } - if (!ApplyPalette(src, src_stride, - enc->argb_, enc->current_width_, - palette, palette_size, width, height, xbits, pic)) { - return 0; - } - enc->argb_content_ = kEncoderPalette; - return 1; -} - -// Save palette_[] to bitstream. -static WebPEncodingError EncodePalette(VP8LBitWriter* const bw, int low_effort, - VP8LEncoder* const enc, - int percent_range, int* const percent) { - int i; - uint32_t tmp_palette[MAX_PALETTE_SIZE]; - const int palette_size = enc->palette_size_; - const uint32_t* const palette = enc->palette_; - VP8LPutBits(bw, TRANSFORM_PRESENT, 1); - VP8LPutBits(bw, COLOR_INDEXING_TRANSFORM, 2); - assert(palette_size >= 1 && palette_size <= MAX_PALETTE_SIZE); - VP8LPutBits(bw, palette_size - 1, 8); - for (i = palette_size - 1; i >= 1; --i) { - tmp_palette[i] = VP8LSubPixels(palette[i], palette[i - 1]); - } - tmp_palette[0] = palette[0]; - return EncodeImageNoHuffman(bw, tmp_palette, &enc->hash_chain_, - &enc->refs_[0], palette_size, 1, /*quality=*/20, - low_effort, enc->pic_, percent_range, percent); -} - -// ----------------------------------------------------------------------------- -// VP8LEncoder - -static VP8LEncoder* VP8LEncoderNew(const WebPConfig* const config, - const WebPPicture* const picture) { - VP8LEncoder* const enc = (VP8LEncoder*)WebPSafeCalloc(1ULL, sizeof(*enc)); - if (enc == NULL) { - WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); - return NULL; - } - enc->config_ = config; - enc->pic_ = picture; - enc->argb_content_ = kEncoderNone; - - VP8LEncDspInit(); - - return enc; -} - -static void VP8LEncoderDelete(VP8LEncoder* enc) { - if (enc != NULL) { - int i; - VP8LHashChainClear(&enc->hash_chain_); - for (i = 0; i < 4; ++i) VP8LBackwardRefsClear(&enc->refs_[i]); - ClearTransformBuffer(enc); - WebPSafeFree(enc); - } -} - -// ----------------------------------------------------------------------------- -// Main call - -typedef struct { - const WebPConfig* config_; - const WebPPicture* picture_; - VP8LBitWriter* bw_; - VP8LEncoder* enc_; - CrunchConfig crunch_configs_[CRUNCH_CONFIGS_MAX]; - int num_crunch_configs_; - int red_and_blue_always_zero_; - WebPAuxStats* stats_; -} StreamEncodeContext; - -static int EncodeStreamHook(void* input, void* data2) { - StreamEncodeContext* const params = (StreamEncodeContext*)input; - const WebPConfig* const config = params->config_; - const WebPPicture* const picture = params->picture_; - VP8LBitWriter* const bw = params->bw_; - VP8LEncoder* const enc = params->enc_; - const CrunchConfig* const crunch_configs = params->crunch_configs_; - const int num_crunch_configs = params->num_crunch_configs_; - const int red_and_blue_always_zero = params->red_and_blue_always_zero_; -#if !defined(WEBP_DISABLE_STATS) - WebPAuxStats* const stats = params->stats_; -#endif - const int quality = (int)config->quality; - const int low_effort = (config->method == 0); -#if (WEBP_NEAR_LOSSLESS == 1) - const int width = picture->width; -#endif - const int height = picture->height; - const size_t byte_position = VP8LBitWriterNumBytes(bw); - int percent = 2; // for WebPProgressHook -#if (WEBP_NEAR_LOSSLESS == 1) - int use_near_lossless = 0; -#endif - int hdr_size = 0; - int data_size = 0; - int use_delta_palette = 0; - int idx; - size_t best_size = ~(size_t)0; - VP8LBitWriter bw_init = *bw, bw_best; - (void)data2; - - if (!VP8LBitWriterInit(&bw_best, 0) || - (num_crunch_configs > 1 && !VP8LBitWriterClone(bw, &bw_best))) { - WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); - goto Error; - } - - for (idx = 0; idx < num_crunch_configs; ++idx) { - const int entropy_idx = crunch_configs[idx].entropy_idx_; - int remaining_percent = 97 / num_crunch_configs, percent_range; - enc->use_palette_ = - (entropy_idx == kPalette) || (entropy_idx == kPaletteAndSpatial); - enc->use_subtract_green_ = - (entropy_idx == kSubGreen) || (entropy_idx == kSpatialSubGreen); - enc->use_predict_ = (entropy_idx == kSpatial) || - (entropy_idx == kSpatialSubGreen) || - (entropy_idx == kPaletteAndSpatial); - // When using a palette, R/B==0, hence no need to test for cross-color. - if (low_effort || enc->use_palette_) { - enc->use_cross_color_ = 0; - } else { - enc->use_cross_color_ = red_and_blue_always_zero ? 0 : enc->use_predict_; - } - // Reset any parameter in the encoder that is set in the previous iteration. - enc->cache_bits_ = 0; - VP8LBackwardRefsClear(&enc->refs_[0]); - VP8LBackwardRefsClear(&enc->refs_[1]); - -#if (WEBP_NEAR_LOSSLESS == 1) - // Apply near-lossless preprocessing. - use_near_lossless = (config->near_lossless < 100) && !enc->use_palette_ && - !enc->use_predict_; - if (use_near_lossless) { - if (!AllocateTransformBuffer(enc, width, height)) goto Error; - if ((enc->argb_content_ != kEncoderNearLossless) && - !VP8ApplyNearLossless(picture, config->near_lossless, enc->argb_)) { - WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); - goto Error; - } - enc->argb_content_ = kEncoderNearLossless; - } else { - enc->argb_content_ = kEncoderNone; - } -#else - enc->argb_content_ = kEncoderNone; -#endif - - // Encode palette - if (enc->use_palette_) { - if (!PaletteSort(crunch_configs[idx].palette_sorting_type_, enc->pic_, - enc->palette_sorted_, enc->palette_size_, - enc->palette_)) { - WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY); - goto Error; - } - percent_range = remaining_percent / 4; - if (!EncodePalette(bw, low_effort, enc, percent_range, &percent)) { - goto Error; - } - remaining_percent -= percent_range; - if (!MapImageFromPalette(enc, use_delta_palette)) goto Error; - // If using a color cache, do not have it bigger than the number of - // colors. - if (enc->palette_size_ < (1 << MAX_COLOR_CACHE_BITS)) { - enc->cache_bits_ = BitsLog2Floor(enc->palette_size_) + 1; - } - } - if (!use_delta_palette) { - // In case image is not packed. - if (enc->argb_content_ != kEncoderNearLossless && - enc->argb_content_ != kEncoderPalette) { - if (!MakeInputImageCopy(enc)) goto Error; - } - - // ----------------------------------------------------------------------- - // Apply transforms and write transform data. - - if (enc->use_subtract_green_) { - ApplySubtractGreen(enc, enc->current_width_, height, bw); - } - - if (enc->use_predict_) { - percent_range = remaining_percent / 3; - if (!ApplyPredictFilter(enc, enc->current_width_, height, quality, - low_effort, enc->use_subtract_green_, bw, - percent_range, &percent)) { - goto Error; - } - remaining_percent -= percent_range; - } - - if (enc->use_cross_color_) { - percent_range = remaining_percent / 2; - if (!ApplyCrossColorFilter(enc, enc->current_width_, height, quality, - low_effort, bw, percent_range, &percent)) { - goto Error; - } - remaining_percent -= percent_range; - } - } - - VP8LPutBits(bw, !TRANSFORM_PRESENT, 1); // No more transforms. - - // ------------------------------------------------------------------------- - // Encode and write the transformed image. - if (!EncodeImageInternal( - bw, enc->argb_, &enc->hash_chain_, enc->refs_, enc->current_width_, - height, quality, low_effort, &crunch_configs[idx], - &enc->cache_bits_, enc->histo_bits_, byte_position, &hdr_size, - &data_size, picture, remaining_percent, &percent)) { - goto Error; - } - - // If we are better than what we already have. - if (VP8LBitWriterNumBytes(bw) < best_size) { - best_size = VP8LBitWriterNumBytes(bw); - // Store the BitWriter. - VP8LBitWriterSwap(bw, &bw_best); -#if !defined(WEBP_DISABLE_STATS) - // Update the stats. - if (stats != NULL) { - stats->lossless_features = 0; - if (enc->use_predict_) stats->lossless_features |= 1; - if (enc->use_cross_color_) stats->lossless_features |= 2; - if (enc->use_subtract_green_) stats->lossless_features |= 4; - if (enc->use_palette_) stats->lossless_features |= 8; - stats->histogram_bits = enc->histo_bits_; - stats->transform_bits = enc->transform_bits_; - stats->cache_bits = enc->cache_bits_; - stats->palette_size = enc->palette_size_; - stats->lossless_size = (int)(best_size - byte_position); - stats->lossless_hdr_size = hdr_size; - stats->lossless_data_size = data_size; - } -#endif - } - // Reset the bit writer for the following iteration if any. - if (num_crunch_configs > 1) VP8LBitWriterReset(&bw_init, bw); - } - VP8LBitWriterSwap(&bw_best, bw); - - Error: - VP8LBitWriterWipeOut(&bw_best); - // The hook should return false in case of error. - return (params->picture_->error_code == VP8_ENC_OK); -} - -int VP8LEncodeStream(const WebPConfig* const config, - const WebPPicture* const picture, - VP8LBitWriter* const bw_main) { - VP8LEncoder* const enc_main = VP8LEncoderNew(config, picture); - VP8LEncoder* enc_side = NULL; - CrunchConfig crunch_configs[CRUNCH_CONFIGS_MAX]; - int num_crunch_configs_main, num_crunch_configs_side = 0; - int idx; - int red_and_blue_always_zero = 0; - WebPWorker worker_main, worker_side; - StreamEncodeContext params_main, params_side; - // The main thread uses picture->stats, the side thread uses stats_side. - WebPAuxStats stats_side; - VP8LBitWriter bw_side; - WebPPicture picture_side; - const WebPWorkerInterface* const worker_interface = WebPGetWorkerInterface(); - int ok_main; - - if (enc_main == NULL || !VP8LBitWriterInit(&bw_side, 0)) { - VP8LEncoderDelete(enc_main); - return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); - } - - // Avoid "garbage value" error from Clang's static analysis tool. - if (!WebPPictureInit(&picture_side)) { - goto Error; - } - - // Analyze image (entropy, num_palettes etc) - if (!EncoderAnalyze(enc_main, crunch_configs, &num_crunch_configs_main, - &red_and_blue_always_zero) || - !EncoderInit(enc_main)) { - WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); - goto Error; - } - - // Split the configs between the main and side threads (if any). - if (config->thread_level > 0) { - num_crunch_configs_side = num_crunch_configs_main / 2; - for (idx = 0; idx < num_crunch_configs_side; ++idx) { - params_side.crunch_configs_[idx] = - crunch_configs[num_crunch_configs_main - num_crunch_configs_side + - idx]; - } - params_side.num_crunch_configs_ = num_crunch_configs_side; - } - num_crunch_configs_main -= num_crunch_configs_side; - for (idx = 0; idx < num_crunch_configs_main; ++idx) { - params_main.crunch_configs_[idx] = crunch_configs[idx]; - } - params_main.num_crunch_configs_ = num_crunch_configs_main; - - // Fill in the parameters for the thread workers. - { - const int params_size = (num_crunch_configs_side > 0) ? 2 : 1; - for (idx = 0; idx < params_size; ++idx) { - // Create the parameters for each worker. - WebPWorker* const worker = (idx == 0) ? &worker_main : &worker_side; - StreamEncodeContext* const param = - (idx == 0) ? ¶ms_main : ¶ms_side; - param->config_ = config; - param->red_and_blue_always_zero_ = red_and_blue_always_zero; - if (idx == 0) { - param->picture_ = picture; - param->stats_ = picture->stats; - param->bw_ = bw_main; - param->enc_ = enc_main; - } else { - // Create a side picture (error_code is not thread-safe). - if (!WebPPictureView(picture, /*left=*/0, /*top=*/0, picture->width, - picture->height, &picture_side)) { - assert(0); - } - picture_side.progress_hook = NULL; // Progress hook is not thread-safe. - param->picture_ = &picture_side; // No need to free a view afterwards. - param->stats_ = (picture->stats == NULL) ? NULL : &stats_side; - // Create a side bit writer. - if (!VP8LBitWriterClone(bw_main, &bw_side)) { - WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); - goto Error; - } - param->bw_ = &bw_side; - // Create a side encoder. - enc_side = VP8LEncoderNew(config, &picture_side); - if (enc_side == NULL || !EncoderInit(enc_side)) { - WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); - goto Error; - } - // Copy the values that were computed for the main encoder. - enc_side->histo_bits_ = enc_main->histo_bits_; - enc_side->transform_bits_ = enc_main->transform_bits_; - enc_side->palette_size_ = enc_main->palette_size_; - memcpy(enc_side->palette_, enc_main->palette_, - sizeof(enc_main->palette_)); - memcpy(enc_side->palette_sorted_, enc_main->palette_sorted_, - sizeof(enc_main->palette_sorted_)); - param->enc_ = enc_side; - } - // Create the workers. - worker_interface->Init(worker); - worker->data1 = param; - worker->data2 = NULL; - worker->hook = EncodeStreamHook; - } - } - - // Start the second thread if needed. - if (num_crunch_configs_side != 0) { - if (!worker_interface->Reset(&worker_side)) { - WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); - goto Error; - } -#if !defined(WEBP_DISABLE_STATS) - // This line is here and not in the param initialization above to remove a - // Clang static analyzer warning. - if (picture->stats != NULL) { - memcpy(&stats_side, picture->stats, sizeof(stats_side)); - } -#endif - worker_interface->Launch(&worker_side); - } - // Execute the main thread. - worker_interface->Execute(&worker_main); - ok_main = worker_interface->Sync(&worker_main); - worker_interface->End(&worker_main); - if (num_crunch_configs_side != 0) { - // Wait for the second thread. - const int ok_side = worker_interface->Sync(&worker_side); - worker_interface->End(&worker_side); - if (!ok_main || !ok_side) { - if (picture->error_code == VP8_ENC_OK) { - assert(picture_side.error_code != VP8_ENC_OK); - WebPEncodingSetError(picture, picture_side.error_code); - } - goto Error; - } - if (VP8LBitWriterNumBytes(&bw_side) < VP8LBitWriterNumBytes(bw_main)) { - VP8LBitWriterSwap(bw_main, &bw_side); -#if !defined(WEBP_DISABLE_STATS) - if (picture->stats != NULL) { - memcpy(picture->stats, &stats_side, sizeof(*picture->stats)); - } -#endif - } - } - - Error: - VP8LBitWriterWipeOut(&bw_side); - VP8LEncoderDelete(enc_main); - VP8LEncoderDelete(enc_side); - return (picture->error_code == VP8_ENC_OK); -} - -#undef CRUNCH_CONFIGS_MAX -#undef CRUNCH_SUBCONFIGS_MAX - -int VP8LEncodeImage(const WebPConfig* const config, - const WebPPicture* const picture) { - int width, height; - int has_alpha; - size_t coded_size; - int percent = 0; - int initial_size; - VP8LBitWriter bw; - - if (picture == NULL) return 0; - - if (config == NULL || picture->argb == NULL) { - return WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER); - } - - width = picture->width; - height = picture->height; - // Initialize BitWriter with size corresponding to 16 bpp to photo images and - // 8 bpp for graphical images. - initial_size = (config->image_hint == WEBP_HINT_GRAPH) ? - width * height : width * height * 2; - if (!VP8LBitWriterInit(&bw, initial_size)) { - WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); - goto Error; - } - - if (!WebPReportProgress(picture, 1, &percent)) { - UserAbort: - WebPEncodingSetError(picture, VP8_ENC_ERROR_USER_ABORT); - goto Error; - } - // Reset stats (for pure lossless coding) - if (picture->stats != NULL) { - WebPAuxStats* const stats = picture->stats; - memset(stats, 0, sizeof(*stats)); - stats->PSNR[0] = 99.f; - stats->PSNR[1] = 99.f; - stats->PSNR[2] = 99.f; - stats->PSNR[3] = 99.f; - stats->PSNR[4] = 99.f; - } - - // Write image size. - if (!WriteImageSize(picture, &bw)) { - WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); - goto Error; - } - - has_alpha = WebPPictureHasTransparency(picture); - // Write the non-trivial Alpha flag and lossless version. - if (!WriteRealAlphaAndVersion(&bw, has_alpha)) { - WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); - goto Error; - } - - if (!WebPReportProgress(picture, 2, &percent)) goto UserAbort; - - // Encode main image stream. - if (!VP8LEncodeStream(config, picture, &bw)) goto Error; - - if (!WebPReportProgress(picture, 99, &percent)) goto UserAbort; - - // Finish the RIFF chunk. - if (!WriteImage(picture, &bw, &coded_size)) goto Error; - - if (!WebPReportProgress(picture, 100, &percent)) goto UserAbort; - -#if !defined(WEBP_DISABLE_STATS) - // Save size. - if (picture->stats != NULL) { - picture->stats->coded_size += (int)coded_size; - picture->stats->lossless_size = (int)coded_size; - } -#endif - - if (picture->extra_info != NULL) { - const int mb_w = (width + 15) >> 4; - const int mb_h = (height + 15) >> 4; - memset(picture->extra_info, 0, mb_w * mb_h * sizeof(*picture->extra_info)); - } - - Error: - if (bw.error_) { - WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); - } - VP8LBitWriterWipeOut(&bw); - return (picture->error_code == VP8_ENC_OK); -} - -//------------------------------------------------------------------------------ diff --git a/libwebp/src/enc/vp8li_enc.h b/libwebp/src/enc/vp8li_enc.h deleted file mode 100644 index c5b60dcb..00000000 --- a/libwebp/src/enc/vp8li_enc.h +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright 2012 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Lossless encoder: internal header. -// -// Author: Vikas Arora (vikaas.arora@gmail.com) - -#ifndef WEBP_ENC_VP8LI_ENC_H_ -#define WEBP_ENC_VP8LI_ENC_H_ - -#ifdef HAVE_CONFIG_H -#include "src/webp/config.h" -#endif -// Either WEBP_NEAR_LOSSLESS is defined as 0 in config.h when compiling to -// disable near-lossless, or it is enabled by default. -#ifndef WEBP_NEAR_LOSSLESS -#define WEBP_NEAR_LOSSLESS 1 -#endif - -#include "src/enc/backward_references_enc.h" -#include "src/enc/histogram_enc.h" -#include "src/utils/bit_writer_utils.h" -#include "src/webp/encode.h" -#include "src/webp/format_constants.h" - -#ifdef __cplusplus -extern "C" { -#endif - -// maximum value of transform_bits_ in VP8LEncoder. -#define MAX_TRANSFORM_BITS 6 - -typedef enum { - kEncoderNone = 0, - kEncoderARGB, - kEncoderNearLossless, - kEncoderPalette -} VP8LEncoderARGBContent; - -typedef struct { - const WebPConfig* config_; // user configuration and parameters - const WebPPicture* pic_; // input picture. - - uint32_t* argb_; // Transformed argb image data. - VP8LEncoderARGBContent argb_content_; // Content type of the argb buffer. - uint32_t* argb_scratch_; // Scratch memory for argb rows - // (used for prediction). - uint32_t* transform_data_; // Scratch memory for transform data. - uint32_t* transform_mem_; // Currently allocated memory. - size_t transform_mem_size_; // Currently allocated memory size. - - int current_width_; // Corresponds to packed image width. - - // Encoding parameters derived from quality parameter. - int histo_bits_; - int transform_bits_; // <= MAX_TRANSFORM_BITS. - int cache_bits_; // If equal to 0, don't use color cache. - - // Encoding parameters derived from image characteristics. - int use_cross_color_; - int use_subtract_green_; - int use_predict_; - int use_palette_; - int palette_size_; - uint32_t palette_[MAX_PALETTE_SIZE]; - // Sorted version of palette_ for cache purposes. - uint32_t palette_sorted_[MAX_PALETTE_SIZE]; - - // Some 'scratch' (potentially large) objects. - struct VP8LBackwardRefs refs_[4]; // Backward Refs array for temporaries. - VP8LHashChain hash_chain_; // HashChain data for constructing - // backward references. -} VP8LEncoder; - -//------------------------------------------------------------------------------ -// internal functions. Not public. - -// Encodes the picture. -// Returns 0 if config or picture is NULL or picture doesn't have valid argb -// input. -int VP8LEncodeImage(const WebPConfig* const config, - const WebPPicture* const picture); - -// Encodes the main image stream using the supplied bit writer. -// Returns false in case of error (stored in picture->error_code). -int VP8LEncodeStream(const WebPConfig* const config, - const WebPPicture* const picture, VP8LBitWriter* const bw); - -#if (WEBP_NEAR_LOSSLESS == 1) -// in near_lossless.c -// Near lossless preprocessing in RGB color-space. -int VP8ApplyNearLossless(const WebPPicture* const picture, int quality, - uint32_t* const argb_dst); -#endif - -//------------------------------------------------------------------------------ -// Image transforms in predictor.c. - -// pic and percent are for progress. -// Returns false in case of error (stored in pic->error_code). -int VP8LResidualImage(int width, int height, int bits, int low_effort, - uint32_t* const argb, uint32_t* const argb_scratch, - uint32_t* const image, int near_lossless, int exact, - int used_subtract_green, const WebPPicture* const pic, - int percent_range, int* const percent); - -int VP8LColorSpaceTransform(int width, int height, int bits, int quality, - uint32_t* const argb, uint32_t* image, - const WebPPicture* const pic, int percent_range, - int* const percent); - -//------------------------------------------------------------------------------ - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // WEBP_ENC_VP8LI_ENC_H_ diff --git a/libwebp/src/enc/webp_enc.c b/libwebp/src/enc/webp_enc.c deleted file mode 100644 index 583fe6a8..00000000 --- a/libwebp/src/enc/webp_enc.c +++ /dev/null @@ -1,410 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// WebP encoder: main entry point -// -// Author: Skal (pascal.massimino@gmail.com) - -#include -#include -#include -#include - -#include "src/enc/cost_enc.h" -#include "src/enc/vp8i_enc.h" -#include "src/enc/vp8li_enc.h" -#include "src/utils/utils.h" - -// #define PRINT_MEMORY_INFO - -#ifdef PRINT_MEMORY_INFO -#include -#endif - -//------------------------------------------------------------------------------ - -int WebPGetEncoderVersion(void) { - return (ENC_MAJ_VERSION << 16) | (ENC_MIN_VERSION << 8) | ENC_REV_VERSION; -} - -//------------------------------------------------------------------------------ -// VP8Encoder -//------------------------------------------------------------------------------ - -static void ResetSegmentHeader(VP8Encoder* const enc) { - VP8EncSegmentHeader* const hdr = &enc->segment_hdr_; - hdr->num_segments_ = enc->config_->segments; - hdr->update_map_ = (hdr->num_segments_ > 1); - hdr->size_ = 0; -} - -static void ResetFilterHeader(VP8Encoder* const enc) { - VP8EncFilterHeader* const hdr = &enc->filter_hdr_; - hdr->simple_ = 1; - hdr->level_ = 0; - hdr->sharpness_ = 0; - hdr->i4x4_lf_delta_ = 0; -} - -static void ResetBoundaryPredictions(VP8Encoder* const enc) { - // init boundary values once for all - // Note: actually, initializing the preds_[] is only needed for intra4. - int i; - uint8_t* const top = enc->preds_ - enc->preds_w_; - uint8_t* const left = enc->preds_ - 1; - for (i = -1; i < 4 * enc->mb_w_; ++i) { - top[i] = B_DC_PRED; - } - for (i = 0; i < 4 * enc->mb_h_; ++i) { - left[i * enc->preds_w_] = B_DC_PRED; - } - enc->nz_[-1] = 0; // constant -} - -// Mapping from config->method_ to coding tools used. -//-------------------+---+---+---+---+---+---+---+ -// Method | 0 | 1 | 2 | 3 |(4)| 5 | 6 | -//-------------------+---+---+---+---+---+---+---+ -// fast probe | x | | | x | | | | -//-------------------+---+---+---+---+---+---+---+ -// dynamic proba | ~ | x | x | x | x | x | x | -//-------------------+---+---+---+---+---+---+---+ -// fast mode analysis|[x]|[x]| | | x | x | x | -//-------------------+---+---+---+---+---+---+---+ -// basic rd-opt | | | | x | x | x | x | -//-------------------+---+---+---+---+---+---+---+ -// disto-refine i4/16| x | x | x | | | | | -//-------------------+---+---+---+---+---+---+---+ -// disto-refine uv | | x | x | | | | | -//-------------------+---+---+---+---+---+---+---+ -// rd-opt i4/16 | | | ~ | x | x | x | x | -//-------------------+---+---+---+---+---+---+---+ -// token buffer (opt)| | | | x | x | x | x | -//-------------------+---+---+---+---+---+---+---+ -// Trellis | | | | | | x |Ful| -//-------------------+---+---+---+---+---+---+---+ -// full-SNS | | | | | x | x | x | -//-------------------+---+---+---+---+---+---+---+ - -static void MapConfigToTools(VP8Encoder* const enc) { - const WebPConfig* const config = enc->config_; - const int method = config->method; - const int limit = 100 - config->partition_limit; - enc->method_ = method; - enc->rd_opt_level_ = (method >= 6) ? RD_OPT_TRELLIS_ALL - : (method >= 5) ? RD_OPT_TRELLIS - : (method >= 3) ? RD_OPT_BASIC - : RD_OPT_NONE; - enc->max_i4_header_bits_ = - 256 * 16 * 16 * // upper bound: up to 16bit per 4x4 block - (limit * limit) / (100 * 100); // ... modulated with a quadratic curve. - - // partition0 = 512k max. - enc->mb_header_limit_ = - (score_t)256 * 510 * 8 * 1024 / (enc->mb_w_ * enc->mb_h_); - - enc->thread_level_ = config->thread_level; - - enc->do_search_ = (config->target_size > 0 || config->target_PSNR > 0); - if (!config->low_memory) { -#if !defined(DISABLE_TOKEN_BUFFER) - enc->use_tokens_ = (enc->rd_opt_level_ >= RD_OPT_BASIC); // need rd stats -#endif - if (enc->use_tokens_) { - enc->num_parts_ = 1; // doesn't work with multi-partition - } - } -} - -// Memory scaling with dimensions: -// memory (bytes) ~= 2.25 * w + 0.0625 * w * h -// -// Typical memory footprint (614x440 picture) -// encoder: 22111 -// info: 4368 -// preds: 17741 -// top samples: 1263 -// non-zero: 175 -// lf-stats: 0 -// total: 45658 -// Transient object sizes: -// VP8EncIterator: 3360 -// VP8ModeScore: 872 -// VP8SegmentInfo: 732 -// VP8EncProba: 18352 -// LFStats: 2048 -// Picture size (yuv): 419328 - -static VP8Encoder* InitVP8Encoder(const WebPConfig* const config, - WebPPicture* const picture) { - VP8Encoder* enc; - const int use_filter = - (config->filter_strength > 0) || (config->autofilter > 0); - const int mb_w = (picture->width + 15) >> 4; - const int mb_h = (picture->height + 15) >> 4; - const int preds_w = 4 * mb_w + 1; - const int preds_h = 4 * mb_h + 1; - const size_t preds_size = preds_w * preds_h * sizeof(*enc->preds_); - const int top_stride = mb_w * 16; - const size_t nz_size = (mb_w + 1) * sizeof(*enc->nz_) + WEBP_ALIGN_CST; - const size_t info_size = mb_w * mb_h * sizeof(*enc->mb_info_); - const size_t samples_size = - 2 * top_stride * sizeof(*enc->y_top_) // top-luma/u/v - + WEBP_ALIGN_CST; // align all - const size_t lf_stats_size = - config->autofilter ? sizeof(*enc->lf_stats_) + WEBP_ALIGN_CST : 0; - const size_t top_derr_size = - (config->quality <= ERROR_DIFFUSION_QUALITY || config->pass > 1) ? - mb_w * sizeof(*enc->top_derr_) : 0; - uint8_t* mem; - const uint64_t size = (uint64_t)sizeof(*enc) // main struct - + WEBP_ALIGN_CST // cache alignment - + info_size // modes info - + preds_size // prediction modes - + samples_size // top/left samples - + top_derr_size // top diffusion error - + nz_size // coeff context bits - + lf_stats_size; // autofilter stats - -#ifdef PRINT_MEMORY_INFO - printf("===================================\n"); - printf("Memory used:\n" - " encoder: %ld\n" - " info: %ld\n" - " preds: %ld\n" - " top samples: %ld\n" - " top diffusion: %ld\n" - " non-zero: %ld\n" - " lf-stats: %ld\n" - " total: %ld\n", - sizeof(*enc) + WEBP_ALIGN_CST, info_size, - preds_size, samples_size, top_derr_size, nz_size, lf_stats_size, size); - printf("Transient object sizes:\n" - " VP8EncIterator: %ld\n" - " VP8ModeScore: %ld\n" - " VP8SegmentInfo: %ld\n" - " VP8EncProba: %ld\n" - " LFStats: %ld\n", - sizeof(VP8EncIterator), sizeof(VP8ModeScore), - sizeof(VP8SegmentInfo), sizeof(VP8EncProba), - sizeof(LFStats)); - printf("Picture size (yuv): %ld\n", - mb_w * mb_h * 384 * sizeof(uint8_t)); - printf("===================================\n"); -#endif - mem = (uint8_t*)WebPSafeMalloc(size, sizeof(*mem)); - if (mem == NULL) { - WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); - return NULL; - } - enc = (VP8Encoder*)mem; - mem = (uint8_t*)WEBP_ALIGN(mem + sizeof(*enc)); - memset(enc, 0, sizeof(*enc)); - enc->num_parts_ = 1 << config->partitions; - enc->mb_w_ = mb_w; - enc->mb_h_ = mb_h; - enc->preds_w_ = preds_w; - enc->mb_info_ = (VP8MBInfo*)mem; - mem += info_size; - enc->preds_ = mem + 1 + enc->preds_w_; - mem += preds_size; - enc->nz_ = 1 + (uint32_t*)WEBP_ALIGN(mem); - mem += nz_size; - enc->lf_stats_ = lf_stats_size ? (LFStats*)WEBP_ALIGN(mem) : NULL; - mem += lf_stats_size; - - // top samples (all 16-aligned) - mem = (uint8_t*)WEBP_ALIGN(mem); - enc->y_top_ = mem; - enc->uv_top_ = enc->y_top_ + top_stride; - mem += 2 * top_stride; - enc->top_derr_ = top_derr_size ? (DError*)mem : NULL; - mem += top_derr_size; - assert(mem <= (uint8_t*)enc + size); - - enc->config_ = config; - enc->profile_ = use_filter ? ((config->filter_type == 1) ? 0 : 1) : 2; - enc->pic_ = picture; - enc->percent_ = 0; - - MapConfigToTools(enc); - VP8EncDspInit(); - VP8DefaultProbas(enc); - ResetSegmentHeader(enc); - ResetFilterHeader(enc); - ResetBoundaryPredictions(enc); - VP8EncDspCostInit(); - VP8EncInitAlpha(enc); - - // lower quality means smaller output -> we modulate a little the page - // size based on quality. This is just a crude 1rst-order prediction. - { - const float scale = 1.f + config->quality * 5.f / 100.f; // in [1,6] - VP8TBufferInit(&enc->tokens_, (int)(mb_w * mb_h * 4 * scale)); - } - return enc; -} - -static int DeleteVP8Encoder(VP8Encoder* enc) { - int ok = 1; - if (enc != NULL) { - ok = VP8EncDeleteAlpha(enc); - VP8TBufferClear(&enc->tokens_); - WebPSafeFree(enc); - } - return ok; -} - -//------------------------------------------------------------------------------ - -#if !defined(WEBP_DISABLE_STATS) -static double GetPSNR(uint64_t err, uint64_t size) { - return (err > 0 && size > 0) ? 10. * log10(255. * 255. * size / err) : 99.; -} - -static void FinalizePSNR(const VP8Encoder* const enc) { - WebPAuxStats* stats = enc->pic_->stats; - const uint64_t size = enc->sse_count_; - const uint64_t* const sse = enc->sse_; - stats->PSNR[0] = (float)GetPSNR(sse[0], size); - stats->PSNR[1] = (float)GetPSNR(sse[1], size / 4); - stats->PSNR[2] = (float)GetPSNR(sse[2], size / 4); - stats->PSNR[3] = (float)GetPSNR(sse[0] + sse[1] + sse[2], size * 3 / 2); - stats->PSNR[4] = (float)GetPSNR(sse[3], size); -} -#endif // !defined(WEBP_DISABLE_STATS) - -static void StoreStats(VP8Encoder* const enc) { -#if !defined(WEBP_DISABLE_STATS) - WebPAuxStats* const stats = enc->pic_->stats; - if (stats != NULL) { - int i, s; - for (i = 0; i < NUM_MB_SEGMENTS; ++i) { - stats->segment_level[i] = enc->dqm_[i].fstrength_; - stats->segment_quant[i] = enc->dqm_[i].quant_; - for (s = 0; s <= 2; ++s) { - stats->residual_bytes[s][i] = enc->residual_bytes_[s][i]; - } - } - FinalizePSNR(enc); - stats->coded_size = enc->coded_size_; - for (i = 0; i < 3; ++i) { - stats->block_count[i] = enc->block_count_[i]; - } - } -#else // defined(WEBP_DISABLE_STATS) - WebPReportProgress(enc->pic_, 100, &enc->percent_); // done! -#endif // !defined(WEBP_DISABLE_STATS) -} - -int WebPEncodingSetError(const WebPPicture* const pic, - WebPEncodingError error) { - assert((int)error < VP8_ENC_ERROR_LAST); - assert((int)error >= VP8_ENC_OK); - // The oldest error reported takes precedence over the new one. - if (pic->error_code == VP8_ENC_OK) { - ((WebPPicture*)pic)->error_code = error; - } - return 0; -} - -int WebPReportProgress(const WebPPicture* const pic, - int percent, int* const percent_store) { - if (percent_store != NULL && percent != *percent_store) { - *percent_store = percent; - if (pic->progress_hook && !pic->progress_hook(percent, pic)) { - // user abort requested - return WebPEncodingSetError(pic, VP8_ENC_ERROR_USER_ABORT); - } - } - return 1; // ok -} -//------------------------------------------------------------------------------ - -int WebPEncode(const WebPConfig* config, WebPPicture* pic) { - int ok = 0; - if (pic == NULL) return 0; - - pic->error_code = VP8_ENC_OK; // all ok so far - if (config == NULL) { // bad params - return WebPEncodingSetError(pic, VP8_ENC_ERROR_NULL_PARAMETER); - } - if (!WebPValidateConfig(config)) { - return WebPEncodingSetError(pic, VP8_ENC_ERROR_INVALID_CONFIGURATION); - } - if (!WebPValidatePicture(pic)) return 0; - if (pic->width > WEBP_MAX_DIMENSION || pic->height > WEBP_MAX_DIMENSION) { - return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_DIMENSION); - } - - if (pic->stats != NULL) memset(pic->stats, 0, sizeof(*pic->stats)); - - if (!config->lossless) { - VP8Encoder* enc = NULL; - - if (pic->use_argb || pic->y == NULL || pic->u == NULL || pic->v == NULL) { - // Make sure we have YUVA samples. - if (config->use_sharp_yuv || (config->preprocessing & 4)) { - if (!WebPPictureSharpARGBToYUVA(pic)) { - return 0; - } - } else { - float dithering = 0.f; - if (config->preprocessing & 2) { - const float x = config->quality / 100.f; - const float x2 = x * x; - // slowly decreasing from max dithering at low quality (q->0) - // to 0.5 dithering amplitude at high quality (q->100) - dithering = 1.0f + (0.5f - 1.0f) * x2 * x2; - } - if (!WebPPictureARGBToYUVADithered(pic, WEBP_YUV420, dithering)) { - return 0; - } - } - } - - if (!config->exact) { - WebPCleanupTransparentArea(pic); - } - - enc = InitVP8Encoder(config, pic); - if (enc == NULL) return 0; // pic->error is already set. - // Note: each of the tasks below account for 20% in the progress report. - ok = VP8EncAnalyze(enc); - - // Analysis is done, proceed to actual coding. - ok = ok && VP8EncStartAlpha(enc); // possibly done in parallel - if (!enc->use_tokens_) { - ok = ok && VP8EncLoop(enc); - } else { - ok = ok && VP8EncTokenLoop(enc); - } - ok = ok && VP8EncFinishAlpha(enc); - - ok = ok && VP8EncWrite(enc); - StoreStats(enc); - if (!ok) { - VP8EncFreeBitWriters(enc); - } - ok &= DeleteVP8Encoder(enc); // must always be called, even if !ok - } else { - // Make sure we have ARGB samples. - if (pic->argb == NULL && !WebPPictureYUVAToARGB(pic)) { - return 0; - } - - if (!config->exact) { - WebPReplaceTransparentPixels(pic, 0x000000); - } - - ok = VP8LEncodeImage(config, pic); // Sets pic->error in case of problem. - } - - return ok; -} diff --git a/libwebp/src/libwebp.pc.in b/libwebp/src/libwebp.pc.in deleted file mode 100644 index 783090ef..00000000 --- a/libwebp/src/libwebp.pc.in +++ /dev/null @@ -1,12 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: libwebp -Description: Library for the WebP graphics format -Version: @PACKAGE_VERSION@ -Requires.private: libsharpyuv -Cflags: -I${includedir} -Libs: -L${libdir} -l@webp_libname_prefix@webp -Libs.private: -lm @PTHREAD_CFLAGS@ @PTHREAD_LIBS@ diff --git a/libwebp/src/libwebp.rc b/libwebp/src/libwebp.rc deleted file mode 100644 index 4e8e4029..00000000 --- a/libwebp/src/libwebp.rc +++ /dev/null @@ -1,41 +0,0 @@ -#define APSTUDIO_READONLY_SYMBOLS -#include "winres.h" -#undef APSTUDIO_READONLY_SYMBOLS - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US - -VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,0,3,2 - PRODUCTVERSION 1,0,3,2 - FILEFLAGSMASK 0x3fL -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x40004L - FILETYPE 0x2L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "CompanyName", "Google, Inc." - VALUE "FileDescription", "libwebp DLL" - VALUE "FileVersion", "1.3.2" - VALUE "InternalName", "libwebp.dll" - VALUE "LegalCopyright", "Copyright (C) 2023" - VALUE "OriginalFilename", "libwebp.dll" - VALUE "ProductName", "WebP Image Codec" - VALUE "ProductVersion", "1.3.2" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - -#endif // English (United States) resources diff --git a/libwebp/src/libwebpdecoder.pc.in b/libwebp/src/libwebpdecoder.pc.in deleted file mode 100644 index 134de0e7..00000000 --- a/libwebp/src/libwebpdecoder.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: libwebpdecoder -Description: Library for the WebP graphics format (decode only) -Version: @PACKAGE_VERSION@ -Cflags: -I${includedir} -Libs: -L${libdir} -l@webp_libname_prefix@webpdecoder -Libs.private: -lm @PTHREAD_CFLAGS@ @PTHREAD_LIBS@ diff --git a/libwebp/src/libwebpdecoder.rc b/libwebp/src/libwebpdecoder.rc deleted file mode 100644 index c3f3e4a1..00000000 --- a/libwebp/src/libwebpdecoder.rc +++ /dev/null @@ -1,41 +0,0 @@ -#define APSTUDIO_READONLY_SYMBOLS -#include "winres.h" -#undef APSTUDIO_READONLY_SYMBOLS - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US - -VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,0,3,2 - PRODUCTVERSION 1,0,3,2 - FILEFLAGSMASK 0x3fL -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x40004L - FILETYPE 0x2L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "CompanyName", "Google, Inc." - VALUE "FileDescription", "libwebpdecoder DLL" - VALUE "FileVersion", "1.3.2" - VALUE "InternalName", "libwebpdecoder.dll" - VALUE "LegalCopyright", "Copyright (C) 2023" - VALUE "OriginalFilename", "libwebpdecoder.dll" - VALUE "ProductName", "WebP Image Decoder" - VALUE "ProductVersion", "1.3.2" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - -#endif // English (United States) resources diff --git a/libwebp/src/mux/Makefile.am b/libwebp/src/mux/Makefile.am deleted file mode 100644 index 9abd8595..00000000 --- a/libwebp/src/mux/Makefile.am +++ /dev/null @@ -1,22 +0,0 @@ -AM_CPPFLAGS += -I$(top_builddir) -I$(top_srcdir) -lib_LTLIBRARIES = libwebpmux.la - -libwebpmux_la_SOURCES = -libwebpmux_la_SOURCES += anim_encode.c -libwebpmux_la_SOURCES += animi.h -libwebpmux_la_SOURCES += muxedit.c -libwebpmux_la_SOURCES += muxi.h -libwebpmux_la_SOURCES += muxinternal.c -libwebpmux_la_SOURCES += muxread.c - -libwebpmuxinclude_HEADERS = -libwebpmuxinclude_HEADERS += ../webp/mux.h -libwebpmuxinclude_HEADERS += ../webp/mux_types.h -libwebpmuxinclude_HEADERS += ../webp/types.h -noinst_HEADERS = -noinst_HEADERS += ../webp/format_constants.h - -libwebpmux_la_LIBADD = ../libwebp.la -libwebpmux_la_LDFLAGS = -no-undefined -version-info 3:13:0 -lm -libwebpmuxincludedir = $(includedir)/webp -pkgconfig_DATA = libwebpmux.pc diff --git a/libwebp/src/mux/anim_encode.c b/libwebp/src/mux/anim_encode.c deleted file mode 100644 index 31bd0457..00000000 --- a/libwebp/src/mux/anim_encode.c +++ /dev/null @@ -1,1611 +0,0 @@ -// Copyright 2014 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// AnimEncoder implementation. -// - -#include -#include -#include // for pow() -#include -#include // for abs() - -#include "src/mux/animi.h" -#include "src/utils/utils.h" -#include "src/webp/decode.h" -#include "src/webp/encode.h" -#include "src/webp/format_constants.h" -#include "src/webp/mux.h" -#include "src/webp/types.h" - -#if defined(_MSC_VER) && _MSC_VER < 1900 -#define snprintf _snprintf -#endif - -#define ERROR_STR_MAX_LENGTH 100 - -//------------------------------------------------------------------------------ -// Internal structs. - -// Stores frame rectangle dimensions. -typedef struct { - int x_offset_, y_offset_, width_, height_; -} FrameRectangle; - -// Used to store two candidates of encoded data for an animation frame. One of -// the two will be chosen later. -typedef struct { - WebPMuxFrameInfo sub_frame_; // Encoded frame rectangle. - WebPMuxFrameInfo key_frame_; // Encoded frame if it is a key-frame. - int is_key_frame_; // True if 'key_frame' has been chosen. -} EncodedFrame; - -struct WebPAnimEncoder { - const int canvas_width_; // Canvas width. - const int canvas_height_; // Canvas height. - const WebPAnimEncoderOptions options_; // Global encoding options. - - FrameRectangle prev_rect_; // Previous WebP frame rectangle. - WebPConfig last_config_; // Cached in case a re-encode is needed. - WebPConfig last_config_reversed_; // If 'last_config_' uses lossless, then - // this config uses lossy and vice versa; - // only valid if 'options_.allow_mixed' - // is true. - - WebPPicture* curr_canvas_; // Only pointer; we don't own memory. - - // Canvas buffers. - WebPPicture curr_canvas_copy_; // Possibly modified current canvas. - int curr_canvas_copy_modified_; // True if pixels in 'curr_canvas_copy_' - // differ from those in 'curr_canvas_'. - - WebPPicture prev_canvas_; // Previous canvas. - WebPPicture prev_canvas_disposed_; // Previous canvas disposed to background. - - // Encoded data. - EncodedFrame* encoded_frames_; // Array of encoded frames. - size_t size_; // Number of allocated frames. - size_t start_; // Frame start index. - size_t count_; // Number of valid frames. - size_t flush_count_; // If >0, 'flush_count' frames starting from - // 'start' are ready to be added to mux. - - // key-frame related. - int64_t best_delta_; // min(canvas size - frame size) over the frames. - // Can be negative in certain cases due to - // transparent pixels in a frame. - int keyframe_; // Index of selected key-frame relative to 'start_'. - int count_since_key_frame_; // Frames seen since the last key-frame. - - int first_timestamp_; // Timestamp of the first frame. - int prev_timestamp_; // Timestamp of the last added frame. - int prev_candidate_undecided_; // True if it's not yet decided if previous - // frame would be a sub-frame or a key-frame. - - // Misc. - int is_first_frame_; // True if first frame is yet to be added/being added. - int got_null_frame_; // True if WebPAnimEncoderAdd() has already been called - // with a NULL frame. - - size_t in_frame_count_; // Number of input frames processed so far. - size_t out_frame_count_; // Number of frames added to mux so far. This may be - // different from 'in_frame_count_' due to merging. - - WebPMux* mux_; // Muxer to assemble the WebP bitstream. - char error_str_[ERROR_STR_MAX_LENGTH]; // Error string. Empty if no error. -}; - -// ----------------------------------------------------------------------------- -// Life of WebPAnimEncoder object. - -#define DELTA_INFINITY (1ULL << 32) -#define KEYFRAME_NONE (-1) - -// Reset the counters in the WebPAnimEncoder. -static void ResetCounters(WebPAnimEncoder* const enc) { - enc->start_ = 0; - enc->count_ = 0; - enc->flush_count_ = 0; - enc->best_delta_ = DELTA_INFINITY; - enc->keyframe_ = KEYFRAME_NONE; -} - -static void DisableKeyframes(WebPAnimEncoderOptions* const enc_options) { - enc_options->kmax = INT_MAX; - enc_options->kmin = enc_options->kmax - 1; -} - -#define MAX_CACHED_FRAMES 30 - -static void SanitizeEncoderOptions(WebPAnimEncoderOptions* const enc_options) { - int print_warning = enc_options->verbose; - - if (enc_options->minimize_size) { - DisableKeyframes(enc_options); - } - - if (enc_options->kmax == 1) { // All frames will be key-frames. - enc_options->kmin = 0; - enc_options->kmax = 0; - return; - } else if (enc_options->kmax <= 0) { - DisableKeyframes(enc_options); - print_warning = 0; - } - - if (enc_options->kmin >= enc_options->kmax) { - enc_options->kmin = enc_options->kmax - 1; - if (print_warning) { - fprintf(stderr, "WARNING: Setting kmin = %d, so that kmin < kmax.\n", - enc_options->kmin); - } - } else { - const int kmin_limit = enc_options->kmax / 2 + 1; - if (enc_options->kmin < kmin_limit && kmin_limit < enc_options->kmax) { - // This ensures that enc.keyframe + kmin >= kmax is always true. So, we - // can flush all the frames in the 'count_since_key_frame == kmax' case. - enc_options->kmin = kmin_limit; - if (print_warning) { - fprintf(stderr, - "WARNING: Setting kmin = %d, so that kmin >= kmax / 2 + 1.\n", - enc_options->kmin); - } - } - } - // Limit the max number of frames that are allocated. - if (enc_options->kmax - enc_options->kmin > MAX_CACHED_FRAMES) { - enc_options->kmin = enc_options->kmax - MAX_CACHED_FRAMES; - if (print_warning) { - fprintf(stderr, - "WARNING: Setting kmin = %d, so that kmax - kmin <= %d.\n", - enc_options->kmin, MAX_CACHED_FRAMES); - } - } - assert(enc_options->kmin < enc_options->kmax); -} - -#undef MAX_CACHED_FRAMES - -static void DefaultEncoderOptions(WebPAnimEncoderOptions* const enc_options) { - enc_options->anim_params.loop_count = 0; - enc_options->anim_params.bgcolor = 0xffffffff; // White. - enc_options->minimize_size = 0; - DisableKeyframes(enc_options); - enc_options->allow_mixed = 0; - enc_options->verbose = 0; -} - -int WebPAnimEncoderOptionsInitInternal(WebPAnimEncoderOptions* enc_options, - int abi_version) { - if (enc_options == NULL || - WEBP_ABI_IS_INCOMPATIBLE(abi_version, WEBP_MUX_ABI_VERSION)) { - return 0; - } - DefaultEncoderOptions(enc_options); - return 1; -} - -// This starting value is more fit to WebPCleanupTransparentAreaLossless(). -#define TRANSPARENT_COLOR 0x00000000 - -static void ClearRectangle(WebPPicture* const picture, - int left, int top, int width, int height) { - int j; - for (j = top; j < top + height; ++j) { - uint32_t* const dst = picture->argb + j * picture->argb_stride; - int i; - for (i = left; i < left + width; ++i) { - dst[i] = TRANSPARENT_COLOR; - } - } -} - -static void WebPUtilClearPic(WebPPicture* const picture, - const FrameRectangle* const rect) { - if (rect != NULL) { - ClearRectangle(picture, rect->x_offset_, rect->y_offset_, - rect->width_, rect->height_); - } else { - ClearRectangle(picture, 0, 0, picture->width, picture->height); - } -} - -static void MarkNoError(WebPAnimEncoder* const enc) { - enc->error_str_[0] = '\0'; // Empty string. -} - -static void MarkError(WebPAnimEncoder* const enc, const char* str) { - if (snprintf(enc->error_str_, ERROR_STR_MAX_LENGTH, "%s.", str) < 0) { - assert(0); // FIX ME! - } -} - -static void MarkError2(WebPAnimEncoder* const enc, - const char* str, int error_code) { - if (snprintf(enc->error_str_, ERROR_STR_MAX_LENGTH, "%s: %d.", str, - error_code) < 0) { - assert(0); // FIX ME! - } -} - -WebPAnimEncoder* WebPAnimEncoderNewInternal( - int width, int height, const WebPAnimEncoderOptions* enc_options, - int abi_version) { - WebPAnimEncoder* enc; - - if (WEBP_ABI_IS_INCOMPATIBLE(abi_version, WEBP_MUX_ABI_VERSION)) { - return NULL; - } - if (width <= 0 || height <= 0 || - (width * (uint64_t)height) >= MAX_IMAGE_AREA) { - return NULL; - } - - enc = (WebPAnimEncoder*)WebPSafeCalloc(1, sizeof(*enc)); - if (enc == NULL) return NULL; - MarkNoError(enc); - - // Dimensions and options. - *(int*)&enc->canvas_width_ = width; - *(int*)&enc->canvas_height_ = height; - if (enc_options != NULL) { - *(WebPAnimEncoderOptions*)&enc->options_ = *enc_options; - SanitizeEncoderOptions((WebPAnimEncoderOptions*)&enc->options_); - } else { - DefaultEncoderOptions((WebPAnimEncoderOptions*)&enc->options_); - } - - // Canvas buffers. - if (!WebPPictureInit(&enc->curr_canvas_copy_) || - !WebPPictureInit(&enc->prev_canvas_) || - !WebPPictureInit(&enc->prev_canvas_disposed_)) { - goto Err; - } - enc->curr_canvas_copy_.width = width; - enc->curr_canvas_copy_.height = height; - enc->curr_canvas_copy_.use_argb = 1; - if (!WebPPictureAlloc(&enc->curr_canvas_copy_) || - !WebPPictureCopy(&enc->curr_canvas_copy_, &enc->prev_canvas_) || - !WebPPictureCopy(&enc->curr_canvas_copy_, &enc->prev_canvas_disposed_)) { - goto Err; - } - WebPUtilClearPic(&enc->prev_canvas_, NULL); - enc->curr_canvas_copy_modified_ = 1; - - // Encoded frames. - ResetCounters(enc); - // Note: one extra storage is for the previous frame. - enc->size_ = enc->options_.kmax - enc->options_.kmin + 1; - // We need space for at least 2 frames. But when kmin, kmax are both zero, - // enc->size_ will be 1. So we handle that special case below. - if (enc->size_ < 2) enc->size_ = 2; - enc->encoded_frames_ = - (EncodedFrame*)WebPSafeCalloc(enc->size_, sizeof(*enc->encoded_frames_)); - if (enc->encoded_frames_ == NULL) goto Err; - - enc->mux_ = WebPMuxNew(); - if (enc->mux_ == NULL) goto Err; - - enc->count_since_key_frame_ = 0; - enc->first_timestamp_ = 0; - enc->prev_timestamp_ = 0; - enc->prev_candidate_undecided_ = 0; - enc->is_first_frame_ = 1; - enc->got_null_frame_ = 0; - - return enc; // All OK. - - Err: - WebPAnimEncoderDelete(enc); - return NULL; -} - -// Release the data contained by 'encoded_frame'. -static void FrameRelease(EncodedFrame* const encoded_frame) { - if (encoded_frame != NULL) { - WebPDataClear(&encoded_frame->sub_frame_.bitstream); - WebPDataClear(&encoded_frame->key_frame_.bitstream); - memset(encoded_frame, 0, sizeof(*encoded_frame)); - } -} - -void WebPAnimEncoderDelete(WebPAnimEncoder* enc) { - if (enc != NULL) { - WebPPictureFree(&enc->curr_canvas_copy_); - WebPPictureFree(&enc->prev_canvas_); - WebPPictureFree(&enc->prev_canvas_disposed_); - if (enc->encoded_frames_ != NULL) { - size_t i; - for (i = 0; i < enc->size_; ++i) { - FrameRelease(&enc->encoded_frames_[i]); - } - WebPSafeFree(enc->encoded_frames_); - } - WebPMuxDelete(enc->mux_); - WebPSafeFree(enc); - } -} - -// ----------------------------------------------------------------------------- -// Frame addition. - -// Returns cached frame at the given 'position'. -static EncodedFrame* GetFrame(const WebPAnimEncoder* const enc, - size_t position) { - assert(enc->start_ + position < enc->size_); - return &enc->encoded_frames_[enc->start_ + position]; -} - -typedef int (*ComparePixelsFunc)(const uint32_t*, int, const uint32_t*, int, - int, int); - -// Returns true if 'length' number of pixels in 'src' and 'dst' are equal, -// assuming the given step sizes between pixels. -// 'max_allowed_diff' is unused and only there to allow function pointer use. -static WEBP_INLINE int ComparePixelsLossless(const uint32_t* src, int src_step, - const uint32_t* dst, int dst_step, - int length, int max_allowed_diff) { - (void)max_allowed_diff; - assert(length > 0); - while (length-- > 0) { - if (*src != *dst) { - return 0; - } - src += src_step; - dst += dst_step; - } - return 1; -} - -// Helper to check if each channel in 'src' and 'dst' is at most off by -// 'max_allowed_diff'. -static WEBP_INLINE int PixelsAreSimilar(uint32_t src, uint32_t dst, - int max_allowed_diff) { - const int src_a = (src >> 24) & 0xff; - const int src_r = (src >> 16) & 0xff; - const int src_g = (src >> 8) & 0xff; - const int src_b = (src >> 0) & 0xff; - const int dst_a = (dst >> 24) & 0xff; - const int dst_r = (dst >> 16) & 0xff; - const int dst_g = (dst >> 8) & 0xff; - const int dst_b = (dst >> 0) & 0xff; - - return (src_a == dst_a) && - (abs(src_r - dst_r) * dst_a <= (max_allowed_diff * 255)) && - (abs(src_g - dst_g) * dst_a <= (max_allowed_diff * 255)) && - (abs(src_b - dst_b) * dst_a <= (max_allowed_diff * 255)); -} - -// Returns true if 'length' number of pixels in 'src' and 'dst' are within an -// error bound, assuming the given step sizes between pixels. -static WEBP_INLINE int ComparePixelsLossy(const uint32_t* src, int src_step, - const uint32_t* dst, int dst_step, - int length, int max_allowed_diff) { - assert(length > 0); - while (length-- > 0) { - if (!PixelsAreSimilar(*src, *dst, max_allowed_diff)) { - return 0; - } - src += src_step; - dst += dst_step; - } - return 1; -} - -static int IsEmptyRect(const FrameRectangle* const rect) { - return (rect->width_ == 0) || (rect->height_ == 0); -} - -static int QualityToMaxDiff(float quality) { - const double val = pow(quality / 100., 0.5); - const double max_diff = 31 * (1 - val) + 1 * val; - return (int)(max_diff + 0.5); -} - -// Assumes that an initial valid guess of change rectangle 'rect' is passed. -static void MinimizeChangeRectangle(const WebPPicture* const src, - const WebPPicture* const dst, - FrameRectangle* const rect, - int is_lossless, float quality) { - int i, j; - const ComparePixelsFunc compare_pixels = - is_lossless ? ComparePixelsLossless : ComparePixelsLossy; - const int max_allowed_diff_lossy = QualityToMaxDiff(quality); - const int max_allowed_diff = is_lossless ? 0 : max_allowed_diff_lossy; - - // Assumption/correctness checks. - assert(src->width == dst->width && src->height == dst->height); - assert(rect->x_offset_ + rect->width_ <= dst->width); - assert(rect->y_offset_ + rect->height_ <= dst->height); - - // Left boundary. - for (i = rect->x_offset_; i < rect->x_offset_ + rect->width_; ++i) { - const uint32_t* const src_argb = - &src->argb[rect->y_offset_ * src->argb_stride + i]; - const uint32_t* const dst_argb = - &dst->argb[rect->y_offset_ * dst->argb_stride + i]; - if (compare_pixels(src_argb, src->argb_stride, dst_argb, dst->argb_stride, - rect->height_, max_allowed_diff)) { - --rect->width_; // Redundant column. - ++rect->x_offset_; - } else { - break; - } - } - if (rect->width_ == 0) goto NoChange; - - // Right boundary. - for (i = rect->x_offset_ + rect->width_ - 1; i >= rect->x_offset_; --i) { - const uint32_t* const src_argb = - &src->argb[rect->y_offset_ * src->argb_stride + i]; - const uint32_t* const dst_argb = - &dst->argb[rect->y_offset_ * dst->argb_stride + i]; - if (compare_pixels(src_argb, src->argb_stride, dst_argb, dst->argb_stride, - rect->height_, max_allowed_diff)) { - --rect->width_; // Redundant column. - } else { - break; - } - } - if (rect->width_ == 0) goto NoChange; - - // Top boundary. - for (j = rect->y_offset_; j < rect->y_offset_ + rect->height_; ++j) { - const uint32_t* const src_argb = - &src->argb[j * src->argb_stride + rect->x_offset_]; - const uint32_t* const dst_argb = - &dst->argb[j * dst->argb_stride + rect->x_offset_]; - if (compare_pixels(src_argb, 1, dst_argb, 1, rect->width_, - max_allowed_diff)) { - --rect->height_; // Redundant row. - ++rect->y_offset_; - } else { - break; - } - } - if (rect->height_ == 0) goto NoChange; - - // Bottom boundary. - for (j = rect->y_offset_ + rect->height_ - 1; j >= rect->y_offset_; --j) { - const uint32_t* const src_argb = - &src->argb[j * src->argb_stride + rect->x_offset_]; - const uint32_t* const dst_argb = - &dst->argb[j * dst->argb_stride + rect->x_offset_]; - if (compare_pixels(src_argb, 1, dst_argb, 1, rect->width_, - max_allowed_diff)) { - --rect->height_; // Redundant row. - } else { - break; - } - } - if (rect->height_ == 0) goto NoChange; - - if (IsEmptyRect(rect)) { - NoChange: - rect->x_offset_ = 0; - rect->y_offset_ = 0; - rect->width_ = 0; - rect->height_ = 0; - } -} - -// Snap rectangle to even offsets (and adjust dimensions if needed). -static WEBP_INLINE void SnapToEvenOffsets(FrameRectangle* const rect) { - rect->width_ += (rect->x_offset_ & 1); - rect->height_ += (rect->y_offset_ & 1); - rect->x_offset_ &= ~1; - rect->y_offset_ &= ~1; -} - -typedef struct { - int should_try_; // Should try this set of parameters. - int empty_rect_allowed_; // Frame with empty rectangle can be skipped. - FrameRectangle rect_ll_; // Frame rectangle for lossless compression. - WebPPicture sub_frame_ll_; // Sub-frame pic for lossless compression. - FrameRectangle rect_lossy_; // Frame rectangle for lossy compression. - // Could be smaller than rect_ll_ as pixels - // with small diffs can be ignored. - WebPPicture sub_frame_lossy_; // Sub-frame pic for lossless compression. -} SubFrameParams; - -static int SubFrameParamsInit(SubFrameParams* const params, - int should_try, int empty_rect_allowed) { - params->should_try_ = should_try; - params->empty_rect_allowed_ = empty_rect_allowed; - if (!WebPPictureInit(¶ms->sub_frame_ll_) || - !WebPPictureInit(¶ms->sub_frame_lossy_)) { - return 0; - } - return 1; -} - -static void SubFrameParamsFree(SubFrameParams* const params) { - WebPPictureFree(¶ms->sub_frame_ll_); - WebPPictureFree(¶ms->sub_frame_lossy_); -} - -// Given previous and current canvas, picks the optimal rectangle for the -// current frame based on 'is_lossless' and other parameters. Assumes that the -// initial guess 'rect' is valid. -static int GetSubRect(const WebPPicture* const prev_canvas, - const WebPPicture* const curr_canvas, int is_key_frame, - int is_first_frame, int empty_rect_allowed, - int is_lossless, float quality, - FrameRectangle* const rect, - WebPPicture* const sub_frame) { - if (!is_key_frame || is_first_frame) { // Optimize frame rectangle. - // Note: This behaves as expected for first frame, as 'prev_canvas' is - // initialized to a fully transparent canvas in the beginning. - MinimizeChangeRectangle(prev_canvas, curr_canvas, rect, - is_lossless, quality); - } - - if (IsEmptyRect(rect)) { - if (empty_rect_allowed) { // No need to get 'sub_frame'. - return 1; - } else { // Force a 1x1 rectangle. - rect->width_ = 1; - rect->height_ = 1; - assert(rect->x_offset_ == 0); - assert(rect->y_offset_ == 0); - } - } - - SnapToEvenOffsets(rect); - return WebPPictureView(curr_canvas, rect->x_offset_, rect->y_offset_, - rect->width_, rect->height_, sub_frame); -} - -// Picks optimal frame rectangle for both lossless and lossy compression. The -// initial guess for frame rectangles will be the full canvas. -static int GetSubRects(const WebPPicture* const prev_canvas, - const WebPPicture* const curr_canvas, int is_key_frame, - int is_first_frame, float quality, - SubFrameParams* const params) { - // Lossless frame rectangle. - params->rect_ll_.x_offset_ = 0; - params->rect_ll_.y_offset_ = 0; - params->rect_ll_.width_ = curr_canvas->width; - params->rect_ll_.height_ = curr_canvas->height; - if (!GetSubRect(prev_canvas, curr_canvas, is_key_frame, is_first_frame, - params->empty_rect_allowed_, 1, quality, - ¶ms->rect_ll_, ¶ms->sub_frame_ll_)) { - return 0; - } - // Lossy frame rectangle. - params->rect_lossy_ = params->rect_ll_; // seed with lossless rect. - return GetSubRect(prev_canvas, curr_canvas, is_key_frame, is_first_frame, - params->empty_rect_allowed_, 0, quality, - ¶ms->rect_lossy_, ¶ms->sub_frame_lossy_); -} - -static WEBP_INLINE int clip(int v, int min_v, int max_v) { - return (v < min_v) ? min_v : (v > max_v) ? max_v : v; -} - -int WebPAnimEncoderRefineRect( - const WebPPicture* const prev_canvas, const WebPPicture* const curr_canvas, - int is_lossless, float quality, int* const x_offset, int* const y_offset, - int* const width, int* const height) { - FrameRectangle rect; - int right, left, bottom, top; - if (prev_canvas == NULL || curr_canvas == NULL || - prev_canvas->width != curr_canvas->width || - prev_canvas->height != curr_canvas->height || - !prev_canvas->use_argb || !curr_canvas->use_argb) { - return 0; - } - right = clip(*x_offset + *width, 0, curr_canvas->width); - left = clip(*x_offset, 0, curr_canvas->width - 1); - bottom = clip(*y_offset + *height, 0, curr_canvas->height); - top = clip(*y_offset, 0, curr_canvas->height - 1); - rect.x_offset_ = left; - rect.y_offset_ = top; - rect.width_ = clip(right - left, 0, curr_canvas->width - rect.x_offset_); - rect.height_ = clip(bottom - top, 0, curr_canvas->height - rect.y_offset_); - MinimizeChangeRectangle(prev_canvas, curr_canvas, &rect, is_lossless, - quality); - SnapToEvenOffsets(&rect); - *x_offset = rect.x_offset_; - *y_offset = rect.y_offset_; - *width = rect.width_; - *height = rect.height_; - return 1; -} - -static void DisposeFrameRectangle(int dispose_method, - const FrameRectangle* const rect, - WebPPicture* const curr_canvas) { - assert(rect != NULL); - if (dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) { - WebPUtilClearPic(curr_canvas, rect); - } -} - -static uint32_t RectArea(const FrameRectangle* const rect) { - return (uint32_t)rect->width_ * rect->height_; -} - -static int IsLosslessBlendingPossible(const WebPPicture* const src, - const WebPPicture* const dst, - const FrameRectangle* const rect) { - int i, j; - assert(src->width == dst->width && src->height == dst->height); - assert(rect->x_offset_ + rect->width_ <= dst->width); - assert(rect->y_offset_ + rect->height_ <= dst->height); - for (j = rect->y_offset_; j < rect->y_offset_ + rect->height_; ++j) { - for (i = rect->x_offset_; i < rect->x_offset_ + rect->width_; ++i) { - const uint32_t src_pixel = src->argb[j * src->argb_stride + i]; - const uint32_t dst_pixel = dst->argb[j * dst->argb_stride + i]; - const uint32_t dst_alpha = dst_pixel >> 24; - if (dst_alpha != 0xff && src_pixel != dst_pixel) { - // In this case, if we use blending, we can't attain the desired - // 'dst_pixel' value for this pixel. So, blending is not possible. - return 0; - } - } - } - return 1; -} - -static int IsLossyBlendingPossible(const WebPPicture* const src, - const WebPPicture* const dst, - const FrameRectangle* const rect, - float quality) { - const int max_allowed_diff_lossy = QualityToMaxDiff(quality); - int i, j; - assert(src->width == dst->width && src->height == dst->height); - assert(rect->x_offset_ + rect->width_ <= dst->width); - assert(rect->y_offset_ + rect->height_ <= dst->height); - for (j = rect->y_offset_; j < rect->y_offset_ + rect->height_; ++j) { - for (i = rect->x_offset_; i < rect->x_offset_ + rect->width_; ++i) { - const uint32_t src_pixel = src->argb[j * src->argb_stride + i]; - const uint32_t dst_pixel = dst->argb[j * dst->argb_stride + i]; - const uint32_t dst_alpha = dst_pixel >> 24; - if (dst_alpha != 0xff && - !PixelsAreSimilar(src_pixel, dst_pixel, max_allowed_diff_lossy)) { - // In this case, if we use blending, we can't attain the desired - // 'dst_pixel' value for this pixel. So, blending is not possible. - return 0; - } - } - } - return 1; -} - -// For pixels in 'rect', replace those pixels in 'dst' that are same as 'src' by -// transparent pixels. -// Returns true if at least one pixel gets modified. -static int IncreaseTransparency(const WebPPicture* const src, - const FrameRectangle* const rect, - WebPPicture* const dst) { - int i, j; - int modified = 0; - assert(src != NULL && dst != NULL && rect != NULL); - assert(src->width == dst->width && src->height == dst->height); - for (j = rect->y_offset_; j < rect->y_offset_ + rect->height_; ++j) { - const uint32_t* const psrc = src->argb + j * src->argb_stride; - uint32_t* const pdst = dst->argb + j * dst->argb_stride; - for (i = rect->x_offset_; i < rect->x_offset_ + rect->width_; ++i) { - if (psrc[i] == pdst[i] && pdst[i] != TRANSPARENT_COLOR) { - pdst[i] = TRANSPARENT_COLOR; - modified = 1; - } - } - } - return modified; -} - -#undef TRANSPARENT_COLOR - -// Replace similar blocks of pixels by a 'see-through' transparent block -// with uniform average color. -// Assumes lossy compression is being used. -// Returns true if at least one pixel gets modified. -static int FlattenSimilarBlocks(const WebPPicture* const src, - const FrameRectangle* const rect, - WebPPicture* const dst, float quality) { - const int max_allowed_diff_lossy = QualityToMaxDiff(quality); - int i, j; - int modified = 0; - const int block_size = 8; - const int y_start = (rect->y_offset_ + block_size) & ~(block_size - 1); - const int y_end = (rect->y_offset_ + rect->height_) & ~(block_size - 1); - const int x_start = (rect->x_offset_ + block_size) & ~(block_size - 1); - const int x_end = (rect->x_offset_ + rect->width_) & ~(block_size - 1); - assert(src != NULL && dst != NULL && rect != NULL); - assert(src->width == dst->width && src->height == dst->height); - assert((block_size & (block_size - 1)) == 0); // must be a power of 2 - // Iterate over each block and count similar pixels. - for (j = y_start; j < y_end; j += block_size) { - for (i = x_start; i < x_end; i += block_size) { - int cnt = 0; - int avg_r = 0, avg_g = 0, avg_b = 0; - int x, y; - const uint32_t* const psrc = src->argb + j * src->argb_stride + i; - uint32_t* const pdst = dst->argb + j * dst->argb_stride + i; - for (y = 0; y < block_size; ++y) { - for (x = 0; x < block_size; ++x) { - const uint32_t src_pixel = psrc[x + y * src->argb_stride]; - const int alpha = src_pixel >> 24; - if (alpha == 0xff && - PixelsAreSimilar(src_pixel, pdst[x + y * dst->argb_stride], - max_allowed_diff_lossy)) { - ++cnt; - avg_r += (src_pixel >> 16) & 0xff; - avg_g += (src_pixel >> 8) & 0xff; - avg_b += (src_pixel >> 0) & 0xff; - } - } - } - // If we have a fully similar block, we replace it with an - // average transparent block. This compresses better in lossy mode. - if (cnt == block_size * block_size) { - const uint32_t color = (0x00 << 24) | - ((avg_r / cnt) << 16) | - ((avg_g / cnt) << 8) | - ((avg_b / cnt) << 0); - for (y = 0; y < block_size; ++y) { - for (x = 0; x < block_size; ++x) { - pdst[x + y * dst->argb_stride] = color; - } - } - modified = 1; - } - } - } - return modified; -} - -static int EncodeFrame(const WebPConfig* const config, WebPPicture* const pic, - WebPMemoryWriter* const memory) { - pic->use_argb = 1; - pic->writer = WebPMemoryWrite; - pic->custom_ptr = memory; - if (!WebPEncode(config, pic)) { - return 0; - } - return 1; -} - -// Struct representing a candidate encoded frame including its metadata. -typedef struct { - WebPMemoryWriter mem_; - WebPMuxFrameInfo info_; - FrameRectangle rect_; - int evaluate_; // True if this candidate should be evaluated. -} Candidate; - -// Generates a candidate encoded frame given a picture and metadata. -static WebPEncodingError EncodeCandidate(WebPPicture* const sub_frame, - const FrameRectangle* const rect, - const WebPConfig* const encoder_config, - int use_blending, - Candidate* const candidate) { - WebPConfig config = *encoder_config; - WebPEncodingError error_code = VP8_ENC_OK; - assert(candidate != NULL); - memset(candidate, 0, sizeof(*candidate)); - - // Set frame rect and info. - candidate->rect_ = *rect; - candidate->info_.id = WEBP_CHUNK_ANMF; - candidate->info_.x_offset = rect->x_offset_; - candidate->info_.y_offset = rect->y_offset_; - candidate->info_.dispose_method = WEBP_MUX_DISPOSE_NONE; // Set later. - candidate->info_.blend_method = - use_blending ? WEBP_MUX_BLEND : WEBP_MUX_NO_BLEND; - candidate->info_.duration = 0; // Set in next call to WebPAnimEncoderAdd(). - - // Encode picture. - WebPMemoryWriterInit(&candidate->mem_); - - if (!config.lossless && use_blending) { - // Disable filtering to avoid blockiness in reconstructed frames at the - // time of decoding. - config.autofilter = 0; - config.filter_strength = 0; - } - if (!EncodeFrame(&config, sub_frame, &candidate->mem_)) { - error_code = sub_frame->error_code; - goto Err; - } - - candidate->evaluate_ = 1; - return error_code; - - Err: - WebPMemoryWriterClear(&candidate->mem_); - return error_code; -} - -static void CopyCurrentCanvas(WebPAnimEncoder* const enc) { - if (enc->curr_canvas_copy_modified_) { - WebPCopyPixels(enc->curr_canvas_, &enc->curr_canvas_copy_); - enc->curr_canvas_copy_.progress_hook = enc->curr_canvas_->progress_hook; - enc->curr_canvas_copy_.user_data = enc->curr_canvas_->user_data; - enc->curr_canvas_copy_modified_ = 0; - } -} - -enum { - LL_DISP_NONE = 0, - LL_DISP_BG, - LOSSY_DISP_NONE, - LOSSY_DISP_BG, - CANDIDATE_COUNT -}; - -#define MIN_COLORS_LOSSY 31 // Don't try lossy below this threshold. -#define MAX_COLORS_LOSSLESS 194 // Don't try lossless above this threshold. - -// Generates candidates for a given dispose method given pre-filled sub-frame -// 'params'. -static WebPEncodingError GenerateCandidates( - WebPAnimEncoder* const enc, Candidate candidates[CANDIDATE_COUNT], - WebPMuxAnimDispose dispose_method, int is_lossless, int is_key_frame, - SubFrameParams* const params, - const WebPConfig* const config_ll, const WebPConfig* const config_lossy) { - WebPEncodingError error_code = VP8_ENC_OK; - const int is_dispose_none = (dispose_method == WEBP_MUX_DISPOSE_NONE); - Candidate* const candidate_ll = - is_dispose_none ? &candidates[LL_DISP_NONE] : &candidates[LL_DISP_BG]; - Candidate* const candidate_lossy = is_dispose_none - ? &candidates[LOSSY_DISP_NONE] - : &candidates[LOSSY_DISP_BG]; - WebPPicture* const curr_canvas = &enc->curr_canvas_copy_; - const WebPPicture* const prev_canvas = - is_dispose_none ? &enc->prev_canvas_ : &enc->prev_canvas_disposed_; - int use_blending_ll, use_blending_lossy; - int evaluate_ll, evaluate_lossy; - - CopyCurrentCanvas(enc); - use_blending_ll = - !is_key_frame && - IsLosslessBlendingPossible(prev_canvas, curr_canvas, ¶ms->rect_ll_); - use_blending_lossy = - !is_key_frame && - IsLossyBlendingPossible(prev_canvas, curr_canvas, ¶ms->rect_lossy_, - config_lossy->quality); - - // Pick candidates to be tried. - if (!enc->options_.allow_mixed) { - evaluate_ll = is_lossless; - evaluate_lossy = !is_lossless; - } else if (enc->options_.minimize_size) { - evaluate_ll = 1; - evaluate_lossy = 1; - } else { // Use a heuristic for trying lossless and/or lossy compression. - const int num_colors = WebPGetColorPalette(¶ms->sub_frame_ll_, NULL); - evaluate_ll = (num_colors < MAX_COLORS_LOSSLESS); - evaluate_lossy = (num_colors >= MIN_COLORS_LOSSY); - } - - // Generate candidates. - if (evaluate_ll) { - CopyCurrentCanvas(enc); - if (use_blending_ll) { - enc->curr_canvas_copy_modified_ = - IncreaseTransparency(prev_canvas, ¶ms->rect_ll_, curr_canvas); - } - error_code = EncodeCandidate(¶ms->sub_frame_ll_, ¶ms->rect_ll_, - config_ll, use_blending_ll, candidate_ll); - if (error_code != VP8_ENC_OK) return error_code; - } - if (evaluate_lossy) { - CopyCurrentCanvas(enc); - if (use_blending_lossy) { - enc->curr_canvas_copy_modified_ = - FlattenSimilarBlocks(prev_canvas, ¶ms->rect_lossy_, curr_canvas, - config_lossy->quality); - } - error_code = - EncodeCandidate(¶ms->sub_frame_lossy_, ¶ms->rect_lossy_, - config_lossy, use_blending_lossy, candidate_lossy); - if (error_code != VP8_ENC_OK) return error_code; - enc->curr_canvas_copy_modified_ = 1; - } - return error_code; -} - -#undef MIN_COLORS_LOSSY -#undef MAX_COLORS_LOSSLESS - -static void GetEncodedData(const WebPMemoryWriter* const memory, - WebPData* const encoded_data) { - encoded_data->bytes = memory->mem; - encoded_data->size = memory->size; -} - -// Sets dispose method of the previous frame to be 'dispose_method'. -static void SetPreviousDisposeMethod(WebPAnimEncoder* const enc, - WebPMuxAnimDispose dispose_method) { - const size_t position = enc->count_ - 2; - EncodedFrame* const prev_enc_frame = GetFrame(enc, position); - assert(enc->count_ >= 2); // As current and previous frames are in enc. - - if (enc->prev_candidate_undecided_) { - assert(dispose_method == WEBP_MUX_DISPOSE_NONE); - prev_enc_frame->sub_frame_.dispose_method = dispose_method; - prev_enc_frame->key_frame_.dispose_method = dispose_method; - } else { - WebPMuxFrameInfo* const prev_info = prev_enc_frame->is_key_frame_ - ? &prev_enc_frame->key_frame_ - : &prev_enc_frame->sub_frame_; - prev_info->dispose_method = dispose_method; - } -} - -static int IncreasePreviousDuration(WebPAnimEncoder* const enc, int duration) { - const size_t position = enc->count_ - 1; - EncodedFrame* const prev_enc_frame = GetFrame(enc, position); - int new_duration; - - assert(enc->count_ >= 1); - assert(!prev_enc_frame->is_key_frame_ || - prev_enc_frame->sub_frame_.duration == - prev_enc_frame->key_frame_.duration); - assert(prev_enc_frame->sub_frame_.duration == - (prev_enc_frame->sub_frame_.duration & (MAX_DURATION - 1))); - assert(duration == (duration & (MAX_DURATION - 1))); - - new_duration = prev_enc_frame->sub_frame_.duration + duration; - if (new_duration >= MAX_DURATION) { // Special case. - // Separate out previous frame from earlier merged frames to avoid overflow. - // We add a 1x1 transparent frame for the previous frame, with blending on. - const FrameRectangle rect = { 0, 0, 1, 1 }; - const uint8_t lossless_1x1_bytes[] = { - 0x52, 0x49, 0x46, 0x46, 0x14, 0x00, 0x00, 0x00, 0x57, 0x45, 0x42, 0x50, - 0x56, 0x50, 0x38, 0x4c, 0x08, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, - 0x10, 0x88, 0x88, 0x08 - }; - const WebPData lossless_1x1 = { - lossless_1x1_bytes, sizeof(lossless_1x1_bytes) - }; - const uint8_t lossy_1x1_bytes[] = { - 0x52, 0x49, 0x46, 0x46, 0x40, 0x00, 0x00, 0x00, 0x57, 0x45, 0x42, 0x50, - 0x56, 0x50, 0x38, 0x58, 0x0a, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x4c, 0x50, 0x48, 0x02, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x56, 0x50, 0x38, 0x20, 0x18, 0x00, 0x00, 0x00, - 0x30, 0x01, 0x00, 0x9d, 0x01, 0x2a, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, - 0x34, 0x25, 0xa4, 0x00, 0x03, 0x70, 0x00, 0xfe, 0xfb, 0xfd, 0x50, 0x00 - }; - const WebPData lossy_1x1 = { lossy_1x1_bytes, sizeof(lossy_1x1_bytes) }; - const int can_use_lossless = - (enc->last_config_.lossless || enc->options_.allow_mixed); - EncodedFrame* const curr_enc_frame = GetFrame(enc, enc->count_); - curr_enc_frame->is_key_frame_ = 0; - curr_enc_frame->sub_frame_.id = WEBP_CHUNK_ANMF; - curr_enc_frame->sub_frame_.x_offset = 0; - curr_enc_frame->sub_frame_.y_offset = 0; - curr_enc_frame->sub_frame_.dispose_method = WEBP_MUX_DISPOSE_NONE; - curr_enc_frame->sub_frame_.blend_method = WEBP_MUX_BLEND; - curr_enc_frame->sub_frame_.duration = duration; - if (!WebPDataCopy(can_use_lossless ? &lossless_1x1 : &lossy_1x1, - &curr_enc_frame->sub_frame_.bitstream)) { - return 0; - } - ++enc->count_; - ++enc->count_since_key_frame_; - enc->flush_count_ = enc->count_ - 1; - enc->prev_candidate_undecided_ = 0; - enc->prev_rect_ = rect; - } else { // Regular case. - // Increase duration of the previous frame by 'duration'. - prev_enc_frame->sub_frame_.duration = new_duration; - prev_enc_frame->key_frame_.duration = new_duration; - } - return 1; -} - -// Pick the candidate encoded frame with smallest size and release other -// candidates. -// TODO(later): Perhaps a rough SSIM/PSNR produced by the encoder should -// also be a criteria, in addition to sizes. -static void PickBestCandidate(WebPAnimEncoder* const enc, - Candidate* const candidates, int is_key_frame, - EncodedFrame* const encoded_frame) { - int i; - int best_idx = -1; - size_t best_size = ~0; - for (i = 0; i < CANDIDATE_COUNT; ++i) { - if (candidates[i].evaluate_) { - const size_t candidate_size = candidates[i].mem_.size; - if (candidate_size < best_size) { - best_idx = i; - best_size = candidate_size; - } - } - } - assert(best_idx != -1); - for (i = 0; i < CANDIDATE_COUNT; ++i) { - if (candidates[i].evaluate_) { - if (i == best_idx) { - WebPMuxFrameInfo* const dst = is_key_frame - ? &encoded_frame->key_frame_ - : &encoded_frame->sub_frame_; - *dst = candidates[i].info_; - GetEncodedData(&candidates[i].mem_, &dst->bitstream); - if (!is_key_frame) { - // Note: Previous dispose method only matters for non-keyframes. - // Also, we don't want to modify previous dispose method that was - // selected when a non key-frame was assumed. - const WebPMuxAnimDispose prev_dispose_method = - (best_idx == LL_DISP_NONE || best_idx == LOSSY_DISP_NONE) - ? WEBP_MUX_DISPOSE_NONE - : WEBP_MUX_DISPOSE_BACKGROUND; - SetPreviousDisposeMethod(enc, prev_dispose_method); - } - enc->prev_rect_ = candidates[i].rect_; // save for next frame. - } else { - WebPMemoryWriterClear(&candidates[i].mem_); - candidates[i].evaluate_ = 0; - } - } - } -} - -// Depending on the configuration, tries different compressions -// (lossy/lossless), dispose methods, blending methods etc to encode the current -// frame and outputs the best one in 'encoded_frame'. -// 'frame_skipped' will be set to true if this frame should actually be skipped. -static WebPEncodingError SetFrame(WebPAnimEncoder* const enc, - const WebPConfig* const config, - int is_key_frame, - EncodedFrame* const encoded_frame, - int* const frame_skipped) { - int i; - WebPEncodingError error_code = VP8_ENC_OK; - const WebPPicture* const curr_canvas = &enc->curr_canvas_copy_; - const WebPPicture* const prev_canvas = &enc->prev_canvas_; - Candidate candidates[CANDIDATE_COUNT]; - const int is_lossless = config->lossless; - const int consider_lossless = is_lossless || enc->options_.allow_mixed; - const int consider_lossy = !is_lossless || enc->options_.allow_mixed; - const int is_first_frame = enc->is_first_frame_; - - // First frame cannot be skipped as there is no 'previous frame' to merge it - // to. So, empty rectangle is not allowed for the first frame. - const int empty_rect_allowed_none = !is_first_frame; - - // Even if there is exact pixel match between 'disposed previous canvas' and - // 'current canvas', we can't skip current frame, as there may not be exact - // pixel match between 'previous canvas' and 'current canvas'. So, we don't - // allow empty rectangle in this case. - const int empty_rect_allowed_bg = 0; - - // If current frame is a key-frame, dispose method of previous frame doesn't - // matter, so we don't try dispose to background. - // Also, if key-frame insertion is on, and previous frame could be picked as - // either a sub-frame or a key-frame, then we can't be sure about what frame - // rectangle would be disposed. In that case too, we don't try dispose to - // background. - const int dispose_bg_possible = - !is_key_frame && !enc->prev_candidate_undecided_; - - SubFrameParams dispose_none_params; - SubFrameParams dispose_bg_params; - - WebPConfig config_ll = *config; - WebPConfig config_lossy = *config; - config_ll.lossless = 1; - config_lossy.lossless = 0; - enc->last_config_ = *config; - enc->last_config_reversed_ = config->lossless ? config_lossy : config_ll; - *frame_skipped = 0; - - if (!SubFrameParamsInit(&dispose_none_params, 1, empty_rect_allowed_none) || - !SubFrameParamsInit(&dispose_bg_params, 0, empty_rect_allowed_bg)) { - return VP8_ENC_ERROR_INVALID_CONFIGURATION; - } - - memset(candidates, 0, sizeof(candidates)); - - // Change-rectangle assuming previous frame was DISPOSE_NONE. - if (!GetSubRects(prev_canvas, curr_canvas, is_key_frame, is_first_frame, - config_lossy.quality, &dispose_none_params)) { - error_code = VP8_ENC_ERROR_INVALID_CONFIGURATION; - goto Err; - } - - if ((consider_lossless && IsEmptyRect(&dispose_none_params.rect_ll_)) || - (consider_lossy && IsEmptyRect(&dispose_none_params.rect_lossy_))) { - // Don't encode the frame at all. Instead, the duration of the previous - // frame will be increased later. - assert(empty_rect_allowed_none); - *frame_skipped = 1; - goto End; - } - - if (dispose_bg_possible) { - // Change-rectangle assuming previous frame was DISPOSE_BACKGROUND. - WebPPicture* const prev_canvas_disposed = &enc->prev_canvas_disposed_; - WebPCopyPixels(prev_canvas, prev_canvas_disposed); - DisposeFrameRectangle(WEBP_MUX_DISPOSE_BACKGROUND, &enc->prev_rect_, - prev_canvas_disposed); - - if (!GetSubRects(prev_canvas_disposed, curr_canvas, is_key_frame, - is_first_frame, config_lossy.quality, - &dispose_bg_params)) { - error_code = VP8_ENC_ERROR_INVALID_CONFIGURATION; - goto Err; - } - assert(!IsEmptyRect(&dispose_bg_params.rect_ll_)); - assert(!IsEmptyRect(&dispose_bg_params.rect_lossy_)); - - if (enc->options_.minimize_size) { // Try both dispose methods. - dispose_bg_params.should_try_ = 1; - dispose_none_params.should_try_ = 1; - } else if ((is_lossless && - RectArea(&dispose_bg_params.rect_ll_) < - RectArea(&dispose_none_params.rect_ll_)) || - (!is_lossless && - RectArea(&dispose_bg_params.rect_lossy_) < - RectArea(&dispose_none_params.rect_lossy_))) { - dispose_bg_params.should_try_ = 1; // Pick DISPOSE_BACKGROUND. - dispose_none_params.should_try_ = 0; - } - } - - if (dispose_none_params.should_try_) { - error_code = GenerateCandidates( - enc, candidates, WEBP_MUX_DISPOSE_NONE, is_lossless, is_key_frame, - &dispose_none_params, &config_ll, &config_lossy); - if (error_code != VP8_ENC_OK) goto Err; - } - - if (dispose_bg_params.should_try_) { - assert(!enc->is_first_frame_); - assert(dispose_bg_possible); - error_code = GenerateCandidates( - enc, candidates, WEBP_MUX_DISPOSE_BACKGROUND, is_lossless, is_key_frame, - &dispose_bg_params, &config_ll, &config_lossy); - if (error_code != VP8_ENC_OK) goto Err; - } - - PickBestCandidate(enc, candidates, is_key_frame, encoded_frame); - - goto End; - - Err: - for (i = 0; i < CANDIDATE_COUNT; ++i) { - if (candidates[i].evaluate_) { - WebPMemoryWriterClear(&candidates[i].mem_); - } - } - - End: - SubFrameParamsFree(&dispose_none_params); - SubFrameParamsFree(&dispose_bg_params); - return error_code; -} - -// Calculate the penalty incurred if we encode given frame as a key frame -// instead of a sub-frame. -static int64_t KeyFramePenalty(const EncodedFrame* const encoded_frame) { - return ((int64_t)encoded_frame->key_frame_.bitstream.size - - encoded_frame->sub_frame_.bitstream.size); -} - -static int CacheFrame(WebPAnimEncoder* const enc, - const WebPConfig* const config) { - int ok = 0; - int frame_skipped = 0; - WebPEncodingError error_code = VP8_ENC_OK; - const size_t position = enc->count_; - EncodedFrame* const encoded_frame = GetFrame(enc, position); - - ++enc->count_; - - if (enc->is_first_frame_) { // Add this as a key-frame. - error_code = SetFrame(enc, config, 1, encoded_frame, &frame_skipped); - if (error_code != VP8_ENC_OK) goto End; - assert(frame_skipped == 0); // First frame can't be skipped, even if empty. - assert(position == 0 && enc->count_ == 1); - encoded_frame->is_key_frame_ = 1; - enc->flush_count_ = 0; - enc->count_since_key_frame_ = 0; - enc->prev_candidate_undecided_ = 0; - } else { - ++enc->count_since_key_frame_; - if (enc->count_since_key_frame_ <= enc->options_.kmin) { - // Add this as a frame rectangle. - error_code = SetFrame(enc, config, 0, encoded_frame, &frame_skipped); - if (error_code != VP8_ENC_OK) goto End; - if (frame_skipped) goto Skip; - encoded_frame->is_key_frame_ = 0; - enc->flush_count_ = enc->count_ - 1; - enc->prev_candidate_undecided_ = 0; - } else { - int64_t curr_delta; - FrameRectangle prev_rect_key, prev_rect_sub; - - // Add this as a frame rectangle to enc. - error_code = SetFrame(enc, config, 0, encoded_frame, &frame_skipped); - if (error_code != VP8_ENC_OK) goto End; - if (frame_skipped) goto Skip; - prev_rect_sub = enc->prev_rect_; - - - // Add this as a key-frame to enc, too. - error_code = SetFrame(enc, config, 1, encoded_frame, &frame_skipped); - if (error_code != VP8_ENC_OK) goto End; - assert(frame_skipped == 0); // Key-frame cannot be an empty rectangle. - prev_rect_key = enc->prev_rect_; - - // Analyze size difference of the two variants. - curr_delta = KeyFramePenalty(encoded_frame); - if (curr_delta <= enc->best_delta_) { // Pick this as the key-frame. - if (enc->keyframe_ != KEYFRAME_NONE) { - EncodedFrame* const old_keyframe = GetFrame(enc, enc->keyframe_); - assert(old_keyframe->is_key_frame_); - old_keyframe->is_key_frame_ = 0; - } - encoded_frame->is_key_frame_ = 1; - enc->prev_candidate_undecided_ = 1; - enc->keyframe_ = (int)position; - enc->best_delta_ = curr_delta; - enc->flush_count_ = enc->count_ - 1; // We can flush previous frames. - } else { - encoded_frame->is_key_frame_ = 0; - enc->prev_candidate_undecided_ = 0; - } - // Note: We need '>=' below because when kmin and kmax are both zero, - // count_since_key_frame will always be > kmax. - if (enc->count_since_key_frame_ >= enc->options_.kmax) { - enc->flush_count_ = enc->count_ - 1; - enc->count_since_key_frame_ = 0; - enc->keyframe_ = KEYFRAME_NONE; - enc->best_delta_ = DELTA_INFINITY; - } - if (!enc->prev_candidate_undecided_) { - enc->prev_rect_ = - encoded_frame->is_key_frame_ ? prev_rect_key : prev_rect_sub; - } - } - } - - // Update previous to previous and previous canvases for next call. - WebPCopyPixels(enc->curr_canvas_, &enc->prev_canvas_); - enc->is_first_frame_ = 0; - - Skip: - ok = 1; - ++enc->in_frame_count_; - - End: - if (!ok || frame_skipped) { - FrameRelease(encoded_frame); - // We reset some counters, as the frame addition failed/was skipped. - --enc->count_; - if (!enc->is_first_frame_) --enc->count_since_key_frame_; - if (!ok) { - MarkError2(enc, "ERROR adding frame. WebPEncodingError", error_code); - } - } - enc->curr_canvas_->error_code = error_code; // report error_code - assert(ok || error_code != VP8_ENC_OK); - return ok; -} - -static int FlushFrames(WebPAnimEncoder* const enc) { - while (enc->flush_count_ > 0) { - WebPMuxError err; - EncodedFrame* const curr = GetFrame(enc, 0); - const WebPMuxFrameInfo* const info = - curr->is_key_frame_ ? &curr->key_frame_ : &curr->sub_frame_; - assert(enc->mux_ != NULL); - err = WebPMuxPushFrame(enc->mux_, info, 1); - if (err != WEBP_MUX_OK) { - MarkError2(enc, "ERROR adding frame. WebPMuxError", err); - return 0; - } - if (enc->options_.verbose) { - fprintf(stderr, "INFO: Added frame. offset:%d,%d dispose:%d blend:%d\n", - info->x_offset, info->y_offset, info->dispose_method, - info->blend_method); - } - ++enc->out_frame_count_; - FrameRelease(curr); - ++enc->start_; - --enc->flush_count_; - --enc->count_; - if (enc->keyframe_ != KEYFRAME_NONE) --enc->keyframe_; - } - - if (enc->count_ == 1 && enc->start_ != 0) { - // Move enc->start to index 0. - const int enc_start_tmp = (int)enc->start_; - EncodedFrame temp = enc->encoded_frames_[0]; - enc->encoded_frames_[0] = enc->encoded_frames_[enc_start_tmp]; - enc->encoded_frames_[enc_start_tmp] = temp; - FrameRelease(&enc->encoded_frames_[enc_start_tmp]); - enc->start_ = 0; - } - return 1; -} - -#undef DELTA_INFINITY -#undef KEYFRAME_NONE - -int WebPAnimEncoderAdd(WebPAnimEncoder* enc, WebPPicture* frame, int timestamp, - const WebPConfig* encoder_config) { - WebPConfig config; - int ok; - - if (enc == NULL) { - return 0; - } - MarkNoError(enc); - - if (!enc->is_first_frame_) { - // Make sure timestamps are non-decreasing (integer wrap-around is OK). - const uint32_t prev_frame_duration = - (uint32_t)timestamp - enc->prev_timestamp_; - if (prev_frame_duration >= MAX_DURATION) { - if (frame != NULL) { - frame->error_code = VP8_ENC_ERROR_INVALID_CONFIGURATION; - } - MarkError(enc, "ERROR adding frame: timestamps must be non-decreasing"); - return 0; - } - if (!IncreasePreviousDuration(enc, (int)prev_frame_duration)) { - return 0; - } - // IncreasePreviousDuration() may add a frame to avoid exceeding - // MAX_DURATION which could cause CacheFrame() to over read encoded_frames_ - // before the next flush. - if (enc->count_ == enc->size_ && !FlushFrames(enc)) { - return 0; - } - } else { - enc->first_timestamp_ = timestamp; - } - - if (frame == NULL) { // Special: last call. - enc->got_null_frame_ = 1; - enc->prev_timestamp_ = timestamp; - return 1; - } - - if (frame->width != enc->canvas_width_ || - frame->height != enc->canvas_height_) { - frame->error_code = VP8_ENC_ERROR_INVALID_CONFIGURATION; - MarkError(enc, "ERROR adding frame: Invalid frame dimensions"); - return 0; - } - - if (!frame->use_argb) { // Convert frame from YUV(A) to ARGB. - if (enc->options_.verbose) { - fprintf(stderr, "WARNING: Converting frame from YUV(A) to ARGB format; " - "this incurs a small loss.\n"); - } - if (!WebPPictureYUVAToARGB(frame)) { - MarkError(enc, "ERROR converting frame from YUV(A) to ARGB"); - return 0; - } - } - - if (encoder_config != NULL) { - if (!WebPValidateConfig(encoder_config)) { - MarkError(enc, "ERROR adding frame: Invalid WebPConfig"); - return 0; - } - config = *encoder_config; - } else { - if (!WebPConfigInit(&config)) { - MarkError(enc, "Cannot Init config"); - return 0; - } - config.lossless = 1; - } - assert(enc->curr_canvas_ == NULL); - enc->curr_canvas_ = frame; // Store reference. - assert(enc->curr_canvas_copy_modified_ == 1); - CopyCurrentCanvas(enc); - - ok = CacheFrame(enc, &config) && FlushFrames(enc); - - enc->curr_canvas_ = NULL; - enc->curr_canvas_copy_modified_ = 1; - if (ok) { - enc->prev_timestamp_ = timestamp; - } - return ok; -} - -// ----------------------------------------------------------------------------- -// Bitstream assembly. - -WEBP_NODISCARD static int DecodeFrameOntoCanvas( - const WebPMuxFrameInfo* const frame, WebPPicture* const canvas) { - const WebPData* const image = &frame->bitstream; - WebPPicture sub_image; - WebPDecoderConfig config; - if (!WebPInitDecoderConfig(&config)) { - return 0; - } - WebPUtilClearPic(canvas, NULL); - if (WebPGetFeatures(image->bytes, image->size, &config.input) != - VP8_STATUS_OK) { - return 0; - } - if (!WebPPictureView(canvas, frame->x_offset, frame->y_offset, - config.input.width, config.input.height, &sub_image)) { - return 0; - } - config.output.is_external_memory = 1; - config.output.colorspace = MODE_BGRA; - config.output.u.RGBA.rgba = (uint8_t*)sub_image.argb; - config.output.u.RGBA.stride = sub_image.argb_stride * 4; - config.output.u.RGBA.size = config.output.u.RGBA.stride * sub_image.height; - - if (WebPDecode(image->bytes, image->size, &config) != VP8_STATUS_OK) { - return 0; - } - return 1; -} - -static int FrameToFullCanvas(WebPAnimEncoder* const enc, - const WebPMuxFrameInfo* const frame, - WebPData* const full_image) { - WebPPicture* const canvas_buf = &enc->curr_canvas_copy_; - WebPMemoryWriter mem1, mem2; - WebPMemoryWriterInit(&mem1); - WebPMemoryWriterInit(&mem2); - - if (!DecodeFrameOntoCanvas(frame, canvas_buf)) goto Err; - if (!EncodeFrame(&enc->last_config_, canvas_buf, &mem1)) goto Err; - GetEncodedData(&mem1, full_image); - - if (enc->options_.allow_mixed) { - if (!EncodeFrame(&enc->last_config_reversed_, canvas_buf, &mem2)) goto Err; - if (mem2.size < mem1.size) { - GetEncodedData(&mem2, full_image); - WebPMemoryWriterClear(&mem1); - } else { - WebPMemoryWriterClear(&mem2); - } - } - return 1; - - Err: - WebPMemoryWriterClear(&mem1); - WebPMemoryWriterClear(&mem2); - return 0; -} - -// Convert a single-frame animation to a non-animated image if appropriate. -// TODO(urvang): Can we pick one of the two heuristically (based on frame -// rectangle and/or presence of alpha)? -static WebPMuxError OptimizeSingleFrame(WebPAnimEncoder* const enc, - WebPData* const webp_data) { - WebPMuxError err = WEBP_MUX_OK; - int canvas_width, canvas_height; - WebPMuxFrameInfo frame; - WebPData full_image; - WebPData webp_data2; - WebPMux* const mux = WebPMuxCreate(webp_data, 0); - if (mux == NULL) return WEBP_MUX_BAD_DATA; - assert(enc->out_frame_count_ == 1); - WebPDataInit(&frame.bitstream); - WebPDataInit(&full_image); - WebPDataInit(&webp_data2); - - err = WebPMuxGetFrame(mux, 1, &frame); - if (err != WEBP_MUX_OK) goto End; - if (frame.id != WEBP_CHUNK_ANMF) goto End; // Non-animation: nothing to do. - err = WebPMuxGetCanvasSize(mux, &canvas_width, &canvas_height); - if (err != WEBP_MUX_OK) goto End; - if (!FrameToFullCanvas(enc, &frame, &full_image)) { - err = WEBP_MUX_BAD_DATA; - goto End; - } - err = WebPMuxSetImage(mux, &full_image, 1); - if (err != WEBP_MUX_OK) goto End; - err = WebPMuxAssemble(mux, &webp_data2); - if (err != WEBP_MUX_OK) goto End; - - if (webp_data2.size < webp_data->size) { // Pick 'webp_data2' if smaller. - WebPDataClear(webp_data); - *webp_data = webp_data2; - WebPDataInit(&webp_data2); - } - - End: - WebPDataClear(&frame.bitstream); - WebPDataClear(&full_image); - WebPMuxDelete(mux); - WebPDataClear(&webp_data2); - return err; -} - -int WebPAnimEncoderAssemble(WebPAnimEncoder* enc, WebPData* webp_data) { - WebPMux* mux; - WebPMuxError err; - - if (enc == NULL) { - return 0; - } - MarkNoError(enc); - - if (webp_data == NULL) { - MarkError(enc, "ERROR assembling: NULL input"); - return 0; - } - - if (enc->in_frame_count_ == 0) { - MarkError(enc, "ERROR: No frames to assemble"); - return 0; - } - - if (!enc->got_null_frame_ && enc->in_frame_count_ > 1 && enc->count_ > 0) { - // set duration of the last frame to be avg of durations of previous frames. - const double delta_time = - (uint32_t)enc->prev_timestamp_ - enc->first_timestamp_; - const int average_duration = (int)(delta_time / (enc->in_frame_count_ - 1)); - if (!IncreasePreviousDuration(enc, average_duration)) { - return 0; - } - } - - // Flush any remaining frames. - enc->flush_count_ = enc->count_; - if (!FlushFrames(enc)) { - return 0; - } - - // Set definitive canvas size. - mux = enc->mux_; - err = WebPMuxSetCanvasSize(mux, enc->canvas_width_, enc->canvas_height_); - if (err != WEBP_MUX_OK) goto Err; - - err = WebPMuxSetAnimationParams(mux, &enc->options_.anim_params); - if (err != WEBP_MUX_OK) goto Err; - - // Assemble into a WebP bitstream. - err = WebPMuxAssemble(mux, webp_data); - if (err != WEBP_MUX_OK) goto Err; - - if (enc->out_frame_count_ == 1) { - err = OptimizeSingleFrame(enc, webp_data); - if (err != WEBP_MUX_OK) goto Err; - } - return 1; - - Err: - MarkError2(enc, "ERROR assembling WebP", err); - return 0; -} - -const char* WebPAnimEncoderGetError(WebPAnimEncoder* enc) { - if (enc == NULL) return NULL; - return enc->error_str_; -} - -WebPMuxError WebPAnimEncoderSetChunk( - WebPAnimEncoder* enc, const char fourcc[4], const WebPData* chunk_data, - int copy_data) { - if (enc == NULL) return WEBP_MUX_INVALID_ARGUMENT; - return WebPMuxSetChunk(enc->mux_, fourcc, chunk_data, copy_data); -} - -WebPMuxError WebPAnimEncoderGetChunk( - const WebPAnimEncoder* enc, const char fourcc[4], WebPData* chunk_data) { - if (enc == NULL) return WEBP_MUX_INVALID_ARGUMENT; - return WebPMuxGetChunk(enc->mux_, fourcc, chunk_data); -} - -WebPMuxError WebPAnimEncoderDeleteChunk( - WebPAnimEncoder* enc, const char fourcc[4]) { - if (enc == NULL) return WEBP_MUX_INVALID_ARGUMENT; - return WebPMuxDeleteChunk(enc->mux_, fourcc); -} - -// ----------------------------------------------------------------------------- diff --git a/libwebp/src/mux/animi.h b/libwebp/src/mux/animi.h deleted file mode 100644 index 34c45ba4..00000000 --- a/libwebp/src/mux/animi.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2016 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Internal header for animation related functions. -// -// Author: Hui Su (huisu@google.com) - -#ifndef WEBP_MUX_ANIMI_H_ -#define WEBP_MUX_ANIMI_H_ - -#include "src/webp/mux.h" - -#ifdef __cplusplus -extern "C" { -#endif - -// Picks the optimal rectangle between two pictures, starting with initial -// values of offsets and dimensions that are passed in. The initial -// values will be clipped, if necessary, to make sure the rectangle is -// within the canvas. "use_argb" must be true for both pictures. -// Parameters: -// prev_canvas, curr_canvas - (in) two input pictures to compare. -// is_lossless, quality - (in) encoding settings. -// x_offset, y_offset, width, height - (in/out) rectangle between the two -// input pictures. -// Returns true on success. -int WebPAnimEncoderRefineRect( - const struct WebPPicture* const prev_canvas, - const struct WebPPicture* const curr_canvas, - int is_lossless, float quality, int* const x_offset, int* const y_offset, - int* const width, int* const height); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // WEBP_MUX_ANIMI_H_ diff --git a/libwebp/src/mux/libwebpmux.pc.in b/libwebp/src/mux/libwebpmux.pc.in deleted file mode 100644 index c770daaf..00000000 --- a/libwebp/src/mux/libwebpmux.pc.in +++ /dev/null @@ -1,12 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: libwebpmux -Description: Library for manipulating the WebP graphics format container -Version: @PACKAGE_VERSION@ -Requires.private: libwebp >= 0.2.0 -Cflags: -I${includedir} -Libs: -L${libdir} -l@webp_libname_prefix@webpmux -Libs.private: -lm diff --git a/libwebp/src/mux/libwebpmux.rc b/libwebp/src/mux/libwebpmux.rc deleted file mode 100644 index bca38f6d..00000000 --- a/libwebp/src/mux/libwebpmux.rc +++ /dev/null @@ -1,41 +0,0 @@ -#define APSTUDIO_READONLY_SYMBOLS -#include "winres.h" -#undef APSTUDIO_READONLY_SYMBOLS - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US - -VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,0,3,2 - PRODUCTVERSION 1,0,3,2 - FILEFLAGSMASK 0x3fL -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x40004L - FILETYPE 0x2L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "CompanyName", "Google, Inc." - VALUE "FileDescription", "libwebpmux DLL" - VALUE "FileVersion", "1.3.2" - VALUE "InternalName", "libwebpmux.dll" - VALUE "LegalCopyright", "Copyright (C) 2023" - VALUE "OriginalFilename", "libwebpmux.dll" - VALUE "ProductName", "WebP Image Muxer" - VALUE "ProductVersion", "1.3.2" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - -#endif // English (United States) resources diff --git a/libwebp/src/mux/muxedit.c b/libwebp/src/mux/muxedit.c deleted file mode 100644 index 48c6834a..00000000 --- a/libwebp/src/mux/muxedit.c +++ /dev/null @@ -1,659 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Set and delete APIs for mux. -// -// Authors: Urvang (urvang@google.com) -// Vikas (vikasa@google.com) - -#include -#include "src/mux/muxi.h" -#include "src/utils/utils.h" - -//------------------------------------------------------------------------------ -// Life of a mux object. - -static void MuxInit(WebPMux* const mux) { - assert(mux != NULL); - memset(mux, 0, sizeof(*mux)); - mux->canvas_width_ = 0; // just to be explicit - mux->canvas_height_ = 0; -} - -WebPMux* WebPNewInternal(int version) { - if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_MUX_ABI_VERSION)) { - return NULL; - } else { - WebPMux* const mux = (WebPMux*)WebPSafeMalloc(1ULL, sizeof(WebPMux)); - if (mux != NULL) MuxInit(mux); - return mux; - } -} - -// Delete all images in 'wpi_list'. -static void DeleteAllImages(WebPMuxImage** const wpi_list) { - while (*wpi_list != NULL) { - *wpi_list = MuxImageDelete(*wpi_list); - } -} - -static void MuxRelease(WebPMux* const mux) { - assert(mux != NULL); - DeleteAllImages(&mux->images_); - ChunkListDelete(&mux->vp8x_); - ChunkListDelete(&mux->iccp_); - ChunkListDelete(&mux->anim_); - ChunkListDelete(&mux->exif_); - ChunkListDelete(&mux->xmp_); - ChunkListDelete(&mux->unknown_); -} - -void WebPMuxDelete(WebPMux* mux) { - if (mux != NULL) { - MuxRelease(mux); - WebPSafeFree(mux); - } -} - -//------------------------------------------------------------------------------ -// Helper method(s). - -// Handy MACRO, makes MuxSet() very symmetric to MuxGet(). -#define SWITCH_ID_LIST(INDEX, LIST) \ - do { \ - if (idx == (INDEX)) { \ - err = ChunkAssignData(&chunk, data, copy_data, tag); \ - if (err == WEBP_MUX_OK) { \ - err = ChunkSetHead(&chunk, (LIST)); \ - if (err != WEBP_MUX_OK) ChunkRelease(&chunk); \ - } \ - return err; \ - } \ - } while (0) - -static WebPMuxError MuxSet(WebPMux* const mux, uint32_t tag, - const WebPData* const data, int copy_data) { - WebPChunk chunk; - WebPMuxError err = WEBP_MUX_NOT_FOUND; - const CHUNK_INDEX idx = ChunkGetIndexFromTag(tag); - assert(mux != NULL); - assert(!IsWPI(kChunks[idx].id)); - - ChunkInit(&chunk); - SWITCH_ID_LIST(IDX_VP8X, &mux->vp8x_); - SWITCH_ID_LIST(IDX_ICCP, &mux->iccp_); - SWITCH_ID_LIST(IDX_ANIM, &mux->anim_); - SWITCH_ID_LIST(IDX_EXIF, &mux->exif_); - SWITCH_ID_LIST(IDX_XMP, &mux->xmp_); - SWITCH_ID_LIST(IDX_UNKNOWN, &mux->unknown_); - return err; -} -#undef SWITCH_ID_LIST - -// Create data for frame given image data, offsets and duration. -static WebPMuxError CreateFrameData( - int width, int height, const WebPMuxFrameInfo* const info, - WebPData* const frame) { - uint8_t* frame_bytes; - const size_t frame_size = kChunks[IDX_ANMF].size; - - assert(width > 0 && height > 0 && info->duration >= 0); - assert(info->dispose_method == (info->dispose_method & 1)); - // Note: assertion on upper bounds is done in PutLE24(). - - frame_bytes = (uint8_t*)WebPSafeMalloc(1ULL, frame_size); - if (frame_bytes == NULL) return WEBP_MUX_MEMORY_ERROR; - - PutLE24(frame_bytes + 0, info->x_offset / 2); - PutLE24(frame_bytes + 3, info->y_offset / 2); - - PutLE24(frame_bytes + 6, width - 1); - PutLE24(frame_bytes + 9, height - 1); - PutLE24(frame_bytes + 12, info->duration); - frame_bytes[15] = - (info->blend_method == WEBP_MUX_NO_BLEND ? 2 : 0) | - (info->dispose_method == WEBP_MUX_DISPOSE_BACKGROUND ? 1 : 0); - - frame->bytes = frame_bytes; - frame->size = frame_size; - return WEBP_MUX_OK; -} - -// Outputs image data given a bitstream. The bitstream can either be a -// single-image WebP file or raw VP8/VP8L data. -// Also outputs 'is_lossless' to be true if the given bitstream is lossless. -static WebPMuxError GetImageData(const WebPData* const bitstream, - WebPData* const image, WebPData* const alpha, - int* const is_lossless) { - WebPDataInit(alpha); // Default: no alpha. - if (bitstream->size < TAG_SIZE || - memcmp(bitstream->bytes, "RIFF", TAG_SIZE)) { - // It is NOT webp file data. Return input data as is. - *image = *bitstream; - } else { - // It is webp file data. Extract image data from it. - const WebPMuxImage* wpi; - WebPMux* const mux = WebPMuxCreate(bitstream, 0); - if (mux == NULL) return WEBP_MUX_BAD_DATA; - wpi = mux->images_; - assert(wpi != NULL && wpi->img_ != NULL); - *image = wpi->img_->data_; - if (wpi->alpha_ != NULL) { - *alpha = wpi->alpha_->data_; - } - WebPMuxDelete(mux); - } - *is_lossless = VP8LCheckSignature(image->bytes, image->size); - return WEBP_MUX_OK; -} - -static WebPMuxError DeleteChunks(WebPChunk** chunk_list, uint32_t tag) { - WebPMuxError err = WEBP_MUX_NOT_FOUND; - assert(chunk_list); - while (*chunk_list) { - WebPChunk* const chunk = *chunk_list; - if (chunk->tag_ == tag) { - *chunk_list = ChunkDelete(chunk); - err = WEBP_MUX_OK; - } else { - chunk_list = &chunk->next_; - } - } - return err; -} - -static WebPMuxError MuxDeleteAllNamedData(WebPMux* const mux, uint32_t tag) { - const WebPChunkId id = ChunkGetIdFromTag(tag); - assert(mux != NULL); - if (IsWPI(id)) return WEBP_MUX_INVALID_ARGUMENT; - return DeleteChunks(MuxGetChunkListFromId(mux, id), tag); -} - -//------------------------------------------------------------------------------ -// Set API(s). - -WebPMuxError WebPMuxSetChunk(WebPMux* mux, const char fourcc[4], - const WebPData* chunk_data, int copy_data) { - uint32_t tag; - WebPMuxError err; - if (mux == NULL || fourcc == NULL || chunk_data == NULL || - chunk_data->bytes == NULL || chunk_data->size > MAX_CHUNK_PAYLOAD) { - return WEBP_MUX_INVALID_ARGUMENT; - } - tag = ChunkGetTagFromFourCC(fourcc); - - // Delete existing chunk(s) with the same 'fourcc'. - err = MuxDeleteAllNamedData(mux, tag); - if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err; - - // Add the given chunk. - return MuxSet(mux, tag, chunk_data, copy_data); -} - -// Creates a chunk from given 'data' and sets it as 1st chunk in 'chunk_list'. -static WebPMuxError AddDataToChunkList( - const WebPData* const data, int copy_data, uint32_t tag, - WebPChunk** chunk_list) { - WebPChunk chunk; - WebPMuxError err; - ChunkInit(&chunk); - err = ChunkAssignData(&chunk, data, copy_data, tag); - if (err != WEBP_MUX_OK) goto Err; - err = ChunkSetHead(&chunk, chunk_list); - if (err != WEBP_MUX_OK) goto Err; - return WEBP_MUX_OK; - Err: - ChunkRelease(&chunk); - return err; -} - -// Extracts image & alpha data from the given bitstream and then sets wpi.alpha_ -// and wpi.img_ appropriately. -static WebPMuxError SetAlphaAndImageChunks( - const WebPData* const bitstream, int copy_data, WebPMuxImage* const wpi) { - int is_lossless = 0; - WebPData image, alpha; - WebPMuxError err = GetImageData(bitstream, &image, &alpha, &is_lossless); - const int image_tag = - is_lossless ? kChunks[IDX_VP8L].tag : kChunks[IDX_VP8].tag; - if (err != WEBP_MUX_OK) return err; - if (alpha.bytes != NULL) { - err = AddDataToChunkList(&alpha, copy_data, kChunks[IDX_ALPHA].tag, - &wpi->alpha_); - if (err != WEBP_MUX_OK) return err; - } - err = AddDataToChunkList(&image, copy_data, image_tag, &wpi->img_); - if (err != WEBP_MUX_OK) return err; - return MuxImageFinalize(wpi) ? WEBP_MUX_OK : WEBP_MUX_INVALID_ARGUMENT; -} - -WebPMuxError WebPMuxSetImage(WebPMux* mux, const WebPData* bitstream, - int copy_data) { - WebPMuxImage wpi; - WebPMuxError err; - - if (mux == NULL || bitstream == NULL || bitstream->bytes == NULL || - bitstream->size > MAX_CHUNK_PAYLOAD) { - return WEBP_MUX_INVALID_ARGUMENT; - } - - if (mux->images_ != NULL) { - // Only one 'simple image' can be added in mux. So, remove present images. - DeleteAllImages(&mux->images_); - } - - MuxImageInit(&wpi); - err = SetAlphaAndImageChunks(bitstream, copy_data, &wpi); - if (err != WEBP_MUX_OK) goto Err; - - // Add this WebPMuxImage to mux. - err = MuxImagePush(&wpi, &mux->images_); - if (err != WEBP_MUX_OK) goto Err; - - // All is well. - return WEBP_MUX_OK; - - Err: // Something bad happened. - MuxImageRelease(&wpi); - return err; -} - -WebPMuxError WebPMuxPushFrame(WebPMux* mux, const WebPMuxFrameInfo* info, - int copy_data) { - WebPMuxImage wpi; - WebPMuxError err; - - if (mux == NULL || info == NULL) return WEBP_MUX_INVALID_ARGUMENT; - - if (info->id != WEBP_CHUNK_ANMF) return WEBP_MUX_INVALID_ARGUMENT; - - if (info->bitstream.bytes == NULL || - info->bitstream.size > MAX_CHUNK_PAYLOAD) { - return WEBP_MUX_INVALID_ARGUMENT; - } - - if (mux->images_ != NULL) { - const WebPMuxImage* const image = mux->images_; - const uint32_t image_id = (image->header_ != NULL) ? - ChunkGetIdFromTag(image->header_->tag_) : WEBP_CHUNK_IMAGE; - if (image_id != info->id) { - return WEBP_MUX_INVALID_ARGUMENT; // Conflicting frame types. - } - } - - MuxImageInit(&wpi); - err = SetAlphaAndImageChunks(&info->bitstream, copy_data, &wpi); - if (err != WEBP_MUX_OK) goto Err; - assert(wpi.img_ != NULL); // As SetAlphaAndImageChunks() was successful. - - { - WebPData frame; - const uint32_t tag = kChunks[IDX_ANMF].tag; - WebPMuxFrameInfo tmp = *info; - tmp.x_offset &= ~1; // Snap offsets to even. - tmp.y_offset &= ~1; - if (tmp.x_offset < 0 || tmp.x_offset >= MAX_POSITION_OFFSET || - tmp.y_offset < 0 || tmp.y_offset >= MAX_POSITION_OFFSET || - (tmp.duration < 0 || tmp.duration >= MAX_DURATION) || - tmp.dispose_method != (tmp.dispose_method & 1)) { - err = WEBP_MUX_INVALID_ARGUMENT; - goto Err; - } - err = CreateFrameData(wpi.width_, wpi.height_, &tmp, &frame); - if (err != WEBP_MUX_OK) goto Err; - // Add frame chunk (with copy_data = 1). - err = AddDataToChunkList(&frame, 1, tag, &wpi.header_); - WebPDataClear(&frame); // frame owned by wpi.header_ now. - if (err != WEBP_MUX_OK) goto Err; - } - - // Add this WebPMuxImage to mux. - err = MuxImagePush(&wpi, &mux->images_); - if (err != WEBP_MUX_OK) goto Err; - - // All is well. - return WEBP_MUX_OK; - - Err: // Something bad happened. - MuxImageRelease(&wpi); - return err; -} - -WebPMuxError WebPMuxSetAnimationParams(WebPMux* mux, - const WebPMuxAnimParams* params) { - WebPMuxError err; - uint8_t data[ANIM_CHUNK_SIZE]; - const WebPData anim = { data, ANIM_CHUNK_SIZE }; - - if (mux == NULL || params == NULL) return WEBP_MUX_INVALID_ARGUMENT; - if (params->loop_count < 0 || params->loop_count >= MAX_LOOP_COUNT) { - return WEBP_MUX_INVALID_ARGUMENT; - } - - // Delete any existing ANIM chunk(s). - err = MuxDeleteAllNamedData(mux, kChunks[IDX_ANIM].tag); - if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err; - - // Set the animation parameters. - PutLE32(data, params->bgcolor); - PutLE16(data + 4, params->loop_count); - return MuxSet(mux, kChunks[IDX_ANIM].tag, &anim, 1); -} - -WebPMuxError WebPMuxSetCanvasSize(WebPMux* mux, - int width, int height) { - WebPMuxError err; - if (mux == NULL) { - return WEBP_MUX_INVALID_ARGUMENT; - } - if (width < 0 || height < 0 || - width > MAX_CANVAS_SIZE || height > MAX_CANVAS_SIZE) { - return WEBP_MUX_INVALID_ARGUMENT; - } - if (width * (uint64_t)height >= MAX_IMAGE_AREA) { - return WEBP_MUX_INVALID_ARGUMENT; - } - if ((width * height) == 0 && (width | height) != 0) { - // one of width / height is zero, but not both -> invalid! - return WEBP_MUX_INVALID_ARGUMENT; - } - // If we already assembled a VP8X chunk, invalidate it. - err = MuxDeleteAllNamedData(mux, kChunks[IDX_VP8X].tag); - if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err; - - mux->canvas_width_ = width; - mux->canvas_height_ = height; - return WEBP_MUX_OK; -} - -//------------------------------------------------------------------------------ -// Delete API(s). - -WebPMuxError WebPMuxDeleteChunk(WebPMux* mux, const char fourcc[4]) { - if (mux == NULL || fourcc == NULL) return WEBP_MUX_INVALID_ARGUMENT; - return MuxDeleteAllNamedData(mux, ChunkGetTagFromFourCC(fourcc)); -} - -WebPMuxError WebPMuxDeleteFrame(WebPMux* mux, uint32_t nth) { - if (mux == NULL) return WEBP_MUX_INVALID_ARGUMENT; - return MuxImageDeleteNth(&mux->images_, nth); -} - -//------------------------------------------------------------------------------ -// Assembly of the WebP RIFF file. - -static WebPMuxError GetFrameInfo( - const WebPChunk* const frame_chunk, - int* const x_offset, int* const y_offset, int* const duration) { - const WebPData* const data = &frame_chunk->data_; - const size_t expected_data_size = ANMF_CHUNK_SIZE; - assert(frame_chunk->tag_ == kChunks[IDX_ANMF].tag); - assert(frame_chunk != NULL); - if (data->size != expected_data_size) return WEBP_MUX_INVALID_ARGUMENT; - - *x_offset = 2 * GetLE24(data->bytes + 0); - *y_offset = 2 * GetLE24(data->bytes + 3); - *duration = GetLE24(data->bytes + 12); - return WEBP_MUX_OK; -} - -static WebPMuxError GetImageInfo(const WebPMuxImage* const wpi, - int* const x_offset, int* const y_offset, - int* const duration, - int* const width, int* const height) { - const WebPChunk* const frame_chunk = wpi->header_; - WebPMuxError err; - assert(wpi != NULL); - assert(frame_chunk != NULL); - - // Get offsets and duration from ANMF chunk. - err = GetFrameInfo(frame_chunk, x_offset, y_offset, duration); - if (err != WEBP_MUX_OK) return err; - - // Get width and height from VP8/VP8L chunk. - if (width != NULL) *width = wpi->width_; - if (height != NULL) *height = wpi->height_; - return WEBP_MUX_OK; -} - -// Returns the tightest dimension for the canvas considering the image list. -static WebPMuxError GetAdjustedCanvasSize(const WebPMux* const mux, - int* const width, int* const height) { - WebPMuxImage* wpi = NULL; - assert(mux != NULL); - assert(width != NULL && height != NULL); - - wpi = mux->images_; - assert(wpi != NULL); - assert(wpi->img_ != NULL); - - if (wpi->next_ != NULL) { - int max_x = 0, max_y = 0; - // if we have a chain of wpi's, header_ is necessarily set - assert(wpi->header_ != NULL); - // Aggregate the bounding box for animation frames. - for (; wpi != NULL; wpi = wpi->next_) { - int x_offset = 0, y_offset = 0, duration = 0, w = 0, h = 0; - const WebPMuxError err = GetImageInfo(wpi, &x_offset, &y_offset, - &duration, &w, &h); - const int max_x_pos = x_offset + w; - const int max_y_pos = y_offset + h; - if (err != WEBP_MUX_OK) return err; - assert(x_offset < MAX_POSITION_OFFSET); - assert(y_offset < MAX_POSITION_OFFSET); - - if (max_x_pos > max_x) max_x = max_x_pos; - if (max_y_pos > max_y) max_y = max_y_pos; - } - *width = max_x; - *height = max_y; - } else { - // For a single image, canvas dimensions are same as image dimensions. - *width = wpi->width_; - *height = wpi->height_; - } - return WEBP_MUX_OK; -} - -// VP8X format: -// Total Size : 10, -// Flags : 4 bytes, -// Width : 3 bytes, -// Height : 3 bytes. -static WebPMuxError CreateVP8XChunk(WebPMux* const mux) { - WebPMuxError err = WEBP_MUX_OK; - uint32_t flags = 0; - int width = 0; - int height = 0; - uint8_t data[VP8X_CHUNK_SIZE]; - const WebPData vp8x = { data, VP8X_CHUNK_SIZE }; - const WebPMuxImage* images = NULL; - - assert(mux != NULL); - images = mux->images_; // First image. - if (images == NULL || images->img_ == NULL || - images->img_->data_.bytes == NULL) { - return WEBP_MUX_INVALID_ARGUMENT; - } - - // If VP8X chunk(s) is(are) already present, remove them (and later add new - // VP8X chunk with updated flags). - err = MuxDeleteAllNamedData(mux, kChunks[IDX_VP8X].tag); - if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err; - - // Set flags. - if (mux->iccp_ != NULL && mux->iccp_->data_.bytes != NULL) { - flags |= ICCP_FLAG; - } - if (mux->exif_ != NULL && mux->exif_->data_.bytes != NULL) { - flags |= EXIF_FLAG; - } - if (mux->xmp_ != NULL && mux->xmp_->data_.bytes != NULL) { - flags |= XMP_FLAG; - } - if (images->header_ != NULL) { - if (images->header_->tag_ == kChunks[IDX_ANMF].tag) { - // This is an image with animation. - flags |= ANIMATION_FLAG; - } - } - if (MuxImageCount(images, WEBP_CHUNK_ALPHA) > 0) { - flags |= ALPHA_FLAG; // Some images have an alpha channel. - } - - err = GetAdjustedCanvasSize(mux, &width, &height); - if (err != WEBP_MUX_OK) return err; - - if (width <= 0 || height <= 0) { - return WEBP_MUX_INVALID_ARGUMENT; - } - if (width > MAX_CANVAS_SIZE || height > MAX_CANVAS_SIZE) { - return WEBP_MUX_INVALID_ARGUMENT; - } - - if (mux->canvas_width_ != 0 || mux->canvas_height_ != 0) { - if (width > mux->canvas_width_ || height > mux->canvas_height_) { - return WEBP_MUX_INVALID_ARGUMENT; - } - width = mux->canvas_width_; - height = mux->canvas_height_; - } - - if (flags == 0 && mux->unknown_ == NULL) { - // For simple file format, VP8X chunk should not be added. - return WEBP_MUX_OK; - } - - if (MuxHasAlpha(images)) { - // This means some frames explicitly/implicitly contain alpha. - // Note: This 'flags' update must NOT be done for a lossless image - // without a VP8X chunk! - flags |= ALPHA_FLAG; - } - - PutLE32(data + 0, flags); // VP8X chunk flags. - PutLE24(data + 4, width - 1); // canvas width. - PutLE24(data + 7, height - 1); // canvas height. - - return MuxSet(mux, kChunks[IDX_VP8X].tag, &vp8x, 1); -} - -// Cleans up 'mux' by removing any unnecessary chunks. -static WebPMuxError MuxCleanup(WebPMux* const mux) { - int num_frames; - int num_anim_chunks; - - // If we have an image with a single frame, and its rectangle - // covers the whole canvas, convert it to a non-animated image - // (to avoid writing ANMF chunk unnecessarily). - WebPMuxError err = WebPMuxNumChunks(mux, kChunks[IDX_ANMF].id, &num_frames); - if (err != WEBP_MUX_OK) return err; - if (num_frames == 1) { - WebPMuxImage* frame = NULL; - err = MuxImageGetNth((const WebPMuxImage**)&mux->images_, 1, &frame); - if (err != WEBP_MUX_OK) return err; - // We know that one frame does exist. - assert(frame != NULL); - if (frame->header_ != NULL && - ((mux->canvas_width_ == 0 && mux->canvas_height_ == 0) || - (frame->width_ == mux->canvas_width_ && - frame->height_ == mux->canvas_height_))) { - assert(frame->header_->tag_ == kChunks[IDX_ANMF].tag); - ChunkDelete(frame->header_); // Removes ANMF chunk. - frame->header_ = NULL; - num_frames = 0; - } - } - // Remove ANIM chunk if this is a non-animated image. - err = WebPMuxNumChunks(mux, kChunks[IDX_ANIM].id, &num_anim_chunks); - if (err != WEBP_MUX_OK) return err; - if (num_anim_chunks >= 1 && num_frames == 0) { - err = MuxDeleteAllNamedData(mux, kChunks[IDX_ANIM].tag); - if (err != WEBP_MUX_OK) return err; - } - return WEBP_MUX_OK; -} - -// Total size of a list of images. -static size_t ImageListDiskSize(const WebPMuxImage* wpi_list) { - size_t size = 0; - while (wpi_list != NULL) { - size += MuxImageDiskSize(wpi_list); - wpi_list = wpi_list->next_; - } - return size; -} - -// Write out the given list of images into 'dst'. -static uint8_t* ImageListEmit(const WebPMuxImage* wpi_list, uint8_t* dst) { - while (wpi_list != NULL) { - dst = MuxImageEmit(wpi_list, dst); - wpi_list = wpi_list->next_; - } - return dst; -} - -WebPMuxError WebPMuxAssemble(WebPMux* mux, WebPData* assembled_data) { - size_t size = 0; - uint8_t* data = NULL; - uint8_t* dst = NULL; - WebPMuxError err; - - if (assembled_data == NULL) { - return WEBP_MUX_INVALID_ARGUMENT; - } - // Clean up returned data, in case something goes wrong. - memset(assembled_data, 0, sizeof(*assembled_data)); - - if (mux == NULL) { - return WEBP_MUX_INVALID_ARGUMENT; - } - - // Finalize mux. - err = MuxCleanup(mux); - if (err != WEBP_MUX_OK) return err; - err = CreateVP8XChunk(mux); - if (err != WEBP_MUX_OK) return err; - - // Allocate data. - size = ChunkListDiskSize(mux->vp8x_) + ChunkListDiskSize(mux->iccp_) - + ChunkListDiskSize(mux->anim_) + ImageListDiskSize(mux->images_) - + ChunkListDiskSize(mux->exif_) + ChunkListDiskSize(mux->xmp_) - + ChunkListDiskSize(mux->unknown_) + RIFF_HEADER_SIZE; - - data = (uint8_t*)WebPSafeMalloc(1ULL, size); - if (data == NULL) return WEBP_MUX_MEMORY_ERROR; - - // Emit header & chunks. - dst = MuxEmitRiffHeader(data, size); - dst = ChunkListEmit(mux->vp8x_, dst); - dst = ChunkListEmit(mux->iccp_, dst); - dst = ChunkListEmit(mux->anim_, dst); - dst = ImageListEmit(mux->images_, dst); - dst = ChunkListEmit(mux->exif_, dst); - dst = ChunkListEmit(mux->xmp_, dst); - dst = ChunkListEmit(mux->unknown_, dst); - assert(dst == data + size); - - // Validate mux. - err = MuxValidate(mux); - if (err != WEBP_MUX_OK) { - WebPSafeFree(data); - data = NULL; - size = 0; - } - - // Finalize data. - assembled_data->bytes = data; - assembled_data->size = size; - - return err; -} - -//------------------------------------------------------------------------------ diff --git a/libwebp/src/mux/muxi.h b/libwebp/src/mux/muxi.h deleted file mode 100644 index afc59543..00000000 --- a/libwebp/src/mux/muxi.h +++ /dev/null @@ -1,234 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Internal header for mux library. -// -// Author: Urvang (urvang@google.com) - -#ifndef WEBP_MUX_MUXI_H_ -#define WEBP_MUX_MUXI_H_ - -#include -#include -#include "src/dec/vp8i_dec.h" -#include "src/dec/vp8li_dec.h" -#include "src/webp/mux.h" - -#ifdef __cplusplus -extern "C" { -#endif - -//------------------------------------------------------------------------------ -// Defines and constants. - -#define MUX_MAJ_VERSION 1 -#define MUX_MIN_VERSION 3 -#define MUX_REV_VERSION 2 - -// Chunk object. -typedef struct WebPChunk WebPChunk; -struct WebPChunk { - uint32_t tag_; - int owner_; // True if *data_ memory is owned internally. - // VP8X, ANIM, and other internally created chunks - // like ANMF are always owned. - WebPData data_; - WebPChunk* next_; -}; - -// MuxImage object. Store a full WebP image (including ANMF chunk, ALPH -// chunk and VP8/VP8L chunk), -typedef struct WebPMuxImage WebPMuxImage; -struct WebPMuxImage { - WebPChunk* header_; // Corresponds to WEBP_CHUNK_ANMF. - WebPChunk* alpha_; // Corresponds to WEBP_CHUNK_ALPHA. - WebPChunk* img_; // Corresponds to WEBP_CHUNK_IMAGE. - WebPChunk* unknown_; // Corresponds to WEBP_CHUNK_UNKNOWN. - int width_; - int height_; - int has_alpha_; // Through ALPH chunk or as part of VP8L. - int is_partial_; // True if only some of the chunks are filled. - WebPMuxImage* next_; -}; - -// Main mux object. Stores data chunks. -struct WebPMux { - WebPMuxImage* images_; - WebPChunk* iccp_; - WebPChunk* exif_; - WebPChunk* xmp_; - WebPChunk* anim_; - WebPChunk* vp8x_; - - WebPChunk* unknown_; - int canvas_width_; - int canvas_height_; -}; - -// CHUNK_INDEX enum: used for indexing within 'kChunks' (defined below) only. -// Note: the reason for having two enums ('WebPChunkId' and 'CHUNK_INDEX') is to -// allow two different chunks to have the same id (e.g. WebPChunkId -// 'WEBP_CHUNK_IMAGE' can correspond to CHUNK_INDEX 'IDX_VP8' or 'IDX_VP8L'). -typedef enum { - IDX_VP8X = 0, - IDX_ICCP, - IDX_ANIM, - IDX_ANMF, - IDX_ALPHA, - IDX_VP8, - IDX_VP8L, - IDX_EXIF, - IDX_XMP, - IDX_UNKNOWN, - - IDX_NIL, - IDX_LAST_CHUNK -} CHUNK_INDEX; - -#define NIL_TAG 0x00000000u // To signal void chunk. - -typedef struct { - uint32_t tag; - WebPChunkId id; - uint32_t size; -} ChunkInfo; - -extern const ChunkInfo kChunks[IDX_LAST_CHUNK]; - -//------------------------------------------------------------------------------ -// Chunk object management. - -// Initialize. -void ChunkInit(WebPChunk* const chunk); - -// Get chunk index from chunk tag. Returns IDX_UNKNOWN if not found. -CHUNK_INDEX ChunkGetIndexFromTag(uint32_t tag); - -// Get chunk id from chunk tag. Returns WEBP_CHUNK_UNKNOWN if not found. -WebPChunkId ChunkGetIdFromTag(uint32_t tag); - -// Convert a fourcc string to a tag. -uint32_t ChunkGetTagFromFourCC(const char fourcc[4]); - -// Get chunk index from fourcc. Returns IDX_UNKNOWN if given fourcc is unknown. -CHUNK_INDEX ChunkGetIndexFromFourCC(const char fourcc[4]); - -// Search for nth chunk with given 'tag' in the chunk list. -// nth = 0 means "last of the list". -WebPChunk* ChunkSearchList(WebPChunk* first, uint32_t nth, uint32_t tag); - -// Fill the chunk with the given data. -WebPMuxError ChunkAssignData(WebPChunk* chunk, const WebPData* const data, - int copy_data, uint32_t tag); - -// Sets 'chunk' as the only element in 'chunk_list' if it is empty. -// On success ownership is transferred from 'chunk' to the 'chunk_list'. -WebPMuxError ChunkSetHead(WebPChunk* const chunk, WebPChunk** const chunk_list); -// Sets 'chunk' at last position in the 'chunk_list'. -// On success ownership is transferred from 'chunk' to the 'chunk_list'. -// *chunk_list also points towards the last valid element of the initial -// *chunk_list. -WebPMuxError ChunkAppend(WebPChunk* const chunk, WebPChunk*** const chunk_list); - -// Releases chunk and returns chunk->next_. -WebPChunk* ChunkRelease(WebPChunk* const chunk); - -// Deletes given chunk & returns chunk->next_. -WebPChunk* ChunkDelete(WebPChunk* const chunk); - -// Deletes all chunks in the given chunk list. -void ChunkListDelete(WebPChunk** const chunk_list); - -// Returns size of the chunk including chunk header and padding byte (if any). -static WEBP_INLINE size_t SizeWithPadding(size_t chunk_size) { - assert(chunk_size <= MAX_CHUNK_PAYLOAD); - return CHUNK_HEADER_SIZE + ((chunk_size + 1) & ~1U); -} - -// Size of a chunk including header and padding. -static WEBP_INLINE size_t ChunkDiskSize(const WebPChunk* chunk) { - const size_t data_size = chunk->data_.size; - return SizeWithPadding(data_size); -} - -// Total size of a list of chunks. -size_t ChunkListDiskSize(const WebPChunk* chunk_list); - -// Write out the given list of chunks into 'dst'. -uint8_t* ChunkListEmit(const WebPChunk* chunk_list, uint8_t* dst); - -//------------------------------------------------------------------------------ -// MuxImage object management. - -// Initialize. -void MuxImageInit(WebPMuxImage* const wpi); - -// Releases image 'wpi' and returns wpi->next. -WebPMuxImage* MuxImageRelease(WebPMuxImage* const wpi); - -// Delete image 'wpi' and return the next image in the list or NULL. -// 'wpi' can be NULL. -WebPMuxImage* MuxImageDelete(WebPMuxImage* const wpi); - -// Count number of images matching the given tag id in the 'wpi_list'. -// If id == WEBP_CHUNK_NIL, all images will be matched. -int MuxImageCount(const WebPMuxImage* wpi_list, WebPChunkId id); - -// Update width/height/has_alpha info from chunks within wpi. -// Also remove ALPH chunk if not needed. -int MuxImageFinalize(WebPMuxImage* const wpi); - -// Check if given ID corresponds to an image related chunk. -static WEBP_INLINE int IsWPI(WebPChunkId id) { - switch (id) { - case WEBP_CHUNK_ANMF: - case WEBP_CHUNK_ALPHA: - case WEBP_CHUNK_IMAGE: return 1; - default: return 0; - } -} - -// Pushes 'wpi' at the end of 'wpi_list'. -WebPMuxError MuxImagePush(const WebPMuxImage* wpi, WebPMuxImage** wpi_list); - -// Delete nth image in the image list. -WebPMuxError MuxImageDeleteNth(WebPMuxImage** wpi_list, uint32_t nth); - -// Get nth image in the image list. -WebPMuxError MuxImageGetNth(const WebPMuxImage** wpi_list, uint32_t nth, - WebPMuxImage** wpi); - -// Total size of the given image. -size_t MuxImageDiskSize(const WebPMuxImage* const wpi); - -// Write out the given image into 'dst'. -uint8_t* MuxImageEmit(const WebPMuxImage* const wpi, uint8_t* dst); - -//------------------------------------------------------------------------------ -// Helper methods for mux. - -// Checks if the given image list contains at least one image with alpha. -int MuxHasAlpha(const WebPMuxImage* images); - -// Write out RIFF header into 'data', given total data size 'size'. -uint8_t* MuxEmitRiffHeader(uint8_t* const data, size_t size); - -// Returns the list where chunk with given ID is to be inserted in mux. -WebPChunk** MuxGetChunkListFromId(const WebPMux* mux, WebPChunkId id); - -// Validates the given mux object. -WebPMuxError MuxValidate(const WebPMux* const mux); - -//------------------------------------------------------------------------------ - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // WEBP_MUX_MUXI_H_ diff --git a/libwebp/src/mux/muxinternal.c b/libwebp/src/mux/muxinternal.c deleted file mode 100644 index 75b6b416..00000000 --- a/libwebp/src/mux/muxinternal.c +++ /dev/null @@ -1,549 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Internal objects and utils for mux. -// -// Authors: Urvang (urvang@google.com) -// Vikas (vikasa@google.com) - -#include -#include "src/mux/muxi.h" -#include "src/utils/utils.h" - -#define UNDEFINED_CHUNK_SIZE ((uint32_t)(-1)) - -const ChunkInfo kChunks[] = { - { MKFOURCC('V', 'P', '8', 'X'), WEBP_CHUNK_VP8X, VP8X_CHUNK_SIZE }, - { MKFOURCC('I', 'C', 'C', 'P'), WEBP_CHUNK_ICCP, UNDEFINED_CHUNK_SIZE }, - { MKFOURCC('A', 'N', 'I', 'M'), WEBP_CHUNK_ANIM, ANIM_CHUNK_SIZE }, - { MKFOURCC('A', 'N', 'M', 'F'), WEBP_CHUNK_ANMF, ANMF_CHUNK_SIZE }, - { MKFOURCC('A', 'L', 'P', 'H'), WEBP_CHUNK_ALPHA, UNDEFINED_CHUNK_SIZE }, - { MKFOURCC('V', 'P', '8', ' '), WEBP_CHUNK_IMAGE, UNDEFINED_CHUNK_SIZE }, - { MKFOURCC('V', 'P', '8', 'L'), WEBP_CHUNK_IMAGE, UNDEFINED_CHUNK_SIZE }, - { MKFOURCC('E', 'X', 'I', 'F'), WEBP_CHUNK_EXIF, UNDEFINED_CHUNK_SIZE }, - { MKFOURCC('X', 'M', 'P', ' '), WEBP_CHUNK_XMP, UNDEFINED_CHUNK_SIZE }, - { NIL_TAG, WEBP_CHUNK_UNKNOWN, UNDEFINED_CHUNK_SIZE }, - - { NIL_TAG, WEBP_CHUNK_NIL, UNDEFINED_CHUNK_SIZE } -}; - -//------------------------------------------------------------------------------ - -int WebPGetMuxVersion(void) { - return (MUX_MAJ_VERSION << 16) | (MUX_MIN_VERSION << 8) | MUX_REV_VERSION; -} - -//------------------------------------------------------------------------------ -// Life of a chunk object. - -void ChunkInit(WebPChunk* const chunk) { - assert(chunk); - memset(chunk, 0, sizeof(*chunk)); - chunk->tag_ = NIL_TAG; -} - -WebPChunk* ChunkRelease(WebPChunk* const chunk) { - WebPChunk* next; - if (chunk == NULL) return NULL; - if (chunk->owner_) { - WebPDataClear(&chunk->data_); - } - next = chunk->next_; - ChunkInit(chunk); - return next; -} - -//------------------------------------------------------------------------------ -// Chunk misc methods. - -CHUNK_INDEX ChunkGetIndexFromTag(uint32_t tag) { - int i; - for (i = 0; kChunks[i].tag != NIL_TAG; ++i) { - if (tag == kChunks[i].tag) return (CHUNK_INDEX)i; - } - return IDX_UNKNOWN; -} - -WebPChunkId ChunkGetIdFromTag(uint32_t tag) { - int i; - for (i = 0; kChunks[i].tag != NIL_TAG; ++i) { - if (tag == kChunks[i].tag) return kChunks[i].id; - } - return WEBP_CHUNK_UNKNOWN; -} - -uint32_t ChunkGetTagFromFourCC(const char fourcc[4]) { - return MKFOURCC(fourcc[0], fourcc[1], fourcc[2], fourcc[3]); -} - -CHUNK_INDEX ChunkGetIndexFromFourCC(const char fourcc[4]) { - const uint32_t tag = ChunkGetTagFromFourCC(fourcc); - return ChunkGetIndexFromTag(tag); -} - -//------------------------------------------------------------------------------ -// Chunk search methods. - -// Returns next chunk in the chunk list with the given tag. -static WebPChunk* ChunkSearchNextInList(WebPChunk* chunk, uint32_t tag) { - while (chunk != NULL && chunk->tag_ != tag) { - chunk = chunk->next_; - } - return chunk; -} - -WebPChunk* ChunkSearchList(WebPChunk* first, uint32_t nth, uint32_t tag) { - uint32_t iter = nth; - first = ChunkSearchNextInList(first, tag); - if (first == NULL) return NULL; - - while (--iter != 0) { - WebPChunk* next_chunk = ChunkSearchNextInList(first->next_, tag); - if (next_chunk == NULL) break; - first = next_chunk; - } - return ((nth > 0) && (iter > 0)) ? NULL : first; -} - -//------------------------------------------------------------------------------ -// Chunk writer methods. - -WebPMuxError ChunkAssignData(WebPChunk* chunk, const WebPData* const data, - int copy_data, uint32_t tag) { - // For internally allocated chunks, always copy data & make it owner of data. - if (tag == kChunks[IDX_VP8X].tag || tag == kChunks[IDX_ANIM].tag) { - copy_data = 1; - } - - ChunkRelease(chunk); - - if (data != NULL) { - if (copy_data) { // Copy data. - if (!WebPDataCopy(data, &chunk->data_)) return WEBP_MUX_MEMORY_ERROR; - chunk->owner_ = 1; // Chunk is owner of data. - } else { // Don't copy data. - chunk->data_ = *data; - } - } - chunk->tag_ = tag; - return WEBP_MUX_OK; -} - -WebPMuxError ChunkSetHead(WebPChunk* const chunk, - WebPChunk** const chunk_list) { - WebPChunk* new_chunk; - - assert(chunk_list != NULL); - if (*chunk_list != NULL) { - return WEBP_MUX_NOT_FOUND; - } - - new_chunk = (WebPChunk*)WebPSafeMalloc(1ULL, sizeof(*new_chunk)); - if (new_chunk == NULL) return WEBP_MUX_MEMORY_ERROR; - *new_chunk = *chunk; - chunk->owner_ = 0; - new_chunk->next_ = NULL; - *chunk_list = new_chunk; - return WEBP_MUX_OK; -} - -WebPMuxError ChunkAppend(WebPChunk* const chunk, - WebPChunk*** const chunk_list) { - WebPMuxError err; - assert(chunk_list != NULL && *chunk_list != NULL); - - if (**chunk_list == NULL) { - err = ChunkSetHead(chunk, *chunk_list); - } else { - WebPChunk* last_chunk = **chunk_list; - while (last_chunk->next_ != NULL) last_chunk = last_chunk->next_; - err = ChunkSetHead(chunk, &last_chunk->next_); - if (err == WEBP_MUX_OK) *chunk_list = &last_chunk->next_; - } - return err; -} - -//------------------------------------------------------------------------------ -// Chunk deletion method(s). - -WebPChunk* ChunkDelete(WebPChunk* const chunk) { - WebPChunk* const next = ChunkRelease(chunk); - WebPSafeFree(chunk); - return next; -} - -void ChunkListDelete(WebPChunk** const chunk_list) { - while (*chunk_list != NULL) { - *chunk_list = ChunkDelete(*chunk_list); - } -} - -//------------------------------------------------------------------------------ -// Chunk serialization methods. - -static uint8_t* ChunkEmit(const WebPChunk* const chunk, uint8_t* dst) { - const size_t chunk_size = chunk->data_.size; - assert(chunk); - assert(chunk->tag_ != NIL_TAG); - PutLE32(dst + 0, chunk->tag_); - PutLE32(dst + TAG_SIZE, (uint32_t)chunk_size); - assert(chunk_size == (uint32_t)chunk_size); - memcpy(dst + CHUNK_HEADER_SIZE, chunk->data_.bytes, chunk_size); - if (chunk_size & 1) - dst[CHUNK_HEADER_SIZE + chunk_size] = 0; // Add padding. - return dst + ChunkDiskSize(chunk); -} - -uint8_t* ChunkListEmit(const WebPChunk* chunk_list, uint8_t* dst) { - while (chunk_list != NULL) { - dst = ChunkEmit(chunk_list, dst); - chunk_list = chunk_list->next_; - } - return dst; -} - -size_t ChunkListDiskSize(const WebPChunk* chunk_list) { - size_t size = 0; - while (chunk_list != NULL) { - size += ChunkDiskSize(chunk_list); - chunk_list = chunk_list->next_; - } - return size; -} - -//------------------------------------------------------------------------------ -// Life of a MuxImage object. - -void MuxImageInit(WebPMuxImage* const wpi) { - assert(wpi); - memset(wpi, 0, sizeof(*wpi)); -} - -WebPMuxImage* MuxImageRelease(WebPMuxImage* const wpi) { - WebPMuxImage* next; - if (wpi == NULL) return NULL; - // There should be at most one chunk of header_, alpha_, img_ but we call - // ChunkListDelete to be safe - ChunkListDelete(&wpi->header_); - ChunkListDelete(&wpi->alpha_); - ChunkListDelete(&wpi->img_); - ChunkListDelete(&wpi->unknown_); - - next = wpi->next_; - MuxImageInit(wpi); - return next; -} - -//------------------------------------------------------------------------------ -// MuxImage search methods. - -// Get a reference to appropriate chunk list within an image given chunk tag. -static WebPChunk** GetChunkListFromId(const WebPMuxImage* const wpi, - WebPChunkId id) { - assert(wpi != NULL); - switch (id) { - case WEBP_CHUNK_ANMF: return (WebPChunk**)&wpi->header_; - case WEBP_CHUNK_ALPHA: return (WebPChunk**)&wpi->alpha_; - case WEBP_CHUNK_IMAGE: return (WebPChunk**)&wpi->img_; - default: return NULL; - } -} - -int MuxImageCount(const WebPMuxImage* wpi_list, WebPChunkId id) { - int count = 0; - const WebPMuxImage* current; - for (current = wpi_list; current != NULL; current = current->next_) { - if (id == WEBP_CHUNK_NIL) { - ++count; // Special case: count all images. - } else { - const WebPChunk* const wpi_chunk = *GetChunkListFromId(current, id); - if (wpi_chunk != NULL) { - const WebPChunkId wpi_chunk_id = ChunkGetIdFromTag(wpi_chunk->tag_); - if (wpi_chunk_id == id) ++count; // Count images with a matching 'id'. - } - } - } - return count; -} - -// Outputs a pointer to 'prev_wpi->next_', -// where 'prev_wpi' is the pointer to the image at position (nth - 1). -// Returns true if nth image was found. -static int SearchImageToGetOrDelete(WebPMuxImage** wpi_list, uint32_t nth, - WebPMuxImage*** const location) { - uint32_t count = 0; - assert(wpi_list); - *location = wpi_list; - - if (nth == 0) { - nth = MuxImageCount(*wpi_list, WEBP_CHUNK_NIL); - if (nth == 0) return 0; // Not found. - } - - while (*wpi_list != NULL) { - WebPMuxImage* const cur_wpi = *wpi_list; - ++count; - if (count == nth) return 1; // Found. - wpi_list = &cur_wpi->next_; - *location = wpi_list; - } - return 0; // Not found. -} - -//------------------------------------------------------------------------------ -// MuxImage writer methods. - -WebPMuxError MuxImagePush(const WebPMuxImage* wpi, WebPMuxImage** wpi_list) { - WebPMuxImage* new_wpi; - - while (*wpi_list != NULL) { - WebPMuxImage* const cur_wpi = *wpi_list; - if (cur_wpi->next_ == NULL) break; - wpi_list = &cur_wpi->next_; - } - - new_wpi = (WebPMuxImage*)WebPSafeMalloc(1ULL, sizeof(*new_wpi)); - if (new_wpi == NULL) return WEBP_MUX_MEMORY_ERROR; - *new_wpi = *wpi; - new_wpi->next_ = NULL; - - if (*wpi_list != NULL) { - (*wpi_list)->next_ = new_wpi; - } else { - *wpi_list = new_wpi; - } - return WEBP_MUX_OK; -} - -//------------------------------------------------------------------------------ -// MuxImage deletion methods. - -WebPMuxImage* MuxImageDelete(WebPMuxImage* const wpi) { - // Delete the components of wpi. If wpi is NULL this is a noop. - WebPMuxImage* const next = MuxImageRelease(wpi); - WebPSafeFree(wpi); - return next; -} - -WebPMuxError MuxImageDeleteNth(WebPMuxImage** wpi_list, uint32_t nth) { - assert(wpi_list); - if (!SearchImageToGetOrDelete(wpi_list, nth, &wpi_list)) { - return WEBP_MUX_NOT_FOUND; - } - *wpi_list = MuxImageDelete(*wpi_list); - return WEBP_MUX_OK; -} - -//------------------------------------------------------------------------------ -// MuxImage reader methods. - -WebPMuxError MuxImageGetNth(const WebPMuxImage** wpi_list, uint32_t nth, - WebPMuxImage** wpi) { - assert(wpi_list); - assert(wpi); - if (!SearchImageToGetOrDelete((WebPMuxImage**)wpi_list, nth, - (WebPMuxImage***)&wpi_list)) { - return WEBP_MUX_NOT_FOUND; - } - *wpi = (WebPMuxImage*)*wpi_list; - return WEBP_MUX_OK; -} - -//------------------------------------------------------------------------------ -// MuxImage serialization methods. - -// Size of an image. -size_t MuxImageDiskSize(const WebPMuxImage* const wpi) { - size_t size = 0; - if (wpi->header_ != NULL) size += ChunkDiskSize(wpi->header_); - if (wpi->alpha_ != NULL) size += ChunkDiskSize(wpi->alpha_); - if (wpi->img_ != NULL) size += ChunkDiskSize(wpi->img_); - if (wpi->unknown_ != NULL) size += ChunkListDiskSize(wpi->unknown_); - return size; -} - -// Special case as ANMF chunk encapsulates other image chunks. -static uint8_t* ChunkEmitSpecial(const WebPChunk* const header, - size_t total_size, uint8_t* dst) { - const size_t header_size = header->data_.size; - const size_t offset_to_next = total_size - CHUNK_HEADER_SIZE; - assert(header->tag_ == kChunks[IDX_ANMF].tag); - PutLE32(dst + 0, header->tag_); - PutLE32(dst + TAG_SIZE, (uint32_t)offset_to_next); - assert(header_size == (uint32_t)header_size); - memcpy(dst + CHUNK_HEADER_SIZE, header->data_.bytes, header_size); - if (header_size & 1) { - dst[CHUNK_HEADER_SIZE + header_size] = 0; // Add padding. - } - return dst + ChunkDiskSize(header); -} - -uint8_t* MuxImageEmit(const WebPMuxImage* const wpi, uint8_t* dst) { - // Ordering of chunks to be emitted is strictly as follows: - // 1. ANMF chunk (if present). - // 2. ALPH chunk (if present). - // 3. VP8/VP8L chunk. - assert(wpi); - if (wpi->header_ != NULL) { - dst = ChunkEmitSpecial(wpi->header_, MuxImageDiskSize(wpi), dst); - } - if (wpi->alpha_ != NULL) dst = ChunkEmit(wpi->alpha_, dst); - if (wpi->img_ != NULL) dst = ChunkEmit(wpi->img_, dst); - if (wpi->unknown_ != NULL) dst = ChunkListEmit(wpi->unknown_, dst); - return dst; -} - -//------------------------------------------------------------------------------ -// Helper methods for mux. - -int MuxHasAlpha(const WebPMuxImage* images) { - while (images != NULL) { - if (images->has_alpha_) return 1; - images = images->next_; - } - return 0; -} - -uint8_t* MuxEmitRiffHeader(uint8_t* const data, size_t size) { - PutLE32(data + 0, MKFOURCC('R', 'I', 'F', 'F')); - PutLE32(data + TAG_SIZE, (uint32_t)size - CHUNK_HEADER_SIZE); - assert(size == (uint32_t)size); - PutLE32(data + TAG_SIZE + CHUNK_SIZE_BYTES, MKFOURCC('W', 'E', 'B', 'P')); - return data + RIFF_HEADER_SIZE; -} - -WebPChunk** MuxGetChunkListFromId(const WebPMux* mux, WebPChunkId id) { - assert(mux != NULL); - switch (id) { - case WEBP_CHUNK_VP8X: return (WebPChunk**)&mux->vp8x_; - case WEBP_CHUNK_ICCP: return (WebPChunk**)&mux->iccp_; - case WEBP_CHUNK_ANIM: return (WebPChunk**)&mux->anim_; - case WEBP_CHUNK_EXIF: return (WebPChunk**)&mux->exif_; - case WEBP_CHUNK_XMP: return (WebPChunk**)&mux->xmp_; - default: return (WebPChunk**)&mux->unknown_; - } -} - -static int IsNotCompatible(int feature, int num_items) { - return (feature != 0) != (num_items > 0); -} - -#define NO_FLAG ((WebPFeatureFlags)0) - -// Test basic constraints: -// retrieval, maximum number of chunks by index (use -1 to skip) -// and feature incompatibility (use NO_FLAG to skip). -// On success returns WEBP_MUX_OK and stores the chunk count in *num. -static WebPMuxError ValidateChunk(const WebPMux* const mux, CHUNK_INDEX idx, - WebPFeatureFlags feature, - uint32_t vp8x_flags, - int max, int* num) { - const WebPMuxError err = - WebPMuxNumChunks(mux, kChunks[idx].id, num); - if (err != WEBP_MUX_OK) return err; - if (max > -1 && *num > max) return WEBP_MUX_INVALID_ARGUMENT; - if (feature != NO_FLAG && IsNotCompatible(vp8x_flags & feature, *num)) { - return WEBP_MUX_INVALID_ARGUMENT; - } - return WEBP_MUX_OK; -} - -WebPMuxError MuxValidate(const WebPMux* const mux) { - int num_iccp; - int num_exif; - int num_xmp; - int num_anim; - int num_frames; - int num_vp8x; - int num_images; - int num_alpha; - uint32_t flags; - WebPMuxError err; - - // Verify mux is not NULL. - if (mux == NULL) return WEBP_MUX_INVALID_ARGUMENT; - - // Verify mux has at least one image. - if (mux->images_ == NULL) return WEBP_MUX_INVALID_ARGUMENT; - - err = WebPMuxGetFeatures(mux, &flags); - if (err != WEBP_MUX_OK) return err; - - // At most one color profile chunk. - err = ValidateChunk(mux, IDX_ICCP, ICCP_FLAG, flags, 1, &num_iccp); - if (err != WEBP_MUX_OK) return err; - - // At most one EXIF metadata. - err = ValidateChunk(mux, IDX_EXIF, EXIF_FLAG, flags, 1, &num_exif); - if (err != WEBP_MUX_OK) return err; - - // At most one XMP metadata. - err = ValidateChunk(mux, IDX_XMP, XMP_FLAG, flags, 1, &num_xmp); - if (err != WEBP_MUX_OK) return err; - - // Animation: ANIMATION_FLAG, ANIM chunk and ANMF chunk(s) are consistent. - // At most one ANIM chunk. - err = ValidateChunk(mux, IDX_ANIM, NO_FLAG, flags, 1, &num_anim); - if (err != WEBP_MUX_OK) return err; - err = ValidateChunk(mux, IDX_ANMF, NO_FLAG, flags, -1, &num_frames); - if (err != WEBP_MUX_OK) return err; - - { - const int has_animation = !!(flags & ANIMATION_FLAG); - if (has_animation && (num_anim == 0 || num_frames == 0)) { - return WEBP_MUX_INVALID_ARGUMENT; - } - if (!has_animation && (num_anim == 1 || num_frames > 0)) { - return WEBP_MUX_INVALID_ARGUMENT; - } - if (!has_animation) { - const WebPMuxImage* images = mux->images_; - // There can be only one image. - if (images == NULL || images->next_ != NULL) { - return WEBP_MUX_INVALID_ARGUMENT; - } - // Size must match. - if (mux->canvas_width_ > 0) { - if (images->width_ != mux->canvas_width_ || - images->height_ != mux->canvas_height_) { - return WEBP_MUX_INVALID_ARGUMENT; - } - } - } - } - - // Verify either VP8X chunk is present OR there is only one elem in - // mux->images_. - err = ValidateChunk(mux, IDX_VP8X, NO_FLAG, flags, 1, &num_vp8x); - if (err != WEBP_MUX_OK) return err; - err = ValidateChunk(mux, IDX_VP8, NO_FLAG, flags, -1, &num_images); - if (err != WEBP_MUX_OK) return err; - if (num_vp8x == 0 && num_images != 1) return WEBP_MUX_INVALID_ARGUMENT; - - // ALPHA_FLAG & alpha chunk(s) are consistent. - // Note: ALPHA_FLAG can be set when there is actually no Alpha data present. - if (MuxHasAlpha(mux->images_)) { - if (num_vp8x > 0) { - // VP8X chunk is present, so it should contain ALPHA_FLAG. - if (!(flags & ALPHA_FLAG)) return WEBP_MUX_INVALID_ARGUMENT; - } else { - // VP8X chunk is not present, so ALPH chunks should NOT be present either. - err = WebPMuxNumChunks(mux, WEBP_CHUNK_ALPHA, &num_alpha); - if (err != WEBP_MUX_OK) return err; - if (num_alpha > 0) return WEBP_MUX_INVALID_ARGUMENT; - } - } - - return WEBP_MUX_OK; -} - -#undef NO_FLAG - -//------------------------------------------------------------------------------ - diff --git a/libwebp/src/mux/muxread.c b/libwebp/src/mux/muxread.c deleted file mode 100644 index 37ddd901..00000000 --- a/libwebp/src/mux/muxread.c +++ /dev/null @@ -1,559 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Read APIs for mux. -// -// Authors: Urvang (urvang@google.com) -// Vikas (vikasa@google.com) - -#include -#include "src/mux/muxi.h" -#include "src/utils/utils.h" - -//------------------------------------------------------------------------------ -// Helper method(s). - -// Handy MACRO. -#define SWITCH_ID_LIST(INDEX, LIST) \ - do { \ - if (idx == (INDEX)) { \ - const WebPChunk* const chunk = ChunkSearchList((LIST), nth, \ - kChunks[(INDEX)].tag); \ - if (chunk) { \ - *data = chunk->data_; \ - return WEBP_MUX_OK; \ - } else { \ - return WEBP_MUX_NOT_FOUND; \ - } \ - } \ - } while (0) - -static WebPMuxError MuxGet(const WebPMux* const mux, CHUNK_INDEX idx, - uint32_t nth, WebPData* const data) { - assert(mux != NULL); - assert(!IsWPI(kChunks[idx].id)); - WebPDataInit(data); - - SWITCH_ID_LIST(IDX_VP8X, mux->vp8x_); - SWITCH_ID_LIST(IDX_ICCP, mux->iccp_); - SWITCH_ID_LIST(IDX_ANIM, mux->anim_); - SWITCH_ID_LIST(IDX_EXIF, mux->exif_); - SWITCH_ID_LIST(IDX_XMP, mux->xmp_); - assert(idx != IDX_UNKNOWN); - return WEBP_MUX_NOT_FOUND; -} -#undef SWITCH_ID_LIST - -// Fill the chunk with the given data (includes chunk header bytes), after some -// verifications. -static WebPMuxError ChunkVerifyAndAssign(WebPChunk* chunk, - const uint8_t* data, size_t data_size, - size_t riff_size, int copy_data) { - uint32_t chunk_size; - WebPData chunk_data; - - // Correctness checks. - if (data_size < CHUNK_HEADER_SIZE) return WEBP_MUX_NOT_ENOUGH_DATA; - chunk_size = GetLE32(data + TAG_SIZE); - if (chunk_size > MAX_CHUNK_PAYLOAD) return WEBP_MUX_BAD_DATA; - - { - const size_t chunk_disk_size = SizeWithPadding(chunk_size); - if (chunk_disk_size > riff_size) return WEBP_MUX_BAD_DATA; - if (chunk_disk_size > data_size) return WEBP_MUX_NOT_ENOUGH_DATA; - } - - // Data assignment. - chunk_data.bytes = data + CHUNK_HEADER_SIZE; - chunk_data.size = chunk_size; - return ChunkAssignData(chunk, &chunk_data, copy_data, GetLE32(data + 0)); -} - -int MuxImageFinalize(WebPMuxImage* const wpi) { - const WebPChunk* const img = wpi->img_; - const WebPData* const image = &img->data_; - const int is_lossless = (img->tag_ == kChunks[IDX_VP8L].tag); - int w, h; - int vp8l_has_alpha = 0; - const int ok = is_lossless ? - VP8LGetInfo(image->bytes, image->size, &w, &h, &vp8l_has_alpha) : - VP8GetInfo(image->bytes, image->size, image->size, &w, &h); - assert(img != NULL); - if (ok) { - // Ignore ALPH chunk accompanying VP8L. - if (is_lossless && (wpi->alpha_ != NULL)) { - ChunkDelete(wpi->alpha_); - wpi->alpha_ = NULL; - } - wpi->width_ = w; - wpi->height_ = h; - wpi->has_alpha_ = vp8l_has_alpha || (wpi->alpha_ != NULL); - } - return ok; -} - -static int MuxImageParse(const WebPChunk* const chunk, int copy_data, - WebPMuxImage* const wpi) { - const uint8_t* bytes = chunk->data_.bytes; - size_t size = chunk->data_.size; - const uint8_t* const last = (bytes == NULL) ? NULL : bytes + size; - WebPChunk subchunk; - size_t subchunk_size; - WebPChunk** unknown_chunk_list = &wpi->unknown_; - ChunkInit(&subchunk); - - assert(chunk->tag_ == kChunks[IDX_ANMF].tag); - assert(!wpi->is_partial_); - - // ANMF. - { - const size_t hdr_size = ANMF_CHUNK_SIZE; - const WebPData temp = { bytes, hdr_size }; - // Each of ANMF chunk contain a header at the beginning. So, its size should - // be at least 'hdr_size'. - if (size < hdr_size) goto Fail; - if (ChunkAssignData(&subchunk, &temp, copy_data, - chunk->tag_) != WEBP_MUX_OK) { - goto Fail; - } - } - if (ChunkSetHead(&subchunk, &wpi->header_) != WEBP_MUX_OK) goto Fail; - wpi->is_partial_ = 1; // Waiting for ALPH and/or VP8/VP8L chunks. - - // Rest of the chunks. - subchunk_size = ChunkDiskSize(&subchunk) - CHUNK_HEADER_SIZE; - bytes += subchunk_size; - size -= subchunk_size; - - while (bytes != last) { - ChunkInit(&subchunk); - if (ChunkVerifyAndAssign(&subchunk, bytes, size, size, - copy_data) != WEBP_MUX_OK) { - goto Fail; - } - switch (ChunkGetIdFromTag(subchunk.tag_)) { - case WEBP_CHUNK_ALPHA: - if (wpi->alpha_ != NULL) goto Fail; // Consecutive ALPH chunks. - if (ChunkSetHead(&subchunk, &wpi->alpha_) != WEBP_MUX_OK) goto Fail; - wpi->is_partial_ = 1; // Waiting for a VP8 chunk. - break; - case WEBP_CHUNK_IMAGE: - if (wpi->img_ != NULL) goto Fail; // Only 1 image chunk allowed. - if (ChunkSetHead(&subchunk, &wpi->img_) != WEBP_MUX_OK) goto Fail; - if (!MuxImageFinalize(wpi)) goto Fail; - wpi->is_partial_ = 0; // wpi is completely filled. - break; - case WEBP_CHUNK_UNKNOWN: - if (wpi->is_partial_) { - goto Fail; // Encountered an unknown chunk - // before some image chunks. - } - if (ChunkAppend(&subchunk, &unknown_chunk_list) != WEBP_MUX_OK) { - goto Fail; - } - break; - default: - goto Fail; - } - subchunk_size = ChunkDiskSize(&subchunk); - bytes += subchunk_size; - size -= subchunk_size; - } - if (wpi->is_partial_) goto Fail; - return 1; - - Fail: - ChunkRelease(&subchunk); - return 0; -} - -//------------------------------------------------------------------------------ -// Create a mux object from WebP-RIFF data. - -WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data, - int version) { - size_t riff_size; - uint32_t tag; - const uint8_t* end; - WebPMux* mux = NULL; - WebPMuxImage* wpi = NULL; - const uint8_t* data; - size_t size; - WebPChunk chunk; - // Stores the end of the chunk lists so that it is faster to append data to - // their ends. - WebPChunk** chunk_list_ends[WEBP_CHUNK_NIL + 1] = { NULL }; - ChunkInit(&chunk); - - if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_MUX_ABI_VERSION)) { - return NULL; // version mismatch - } - if (bitstream == NULL) return NULL; - - data = bitstream->bytes; - size = bitstream->size; - - if (data == NULL) return NULL; - if (size < RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE) return NULL; - if (GetLE32(data + 0) != MKFOURCC('R', 'I', 'F', 'F') || - GetLE32(data + CHUNK_HEADER_SIZE) != MKFOURCC('W', 'E', 'B', 'P')) { - return NULL; - } - - mux = WebPMuxNew(); - if (mux == NULL) return NULL; - - tag = GetLE32(data + RIFF_HEADER_SIZE); - if (tag != kChunks[IDX_VP8].tag && - tag != kChunks[IDX_VP8L].tag && - tag != kChunks[IDX_VP8X].tag) { - goto Err; // First chunk should be VP8, VP8L or VP8X. - } - - riff_size = GetLE32(data + TAG_SIZE); - if (riff_size > MAX_CHUNK_PAYLOAD) goto Err; - - // Note this padding is historical and differs from demux.c which does not - // pad the file size. - riff_size = SizeWithPadding(riff_size); - if (riff_size < CHUNK_HEADER_SIZE) goto Err; - if (riff_size > size) goto Err; - // There's no point in reading past the end of the RIFF chunk. - if (size > riff_size + CHUNK_HEADER_SIZE) { - size = riff_size + CHUNK_HEADER_SIZE; - } - - end = data + size; - data += RIFF_HEADER_SIZE; - size -= RIFF_HEADER_SIZE; - - wpi = (WebPMuxImage*)WebPSafeMalloc(1ULL, sizeof(*wpi)); - if (wpi == NULL) goto Err; - MuxImageInit(wpi); - - // Loop over chunks. - while (data != end) { - size_t data_size; - WebPChunkId id; - if (ChunkVerifyAndAssign(&chunk, data, size, riff_size, - copy_data) != WEBP_MUX_OK) { - goto Err; - } - data_size = ChunkDiskSize(&chunk); - id = ChunkGetIdFromTag(chunk.tag_); - switch (id) { - case WEBP_CHUNK_ALPHA: - if (wpi->alpha_ != NULL) goto Err; // Consecutive ALPH chunks. - if (ChunkSetHead(&chunk, &wpi->alpha_) != WEBP_MUX_OK) goto Err; - wpi->is_partial_ = 1; // Waiting for a VP8 chunk. - break; - case WEBP_CHUNK_IMAGE: - if (ChunkSetHead(&chunk, &wpi->img_) != WEBP_MUX_OK) goto Err; - if (!MuxImageFinalize(wpi)) goto Err; - wpi->is_partial_ = 0; // wpi is completely filled. - PushImage: - // Add this to mux->images_ list. - if (MuxImagePush(wpi, &mux->images_) != WEBP_MUX_OK) goto Err; - MuxImageInit(wpi); // Reset for reading next image. - break; - case WEBP_CHUNK_ANMF: - if (wpi->is_partial_) goto Err; // Previous wpi is still incomplete. - if (!MuxImageParse(&chunk, copy_data, wpi)) goto Err; - ChunkRelease(&chunk); - goto PushImage; - default: // A non-image chunk. - if (wpi->is_partial_) goto Err; // Encountered a non-image chunk before - // getting all chunks of an image. - if (chunk_list_ends[id] == NULL) { - chunk_list_ends[id] = - MuxGetChunkListFromId(mux, id); // List to add this chunk. - } - if (ChunkAppend(&chunk, &chunk_list_ends[id]) != WEBP_MUX_OK) goto Err; - if (id == WEBP_CHUNK_VP8X) { // grab global specs - if (data_size < CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE) goto Err; - mux->canvas_width_ = GetLE24(data + 12) + 1; - mux->canvas_height_ = GetLE24(data + 15) + 1; - } - break; - } - data += data_size; - size -= data_size; - ChunkInit(&chunk); - } - - // Incomplete image. - if (wpi->is_partial_) goto Err; - - // Validate mux if complete. - if (MuxValidate(mux) != WEBP_MUX_OK) goto Err; - - MuxImageDelete(wpi); - return mux; // All OK; - - Err: // Something bad happened. - ChunkRelease(&chunk); - MuxImageDelete(wpi); - WebPMuxDelete(mux); - return NULL; -} - -//------------------------------------------------------------------------------ -// Get API(s). - -// Validates that the given mux has a single image. -static WebPMuxError ValidateForSingleImage(const WebPMux* const mux) { - const int num_images = MuxImageCount(mux->images_, WEBP_CHUNK_IMAGE); - const int num_frames = MuxImageCount(mux->images_, WEBP_CHUNK_ANMF); - - if (num_images == 0) { - // No images in mux. - return WEBP_MUX_NOT_FOUND; - } else if (num_images == 1 && num_frames == 0) { - // Valid case (single image). - return WEBP_MUX_OK; - } else { - // Frame case OR an invalid mux. - return WEBP_MUX_INVALID_ARGUMENT; - } -} - -// Get the canvas width, height and flags after validating that VP8X/VP8/VP8L -// chunk and canvas size are valid. -static WebPMuxError MuxGetCanvasInfo(const WebPMux* const mux, - int* width, int* height, uint32_t* flags) { - int w, h; - uint32_t f = 0; - WebPData data; - assert(mux != NULL); - - // Check if VP8X chunk is present. - if (MuxGet(mux, IDX_VP8X, 1, &data) == WEBP_MUX_OK) { - if (data.size < VP8X_CHUNK_SIZE) return WEBP_MUX_BAD_DATA; - f = GetLE32(data.bytes + 0); - w = GetLE24(data.bytes + 4) + 1; - h = GetLE24(data.bytes + 7) + 1; - } else { - const WebPMuxImage* const wpi = mux->images_; - // Grab user-forced canvas size as default. - w = mux->canvas_width_; - h = mux->canvas_height_; - if (w == 0 && h == 0 && ValidateForSingleImage(mux) == WEBP_MUX_OK) { - // single image and not forced canvas size => use dimension of first frame - assert(wpi != NULL); - w = wpi->width_; - h = wpi->height_; - } - if (wpi != NULL) { - if (wpi->has_alpha_) f |= ALPHA_FLAG; - } - } - if (w * (uint64_t)h >= MAX_IMAGE_AREA) return WEBP_MUX_BAD_DATA; - - if (width != NULL) *width = w; - if (height != NULL) *height = h; - if (flags != NULL) *flags = f; - return WEBP_MUX_OK; -} - -WebPMuxError WebPMuxGetCanvasSize(const WebPMux* mux, int* width, int* height) { - if (mux == NULL || width == NULL || height == NULL) { - return WEBP_MUX_INVALID_ARGUMENT; - } - return MuxGetCanvasInfo(mux, width, height, NULL); -} - -WebPMuxError WebPMuxGetFeatures(const WebPMux* mux, uint32_t* flags) { - if (mux == NULL || flags == NULL) return WEBP_MUX_INVALID_ARGUMENT; - return MuxGetCanvasInfo(mux, NULL, NULL, flags); -} - -static uint8_t* EmitVP8XChunk(uint8_t* const dst, int width, - int height, uint32_t flags) { - const size_t vp8x_size = CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE; - assert(width >= 1 && height >= 1); - assert(width <= MAX_CANVAS_SIZE && height <= MAX_CANVAS_SIZE); - assert(width * (uint64_t)height < MAX_IMAGE_AREA); - PutLE32(dst, MKFOURCC('V', 'P', '8', 'X')); - PutLE32(dst + TAG_SIZE, VP8X_CHUNK_SIZE); - PutLE32(dst + CHUNK_HEADER_SIZE, flags); - PutLE24(dst + CHUNK_HEADER_SIZE + 4, width - 1); - PutLE24(dst + CHUNK_HEADER_SIZE + 7, height - 1); - return dst + vp8x_size; -} - -// Assemble a single image WebP bitstream from 'wpi'. -static WebPMuxError SynthesizeBitstream(const WebPMuxImage* const wpi, - WebPData* const bitstream) { - uint8_t* dst; - - // Allocate data. - const int need_vp8x = (wpi->alpha_ != NULL); - const size_t vp8x_size = need_vp8x ? CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE : 0; - const size_t alpha_size = need_vp8x ? ChunkDiskSize(wpi->alpha_) : 0; - // Note: No need to output ANMF chunk for a single image. - const size_t size = RIFF_HEADER_SIZE + vp8x_size + alpha_size + - ChunkDiskSize(wpi->img_); - uint8_t* const data = (uint8_t*)WebPSafeMalloc(1ULL, size); - if (data == NULL) return WEBP_MUX_MEMORY_ERROR; - - // There should be at most one alpha_ chunk and exactly one img_ chunk. - assert(wpi->alpha_ == NULL || wpi->alpha_->next_ == NULL); - assert(wpi->img_ != NULL && wpi->img_->next_ == NULL); - - // Main RIFF header. - dst = MuxEmitRiffHeader(data, size); - - if (need_vp8x) { - dst = EmitVP8XChunk(dst, wpi->width_, wpi->height_, ALPHA_FLAG); // VP8X. - dst = ChunkListEmit(wpi->alpha_, dst); // ALPH. - } - - // Bitstream. - dst = ChunkListEmit(wpi->img_, dst); - assert(dst == data + size); - - // Output. - bitstream->bytes = data; - bitstream->size = size; - return WEBP_MUX_OK; -} - -WebPMuxError WebPMuxGetChunk(const WebPMux* mux, const char fourcc[4], - WebPData* chunk_data) { - CHUNK_INDEX idx; - if (mux == NULL || fourcc == NULL || chunk_data == NULL) { - return WEBP_MUX_INVALID_ARGUMENT; - } - idx = ChunkGetIndexFromFourCC(fourcc); - if (IsWPI(kChunks[idx].id)) { // An image chunk. - return WEBP_MUX_INVALID_ARGUMENT; - } else if (idx != IDX_UNKNOWN) { // A known chunk type. - return MuxGet(mux, idx, 1, chunk_data); - } else { // An unknown chunk type. - const WebPChunk* const chunk = - ChunkSearchList(mux->unknown_, 1, ChunkGetTagFromFourCC(fourcc)); - if (chunk == NULL) return WEBP_MUX_NOT_FOUND; - *chunk_data = chunk->data_; - return WEBP_MUX_OK; - } -} - -static WebPMuxError MuxGetImageInternal(const WebPMuxImage* const wpi, - WebPMuxFrameInfo* const info) { - // Set some defaults for unrelated fields. - info->x_offset = 0; - info->y_offset = 0; - info->duration = 1; - info->dispose_method = WEBP_MUX_DISPOSE_NONE; - info->blend_method = WEBP_MUX_BLEND; - // Extract data for related fields. - info->id = ChunkGetIdFromTag(wpi->img_->tag_); - return SynthesizeBitstream(wpi, &info->bitstream); -} - -static WebPMuxError MuxGetFrameInternal(const WebPMuxImage* const wpi, - WebPMuxFrameInfo* const frame) { - const int is_frame = (wpi->header_->tag_ == kChunks[IDX_ANMF].tag); - const WebPData* frame_data; - if (!is_frame) return WEBP_MUX_INVALID_ARGUMENT; - assert(wpi->header_ != NULL); // Already checked by WebPMuxGetFrame(). - // Get frame chunk. - frame_data = &wpi->header_->data_; - if (frame_data->size < kChunks[IDX_ANMF].size) return WEBP_MUX_BAD_DATA; - // Extract info. - frame->x_offset = 2 * GetLE24(frame_data->bytes + 0); - frame->y_offset = 2 * GetLE24(frame_data->bytes + 3); - { - const uint8_t bits = frame_data->bytes[15]; - frame->duration = GetLE24(frame_data->bytes + 12); - frame->dispose_method = - (bits & 1) ? WEBP_MUX_DISPOSE_BACKGROUND : WEBP_MUX_DISPOSE_NONE; - frame->blend_method = (bits & 2) ? WEBP_MUX_NO_BLEND : WEBP_MUX_BLEND; - } - frame->id = ChunkGetIdFromTag(wpi->header_->tag_); - return SynthesizeBitstream(wpi, &frame->bitstream); -} - -WebPMuxError WebPMuxGetFrame( - const WebPMux* mux, uint32_t nth, WebPMuxFrameInfo* frame) { - WebPMuxError err; - WebPMuxImage* wpi; - - if (mux == NULL || frame == NULL) { - return WEBP_MUX_INVALID_ARGUMENT; - } - - // Get the nth WebPMuxImage. - err = MuxImageGetNth((const WebPMuxImage**)&mux->images_, nth, &wpi); - if (err != WEBP_MUX_OK) return err; - - // Get frame info. - if (wpi->header_ == NULL) { - return MuxGetImageInternal(wpi, frame); - } else { - return MuxGetFrameInternal(wpi, frame); - } -} - -WebPMuxError WebPMuxGetAnimationParams(const WebPMux* mux, - WebPMuxAnimParams* params) { - WebPData anim; - WebPMuxError err; - - if (mux == NULL || params == NULL) return WEBP_MUX_INVALID_ARGUMENT; - - err = MuxGet(mux, IDX_ANIM, 1, &anim); - if (err != WEBP_MUX_OK) return err; - if (anim.size < kChunks[WEBP_CHUNK_ANIM].size) return WEBP_MUX_BAD_DATA; - params->bgcolor = GetLE32(anim.bytes); - params->loop_count = GetLE16(anim.bytes + 4); - - return WEBP_MUX_OK; -} - -// Get chunk index from chunk id. Returns IDX_NIL if not found. -static CHUNK_INDEX ChunkGetIndexFromId(WebPChunkId id) { - int i; - for (i = 0; kChunks[i].id != WEBP_CHUNK_NIL; ++i) { - if (id == kChunks[i].id) return (CHUNK_INDEX)i; - } - return IDX_NIL; -} - -// Count number of chunks matching 'tag' in the 'chunk_list'. -// If tag == NIL_TAG, any tag will be matched. -static int CountChunks(const WebPChunk* const chunk_list, uint32_t tag) { - int count = 0; - const WebPChunk* current; - for (current = chunk_list; current != NULL; current = current->next_) { - if (tag == NIL_TAG || current->tag_ == tag) { - count++; // Count chunks whose tags match. - } - } - return count; -} - -WebPMuxError WebPMuxNumChunks(const WebPMux* mux, - WebPChunkId id, int* num_elements) { - if (mux == NULL || num_elements == NULL) { - return WEBP_MUX_INVALID_ARGUMENT; - } - - if (IsWPI(id)) { - *num_elements = MuxImageCount(mux->images_, id); - } else { - WebPChunk* const* chunk_list = MuxGetChunkListFromId(mux, id); - const CHUNK_INDEX idx = ChunkGetIndexFromId(id); - *num_elements = CountChunks(*chunk_list, kChunks[idx].tag); - } - - return WEBP_MUX_OK; -} - -//------------------------------------------------------------------------------ diff --git a/libwebp/src/utils/Makefile.am b/libwebp/src/utils/Makefile.am deleted file mode 100644 index a0b7fe35..00000000 --- a/libwebp/src/utils/Makefile.am +++ /dev/null @@ -1,54 +0,0 @@ -AM_CPPFLAGS += -I$(top_builddir) -I$(top_srcdir) -noinst_LTLIBRARIES = libwebputils.la - -if BUILD_LIBWEBPDECODER - noinst_LTLIBRARIES += libwebputilsdecode.la -endif - -common_HEADERS = ../webp/types.h -commondir = $(includedir)/webp - -noinst_HEADERS = -noinst_HEADERS += ../dsp/cpu.h -noinst_HEADERS += ../dsp/dsp.h -noinst_HEADERS += ../webp/decode.h -noinst_HEADERS += ../webp/encode.h -noinst_HEADERS += ../webp/format_constants.h - -COMMON_SOURCES = -COMMON_SOURCES += bit_reader_utils.c -COMMON_SOURCES += bit_reader_utils.h -COMMON_SOURCES += bit_reader_inl_utils.h -COMMON_SOURCES += color_cache_utils.c -COMMON_SOURCES += color_cache_utils.h -COMMON_SOURCES += endian_inl_utils.h -COMMON_SOURCES += filters_utils.c -COMMON_SOURCES += filters_utils.h -COMMON_SOURCES += huffman_utils.c -COMMON_SOURCES += huffman_utils.h -COMMON_SOURCES += palette.c -COMMON_SOURCES += palette.h -COMMON_SOURCES += quant_levels_dec_utils.c -COMMON_SOURCES += quant_levels_dec_utils.h -COMMON_SOURCES += rescaler_utils.c -COMMON_SOURCES += rescaler_utils.h -COMMON_SOURCES += random_utils.c -COMMON_SOURCES += random_utils.h -COMMON_SOURCES += thread_utils.c -COMMON_SOURCES += thread_utils.h -COMMON_SOURCES += utils.c -COMMON_SOURCES += utils.h - -ENC_SOURCES = -ENC_SOURCES += bit_writer_utils.c -ENC_SOURCES += bit_writer_utils.h -ENC_SOURCES += huffman_encode_utils.c -ENC_SOURCES += huffman_encode_utils.h -ENC_SOURCES += quant_levels_utils.c -ENC_SOURCES += quant_levels_utils.h - -libwebputils_la_SOURCES = $(COMMON_SOURCES) $(ENC_SOURCES) - -if BUILD_LIBWEBPDECODER - libwebputilsdecode_la_SOURCES = $(COMMON_SOURCES) -endif diff --git a/libwebp/src/utils/bit_reader_inl_utils.h b/libwebp/src/utils/bit_reader_inl_utils.h index 24f3af7b..8179c2fa 100644 --- a/libwebp/src/utils/bit_reader_inl_utils.h +++ b/libwebp/src/utils/bit_reader_inl_utils.h @@ -20,12 +20,15 @@ #include "src/webp/config.h" #endif +#include #include // for memcpy +#include "src/dsp/cpu.h" #include "src/dsp/dsp.h" #include "src/utils/bit_reader_utils.h" #include "src/utils/endian_inl_utils.h" #include "src/utils/utils.h" +#include "src/webp/types.h" #ifdef __cplusplus extern "C" { @@ -53,33 +56,33 @@ void VP8LoadFinalBytes(VP8BitReader* const br); //------------------------------------------------------------------------------ // Inlined critical functions -// makes sure br->value_ has at least BITS bits worth of data +// makes sure br->value has at least BITS bits worth of data static WEBP_UBSAN_IGNORE_UNDEF WEBP_INLINE void VP8LoadNewBytes(VP8BitReader* WEBP_RESTRICT const br) { - assert(br != NULL && br->buf_ != NULL); + assert(br != NULL && br->buf != NULL); // Read 'BITS' bits at a time if possible. - if (br->buf_ < br->buf_max_) { + if (br->buf < br->buf_max) { // convert memory type to register type (with some zero'ing!) bit_t bits; #if defined(WEBP_USE_MIPS32) // This is needed because of un-aligned read. lbit_t in_bits; - lbit_t* p_buf_ = (lbit_t*)br->buf_; + lbit_t* p_buf = (lbit_t*)br->buf; __asm__ volatile( ".set push \n\t" ".set at \n\t" ".set macro \n\t" - "ulw %[in_bits], 0(%[p_buf_]) \n\t" + "ulw %[in_bits], 0(%[p_buf]) \n\t" ".set pop \n\t" : [in_bits]"=r"(in_bits) - : [p_buf_]"r"(p_buf_) + : [p_buf]"r"(p_buf) : "memory", "at" ); #else lbit_t in_bits; - memcpy(&in_bits, br->buf_, sizeof(in_bits)); + memcpy(&in_bits, br->buf, sizeof(in_bits)); #endif - br->buf_ += BITS >> 3; + br->buf += BITS >> 3; #if !defined(WORDS_BIGENDIAN) #if (BITS > 32) bits = BSwap64(in_bits); @@ -96,8 +99,8 @@ void VP8LoadNewBytes(VP8BitReader* WEBP_RESTRICT const br) { bits = (bit_t)in_bits; if (BITS != 8 * sizeof(bit_t)) bits >>= (8 * sizeof(bit_t) - BITS); #endif - br->value_ = bits | (br->value_ << BITS); - br->bits_ += BITS; + br->value = bits | (br->value << BITS); + br->bits += BITS; } else { VP8LoadFinalBytes(br); // no need to be inlined } @@ -108,28 +111,28 @@ static WEBP_INLINE int VP8GetBit(VP8BitReader* WEBP_RESTRICT const br, int prob, const char label[]) { // Don't move this declaration! It makes a big speed difference to store // 'range' *before* calling VP8LoadNewBytes(), even if this function doesn't - // alter br->range_ value. - range_t range = br->range_; - if (br->bits_ < 0) { + // alter br->range value. + range_t range = br->range; + if (br->bits < 0) { VP8LoadNewBytes(br); } { - const int pos = br->bits_; + const int pos = br->bits; const range_t split = (range * prob) >> 8; - const range_t value = (range_t)(br->value_ >> pos); + const range_t value = (range_t)(br->value >> pos); const int bit = (value > split); if (bit) { range -= split; - br->value_ -= (bit_t)(split + 1) << pos; + br->value -= (bit_t)(split + 1) << pos; } else { range = split + 1; } { const int shift = 7 ^ BitsLog2Floor(range); range <<= shift; - br->bits_ -= shift; + br->bits -= shift; } - br->range_ = range - 1; + br->range = range - 1; BT_TRACK(br); return bit; } @@ -139,18 +142,18 @@ static WEBP_INLINE int VP8GetBit(VP8BitReader* WEBP_RESTRICT const br, static WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW WEBP_INLINE int VP8GetSigned(VP8BitReader* WEBP_RESTRICT const br, int v, const char label[]) { - if (br->bits_ < 0) { + if (br->bits < 0) { VP8LoadNewBytes(br); } { - const int pos = br->bits_; - const range_t split = br->range_ >> 1; - const range_t value = (range_t)(br->value_ >> pos); + const int pos = br->bits; + const range_t split = br->range >> 1; + const range_t value = (range_t)(br->value >> pos); const int32_t mask = (int32_t)(split - value) >> 31; // -1 or 0 - br->bits_ -= 1; - br->range_ += (range_t)mask; - br->range_ |= 1; - br->value_ -= (bit_t)((split + 1) & (uint32_t)mask) << pos; + br->bits -= 1; + br->range += (range_t)mask; + br->range |= 1; + br->value -= (bit_t)((split + 1) & (uint32_t)mask) << pos; BT_TRACK(br); return (v ^ mask) - mask; } @@ -160,19 +163,19 @@ static WEBP_INLINE int VP8GetBitAlt(VP8BitReader* WEBP_RESTRICT const br, int prob, const char label[]) { // Don't move this declaration! It makes a big speed difference to store // 'range' *before* calling VP8LoadNewBytes(), even if this function doesn't - // alter br->range_ value. - range_t range = br->range_; - if (br->bits_ < 0) { + // alter br->range value. + range_t range = br->range; + if (br->bits < 0) { VP8LoadNewBytes(br); } { - const int pos = br->bits_; + const int pos = br->bits; const range_t split = (range * prob) >> 8; - const range_t value = (range_t)(br->value_ >> pos); + const range_t value = (range_t)(br->value >> pos); int bit; // Don't use 'const int bit = (value > split);", it's slower. if (value > split) { range -= split + 1; - br->value_ -= (bit_t)(split + 1) << pos; + br->value -= (bit_t)(split + 1) << pos; bit = 1; } else { range = split; @@ -181,9 +184,9 @@ static WEBP_INLINE int VP8GetBitAlt(VP8BitReader* WEBP_RESTRICT const br, if (range <= (range_t)0x7e) { const int shift = kVP8Log2Range[range]; range = kVP8NewRange[range]; - br->bits_ -= shift; + br->bits -= shift; } - br->range_ = range; + br->range = range; BT_TRACK(br); return bit; } diff --git a/libwebp/src/utils/bit_reader_utils.c b/libwebp/src/utils/bit_reader_utils.c index a26557aa..5e3a8b37 100644 --- a/libwebp/src/utils/bit_reader_utils.c +++ b/libwebp/src/utils/bit_reader_utils.c @@ -15,8 +15,14 @@ #include "src/webp/config.h" #endif +#include +#include + +#include "src/webp/types.h" #include "src/dsp/cpu.h" #include "src/utils/bit_reader_inl_utils.h" +#include "src/utils/bit_reader_utils.h" +#include "src/utils/endian_inl_utils.h" #include "src/utils/utils.h" //------------------------------------------------------------------------------ @@ -25,11 +31,11 @@ void VP8BitReaderSetBuffer(VP8BitReader* const br, const uint8_t* const start, size_t size) { - br->buf_ = start; - br->buf_end_ = start + size; - br->buf_max_ = - (size >= sizeof(lbit_t)) ? start + size - sizeof(lbit_t) + 1 - : start; + assert(start != NULL); + br->buf = start; + br->buf_end = start + size; + br->buf_max = + (size >= sizeof(lbit_t)) ? start + size - sizeof(lbit_t) + 1 : start; } void VP8InitBitReader(VP8BitReader* const br, @@ -37,19 +43,19 @@ void VP8InitBitReader(VP8BitReader* const br, assert(br != NULL); assert(start != NULL); assert(size < (1u << 31)); // limit ensured by format and upstream checks - br->range_ = 255 - 1; - br->value_ = 0; - br->bits_ = -8; // to load the very first 8bits - br->eof_ = 0; + br->range = 255 - 1; + br->value = 0; + br->bits = -8; // to load the very first 8bits + br->eof = 0; VP8BitReaderSetBuffer(br, start, size); VP8LoadNewBytes(br); } void VP8RemapBitReader(VP8BitReader* const br, ptrdiff_t offset) { - if (br->buf_ != NULL) { - br->buf_ += offset; - br->buf_end_ += offset; - br->buf_max_ += offset; + if (br->buf != NULL) { + br->buf += offset; + br->buf_end += offset; + br->buf_max += offset; } } @@ -86,17 +92,17 @@ const uint8_t kVP8NewRange[128] = { }; void VP8LoadFinalBytes(VP8BitReader* const br) { - assert(br != NULL && br->buf_ != NULL); + assert(br != NULL && br->buf != NULL); // Only read 8bits at a time - if (br->buf_ < br->buf_end_) { - br->bits_ += 8; - br->value_ = (bit_t)(*br->buf_++) | (br->value_ << 8); - } else if (!br->eof_) { - br->value_ <<= 8; - br->bits_ += 8; - br->eof_ = 1; + if (br->buf < br->buf_end) { + br->bits += 8; + br->value = (bit_t)(*br->buf++) | (br->value << 8); + } else if (!br->eof) { + br->value <<= 8; + br->bits += 8; + br->eof = 1; } else { - br->bits_ = 0; // This is to avoid undefined behaviour with shifts. + br->bits = 0; // This is to avoid undefined behaviour with shifts. } } @@ -124,7 +130,8 @@ int32_t VP8GetSignedValue(VP8BitReader* const br, int bits, #if defined(__arm__) || defined(_M_ARM) || WEBP_AARCH64 || \ defined(__i386__) || defined(_M_IX86) || \ - defined(__x86_64__) || defined(_M_X64) + defined(__x86_64__) || defined(_M_X64) || \ + defined(__wasm__) #define VP8L_USE_FAST_LOAD #endif @@ -146,20 +153,20 @@ void VP8LInitBitReader(VP8LBitReader* const br, const uint8_t* const start, assert(start != NULL); assert(length < 0xfffffff8u); // can't happen with a RIFF chunk. - br->len_ = length; - br->val_ = 0; - br->bit_pos_ = 0; - br->eos_ = 0; + br->len = length; + br->val = 0; + br->bit_pos = 0; + br->eos = 0; - if (length > sizeof(br->val_)) { - length = sizeof(br->val_); + if (length > sizeof(br->val)) { + length = sizeof(br->val); } for (i = 0; i < length; ++i) { value |= (vp8l_val_t)start[i] << (8 * i); } - br->val_ = value; - br->pos_ = length; - br->buf_ = start; + br->val = value; + br->pos = length; + br->buf = start; } void VP8LBitReaderSetBuffer(VP8LBitReader* const br, @@ -167,24 +174,24 @@ void VP8LBitReaderSetBuffer(VP8LBitReader* const br, assert(br != NULL); assert(buf != NULL); assert(len < 0xfffffff8u); // can't happen with a RIFF chunk. - br->buf_ = buf; - br->len_ = len; - // pos_ > len_ should be considered a param error. - br->eos_ = (br->pos_ > br->len_) || VP8LIsEndOfStream(br); + br->buf = buf; + br->len = len; + // 'pos' > 'len' should be considered a param error. + br->eos = (br->pos > br->len) || VP8LIsEndOfStream(br); } static void VP8LSetEndOfStream(VP8LBitReader* const br) { - br->eos_ = 1; - br->bit_pos_ = 0; // To avoid undefined behaviour with shifts. + br->eos = 1; + br->bit_pos = 0; // To avoid undefined behaviour with shifts. } // If not at EOS, reload up to VP8L_LBITS byte-by-byte static void ShiftBytes(VP8LBitReader* const br) { - while (br->bit_pos_ >= 8 && br->pos_ < br->len_) { - br->val_ >>= 8; - br->val_ |= ((vp8l_val_t)br->buf_[br->pos_]) << (VP8L_LBITS - 8); - ++br->pos_; - br->bit_pos_ -= 8; + while (br->bit_pos >= 8 && br->pos < br->len) { + br->val >>= 8; + br->val |= ((vp8l_val_t)br->buf[br->pos]) << (VP8L_LBITS - 8); + ++br->pos; + br->bit_pos -= 8; } if (VP8LIsEndOfStream(br)) { VP8LSetEndOfStream(br); @@ -192,14 +199,14 @@ static void ShiftBytes(VP8LBitReader* const br) { } void VP8LDoFillBitWindow(VP8LBitReader* const br) { - assert(br->bit_pos_ >= VP8L_WBITS); + assert(br->bit_pos >= VP8L_WBITS); #if defined(VP8L_USE_FAST_LOAD) - if (br->pos_ + sizeof(br->val_) < br->len_) { - br->val_ >>= VP8L_WBITS; - br->bit_pos_ -= VP8L_WBITS; - br->val_ |= (vp8l_val_t)HToLE32(WebPMemToUint32(br->buf_ + br->pos_)) << - (VP8L_LBITS - VP8L_WBITS); - br->pos_ += VP8L_LOG8_WBITS; + if (br->pos + sizeof(br->val) < br->len) { + br->val >>= VP8L_WBITS; + br->bit_pos -= VP8L_WBITS; + br->val |= (vp8l_val_t)HToLE32(WebPMemToUint32(br->buf + br->pos)) << + (VP8L_LBITS - VP8L_WBITS); + br->pos += VP8L_LOG8_WBITS; return; } #endif @@ -209,10 +216,10 @@ void VP8LDoFillBitWindow(VP8LBitReader* const br) { uint32_t VP8LReadBits(VP8LBitReader* const br, int n_bits) { assert(n_bits >= 0); // Flag an error if end_of_stream or n_bits is more than allowed limit. - if (!br->eos_ && n_bits <= VP8L_MAX_NUM_BIT_READ) { + if (!br->eos && n_bits <= VP8L_MAX_NUM_BIT_READ) { const uint32_t val = VP8LPrefetchBits(br) & kBitMask[n_bits]; - const int new_bits = br->bit_pos_ + n_bits; - br->bit_pos_ = new_bits; + const int new_bits = br->bit_pos + n_bits; + br->bit_pos = new_bits; ShiftBytes(br); return val; } else { @@ -272,17 +279,17 @@ void BitTrace(const struct VP8BitReader* const br, const char label[]) { if (!init_done) { memset(kLabels, 0, sizeof(kLabels)); atexit(PrintBitTraces); - buf_start = br->buf_; + buf_start = br->buf; init_done = 1; } - pos = (int)(br->buf_ - buf_start) * 8 - br->bits_; + pos = (int)(br->buf - buf_start) * 8 - br->bits; // if there's a too large jump, we've changed partition -> reset counter if (abs(pos - last_pos) > 32) { - buf_start = br->buf_; + buf_start = br->buf; pos = 0; last_pos = 0; } - if (br->range_ >= 0x7f) pos += kVP8Log2Range[br->range_ - 0x7f]; + if (br->range >= 0x7f) pos += kVP8Log2Range[br->range - 0x7f]; for (i = 0; i < last_label; ++i) { if (!strcmp(label, kLabels[i].label)) break; } diff --git a/libwebp/src/utils/bit_reader_utils.h b/libwebp/src/utils/bit_reader_utils.h index 25ff31e5..ddce8606 100644 --- a/libwebp/src/utils/bit_reader_utils.h +++ b/libwebp/src/utils/bit_reader_utils.h @@ -16,6 +16,8 @@ #define WEBP_UTILS_BIT_READER_UTILS_H_ #include +#include + #ifdef _MSC_VER #include // _byteswap_ulong #endif @@ -47,14 +49,14 @@ extern void BitTrace(const struct VP8BitReader* const br, const char label[]); extern "C" { #endif -// The Boolean decoder needs to maintain infinite precision on the value_ field. -// However, since range_ is only 8bit, we only need an active window of 8 bits -// for value_. Left bits (MSB) gets zeroed and shifted away when value_ falls -// below 128, range_ is updated, and fresh bits read from the bitstream are -// brought in as LSB. To avoid reading the fresh bits one by one (slow), we -// cache BITS of them ahead. The total of (BITS + 8) bits must fit into a -// natural register (with type bit_t). To fetch BITS bits from bitstream we -// use a type lbit_t. +// The Boolean decoder needs to maintain infinite precision on the 'value' +// field. However, since 'range' is only 8bit, we only need an active window of +// 8 bits for 'value". Left bits (MSB) gets zeroed and shifted away when +// 'value' falls below 128, 'range' is updated, and fresh bits read from the +// bitstream are brought in as LSB. To avoid reading the fresh bits one by one +// (slow), we cache BITS of them ahead. The total of (BITS + 8) bits must fit +// into a natural register (with type bit_t). To fetch BITS bits from bitstream +// we use a type lbit_t. // // BITS can be any multiple of 8 from 8 to 56 (inclusive). // Pick values that fit natural register size. @@ -69,14 +71,16 @@ extern "C" { #define BITS 56 #elif defined(__mips__) // MIPS #define BITS 24 +#elif defined(__wasm__) // WASM +#define BITS 56 #else // reasonable default #define BITS 24 #endif //------------------------------------------------------------------------------ // Derived types and constants: -// bit_t = natural register type for storing 'value_' (which is BITS+8 bits) -// range_t = register for 'range_' (which is 8bits only) +// bit_t = natural register type for storing 'value' (which is BITS+8 bits) +// range_t = register for 'range' (which is 8bits only) #if (BITS > 24) typedef uint64_t bit_t; @@ -92,14 +96,14 @@ typedef uint32_t range_t; typedef struct VP8BitReader VP8BitReader; struct VP8BitReader { // boolean decoder (keep the field ordering as is!) - bit_t value_; // current value - range_t range_; // current range minus 1. In [127, 254] interval. - int bits_; // number of valid bits left + bit_t value; // current value + range_t range; // current range minus 1. In [127, 254] interval. + int bits; // number of valid bits left // read buffer - const uint8_t* buf_; // next byte to be read - const uint8_t* buf_end_; // end of read buffer - const uint8_t* buf_max_; // max packed-read position on buffer - int eof_; // true if input is exhausted + const uint8_t* buf; // next byte to be read + const uint8_t* buf_end; // end of read buffer + const uint8_t* buf_max; // max packed-read position on buffer + int eof; // true if input is exhausted }; // Initialize the bit reader and the boolean decoder. @@ -139,12 +143,12 @@ int32_t VP8GetSignedValue(VP8BitReader* const br, int num_bits, typedef uint64_t vp8l_val_t; // right now, this bit-reader can only use 64bit. typedef struct { - vp8l_val_t val_; // pre-fetched bits - const uint8_t* buf_; // input byte buffer - size_t len_; // buffer length - size_t pos_; // byte position in buf_ - int bit_pos_; // current bit-reading position in val_ - int eos_; // true if a bit was read past the end of buffer + vp8l_val_t val; // pre-fetched bits + const uint8_t* buf; // input byte buffer + size_t len; // buffer length + size_t pos; // byte position in buf + int bit_pos; // current bit-reading position in val + int eos; // true if a bit was read past the end of buffer } VP8LBitReader; void VP8LInitBitReader(VP8LBitReader* const br, @@ -158,34 +162,34 @@ void VP8LBitReaderSetBuffer(VP8LBitReader* const br, // Reads the specified number of bits from read buffer. // Flags an error in case end_of_stream or n_bits is more than the allowed limit // of VP8L_MAX_NUM_BIT_READ (inclusive). -// Flags eos_ if this read attempt is going to cross the read buffer. +// Flags 'eos' if this read attempt is going to cross the read buffer. uint32_t VP8LReadBits(VP8LBitReader* const br, int n_bits); // Return the prefetched bits, so they can be looked up. static WEBP_INLINE uint32_t VP8LPrefetchBits(VP8LBitReader* const br) { - return (uint32_t)(br->val_ >> (br->bit_pos_ & (VP8L_LBITS - 1))); + return (uint32_t)(br->val >> (br->bit_pos & (VP8L_LBITS - 1))); } // Returns true if there was an attempt at reading bit past the end of -// the buffer. Doesn't set br->eos_ flag. +// the buffer. Doesn't set br->eos flag. static WEBP_INLINE int VP8LIsEndOfStream(const VP8LBitReader* const br) { - assert(br->pos_ <= br->len_); - return br->eos_ || ((br->pos_ == br->len_) && (br->bit_pos_ > VP8L_LBITS)); + assert(br->pos <= br->len); + return br->eos || ((br->pos == br->len) && (br->bit_pos > VP8L_LBITS)); } // For jumping over a number of bits in the bit stream when accessed with // VP8LPrefetchBits and VP8LFillBitWindow. -// This function does *not* set br->eos_, since it's speed-critical. +// This function does *not* set br->eos, since it's speed-critical. // Use with extreme care! static WEBP_INLINE void VP8LSetBitPos(VP8LBitReader* const br, int val) { - br->bit_pos_ = val; + br->bit_pos = val; } // Advances the read buffer by 4 bytes to make room for reading next 32 bits. // Speed critical, but infrequent part of the code can be non-inlined. extern void VP8LDoFillBitWindow(VP8LBitReader* const br); static WEBP_INLINE void VP8LFillBitWindow(VP8LBitReader* const br) { - if (br->bit_pos_ >= VP8L_WBITS) VP8LDoFillBitWindow(br); + if (br->bit_pos >= VP8L_WBITS) VP8LDoFillBitWindow(br); } #ifdef __cplusplus diff --git a/libwebp/src/utils/bit_writer_utils.c b/libwebp/src/utils/bit_writer_utils.c deleted file mode 100644 index 2f408508..00000000 --- a/libwebp/src/utils/bit_writer_utils.c +++ /dev/null @@ -1,347 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Bit writing and boolean coder -// -// Author: Skal (pascal.massimino@gmail.com) -// Vikas Arora (vikaas.arora@gmail.com) - -#include -#include // for memcpy() -#include - -#include "src/utils/bit_writer_utils.h" -#include "src/utils/endian_inl_utils.h" -#include "src/utils/utils.h" - -//------------------------------------------------------------------------------ -// VP8BitWriter - -static int BitWriterResize(VP8BitWriter* const bw, size_t extra_size) { - uint8_t* new_buf; - size_t new_size; - const uint64_t needed_size_64b = (uint64_t)bw->pos_ + extra_size; - const size_t needed_size = (size_t)needed_size_64b; - if (needed_size_64b != needed_size) { - bw->error_ = 1; - return 0; - } - if (needed_size <= bw->max_pos_) return 1; - // If the following line wraps over 32bit, the test just after will catch it. - new_size = 2 * bw->max_pos_; - if (new_size < needed_size) new_size = needed_size; - if (new_size < 1024) new_size = 1024; - new_buf = (uint8_t*)WebPSafeMalloc(1ULL, new_size); - if (new_buf == NULL) { - bw->error_ = 1; - return 0; - } - if (bw->pos_ > 0) { - assert(bw->buf_ != NULL); - memcpy(new_buf, bw->buf_, bw->pos_); - } - WebPSafeFree(bw->buf_); - bw->buf_ = new_buf; - bw->max_pos_ = new_size; - return 1; -} - -static void Flush(VP8BitWriter* const bw) { - const int s = 8 + bw->nb_bits_; - const int32_t bits = bw->value_ >> s; - assert(bw->nb_bits_ >= 0); - bw->value_ -= bits << s; - bw->nb_bits_ -= 8; - if ((bits & 0xff) != 0xff) { - size_t pos = bw->pos_; - if (!BitWriterResize(bw, bw->run_ + 1)) { - return; - } - if (bits & 0x100) { // overflow -> propagate carry over pending 0xff's - if (pos > 0) bw->buf_[pos - 1]++; - } - if (bw->run_ > 0) { - const int value = (bits & 0x100) ? 0x00 : 0xff; - for (; bw->run_ > 0; --bw->run_) bw->buf_[pos++] = value; - } - bw->buf_[pos++] = bits & 0xff; - bw->pos_ = pos; - } else { - bw->run_++; // delay writing of bytes 0xff, pending eventual carry. - } -} - -//------------------------------------------------------------------------------ -// renormalization - -static const uint8_t kNorm[128] = { // renorm_sizes[i] = 8 - log2(i) - 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 0 -}; - -// range = ((range + 1) << kVP8Log2Range[range]) - 1 -static const uint8_t kNewRange[128] = { - 127, 127, 191, 127, 159, 191, 223, 127, 143, 159, 175, 191, 207, 223, 239, - 127, 135, 143, 151, 159, 167, 175, 183, 191, 199, 207, 215, 223, 231, 239, - 247, 127, 131, 135, 139, 143, 147, 151, 155, 159, 163, 167, 171, 175, 179, - 183, 187, 191, 195, 199, 203, 207, 211, 215, 219, 223, 227, 231, 235, 239, - 243, 247, 251, 127, 129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149, - 151, 153, 155, 157, 159, 161, 163, 165, 167, 169, 171, 173, 175, 177, 179, - 181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203, 205, 207, 209, - 211, 213, 215, 217, 219, 221, 223, 225, 227, 229, 231, 233, 235, 237, 239, - 241, 243, 245, 247, 249, 251, 253, 127 -}; - -int VP8PutBit(VP8BitWriter* const bw, int bit, int prob) { - const int split = (bw->range_ * prob) >> 8; - if (bit) { - bw->value_ += split + 1; - bw->range_ -= split + 1; - } else { - bw->range_ = split; - } - if (bw->range_ < 127) { // emit 'shift' bits out and renormalize - const int shift = kNorm[bw->range_]; - bw->range_ = kNewRange[bw->range_]; - bw->value_ <<= shift; - bw->nb_bits_ += shift; - if (bw->nb_bits_ > 0) Flush(bw); - } - return bit; -} - -int VP8PutBitUniform(VP8BitWriter* const bw, int bit) { - const int split = bw->range_ >> 1; - if (bit) { - bw->value_ += split + 1; - bw->range_ -= split + 1; - } else { - bw->range_ = split; - } - if (bw->range_ < 127) { - bw->range_ = kNewRange[bw->range_]; - bw->value_ <<= 1; - bw->nb_bits_ += 1; - if (bw->nb_bits_ > 0) Flush(bw); - } - return bit; -} - -void VP8PutBits(VP8BitWriter* const bw, uint32_t value, int nb_bits) { - uint32_t mask; - assert(nb_bits > 0 && nb_bits < 32); - for (mask = 1u << (nb_bits - 1); mask; mask >>= 1) { - VP8PutBitUniform(bw, value & mask); - } -} - -void VP8PutSignedBits(VP8BitWriter* const bw, int value, int nb_bits) { - if (!VP8PutBitUniform(bw, value != 0)) return; - if (value < 0) { - VP8PutBits(bw, ((-value) << 1) | 1, nb_bits + 1); - } else { - VP8PutBits(bw, value << 1, nb_bits + 1); - } -} - -//------------------------------------------------------------------------------ - -int VP8BitWriterInit(VP8BitWriter* const bw, size_t expected_size) { - bw->range_ = 255 - 1; - bw->value_ = 0; - bw->run_ = 0; - bw->nb_bits_ = -8; - bw->pos_ = 0; - bw->max_pos_ = 0; - bw->error_ = 0; - bw->buf_ = NULL; - return (expected_size > 0) ? BitWriterResize(bw, expected_size) : 1; -} - -uint8_t* VP8BitWriterFinish(VP8BitWriter* const bw) { - VP8PutBits(bw, 0, 9 - bw->nb_bits_); - bw->nb_bits_ = 0; // pad with zeroes - Flush(bw); - return bw->buf_; -} - -int VP8BitWriterAppend(VP8BitWriter* const bw, - const uint8_t* data, size_t size) { - assert(data != NULL); - if (bw->nb_bits_ != -8) return 0; // Flush() must have been called - if (!BitWriterResize(bw, size)) return 0; - memcpy(bw->buf_ + bw->pos_, data, size); - bw->pos_ += size; - return 1; -} - -void VP8BitWriterWipeOut(VP8BitWriter* const bw) { - if (bw != NULL) { - WebPSafeFree(bw->buf_); - memset(bw, 0, sizeof(*bw)); - } -} - -//------------------------------------------------------------------------------ -// VP8LBitWriter - -// This is the minimum amount of size the memory buffer is guaranteed to grow -// when extra space is needed. -#define MIN_EXTRA_SIZE (32768ULL) - -// Returns 1 on success. -static int VP8LBitWriterResize(VP8LBitWriter* const bw, size_t extra_size) { - uint8_t* allocated_buf; - size_t allocated_size; - const size_t max_bytes = bw->end_ - bw->buf_; - const size_t current_size = bw->cur_ - bw->buf_; - const uint64_t size_required_64b = (uint64_t)current_size + extra_size; - const size_t size_required = (size_t)size_required_64b; - if (size_required != size_required_64b) { - bw->error_ = 1; - return 0; - } - if (max_bytes > 0 && size_required <= max_bytes) return 1; - allocated_size = (3 * max_bytes) >> 1; - if (allocated_size < size_required) allocated_size = size_required; - // make allocated size multiple of 1k - allocated_size = (((allocated_size >> 10) + 1) << 10); - allocated_buf = (uint8_t*)WebPSafeMalloc(1ULL, allocated_size); - if (allocated_buf == NULL) { - bw->error_ = 1; - return 0; - } - if (current_size > 0) { - memcpy(allocated_buf, bw->buf_, current_size); - } - WebPSafeFree(bw->buf_); - bw->buf_ = allocated_buf; - bw->cur_ = bw->buf_ + current_size; - bw->end_ = bw->buf_ + allocated_size; - return 1; -} - -int VP8LBitWriterInit(VP8LBitWriter* const bw, size_t expected_size) { - memset(bw, 0, sizeof(*bw)); - return VP8LBitWriterResize(bw, expected_size); -} - -int VP8LBitWriterClone(const VP8LBitWriter* const src, - VP8LBitWriter* const dst) { - const size_t current_size = src->cur_ - src->buf_; - assert(src->cur_ >= src->buf_ && src->cur_ <= src->end_); - if (!VP8LBitWriterResize(dst, current_size)) return 0; - memcpy(dst->buf_, src->buf_, current_size); - dst->bits_ = src->bits_; - dst->used_ = src->used_; - dst->error_ = src->error_; - dst->cur_ = dst->buf_ + current_size; - return 1; -} - -void VP8LBitWriterWipeOut(VP8LBitWriter* const bw) { - if (bw != NULL) { - WebPSafeFree(bw->buf_); - memset(bw, 0, sizeof(*bw)); - } -} - -void VP8LBitWriterReset(const VP8LBitWriter* const bw_init, - VP8LBitWriter* const bw) { - bw->bits_ = bw_init->bits_; - bw->used_ = bw_init->used_; - bw->cur_ = bw->buf_ + (bw_init->cur_ - bw_init->buf_); - assert(bw->cur_ <= bw->end_); - bw->error_ = bw_init->error_; -} - -void VP8LBitWriterSwap(VP8LBitWriter* const src, VP8LBitWriter* const dst) { - const VP8LBitWriter tmp = *src; - *src = *dst; - *dst = tmp; -} - -void VP8LPutBitsFlushBits(VP8LBitWriter* const bw) { - // If needed, make some room by flushing some bits out. - if (bw->cur_ + VP8L_WRITER_BYTES > bw->end_) { - const uint64_t extra_size = (bw->end_ - bw->buf_) + MIN_EXTRA_SIZE; - if (!CheckSizeOverflow(extra_size) || - !VP8LBitWriterResize(bw, (size_t)extra_size)) { - bw->cur_ = bw->buf_; - bw->error_ = 1; - return; - } - } - *(vp8l_wtype_t*)bw->cur_ = (vp8l_wtype_t)WSWAP((vp8l_wtype_t)bw->bits_); - bw->cur_ += VP8L_WRITER_BYTES; - bw->bits_ >>= VP8L_WRITER_BITS; - bw->used_ -= VP8L_WRITER_BITS; -} - -void VP8LPutBitsInternal(VP8LBitWriter* const bw, uint32_t bits, int n_bits) { - assert(n_bits <= 32); - // That's the max we can handle: - assert(sizeof(vp8l_wtype_t) == 2); - if (n_bits > 0) { - vp8l_atype_t lbits = bw->bits_; - int used = bw->used_; - // Special case of overflow handling for 32bit accumulator (2-steps flush). -#if VP8L_WRITER_BITS == 16 - if (used + n_bits >= VP8L_WRITER_MAX_BITS) { - // Fill up all the VP8L_WRITER_MAX_BITS so it can be flushed out below. - const int shift = VP8L_WRITER_MAX_BITS - used; - lbits |= (vp8l_atype_t)bits << used; - used = VP8L_WRITER_MAX_BITS; - n_bits -= shift; - bits >>= shift; - assert(n_bits <= VP8L_WRITER_MAX_BITS); - } -#endif - // If needed, make some room by flushing some bits out. - while (used >= VP8L_WRITER_BITS) { - if (bw->cur_ + VP8L_WRITER_BYTES > bw->end_) { - const uint64_t extra_size = (bw->end_ - bw->buf_) + MIN_EXTRA_SIZE; - if (!CheckSizeOverflow(extra_size) || - !VP8LBitWriterResize(bw, (size_t)extra_size)) { - bw->cur_ = bw->buf_; - bw->error_ = 1; - return; - } - } - *(vp8l_wtype_t*)bw->cur_ = (vp8l_wtype_t)WSWAP((vp8l_wtype_t)lbits); - bw->cur_ += VP8L_WRITER_BYTES; - lbits >>= VP8L_WRITER_BITS; - used -= VP8L_WRITER_BITS; - } - bw->bits_ = lbits | ((vp8l_atype_t)bits << used); - bw->used_ = used + n_bits; - } -} - -uint8_t* VP8LBitWriterFinish(VP8LBitWriter* const bw) { - // flush leftover bits - if (VP8LBitWriterResize(bw, (bw->used_ + 7) >> 3)) { - while (bw->used_ > 0) { - *bw->cur_++ = (uint8_t)bw->bits_; - bw->bits_ >>= 8; - bw->used_ -= 8; - } - bw->used_ = 0; - } - return bw->buf_; -} - -//------------------------------------------------------------------------------ diff --git a/libwebp/src/utils/bit_writer_utils.h b/libwebp/src/utils/bit_writer_utils.h deleted file mode 100644 index b9d5102a..00000000 --- a/libwebp/src/utils/bit_writer_utils.h +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Bit writing and boolean coder -// -// Author: Skal (pascal.massimino@gmail.com) - -#ifndef WEBP_UTILS_BIT_WRITER_UTILS_H_ -#define WEBP_UTILS_BIT_WRITER_UTILS_H_ - -#include "src/webp/types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -//------------------------------------------------------------------------------ -// Bit-writing - -typedef struct VP8BitWriter VP8BitWriter; -struct VP8BitWriter { - int32_t range_; // range-1 - int32_t value_; - int run_; // number of outstanding bits - int nb_bits_; // number of pending bits - uint8_t* buf_; // internal buffer. Re-allocated regularly. Not owned. - size_t pos_; - size_t max_pos_; - int error_; // true in case of error -}; - -// Initialize the object. Allocates some initial memory based on expected_size. -int VP8BitWriterInit(VP8BitWriter* const bw, size_t expected_size); -// Finalize the bitstream coding. Returns a pointer to the internal buffer. -uint8_t* VP8BitWriterFinish(VP8BitWriter* const bw); -// Release any pending memory and zeroes the object. Not a mandatory call. -// Only useful in case of error, when the internal buffer hasn't been grabbed! -void VP8BitWriterWipeOut(VP8BitWriter* const bw); - -int VP8PutBit(VP8BitWriter* const bw, int bit, int prob); -int VP8PutBitUniform(VP8BitWriter* const bw, int bit); -void VP8PutBits(VP8BitWriter* const bw, uint32_t value, int nb_bits); -void VP8PutSignedBits(VP8BitWriter* const bw, int value, int nb_bits); - -// Appends some bytes to the internal buffer. Data is copied. -int VP8BitWriterAppend(VP8BitWriter* const bw, - const uint8_t* data, size_t size); - -// return approximate write position (in bits) -static WEBP_INLINE uint64_t VP8BitWriterPos(const VP8BitWriter* const bw) { - const uint64_t nb_bits = 8 + bw->nb_bits_; // bw->nb_bits_ is <= 0, note - return (bw->pos_ + bw->run_) * 8 + nb_bits; -} - -// Returns a pointer to the internal buffer. -static WEBP_INLINE uint8_t* VP8BitWriterBuf(const VP8BitWriter* const bw) { - return bw->buf_; -} -// Returns the size of the internal buffer. -static WEBP_INLINE size_t VP8BitWriterSize(const VP8BitWriter* const bw) { - return bw->pos_; -} - -//------------------------------------------------------------------------------ -// VP8LBitWriter - -#if defined(__x86_64__) || defined(_M_X64) // 64bit -typedef uint64_t vp8l_atype_t; // accumulator type -typedef uint32_t vp8l_wtype_t; // writing type -#define WSWAP HToLE32 -#define VP8L_WRITER_BYTES 4 // sizeof(vp8l_wtype_t) -#define VP8L_WRITER_BITS 32 // 8 * sizeof(vp8l_wtype_t) -#define VP8L_WRITER_MAX_BITS 64 // 8 * sizeof(vp8l_atype_t) -#else -typedef uint32_t vp8l_atype_t; -typedef uint16_t vp8l_wtype_t; -#define WSWAP HToLE16 -#define VP8L_WRITER_BYTES 2 -#define VP8L_WRITER_BITS 16 -#define VP8L_WRITER_MAX_BITS 32 -#endif - -typedef struct { - vp8l_atype_t bits_; // bit accumulator - int used_; // number of bits used in accumulator - uint8_t* buf_; // start of buffer - uint8_t* cur_; // current write position - uint8_t* end_; // end of buffer - - // After all bits are written (VP8LBitWriterFinish()), the caller must observe - // the state of error_. A value of 1 indicates that a memory allocation - // failure has happened during bit writing. A value of 0 indicates successful - // writing of bits. - int error_; -} VP8LBitWriter; - -static WEBP_INLINE size_t VP8LBitWriterNumBytes(const VP8LBitWriter* const bw) { - return (bw->cur_ - bw->buf_) + ((bw->used_ + 7) >> 3); -} - -// Returns false in case of memory allocation error. -int VP8LBitWriterInit(VP8LBitWriter* const bw, size_t expected_size); -// Returns false in case of memory allocation error. -int VP8LBitWriterClone(const VP8LBitWriter* const src, - VP8LBitWriter* const dst); -// Finalize the bitstream coding. Returns a pointer to the internal buffer. -uint8_t* VP8LBitWriterFinish(VP8LBitWriter* const bw); -// Release any pending memory and zeroes the object. -void VP8LBitWriterWipeOut(VP8LBitWriter* const bw); -// Resets the cursor of the BitWriter bw to when it was like in bw_init. -void VP8LBitWriterReset(const VP8LBitWriter* const bw_init, - VP8LBitWriter* const bw); -// Swaps the memory held by two BitWriters. -void VP8LBitWriterSwap(VP8LBitWriter* const src, VP8LBitWriter* const dst); - -// Internal function for VP8LPutBits flushing 32 bits from the written state. -void VP8LPutBitsFlushBits(VP8LBitWriter* const bw); - -// PutBits internal function used in the 16 bit vp8l_wtype_t case. -void VP8LPutBitsInternal(VP8LBitWriter* const bw, uint32_t bits, int n_bits); - -// This function writes bits into bytes in increasing addresses (little endian), -// and within a byte least-significant-bit first. -// This function can write up to 32 bits in one go, but VP8LBitReader can only -// read 24 bits max (VP8L_MAX_NUM_BIT_READ). -// VP8LBitWriter's error_ flag is set in case of memory allocation error. -static WEBP_INLINE void VP8LPutBits(VP8LBitWriter* const bw, - uint32_t bits, int n_bits) { - if (sizeof(vp8l_wtype_t) == 4) { - if (n_bits > 0) { - if (bw->used_ >= 32) { - VP8LPutBitsFlushBits(bw); - } - bw->bits_ |= (vp8l_atype_t)bits << bw->used_; - bw->used_ += n_bits; - } - } else { - VP8LPutBitsInternal(bw, bits, n_bits); - } -} - -//------------------------------------------------------------------------------ - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // WEBP_UTILS_BIT_WRITER_UTILS_H_ diff --git a/libwebp/src/utils/color_cache_utils.c b/libwebp/src/utils/color_cache_utils.c index 7b5222b6..cd8be1f7 100644 --- a/libwebp/src/utils/color_cache_utils.c +++ b/libwebp/src/utils/color_cache_utils.c @@ -14,7 +14,9 @@ #include #include #include + #include "src/utils/color_cache_utils.h" +#include "src/webp/types.h" #include "src/utils/utils.h" //------------------------------------------------------------------------------ @@ -24,18 +26,18 @@ int VP8LColorCacheInit(VP8LColorCache* const color_cache, int hash_bits) { const int hash_size = 1 << hash_bits; assert(color_cache != NULL); assert(hash_bits > 0); - color_cache->colors_ = (uint32_t*)WebPSafeCalloc( - (uint64_t)hash_size, sizeof(*color_cache->colors_)); - if (color_cache->colors_ == NULL) return 0; - color_cache->hash_shift_ = 32 - hash_bits; - color_cache->hash_bits_ = hash_bits; + color_cache->colors = (uint32_t*)WebPSafeCalloc( + (uint64_t)hash_size, sizeof(*color_cache->colors)); + if (color_cache->colors == NULL) return 0; + color_cache->hash_shift = 32 - hash_bits; + color_cache->hash_bits = hash_bits; return 1; } void VP8LColorCacheClear(VP8LColorCache* const color_cache) { if (color_cache != NULL) { - WebPSafeFree(color_cache->colors_); - color_cache->colors_ = NULL; + WebPSafeFree(color_cache->colors); + color_cache->colors = NULL; } } @@ -43,7 +45,7 @@ void VP8LColorCacheCopy(const VP8LColorCache* const src, VP8LColorCache* const dst) { assert(src != NULL); assert(dst != NULL); - assert(src->hash_bits_ == dst->hash_bits_); - memcpy(dst->colors_, src->colors_, - ((size_t)1u << dst->hash_bits_) * sizeof(*dst->colors_)); + assert(src->hash_bits == dst->hash_bits); + memcpy(dst->colors, src->colors, + ((size_t)1u << dst->hash_bits) * sizeof(*dst->colors)); } diff --git a/libwebp/src/utils/color_cache_utils.h b/libwebp/src/utils/color_cache_utils.h index b45d47c2..ac8d9815 100644 --- a/libwebp/src/utils/color_cache_utils.h +++ b/libwebp/src/utils/color_cache_utils.h @@ -17,6 +17,7 @@ #include +#include "src/dsp/cpu.h" #include "src/dsp/dsp.h" #include "src/webp/types.h" @@ -26,9 +27,9 @@ extern "C" { // Main color cache struct. typedef struct { - uint32_t* colors_; // color entries - int hash_shift_; // Hash shift: 32 - hash_bits_. - int hash_bits_; + uint32_t* colors; // color entries + int hash_shift; // Hash shift: 32 - 'hash_bits'. + int hash_bits; } VP8LColorCache; static const uint32_t kHashMul = 0x1e35a7bdu; @@ -40,32 +41,32 @@ int VP8LHashPix(uint32_t argb, int shift) { static WEBP_INLINE uint32_t VP8LColorCacheLookup( const VP8LColorCache* const cc, uint32_t key) { - assert((key >> cc->hash_bits_) == 0u); - return cc->colors_[key]; + assert((key >> cc->hash_bits) == 0u); + return cc->colors[key]; } static WEBP_INLINE void VP8LColorCacheSet(const VP8LColorCache* const cc, uint32_t key, uint32_t argb) { - assert((key >> cc->hash_bits_) == 0u); - cc->colors_[key] = argb; + assert((key >> cc->hash_bits) == 0u); + cc->colors[key] = argb; } static WEBP_INLINE void VP8LColorCacheInsert(const VP8LColorCache* const cc, uint32_t argb) { - const int key = VP8LHashPix(argb, cc->hash_shift_); - cc->colors_[key] = argb; + const int key = VP8LHashPix(argb, cc->hash_shift); + cc->colors[key] = argb; } static WEBP_INLINE int VP8LColorCacheGetIndex(const VP8LColorCache* const cc, uint32_t argb) { - return VP8LHashPix(argb, cc->hash_shift_); + return VP8LHashPix(argb, cc->hash_shift); } // Return the key if cc contains argb, and -1 otherwise. static WEBP_INLINE int VP8LColorCacheContains(const VP8LColorCache* const cc, uint32_t argb) { - const int key = VP8LHashPix(argb, cc->hash_shift_); - return (cc->colors_[key] == argb) ? key : -1; + const int key = VP8LHashPix(argb, cc->hash_shift); + return (cc->colors[key] == argb) ? key : -1; } //------------------------------------------------------------------------------ diff --git a/libwebp/src/utils/filters_utils.c b/libwebp/src/utils/filters_utils.c index bbc2c34d..9286d371 100644 --- a/libwebp/src/utils/filters_utils.c +++ b/libwebp/src/utils/filters_utils.c @@ -11,10 +11,13 @@ // // Author: Urvang (urvang@google.com) -#include "src/utils/filters_utils.h" #include #include +#include "src/dsp/dsp.h" +#include "src/webp/types.h" +#include "src/utils/filters_utils.h" + // ----------------------------------------------------------------------------- // Quick estimate of a potentially interesting filter mode to try. diff --git a/libwebp/src/utils/filters_utils.h b/libwebp/src/utils/filters_utils.h index 61da66e2..8e9418df 100644 --- a/libwebp/src/utils/filters_utils.h +++ b/libwebp/src/utils/filters_utils.h @@ -14,8 +14,8 @@ #ifndef WEBP_UTILS_FILTERS_UTILS_H_ #define WEBP_UTILS_FILTERS_UTILS_H_ -#include "src/webp/types.h" #include "src/dsp/dsp.h" +#include "src/webp/types.h" #ifdef __cplusplus extern "C" { diff --git a/libwebp/src/utils/huffman_encode_utils.c b/libwebp/src/utils/huffman_encode_utils.c deleted file mode 100644 index 585db919..00000000 --- a/libwebp/src/utils/huffman_encode_utils.c +++ /dev/null @@ -1,416 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Author: Jyrki Alakuijala (jyrki@google.com) -// -// Entropy encoding (Huffman) for webp lossless. - -#include -#include -#include -#include "src/utils/huffman_encode_utils.h" -#include "src/utils/utils.h" -#include "src/webp/format_constants.h" - -// ----------------------------------------------------------------------------- -// Util function to optimize the symbol map for RLE coding - -// Heuristics for selecting the stride ranges to collapse. -static int ValuesShouldBeCollapsedToStrideAverage(int a, int b) { - return abs(a - b) < 4; -} - -// Change the population counts in a way that the consequent -// Huffman tree compression, especially its RLE-part, give smaller output. -static void OptimizeHuffmanForRle(int length, uint8_t* const good_for_rle, - uint32_t* const counts) { - // 1) Let's make the Huffman code more compatible with rle encoding. - int i; - for (; length >= 0; --length) { - if (length == 0) { - return; // All zeros. - } - if (counts[length - 1] != 0) { - // Now counts[0..length - 1] does not have trailing zeros. - break; - } - } - // 2) Let's mark all population counts that already can be encoded - // with an rle code. - { - // Let's not spoil any of the existing good rle codes. - // Mark any seq of 0's that is longer as 5 as a good_for_rle. - // Mark any seq of non-0's that is longer as 7 as a good_for_rle. - uint32_t symbol = counts[0]; - int stride = 0; - for (i = 0; i < length + 1; ++i) { - if (i == length || counts[i] != symbol) { - if ((symbol == 0 && stride >= 5) || - (symbol != 0 && stride >= 7)) { - int k; - for (k = 0; k < stride; ++k) { - good_for_rle[i - k - 1] = 1; - } - } - stride = 1; - if (i != length) { - symbol = counts[i]; - } - } else { - ++stride; - } - } - } - // 3) Let's replace those population counts that lead to more rle codes. - { - uint32_t stride = 0; - uint32_t limit = counts[0]; - uint32_t sum = 0; - for (i = 0; i < length + 1; ++i) { - if (i == length || good_for_rle[i] || - (i != 0 && good_for_rle[i - 1]) || - !ValuesShouldBeCollapsedToStrideAverage(counts[i], limit)) { - if (stride >= 4 || (stride >= 3 && sum == 0)) { - uint32_t k; - // The stride must end, collapse what we have, if we have enough (4). - uint32_t count = (sum + stride / 2) / stride; - if (count < 1) { - count = 1; - } - if (sum == 0) { - // Don't make an all zeros stride to be upgraded to ones. - count = 0; - } - for (k = 0; k < stride; ++k) { - // We don't want to change value at counts[i], - // that is already belonging to the next stride. Thus - 1. - counts[i - k - 1] = count; - } - } - stride = 0; - sum = 0; - if (i < length - 3) { - // All interesting strides have a count of at least 4, - // at least when non-zeros. - limit = (counts[i] + counts[i + 1] + - counts[i + 2] + counts[i + 3] + 2) / 4; - } else if (i < length) { - limit = counts[i]; - } else { - limit = 0; - } - } - ++stride; - if (i != length) { - sum += counts[i]; - if (stride >= 4) { - limit = (sum + stride / 2) / stride; - } - } - } - } -} - -// A comparer function for two Huffman trees: sorts first by 'total count' -// (more comes first), and then by 'value' (more comes first). -static int CompareHuffmanTrees(const void* ptr1, const void* ptr2) { - const HuffmanTree* const t1 = (const HuffmanTree*)ptr1; - const HuffmanTree* const t2 = (const HuffmanTree*)ptr2; - if (t1->total_count_ > t2->total_count_) { - return -1; - } else if (t1->total_count_ < t2->total_count_) { - return 1; - } else { - assert(t1->value_ != t2->value_); - return (t1->value_ < t2->value_) ? -1 : 1; - } -} - -static void SetBitDepths(const HuffmanTree* const tree, - const HuffmanTree* const pool, - uint8_t* const bit_depths, int level) { - if (tree->pool_index_left_ >= 0) { - SetBitDepths(&pool[tree->pool_index_left_], pool, bit_depths, level + 1); - SetBitDepths(&pool[tree->pool_index_right_], pool, bit_depths, level + 1); - } else { - bit_depths[tree->value_] = level; - } -} - -// Create an optimal Huffman tree. -// -// (data,length): population counts. -// tree_limit: maximum bit depth (inclusive) of the codes. -// bit_depths[]: how many bits are used for the symbol. -// -// Returns 0 when an error has occurred. -// -// The catch here is that the tree cannot be arbitrarily deep -// -// count_limit is the value that is to be faked as the minimum value -// and this minimum value is raised until the tree matches the -// maximum length requirement. -// -// This algorithm is not of excellent performance for very long data blocks, -// especially when population counts are longer than 2**tree_limit, but -// we are not planning to use this with extremely long blocks. -// -// See https://en.wikipedia.org/wiki/Huffman_coding -static void GenerateOptimalTree(const uint32_t* const histogram, - int histogram_size, - HuffmanTree* tree, int tree_depth_limit, - uint8_t* const bit_depths) { - uint32_t count_min; - HuffmanTree* tree_pool; - int tree_size_orig = 0; - int i; - - for (i = 0; i < histogram_size; ++i) { - if (histogram[i] != 0) { - ++tree_size_orig; - } - } - - if (tree_size_orig == 0) { // pretty optimal already! - return; - } - - tree_pool = tree + tree_size_orig; - - // For block sizes with less than 64k symbols we never need to do a - // second iteration of this loop. - // If we actually start running inside this loop a lot, we would perhaps - // be better off with the Katajainen algorithm. - assert(tree_size_orig <= (1 << (tree_depth_limit - 1))); - for (count_min = 1; ; count_min *= 2) { - int tree_size = tree_size_orig; - // We need to pack the Huffman tree in tree_depth_limit bits. - // So, we try by faking histogram entries to be at least 'count_min'. - int idx = 0; - int j; - for (j = 0; j < histogram_size; ++j) { - if (histogram[j] != 0) { - const uint32_t count = - (histogram[j] < count_min) ? count_min : histogram[j]; - tree[idx].total_count_ = count; - tree[idx].value_ = j; - tree[idx].pool_index_left_ = -1; - tree[idx].pool_index_right_ = -1; - ++idx; - } - } - - // Build the Huffman tree. - qsort(tree, tree_size, sizeof(*tree), CompareHuffmanTrees); - - if (tree_size > 1) { // Normal case. - int tree_pool_size = 0; - while (tree_size > 1) { // Finish when we have only one root. - uint32_t count; - tree_pool[tree_pool_size++] = tree[tree_size - 1]; - tree_pool[tree_pool_size++] = tree[tree_size - 2]; - count = tree_pool[tree_pool_size - 1].total_count_ + - tree_pool[tree_pool_size - 2].total_count_; - tree_size -= 2; - { - // Search for the insertion point. - int k; - for (k = 0; k < tree_size; ++k) { - if (tree[k].total_count_ <= count) { - break; - } - } - memmove(tree + (k + 1), tree + k, (tree_size - k) * sizeof(*tree)); - tree[k].total_count_ = count; - tree[k].value_ = -1; - - tree[k].pool_index_left_ = tree_pool_size - 1; - tree[k].pool_index_right_ = tree_pool_size - 2; - tree_size = tree_size + 1; - } - } - SetBitDepths(&tree[0], tree_pool, bit_depths, 0); - } else if (tree_size == 1) { // Trivial case: only one element. - bit_depths[tree[0].value_] = 1; - } - - { - // Test if this Huffman tree satisfies our 'tree_depth_limit' criteria. - int max_depth = bit_depths[0]; - for (j = 1; j < histogram_size; ++j) { - if (max_depth < bit_depths[j]) { - max_depth = bit_depths[j]; - } - } - if (max_depth <= tree_depth_limit) { - break; - } - } - } -} - -// ----------------------------------------------------------------------------- -// Coding of the Huffman tree values - -static HuffmanTreeToken* CodeRepeatedValues(int repetitions, - HuffmanTreeToken* tokens, - int value, int prev_value) { - assert(value <= MAX_ALLOWED_CODE_LENGTH); - if (value != prev_value) { - tokens->code = value; - tokens->extra_bits = 0; - ++tokens; - --repetitions; - } - while (repetitions >= 1) { - if (repetitions < 3) { - int i; - for (i = 0; i < repetitions; ++i) { - tokens->code = value; - tokens->extra_bits = 0; - ++tokens; - } - break; - } else if (repetitions < 7) { - tokens->code = 16; - tokens->extra_bits = repetitions - 3; - ++tokens; - break; - } else { - tokens->code = 16; - tokens->extra_bits = 3; - ++tokens; - repetitions -= 6; - } - } - return tokens; -} - -static HuffmanTreeToken* CodeRepeatedZeros(int repetitions, - HuffmanTreeToken* tokens) { - while (repetitions >= 1) { - if (repetitions < 3) { - int i; - for (i = 0; i < repetitions; ++i) { - tokens->code = 0; // 0-value - tokens->extra_bits = 0; - ++tokens; - } - break; - } else if (repetitions < 11) { - tokens->code = 17; - tokens->extra_bits = repetitions - 3; - ++tokens; - break; - } else if (repetitions < 139) { - tokens->code = 18; - tokens->extra_bits = repetitions - 11; - ++tokens; - break; - } else { - tokens->code = 18; - tokens->extra_bits = 0x7f; // 138 repeated 0s - ++tokens; - repetitions -= 138; - } - } - return tokens; -} - -int VP8LCreateCompressedHuffmanTree(const HuffmanTreeCode* const tree, - HuffmanTreeToken* tokens, int max_tokens) { - HuffmanTreeToken* const starting_token = tokens; - HuffmanTreeToken* const ending_token = tokens + max_tokens; - const int depth_size = tree->num_symbols; - int prev_value = 8; // 8 is the initial value for rle. - int i = 0; - assert(tokens != NULL); - while (i < depth_size) { - const int value = tree->code_lengths[i]; - int k = i + 1; - int runs; - while (k < depth_size && tree->code_lengths[k] == value) ++k; - runs = k - i; - if (value == 0) { - tokens = CodeRepeatedZeros(runs, tokens); - } else { - tokens = CodeRepeatedValues(runs, tokens, value, prev_value); - prev_value = value; - } - i += runs; - assert(tokens <= ending_token); - } - (void)ending_token; // suppress 'unused variable' warning - return (int)(tokens - starting_token); -} - -// ----------------------------------------------------------------------------- - -// Pre-reversed 4-bit values. -static const uint8_t kReversedBits[16] = { - 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe, - 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf -}; - -static uint32_t ReverseBits(int num_bits, uint32_t bits) { - uint32_t retval = 0; - int i = 0; - while (i < num_bits) { - i += 4; - retval |= kReversedBits[bits & 0xf] << (MAX_ALLOWED_CODE_LENGTH + 1 - i); - bits >>= 4; - } - retval >>= (MAX_ALLOWED_CODE_LENGTH + 1 - num_bits); - return retval; -} - -// Get the actual bit values for a tree of bit depths. -static void ConvertBitDepthsToSymbols(HuffmanTreeCode* const tree) { - // 0 bit-depth means that the symbol does not exist. - int i; - int len; - uint32_t next_code[MAX_ALLOWED_CODE_LENGTH + 1]; - int depth_count[MAX_ALLOWED_CODE_LENGTH + 1] = { 0 }; - - assert(tree != NULL); - len = tree->num_symbols; - for (i = 0; i < len; ++i) { - const int code_length = tree->code_lengths[i]; - assert(code_length <= MAX_ALLOWED_CODE_LENGTH); - ++depth_count[code_length]; - } - depth_count[0] = 0; // ignore unused symbol - next_code[0] = 0; - { - uint32_t code = 0; - for (i = 1; i <= MAX_ALLOWED_CODE_LENGTH; ++i) { - code = (code + depth_count[i - 1]) << 1; - next_code[i] = code; - } - } - for (i = 0; i < len; ++i) { - const int code_length = tree->code_lengths[i]; - tree->codes[i] = ReverseBits(code_length, next_code[code_length]++); - } -} - -// ----------------------------------------------------------------------------- -// Main entry point - -void VP8LCreateHuffmanTree(uint32_t* const histogram, int tree_depth_limit, - uint8_t* const buf_rle, HuffmanTree* const huff_tree, - HuffmanTreeCode* const huff_code) { - const int num_symbols = huff_code->num_symbols; - memset(buf_rle, 0, num_symbols * sizeof(*buf_rle)); - OptimizeHuffmanForRle(num_symbols, buf_rle, histogram); - GenerateOptimalTree(histogram, num_symbols, huff_tree, tree_depth_limit, - huff_code->code_lengths); - // Create the actual bit codes for the bit lengths. - ConvertBitDepthsToSymbols(huff_code); -} diff --git a/libwebp/src/utils/huffman_encode_utils.h b/libwebp/src/utils/huffman_encode_utils.h deleted file mode 100644 index 3f7f1d80..00000000 --- a/libwebp/src/utils/huffman_encode_utils.h +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Author: Jyrki Alakuijala (jyrki@google.com) -// -// Entropy encoding (Huffman) for webp lossless - -#ifndef WEBP_UTILS_HUFFMAN_ENCODE_UTILS_H_ -#define WEBP_UTILS_HUFFMAN_ENCODE_UTILS_H_ - -#include "src/webp/types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -// Struct for holding the tree header in coded form. -typedef struct { - uint8_t code; // value (0..15) or escape code (16,17,18) - uint8_t extra_bits; // extra bits for escape codes -} HuffmanTreeToken; - -// Struct to represent the tree codes (depth and bits array). -typedef struct { - int num_symbols; // Number of symbols. - uint8_t* code_lengths; // Code lengths of the symbols. - uint16_t* codes; // Symbol Codes. -} HuffmanTreeCode; - -// Struct to represent the Huffman tree. -typedef struct { - uint32_t total_count_; // Symbol frequency. - int value_; // Symbol value. - int pool_index_left_; // Index for the left sub-tree. - int pool_index_right_; // Index for the right sub-tree. -} HuffmanTree; - -// Turn the Huffman tree into a token sequence. -// Returns the number of tokens used. -int VP8LCreateCompressedHuffmanTree(const HuffmanTreeCode* const tree, - HuffmanTreeToken* tokens, int max_tokens); - -// Create an optimized tree, and tokenize it. -// 'buf_rle' and 'huff_tree' are pre-allocated and the 'tree' is the constructed -// huffman code tree. -void VP8LCreateHuffmanTree(uint32_t* const histogram, int tree_depth_limit, - uint8_t* const buf_rle, HuffmanTree* const huff_tree, - HuffmanTreeCode* const huff_code); - -#ifdef __cplusplus -} -#endif - -#endif // WEBP_UTILS_HUFFMAN_ENCODE_UTILS_H_ diff --git a/libwebp/src/utils/huffman_utils.c b/libwebp/src/utils/huffman_utils.c index 16f9faaa..b3f93a0f 100644 --- a/libwebp/src/utils/huffman_utils.c +++ b/libwebp/src/utils/huffman_utils.c @@ -14,9 +14,11 @@ #include #include #include + #include "src/utils/huffman_utils.h" #include "src/utils/utils.h" #include "src/webp/format_constants.h" +#include "src/webp/types.h" // Huffman data read via DecodeImageStream is represented in two (red and green) // bytes. diff --git a/libwebp/src/utils/huffman_utils.h b/libwebp/src/utils/huffman_utils.h index d511dc05..5e19a7e2 100644 --- a/libwebp/src/utils/huffman_utils.h +++ b/libwebp/src/utils/huffman_utils.h @@ -15,6 +15,7 @@ #define WEBP_UTILS_HUFFMAN_UTILS_H_ #include + #include "src/webp/format_constants.h" #include "src/webp/types.h" diff --git a/libwebp/src/utils/palette.c b/libwebp/src/utils/palette.c index 515da210..6251db19 100644 --- a/libwebp/src/utils/palette.c +++ b/libwebp/src/utils/palette.c @@ -15,12 +15,14 @@ #include #include +#include #include "src/dsp/lossless_common.h" #include "src/utils/color_cache_utils.h" #include "src/utils/utils.h" #include "src/webp/encode.h" #include "src/webp/format_constants.h" +#include "src/webp/types.h" // ----------------------------------------------------------------------------- @@ -191,6 +193,12 @@ static void PaletteSortMinimizeDeltas(const uint32_t* const palette_sorted, // Find greedily always the closest color of the predicted color to minimize // deltas in the palette. This reduces storage needs since the // palette is stored with delta encoding. + if (num_colors > 17) { + if (palette[0] == 0) { + --num_colors; + SwapColor(&palette[num_colors], &palette[0]); + } + } for (i = 0; i < num_colors; ++i) { int best_ix = i; uint32_t best_score = ~0U; @@ -384,8 +392,13 @@ int PaletteSort(PaletteSorting method, const struct WebPPicture* const pic, uint32_t* const palette) { switch (method) { case kSortedDefault: - // Nothing to do, we have already sorted the palette. - memcpy(palette, palette_sorted, num_colors * sizeof(*palette)); + if (palette_sorted[0] == 0 && num_colors > 17) { + memcpy(palette, palette_sorted + 1, + (num_colors - 1) * sizeof(*palette_sorted)); + palette[num_colors - 1] = 0; + } else { + memcpy(palette, palette_sorted, num_colors * sizeof(*palette)); + } return 1; case kMinimizeDelta: PaletteSortMinimizeDeltas(palette_sorted, num_colors, palette); diff --git a/libwebp/src/utils/palette.h b/libwebp/src/utils/palette.h index 34479e46..417c61fa 100644 --- a/libwebp/src/utils/palette.h +++ b/libwebp/src/utils/palette.h @@ -53,6 +53,8 @@ int GetColorPalette(const struct WebPPicture* const pic, // Sorts the palette according to the criterion defined by 'method'. // 'palette_sorted' is the input palette sorted lexicographically, as done in // PrepareMapToPalette. Returns 0 on memory allocation error. +// For kSortedDefault and kMinimizeDelta methods, 0 (if present) is set as the +// last element to optimize later storage. int PaletteSort(PaletteSorting method, const struct WebPPicture* const pic, const uint32_t* const palette_sorted, uint32_t num_colors, uint32_t* const palette); diff --git a/libwebp/src/utils/quant_levels_dec_utils.c b/libwebp/src/utils/quant_levels_dec_utils.c index 97e78937..b42aa1b3 100644 --- a/libwebp/src/utils/quant_levels_dec_utils.c +++ b/libwebp/src/utils/quant_levels_dec_utils.c @@ -19,6 +19,7 @@ #include // for memset #include "src/utils/utils.h" +#include "src/webp/types.h" // #define USE_DITHERING // uncomment to enable ordered dithering (not vital) @@ -43,30 +44,30 @@ static const uint8_t kOrderedDither[DSIZE][DSIZE] = { #endif typedef struct { - int width_, height_; // dimension - int stride_; // stride in bytes - int row_; // current input row being processed - uint8_t* src_; // input pointer - uint8_t* dst_; // output pointer + int width, height; // dimension + int stride; // stride in bytes + int row; // current input row being processed + uint8_t* src; // input pointer + uint8_t* dst; // output pointer - int radius_; // filter radius (=delay) - int scale_; // normalization factor, in FIX bits precision + int radius; // filter radius (=delay) + int scale; // normalization factor, in FIX bits precision - void* mem_; // all memory + void* mem; // all memory // various scratch buffers - uint16_t* start_; - uint16_t* cur_; - uint16_t* end_; - uint16_t* top_; - uint16_t* average_; + uint16_t* start; + uint16_t* cur; + uint16_t* end; + uint16_t* top; + uint16_t* average; // input levels distribution - int num_levels_; // number of quantized levels - int min_, max_; // min and max level values - int min_level_dist_; // smallest distance between two consecutive levels + int num_levels; // number of quantized levels + int min, max; // min and max level values + int min_level_dist; // smallest distance between two consecutive levels - int16_t* correction_; // size = 1 + 2*LUT_SIZE -> ~4k memory + int16_t* correction; // size = 1 + 2*LUT_SIZE -> ~4k memory } SmoothParams; //------------------------------------------------------------------------------ @@ -79,11 +80,11 @@ static WEBP_INLINE uint8_t clip_8b(int v) { // vertical accumulation static void VFilter(SmoothParams* const p) { - const uint8_t* src = p->src_; - const int w = p->width_; - uint16_t* const cur = p->cur_; - const uint16_t* const top = p->top_; - uint16_t* const out = p->end_; + const uint8_t* src = p->src; + const int w = p->width; + uint16_t* const cur = p->cur; + const uint16_t* const top = p->top; + uint16_t* const out = p->end; uint16_t sum = 0; // all arithmetic is modulo 16bit int x; @@ -95,24 +96,24 @@ static void VFilter(SmoothParams* const p) { cur[x] = new_value; } // move input pointers one row down - p->top_ = p->cur_; - p->cur_ += w; - if (p->cur_ == p->end_) p->cur_ = p->start_; // roll-over + p->top = p->cur; + p->cur += w; + if (p->cur == p->end) p->cur = p->start; // roll-over // We replicate edges, as it's somewhat easier as a boundary condition. // That's why we don't update the 'src' pointer on top/bottom area: - if (p->row_ >= 0 && p->row_ < p->height_ - 1) { - p->src_ += p->stride_; + if (p->row >= 0 && p->row < p->height - 1) { + p->src += p->stride; } } // horizontal accumulation. We use mirror replication of missing pixels, as it's // a little easier to implement (surprisingly). static void HFilter(SmoothParams* const p) { - const uint16_t* const in = p->end_; - uint16_t* const out = p->average_; - const uint32_t scale = p->scale_; - const int w = p->width_; - const int r = p->radius_; + const uint16_t* const in = p->end; + uint16_t* const out = p->average; + const uint32_t scale = p->scale; + const int w = p->width; + const int r = p->radius; int x; for (x = 0; x <= r; ++x) { // left mirroring @@ -132,17 +133,17 @@ static void HFilter(SmoothParams* const p) { // emit one filtered output row static void ApplyFilter(SmoothParams* const p) { - const uint16_t* const average = p->average_; - const int w = p->width_; - const int16_t* const correction = p->correction_; + const uint16_t* const average = p->average; + const int w = p->width; + const int16_t* const correction = p->correction; #if defined(USE_DITHERING) - const uint8_t* const dither = kOrderedDither[p->row_ % DSIZE]; + const uint8_t* const dither = kOrderedDither[p->row % DSIZE]; #endif - uint8_t* const dst = p->dst_; + uint8_t* const dst = p->dst; int x; for (x = 0; x < w; ++x) { const int v = dst[x]; - if (v < p->max_ && v > p->min_) { + if (v < p->max && v > p->min) { const int c = (v << DFIX) + correction[average[x] - (v << LFIX)]; #if defined(USE_DITHERING) dst[x] = clip_8b(c + dither[x % DSIZE]); @@ -151,7 +152,7 @@ static void ApplyFilter(SmoothParams* const p) { #endif } } - p->dst_ += p->stride_; // advance output pointer + p->dst += p->stride; // advance output pointer } //------------------------------------------------------------------------------ @@ -183,28 +184,28 @@ static void InitCorrectionLUT(int16_t* const lut, int min_dist) { static void CountLevels(SmoothParams* const p) { int i, j, last_level; uint8_t used_levels[256] = { 0 }; - const uint8_t* data = p->src_; - p->min_ = 255; - p->max_ = 0; - for (j = 0; j < p->height_; ++j) { - for (i = 0; i < p->width_; ++i) { + const uint8_t* data = p->src; + p->min = 255; + p->max = 0; + for (j = 0; j < p->height; ++j) { + for (i = 0; i < p->width; ++i) { const int v = data[i]; - if (v < p->min_) p->min_ = v; - if (v > p->max_) p->max_ = v; + if (v < p->min) p->min = v; + if (v > p->max) p->max = v; used_levels[v] = 1; } - data += p->stride_; + data += p->stride; } // Compute the mininum distance between two non-zero levels. - p->min_level_dist_ = p->max_ - p->min_; + p->min_level_dist = p->max - p->min; last_level = -1; for (i = 0; i < 256; ++i) { if (used_levels[i]) { - ++p->num_levels_; + ++p->num_levels; if (last_level >= 0) { const int level_dist = i - last_level; - if (level_dist < p->min_level_dist_) { - p->min_level_dist_ = level_dist; + if (level_dist < p->min_level_dist) { + p->min_level_dist = level_dist; } } last_level = i; @@ -217,46 +218,46 @@ static int InitParams(uint8_t* const data, int width, int height, int stride, int radius, SmoothParams* const p) { const int R = 2 * radius + 1; // total size of the kernel - const size_t size_scratch_m = (R + 1) * width * sizeof(*p->start_); - const size_t size_m = width * sizeof(*p->average_); - const size_t size_lut = (1 + 2 * LUT_SIZE) * sizeof(*p->correction_); + const size_t size_scratch_m = (R + 1) * width * sizeof(*p->start); + const size_t size_m = width * sizeof(*p->average); + const size_t size_lut = (1 + 2 * LUT_SIZE) * sizeof(*p->correction); const size_t total_size = size_scratch_m + size_m + size_lut; uint8_t* mem = (uint8_t*)WebPSafeMalloc(1U, total_size); if (mem == NULL) return 0; - p->mem_ = (void*)mem; + p->mem = (void*)mem; - p->start_ = (uint16_t*)mem; - p->cur_ = p->start_; - p->end_ = p->start_ + R * width; - p->top_ = p->end_ - width; - memset(p->top_, 0, width * sizeof(*p->top_)); + p->start = (uint16_t*)mem; + p->cur = p->start; + p->end = p->start + R * width; + p->top = p->end - width; + memset(p->top, 0, width * sizeof(*p->top)); mem += size_scratch_m; - p->average_ = (uint16_t*)mem; + p->average = (uint16_t*)mem; mem += size_m; - p->width_ = width; - p->height_ = height; - p->stride_ = stride; - p->src_ = data; - p->dst_ = data; - p->radius_ = radius; - p->scale_ = (1 << (FIX + LFIX)) / (R * R); // normalization constant - p->row_ = -radius; + p->width = width; + p->height = height; + p->stride = stride; + p->src = data; + p->dst = data; + p->radius = radius; + p->scale = (1 << (FIX + LFIX)) / (R * R); // normalization constant + p->row = -radius; // analyze the input distribution so we can best-fit the threshold CountLevels(p); // correction table - p->correction_ = ((int16_t*)mem) + LUT_SIZE; - InitCorrectionLUT(p->correction_, p->min_level_dist_); + p->correction = ((int16_t*)mem) + LUT_SIZE; + InitCorrectionLUT(p->correction, p->min_level_dist); return 1; } static void CleanupParams(SmoothParams* const p) { - WebPSafeFree(p->mem_); + WebPSafeFree(p->mem); } int WebPDequantizeLevels(uint8_t* const data, int width, int height, int stride, @@ -274,12 +275,12 @@ int WebPDequantizeLevels(uint8_t* const data, int width, int height, int stride, SmoothParams p; memset(&p, 0, sizeof(p)); if (!InitParams(data, width, height, stride, radius, &p)) return 0; - if (p.num_levels_ > 2) { - for (; p.row_ < p.height_; ++p.row_) { + if (p.num_levels > 2) { + for (; p.row < p.height; ++p.row) { VFilter(&p); // accumulate average of input // Need to wait few rows in order to prime the filter, // before emitting some output. - if (p.row_ >= p.radius_) { + if (p.row >= p.radius) { HFilter(&p); ApplyFilter(&p); } diff --git a/libwebp/src/utils/quant_levels_utils.c b/libwebp/src/utils/quant_levels_utils.c deleted file mode 100644 index d65ad3c2..00000000 --- a/libwebp/src/utils/quant_levels_utils.c +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Quantize levels for specified number of quantization-levels ([2, 256]). -// Min and max values are preserved (usual 0 and 255 for alpha plane). -// -// Author: Skal (pascal.massimino@gmail.com) - -#include - -#include "src/utils/quant_levels_utils.h" - -#define NUM_SYMBOLS 256 - -#define MAX_ITER 6 // Maximum number of convergence steps. -#define ERROR_THRESHOLD 1e-4 // MSE stopping criterion. - -// ----------------------------------------------------------------------------- -// Quantize levels. - -int QuantizeLevels(uint8_t* const data, int width, int height, - int num_levels, uint64_t* const sse) { - int freq[NUM_SYMBOLS] = { 0 }; - int q_level[NUM_SYMBOLS] = { 0 }; - double inv_q_level[NUM_SYMBOLS] = { 0 }; - int min_s = 255, max_s = 0; - const size_t data_size = height * width; - int i, num_levels_in, iter; - double last_err = 1.e38, err = 0.; - const double err_threshold = ERROR_THRESHOLD * data_size; - - if (data == NULL) { - return 0; - } - - if (width <= 0 || height <= 0) { - return 0; - } - - if (num_levels < 2 || num_levels > 256) { - return 0; - } - - { - size_t n; - num_levels_in = 0; - for (n = 0; n < data_size; ++n) { - num_levels_in += (freq[data[n]] == 0); - if (min_s > data[n]) min_s = data[n]; - if (max_s < data[n]) max_s = data[n]; - ++freq[data[n]]; - } - } - - if (num_levels_in <= num_levels) goto End; // nothing to do! - - // Start with uniformly spread centroids. - for (i = 0; i < num_levels; ++i) { - inv_q_level[i] = min_s + (double)(max_s - min_s) * i / (num_levels - 1); - } - - // Fixed values. Won't be changed. - q_level[min_s] = 0; - q_level[max_s] = num_levels - 1; - assert(inv_q_level[0] == min_s); - assert(inv_q_level[num_levels - 1] == max_s); - - // k-Means iterations. - for (iter = 0; iter < MAX_ITER; ++iter) { - double q_sum[NUM_SYMBOLS] = { 0 }; - double q_count[NUM_SYMBOLS] = { 0 }; - int s, slot = 0; - - // Assign classes to representatives. - for (s = min_s; s <= max_s; ++s) { - // Keep track of the nearest neighbour 'slot' - while (slot < num_levels - 1 && - 2 * s > inv_q_level[slot] + inv_q_level[slot + 1]) { - ++slot; - } - if (freq[s] > 0) { - q_sum[slot] += s * freq[s]; - q_count[slot] += freq[s]; - } - q_level[s] = slot; - } - - // Assign new representatives to classes. - if (num_levels > 2) { - for (slot = 1; slot < num_levels - 1; ++slot) { - const double count = q_count[slot]; - if (count > 0.) { - inv_q_level[slot] = q_sum[slot] / count; - } - } - } - - // Compute convergence error. - err = 0.; - for (s = min_s; s <= max_s; ++s) { - const double error = s - inv_q_level[q_level[s]]; - err += freq[s] * error * error; - } - - // Check for convergence: we stop as soon as the error is no - // longer improving. - if (last_err - err < err_threshold) break; - last_err = err; - } - - // Remap the alpha plane to quantized values. - { - // double->int rounding operation can be costly, so we do it - // once for all before remapping. We also perform the data[] -> slot - // mapping, while at it (avoid one indirection in the final loop). - uint8_t map[NUM_SYMBOLS]; - int s; - size_t n; - for (s = min_s; s <= max_s; ++s) { - const int slot = q_level[s]; - map[s] = (uint8_t)(inv_q_level[slot] + .5); - } - // Final pass. - for (n = 0; n < data_size; ++n) { - data[n] = map[data[n]]; - } - } - End: - // Store sum of squared error if needed. - if (sse != NULL) *sse = (uint64_t)err; - - return 1; -} - diff --git a/libwebp/src/utils/quant_levels_utils.h b/libwebp/src/utils/quant_levels_utils.h deleted file mode 100644 index 9ee3ea00..00000000 --- a/libwebp/src/utils/quant_levels_utils.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// Alpha plane quantization utility -// -// Author: Vikas Arora (vikasa@google.com) - -#ifndef WEBP_UTILS_QUANT_LEVELS_UTILS_H_ -#define WEBP_UTILS_QUANT_LEVELS_UTILS_H_ - -#include - -#include "src/webp/types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -// Replace the input 'data' of size 'width'x'height' with 'num-levels' -// quantized values. If not NULL, 'sse' will contain the sum of squared error. -// Valid range for 'num_levels' is [2, 256]. -// Returns false in case of error (data is NULL, or parameters are invalid). -int QuantizeLevels(uint8_t* const data, int width, int height, int num_levels, - uint64_t* const sse); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // WEBP_UTILS_QUANT_LEVELS_UTILS_H_ diff --git a/libwebp/src/utils/random_utils.c b/libwebp/src/utils/random_utils.c index 7edb3fef..56380610 100644 --- a/libwebp/src/utils/random_utils.c +++ b/libwebp/src/utils/random_utils.c @@ -12,6 +12,8 @@ // Author: Skal (pascal.massimino@gmail.com) #include + +#include "src/webp/types.h" #include "src/utils/random_utils.h" //------------------------------------------------------------------------------ @@ -31,13 +33,12 @@ static const uint32_t kRandomTable[VP8_RANDOM_TABLE_SIZE] = { }; void VP8InitRandom(VP8Random* const rg, float dithering) { - memcpy(rg->tab_, kRandomTable, sizeof(rg->tab_)); - rg->index1_ = 0; - rg->index2_ = 31; - rg->amp_ = (dithering < 0.0) ? 0 - : (dithering > 1.0) ? (1 << VP8_RANDOM_DITHER_FIX) - : (uint32_t)((1 << VP8_RANDOM_DITHER_FIX) * dithering); + memcpy(rg->tab, kRandomTable, sizeof(rg->tab)); + rg->index1 = 0; + rg->index2 = 31; + rg->amp = (dithering < 0.0) ? 0 + : (dithering > 1.0) ? (1 << VP8_RANDOM_DITHER_FIX) + : (uint32_t)((1 << VP8_RANDOM_DITHER_FIX) * dithering); } //------------------------------------------------------------------------------ - diff --git a/libwebp/src/utils/random_utils.h b/libwebp/src/utils/random_utils.h index a5006f84..2fbb2002 100644 --- a/libwebp/src/utils/random_utils.h +++ b/libwebp/src/utils/random_utils.h @@ -15,6 +15,7 @@ #define WEBP_UTILS_RANDOM_UTILS_H_ #include + #include "src/webp/types.h" #ifdef __cplusplus @@ -25,9 +26,9 @@ extern "C" { #define VP8_RANDOM_TABLE_SIZE 55 typedef struct { - int index1_, index2_; - uint32_t tab_[VP8_RANDOM_TABLE_SIZE]; - int amp_; + int index1, index2; + uint32_t tab[VP8_RANDOM_TABLE_SIZE]; + int amp; } VP8Random; // Initializes random generator with an amplitude 'dithering' in range [0..1]. @@ -40,11 +41,11 @@ static WEBP_INLINE int VP8RandomBits2(VP8Random* const rg, int num_bits, int amp) { int diff; assert(num_bits + VP8_RANDOM_DITHER_FIX <= 31); - diff = rg->tab_[rg->index1_] - rg->tab_[rg->index2_]; + diff = rg->tab[rg->index1] - rg->tab[rg->index2]; if (diff < 0) diff += (1u << 31); - rg->tab_[rg->index1_] = diff; - if (++rg->index1_ == VP8_RANDOM_TABLE_SIZE) rg->index1_ = 0; - if (++rg->index2_ == VP8_RANDOM_TABLE_SIZE) rg->index2_ = 0; + rg->tab[rg->index1] = diff; + if (++rg->index1 == VP8_RANDOM_TABLE_SIZE) rg->index1 = 0; + if (++rg->index2 == VP8_RANDOM_TABLE_SIZE) rg->index2 = 0; // sign-extend, 0-center diff = (int)((uint32_t)diff << 1) >> (32 - num_bits); diff = (diff * amp) >> VP8_RANDOM_DITHER_FIX; // restrict range @@ -53,7 +54,7 @@ static WEBP_INLINE int VP8RandomBits2(VP8Random* const rg, int num_bits, } static WEBP_INLINE int VP8RandomBits(VP8Random* const rg, int num_bits) { - return VP8RandomBits2(rg, num_bits, rg->amp_); + return VP8RandomBits2(rg, num_bits, rg->amp); } #ifdef __cplusplus diff --git a/libwebp/src/utils/rescaler_utils.c b/libwebp/src/utils/rescaler_utils.c index a0581a14..32dd0af2 100644 --- a/libwebp/src/utils/rescaler_utils.c +++ b/libwebp/src/utils/rescaler_utils.c @@ -15,7 +15,9 @@ #include #include #include + #include "src/dsp/dsp.h" +#include "src/webp/types.h" #include "src/utils/rescaler_utils.h" #include "src/utils/utils.h" diff --git a/libwebp/src/utils/thread_utils.c b/libwebp/src/utils/thread_utils.c index 4e470e17..d61a0bb7 100644 --- a/libwebp/src/utils/thread_utils.c +++ b/libwebp/src/utils/thread_utils.c @@ -13,6 +13,7 @@ #include #include // for memset() + #include "src/utils/thread_utils.h" #include "src/utils/utils.h" @@ -29,9 +30,9 @@ typedef CRITICAL_SECTION pthread_mutex_t; typedef CONDITION_VARIABLE pthread_cond_t; #else typedef struct { - HANDLE waiting_sem_; - HANDLE received_sem_; - HANDLE signal_event_; + HANDLE waiting_sem; + HANDLE received_sem; + HANDLE signal_event; } pthread_cond_t; #endif // _WIN32_WINNT >= 0x600 @@ -51,9 +52,9 @@ typedef struct { #endif // _WIN32 typedef struct { - pthread_mutex_t mutex_; - pthread_cond_t condition_; - pthread_t thread_; + pthread_mutex_t mutex; + pthread_cond_t condition; + pthread_t thread; } WebPWorkerImpl; #if defined(_WIN32) @@ -133,9 +134,9 @@ static int pthread_cond_destroy(pthread_cond_t* const condition) { #ifdef USE_WINDOWS_CONDITION_VARIABLE (void)condition; #else - ok &= (CloseHandle(condition->waiting_sem_) != 0); - ok &= (CloseHandle(condition->received_sem_) != 0); - ok &= (CloseHandle(condition->signal_event_) != 0); + ok &= (CloseHandle(condition->waiting_sem) != 0); + ok &= (CloseHandle(condition->received_sem) != 0); + ok &= (CloseHandle(condition->signal_event) != 0); #endif return !ok; } @@ -145,12 +146,12 @@ static int pthread_cond_init(pthread_cond_t* const condition, void* cond_attr) { #ifdef USE_WINDOWS_CONDITION_VARIABLE InitializeConditionVariable(condition); #else - condition->waiting_sem_ = CreateSemaphore(NULL, 0, 1, NULL); - condition->received_sem_ = CreateSemaphore(NULL, 0, 1, NULL); - condition->signal_event_ = CreateEvent(NULL, FALSE, FALSE, NULL); - if (condition->waiting_sem_ == NULL || - condition->received_sem_ == NULL || - condition->signal_event_ == NULL) { + condition->waiting_sem = CreateSemaphore(NULL, 0, 1, NULL); + condition->received_sem = CreateSemaphore(NULL, 0, 1, NULL); + condition->signal_event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (condition->waiting_sem == NULL || + condition->received_sem == NULL || + condition->signal_event == NULL) { pthread_cond_destroy(condition); return 1; } @@ -163,12 +164,12 @@ static int pthread_cond_signal(pthread_cond_t* const condition) { #ifdef USE_WINDOWS_CONDITION_VARIABLE WakeConditionVariable(condition); #else - if (WaitForSingleObject(condition->waiting_sem_, 0) == WAIT_OBJECT_0) { + if (WaitForSingleObject(condition->waiting_sem, 0) == WAIT_OBJECT_0) { // a thread is waiting in pthread_cond_wait: allow it to be notified - ok = SetEvent(condition->signal_event_); + ok = SetEvent(condition->signal_event); // wait until the event is consumed so the signaler cannot consume // the event via its own pthread_cond_wait. - ok &= (WaitForSingleObject(condition->received_sem_, INFINITE) != + ok &= (WaitForSingleObject(condition->received_sem, INFINITE) != WAIT_OBJECT_0); } #endif @@ -183,12 +184,12 @@ static int pthread_cond_wait(pthread_cond_t* const condition, #else // note that there is a consumer available so the signal isn't dropped in // pthread_cond_signal - if (!ReleaseSemaphore(condition->waiting_sem_, 1, NULL)) return 1; + if (!ReleaseSemaphore(condition->waiting_sem, 1, NULL)) return 1; // now unlock the mutex so pthread_cond_signal may be issued pthread_mutex_unlock(mutex); - ok = (WaitForSingleObject(condition->signal_event_, INFINITE) == + ok = (WaitForSingleObject(condition->signal_event, INFINITE) == WAIT_OBJECT_0); - ok &= ReleaseSemaphore(condition->received_sem_, 1, NULL); + ok &= ReleaseSemaphore(condition->received_sem, 1, NULL); pthread_mutex_lock(mutex); #endif return !ok; @@ -203,17 +204,17 @@ static int pthread_cond_wait(pthread_cond_t* const condition, static THREADFN ThreadLoop(void* ptr) { WebPWorker* const worker = (WebPWorker*)ptr; - WebPWorkerImpl* const impl = (WebPWorkerImpl*)worker->impl_; + WebPWorkerImpl* const impl = (WebPWorkerImpl*)worker->impl; int done = 0; while (!done) { - pthread_mutex_lock(&impl->mutex_); - while (worker->status_ == OK) { // wait in idling mode - pthread_cond_wait(&impl->condition_, &impl->mutex_); + pthread_mutex_lock(&impl->mutex); + while (worker->status == OK) { // wait in idling mode + pthread_cond_wait(&impl->condition, &impl->mutex); } - if (worker->status_ == WORK) { + if (worker->status == WORK) { WebPGetWorkerInterface()->Execute(worker); - worker->status_ = OK; - } else if (worker->status_ == NOT_OK) { // finish the worker + worker->status = OK; + } else if (worker->status == NOT_OK) { // finish the worker done = 1; } // signal to the main thread that we're done (for Sync()) @@ -221,8 +222,8 @@ static THREADFN ThreadLoop(void* ptr) { // condition. Unlocking the mutex first may improve performance in some // implementations, avoiding the case where the waiting thread can't // reacquire the mutex when woken. - pthread_mutex_unlock(&impl->mutex_); - pthread_cond_signal(&impl->condition_); + pthread_mutex_unlock(&impl->mutex); + pthread_cond_signal(&impl->condition); } return THREAD_RETURN(NULL); // Thread is finished } @@ -230,30 +231,30 @@ static THREADFN ThreadLoop(void* ptr) { // main thread state control static void ChangeState(WebPWorker* const worker, WebPWorkerStatus new_status) { // No-op when attempting to change state on a thread that didn't come up. - // Checking status_ without acquiring the lock first would result in a data + // Checking 'status' without acquiring the lock first would result in a data // race. - WebPWorkerImpl* const impl = (WebPWorkerImpl*)worker->impl_; + WebPWorkerImpl* const impl = (WebPWorkerImpl*)worker->impl; if (impl == NULL) return; - pthread_mutex_lock(&impl->mutex_); - if (worker->status_ >= OK) { + pthread_mutex_lock(&impl->mutex); + if (worker->status >= OK) { // wait for the worker to finish - while (worker->status_ != OK) { - pthread_cond_wait(&impl->condition_, &impl->mutex_); + while (worker->status != OK) { + pthread_cond_wait(&impl->condition, &impl->mutex); } // assign new status and release the working thread if needed if (new_status != OK) { - worker->status_ = new_status; + worker->status = new_status; // Note the associated mutex does not need to be held when signaling the // condition. Unlocking the mutex first may improve performance in some // implementations, avoiding the case where the waiting thread can't // reacquire the mutex when woken. - pthread_mutex_unlock(&impl->mutex_); - pthread_cond_signal(&impl->condition_); + pthread_mutex_unlock(&impl->mutex); + pthread_cond_signal(&impl->condition); return; } } - pthread_mutex_unlock(&impl->mutex_); + pthread_mutex_unlock(&impl->mutex); } #endif // WEBP_USE_THREAD @@ -262,54 +263,54 @@ static void ChangeState(WebPWorker* const worker, WebPWorkerStatus new_status) { static void Init(WebPWorker* const worker) { memset(worker, 0, sizeof(*worker)); - worker->status_ = NOT_OK; + worker->status = NOT_OK; } static int Sync(WebPWorker* const worker) { #ifdef WEBP_USE_THREAD ChangeState(worker, OK); #endif - assert(worker->status_ <= OK); + assert(worker->status <= OK); return !worker->had_error; } static int Reset(WebPWorker* const worker) { int ok = 1; worker->had_error = 0; - if (worker->status_ < OK) { + if (worker->status < OK) { #ifdef WEBP_USE_THREAD WebPWorkerImpl* const impl = (WebPWorkerImpl*)WebPSafeCalloc(1, sizeof(WebPWorkerImpl)); - worker->impl_ = (void*)impl; - if (worker->impl_ == NULL) { + worker->impl = (void*)impl; + if (worker->impl == NULL) { return 0; } - if (pthread_mutex_init(&impl->mutex_, NULL)) { + if (pthread_mutex_init(&impl->mutex, NULL)) { goto Error; } - if (pthread_cond_init(&impl->condition_, NULL)) { - pthread_mutex_destroy(&impl->mutex_); + if (pthread_cond_init(&impl->condition, NULL)) { + pthread_mutex_destroy(&impl->mutex); goto Error; } - pthread_mutex_lock(&impl->mutex_); - ok = !pthread_create(&impl->thread_, NULL, ThreadLoop, worker); - if (ok) worker->status_ = OK; - pthread_mutex_unlock(&impl->mutex_); + pthread_mutex_lock(&impl->mutex); + ok = !pthread_create(&impl->thread, NULL, ThreadLoop, worker); + if (ok) worker->status = OK; + pthread_mutex_unlock(&impl->mutex); if (!ok) { - pthread_mutex_destroy(&impl->mutex_); - pthread_cond_destroy(&impl->condition_); + pthread_mutex_destroy(&impl->mutex); + pthread_cond_destroy(&impl->condition); Error: WebPSafeFree(impl); - worker->impl_ = NULL; + worker->impl = NULL; return 0; } #else - worker->status_ = OK; + worker->status = OK; #endif - } else if (worker->status_ > OK) { + } else if (worker->status > OK) { ok = Sync(worker); } - assert(!ok || (worker->status_ == OK)); + assert(!ok || (worker->status == OK)); return ok; } @@ -329,20 +330,20 @@ static void Launch(WebPWorker* const worker) { static void End(WebPWorker* const worker) { #ifdef WEBP_USE_THREAD - if (worker->impl_ != NULL) { - WebPWorkerImpl* const impl = (WebPWorkerImpl*)worker->impl_; + if (worker->impl != NULL) { + WebPWorkerImpl* const impl = (WebPWorkerImpl*)worker->impl; ChangeState(worker, NOT_OK); - pthread_join(impl->thread_, NULL); - pthread_mutex_destroy(&impl->mutex_); - pthread_cond_destroy(&impl->condition_); + pthread_join(impl->thread, NULL); + pthread_mutex_destroy(&impl->mutex); + pthread_cond_destroy(&impl->condition); WebPSafeFree(impl); - worker->impl_ = NULL; + worker->impl = NULL; } #else - worker->status_ = NOT_OK; - assert(worker->impl_ == NULL); + worker->status = NOT_OK; + assert(worker->impl == NULL); #endif - assert(worker->status_ == NOT_OK); + assert(worker->status == NOT_OK); } //------------------------------------------------------------------------------ diff --git a/libwebp/src/utils/thread_utils.h b/libwebp/src/utils/thread_utils.h index 29ad49f7..3575815d 100644 --- a/libwebp/src/utils/thread_utils.h +++ b/libwebp/src/utils/thread_utils.h @@ -37,8 +37,8 @@ typedef int (*WebPWorkerHook)(void*, void*); // Synchronization object used to launch job in the worker thread typedef struct { - void* impl_; // platform-dependent implementation worker details - WebPWorkerStatus status_; + void* impl; // platform-dependent implementation worker details + WebPWorkerStatus status; WebPWorkerHook hook; // hook to call void* data1; // first argument passed to 'hook' void* data2; // second argument passed to 'hook' diff --git a/libwebp/src/utils/utils.c b/libwebp/src/utils/utils.c index 408ce88f..b80bae01 100644 --- a/libwebp/src/utils/utils.c +++ b/libwebp/src/utils/utils.c @@ -13,9 +13,11 @@ #include "src/utils/utils.h" +#include #include #include // for memcpy() +#include "src/webp/types.h" #include "src/utils/palette.h" #include "src/webp/encode.h" @@ -60,9 +62,9 @@ static int countdown_to_fail = 0; // 0 = off typedef struct MemBlock MemBlock; struct MemBlock { - void* ptr_; - size_t size_; - MemBlock* next_; + void* ptr; + size_t size; + MemBlock* next; }; static MemBlock* all_blocks = NULL; @@ -83,7 +85,7 @@ static void PrintMemInfo(void) { fprintf(stderr, "high-water mark: %u\n", (uint32_t)high_water_mark); while (all_blocks != NULL) { MemBlock* b = all_blocks; - all_blocks = b->next_; + all_blocks = b->next; free(b); } } @@ -121,10 +123,10 @@ static void AddMem(void* ptr, size_t size) { if (ptr != NULL) { MemBlock* const b = (MemBlock*)malloc(sizeof(*b)); if (b == NULL) abort(); - b->next_ = all_blocks; + b->next = all_blocks; all_blocks = b; - b->ptr_ = ptr; - b->size_ = size; + b->ptr = ptr; + b->size = size; total_mem += size; total_mem_allocated += size; #if defined(PRINT_MEM_TRAFFIC) @@ -143,18 +145,18 @@ static void SubMem(void* ptr) { if (ptr != NULL) { MemBlock** b = &all_blocks; // Inefficient search, but that's just for debugging. - while (*b != NULL && (*b)->ptr_ != ptr) b = &(*b)->next_; + while (*b != NULL && (*b)->ptr != ptr) b = &(*b)->next; if (*b == NULL) { fprintf(stderr, "Invalid pointer free! (%p)\n", ptr); abort(); } { MemBlock* const block = *b; - *b = block->next_; - total_mem -= block->size_; + *b = block->next; + total_mem -= block->size; #if defined(PRINT_MEM_TRAFFIC) fprintf(stderr, "Mem: %u (-%u)\n", - (uint32_t)total_mem, (uint32_t)block->size_); + (uint32_t)total_mem, (uint32_t)block->size); #endif free(block); } diff --git a/libwebp/src/webp/decode.h b/libwebp/src/webp/decode.h index d6895f5c..1f0d0c22 100644 --- a/libwebp/src/webp/decode.h +++ b/libwebp/src/webp/decode.h @@ -14,13 +14,15 @@ #ifndef WEBP_WEBP_DECODE_H_ #define WEBP_WEBP_DECODE_H_ +#include + #include "./types.h" #ifdef __cplusplus extern "C" { #endif -#define WEBP_DECODER_ABI_VERSION 0x0209 // MAJOR(8b) + MINOR(8b) +#define WEBP_DECODER_ABI_VERSION 0x0210 // MAJOR(8b) + MINOR(8b) // Note: forward declaring enumerations is not allowed in (strict) C and C++, // the types are left here for reference. @@ -451,7 +453,9 @@ struct WebPDecoderOptions { // Will be snapped to even values. int crop_width, crop_height; // dimension of the cropping area int use_scaling; // if true, scaling is applied _afterward_ - int scaled_width, scaled_height; // final resolution + int scaled_width, scaled_height; // final resolution. if one is 0, it is + // guessed from the other one to keep the + // original ratio. int use_threads; // if true, use multi-threaded decoding int dithering_strength; // dithering strength (0=Off, 100=full) int flip; // if true, flip output vertically @@ -479,6 +483,11 @@ WEBP_NODISCARD static WEBP_INLINE int WebPInitDecoderConfig( return WebPInitDecoderConfigInternal(config, WEBP_DECODER_ABI_VERSION); } +// Returns true if 'config' is non-NULL and all configuration parameters are +// within their valid ranges. +WEBP_NODISCARD WEBP_EXTERN int WebPValidateDecoderConfig( + const WebPDecoderConfig* config); + // Instantiate a new incremental decoder object with the requested // configuration. The bitstream can be passed using 'data' and 'data_size' // parameter, in which case the features will be parsed and stored into diff --git a/libwebp/src/webp/demux.h b/libwebp/src/webp/demux.h index 8d246550..0f5bc2b8 100644 --- a/libwebp/src/webp/demux.h +++ b/libwebp/src/webp/demux.h @@ -48,6 +48,8 @@ #ifndef WEBP_WEBP_DEMUX_H_ #define WEBP_WEBP_DEMUX_H_ +#include + #include "./decode.h" // for WEBP_CSP_MODE #include "./mux_types.h" #include "./types.h" diff --git a/libwebp/src/webp/encode.h b/libwebp/src/webp/encode.h index f3d59297..ed493932 100644 --- a/libwebp/src/webp/encode.h +++ b/libwebp/src/webp/encode.h @@ -14,13 +14,15 @@ #ifndef WEBP_WEBP_ENCODE_H_ #define WEBP_WEBP_ENCODE_H_ +#include + #include "./types.h" #ifdef __cplusplus extern "C" { #endif -#define WEBP_ENCODER_ABI_VERSION 0x020f // MAJOR(8b) + MINOR(8b) +#define WEBP_ENCODER_ABI_VERSION 0x0210 // MAJOR(8b) + MINOR(8b) // Note: forward declaring enumerations is not allowed in (strict) C and C++, // the types are left here for reference. @@ -145,7 +147,7 @@ struct WebPConfig { // RGB information for better compression. The default // value is 0. - int use_delta_palette; // reserved for future lossless feature + int use_delta_palette; // reserved int use_sharp_yuv; // if needed, use sharp (and slow) RGB->YUV conversion int qmin; // minimum permissible quality factor @@ -224,14 +226,15 @@ struct WebPAuxStats { uint32_t lossless_features; // bit0:predictor bit1:cross-color transform // bit2:subtract-green bit3:color indexing int histogram_bits; // number of precision bits of histogram - int transform_bits; // precision bits for transform + int transform_bits; // precision bits for predictor transform int cache_bits; // number of bits for color cache lookup int palette_size; // number of color in palette, if used int lossless_size; // final lossless size int lossless_hdr_size; // lossless header (transform, huffman etc) size int lossless_data_size; // lossless image data size + int cross_color_transform_bits; // precision bits for cross-color transform - uint32_t pad[2]; // padding for later use + uint32_t pad[1]; // padding for later use }; // Signature for output function. Should return true if writing was successful. diff --git a/libwebp/src/webp/format_constants.h b/libwebp/src/webp/format_constants.h index 999035c5..9b007c8a 100644 --- a/libwebp/src/webp/format_constants.h +++ b/libwebp/src/webp/format_constants.h @@ -46,7 +46,12 @@ #define CODE_LENGTH_CODES 19 #define MIN_HUFFMAN_BITS 2 // min number of Huffman bits -#define MAX_HUFFMAN_BITS 9 // max number of Huffman bits +#define NUM_HUFFMAN_BITS 3 + +// the maximum number of bits defining a transform is +// MIN_TRANSFORM_BITS + (1 << NUM_TRANSFORM_BITS) - 1 +#define MIN_TRANSFORM_BITS 2 +#define NUM_TRANSFORM_BITS 3 #define TRANSFORM_PRESENT 1 // The bit to be written when next data // to be read is a transform. diff --git a/libwebp/src/webp/mux_types.h b/libwebp/src/webp/mux_types.h index c585d208..c1bbad39 100644 --- a/libwebp/src/webp/mux_types.h +++ b/libwebp/src/webp/mux_types.h @@ -15,6 +15,7 @@ #define WEBP_WEBP_MUX_TYPES_H_ #include // memset() + #include "./types.h" #ifdef __cplusplus diff --git a/libwebp/src/webp/types.h b/libwebp/src/webp/types.h index 0e7ef129..549a0a7d 100644 --- a/libwebp/src/webp/types.h +++ b/libwebp/src/webp/types.h @@ -14,10 +14,10 @@ #ifndef WEBP_WEBP_TYPES_H_ #define WEBP_WEBP_TYPES_H_ -#include // for size_t +#include // IWYU pragma: export for size_t #ifndef _MSC_VER -#include +#include // IWYU pragma: export #if defined(__cplusplus) || !defined(__STRICT_ANSI__) || \ (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) #define WEBP_INLINE inline @@ -36,22 +36,28 @@ typedef long long int int64_t; #define WEBP_INLINE __forceinline #endif /* _MSC_VER */ -#if defined(WEBP_ENABLE_NODISCARD) || \ - (defined(__cplusplus) && __cplusplus >= 201700L) || \ +#ifndef WEBP_NODISCARD +#if defined(WEBP_ENABLE_NODISCARD) && WEBP_ENABLE_NODISCARD +#if (defined(__cplusplus) && __cplusplus >= 201703L) || \ (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L) #define WEBP_NODISCARD [[nodiscard]] #else -// gcc's __has_attribute does not work for enums. +// gcc's __attribute__((warn_unused_result)) does not work for enums. #if defined(__clang__) && defined(__has_attribute) #if __has_attribute(warn_unused_result) #define WEBP_NODISCARD __attribute__((warn_unused_result)) #else #define WEBP_NODISCARD -#endif +#endif /* __has_attribute(warn_unused_result) */ #else #define WEBP_NODISCARD -#endif -#endif +#endif /* defined(__clang__) && defined(__has_attribute) */ +#endif /* (defined(__cplusplus) && __cplusplus >= 201700L) || + (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L) */ +#else +#define WEBP_NODISCARD +#endif /* defined(WEBP_ENABLE_NODISCARD) && WEBP_ENABLE_NODISCARD */ +#endif /* WEBP_NODISCARD */ #ifndef WEBP_EXTERN // This explicitly marks library functions and allows for changing the diff --git a/libwebp/swig/README.md b/libwebp/swig/README.md deleted file mode 100644 index 7fa1c388..00000000 --- a/libwebp/swig/README.md +++ /dev/null @@ -1,67 +0,0 @@ -# SWIG bindings - -## Building - -### JNI SWIG bindings - -```shell - $ gcc -shared -fPIC -fno-strict-aliasing -O2 \ - -I/path/to/your/jdk/includes \ - libwebp_java_wrap.c \ - -lwebp \ - -o libwebp_jni.so -``` - -Example usage: - -```java -import com.google.webp.libwebp; - -import java.lang.reflect.Method; - -public class libwebp_jni_example { - static { - System.loadLibrary("webp_jni"); - } - - /** - * usage: java -cp libwebp.jar:. libwebp_jni_example - */ - public static void main(String argv[]) { - final int version = libwebp.WebPGetDecoderVersion(); - System.out.println("libwebp version: " + Integer.toHexString(version)); - - System.out.println("libwebp methods:"); - final Method[] libwebpMethods = libwebp.class.getDeclaredMethods(); - for (int i = 0; i < libwebpMethods.length; i++) { - System.out.println(libwebpMethods[i]); - } - } -} -``` - -```shell - $ javac -cp libwebp.jar libwebp_jni_example.java - $ java -Djava.library.path=. -cp libwebp.jar:. libwebp_jni_example -``` - -### Python SWIG bindings: - -```shell - $ python setup.py build_ext - $ python setup.py install --prefix=pylocal -``` - -Example usage: - -```python -import glob -import sys -sys.path.append(glob.glob('pylocal/lib/python*/site-packages')[0]) - -from com.google.webp import libwebp -print "libwebp decoder version: %x" % libwebp.WebPGetDecoderVersion() - -print "libwebp attributes:" -for attr in dir(libwebp): print attr -``` diff --git a/libwebp/swig/libwebp.go b/libwebp/swig/libwebp.go deleted file mode 100644 index df205aa3..00000000 --- a/libwebp/swig/libwebp.go +++ /dev/null @@ -1,45 +0,0 @@ -/* ---------------------------------------------------------------------------- - * This file was automatically generated by SWIG (http://www.swig.org). - * Version 2.0.10 - * - * This file is not intended to be easily readable and contains a number of - * coding conventions designed to improve portability and efficiency. Do not make - * changes to this file unless you know what you are doing--modify the SWIG - * interface file instead. - * ----------------------------------------------------------------------------- */ - -package libwebp - -import _ "runtime/cgo" -import "unsafe" - -type _ unsafe.Pointer - -type _swig_fnptr *byte -type _swig_memberptr *byte - -//extern libwebpSwigCgocall -func SwigCgocall() - -//extern libwebpSwigCgocallDone -func SwigCgocallDone() - -//extern libwebpSwigCgocallBack -func SwigCgocallBack() - -//extern libwebpSwigCgocallBackDone -func SwigCgocallBackDone() - -func WebPGetDecoderVersion() int -func Wrapped_WebPGetInfo(string, []int, []int) int - -// WebPGetInfo has 2 output parameters, provide a version in the more natural -// go idiom: -func WebPGetInfo(webp []byte) (ok bool, width int, height int) { - w := []int{0} - h := []int{0} - ok = Wrapped_WebPGetInfo(string(webp), w, h) != 0 - width = w[0] - height = h[0] - return -} diff --git a/libwebp/swig/libwebp.jar b/libwebp/swig/libwebp.jar deleted file mode 100644 index 2fc502b9..00000000 Binary files a/libwebp/swig/libwebp.jar and /dev/null differ diff --git a/libwebp/swig/libwebp.py b/libwebp/swig/libwebp.py deleted file mode 100644 index 2d126b5d..00000000 --- a/libwebp/swig/libwebp.py +++ /dev/null @@ -1,235 +0,0 @@ -# This file was automatically generated by SWIG (http://www.swig.org). -# Version 3.0.12 -# -# Do not make changes to this file unless you know what you are doing--modify -# the SWIG interface file instead. - -from sys import version_info as _swig_python_version_info -if _swig_python_version_info >= (2, 7, 0): - def swig_import_helper(): - import importlib - pkg = __name__.rpartition('.')[0] - mname = '.'.join((pkg, '_libwebp')).lstrip('.') - try: - return importlib.import_module(mname) - except ImportError: - return importlib.import_module('_libwebp') - _libwebp = swig_import_helper() - del swig_import_helper -elif _swig_python_version_info >= (2, 6, 0): - def swig_import_helper(): - from os.path import dirname - import imp - fp = None - try: - fp, pathname, description = imp.find_module('_libwebp', [dirname(__file__)]) - except ImportError: - import _libwebp - return _libwebp - try: - _mod = imp.load_module('_libwebp', fp, pathname, description) - finally: - if fp is not None: - fp.close() - return _mod - _libwebp = swig_import_helper() - del swig_import_helper -else: - import _libwebp -del _swig_python_version_info - -try: - _swig_property = property -except NameError: - pass # Python < 2.2 doesn't have 'property'. - -try: - import builtins as __builtin__ -except ImportError: - import __builtin__ - -def _swig_setattr_nondynamic(self, class_type, name, value, static=1): - if (name == "thisown"): - return self.this.own(value) - if (name == "this"): - if type(value).__name__ == 'SwigPyObject': - self.__dict__[name] = value - return - method = class_type.__swig_setmethods__.get(name, None) - if method: - return method(self, value) - if (not static): - if _newclass: - object.__setattr__(self, name, value) - else: - self.__dict__[name] = value - else: - raise AttributeError("You cannot add attributes to %s" % self) - - -def _swig_setattr(self, class_type, name, value): - return _swig_setattr_nondynamic(self, class_type, name, value, 0) - - -def _swig_getattr(self, class_type, name): - if (name == "thisown"): - return self.this.own() - method = class_type.__swig_getmethods__.get(name, None) - if method: - return method(self) - raise AttributeError("'%s' object has no attribute '%s'" % (class_type.__name__, name)) - - -def _swig_repr(self): - try: - strthis = "proxy of " + self.this.__repr__() - except __builtin__.Exception: - strthis = "" - return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,) - -try: - _object = object - _newclass = 1 -except __builtin__.Exception: - class _object: - pass - _newclass = 0 - - -def WebPGetDecoderVersion(): - """WebPGetDecoderVersion() -> int""" - return _libwebp.WebPGetDecoderVersion() - -def WebPGetInfo(data): - """WebPGetInfo(uint8_t data) -> (width, height)""" - return _libwebp.WebPGetInfo(data) - -def WebPDecodeRGB(data): - """WebPDecodeRGB(uint8_t data) -> (rgb, width, height)""" - return _libwebp.WebPDecodeRGB(data) - -def WebPDecodeRGBA(data): - """WebPDecodeRGBA(uint8_t data) -> (rgb, width, height)""" - return _libwebp.WebPDecodeRGBA(data) - -def WebPDecodeARGB(data): - """WebPDecodeARGB(uint8_t data) -> (rgb, width, height)""" - return _libwebp.WebPDecodeARGB(data) - -def WebPDecodeBGR(data): - """WebPDecodeBGR(uint8_t data) -> (rgb, width, height)""" - return _libwebp.WebPDecodeBGR(data) - -def WebPDecodeBGRA(data): - """WebPDecodeBGRA(uint8_t data) -> (rgb, width, height)""" - return _libwebp.WebPDecodeBGRA(data) - -def WebPGetEncoderVersion(): - """WebPGetEncoderVersion() -> int""" - return _libwebp.WebPGetEncoderVersion() - -def wrap_WebPEncodeRGB(rgb, unused1, unused2, width, height, stride, quality_factor): - """private, do not call directly.""" - return _libwebp.wrap_WebPEncodeRGB(rgb, unused1, unused2, width, height, stride, quality_factor) - -def wrap_WebPEncodeBGR(rgb, unused1, unused2, width, height, stride, quality_factor): - """private, do not call directly.""" - return _libwebp.wrap_WebPEncodeBGR(rgb, unused1, unused2, width, height, stride, quality_factor) - -def wrap_WebPEncodeRGBA(rgb, unused1, unused2, width, height, stride, quality_factor): - """private, do not call directly.""" - return _libwebp.wrap_WebPEncodeRGBA(rgb, unused1, unused2, width, height, stride, quality_factor) - -def wrap_WebPEncodeBGRA(rgb, unused1, unused2, width, height, stride, quality_factor): - """private, do not call directly.""" - return _libwebp.wrap_WebPEncodeBGRA(rgb, unused1, unused2, width, height, stride, quality_factor) - -def wrap_WebPEncodeLosslessRGB(rgb, unused1, unused2, width, height, stride): - """private, do not call directly.""" - return _libwebp.wrap_WebPEncodeLosslessRGB(rgb, unused1, unused2, width, height, stride) - -def wrap_WebPEncodeLosslessBGR(rgb, unused1, unused2, width, height, stride): - """private, do not call directly.""" - return _libwebp.wrap_WebPEncodeLosslessBGR(rgb, unused1, unused2, width, height, stride) - -def wrap_WebPEncodeLosslessRGBA(rgb, unused1, unused2, width, height, stride): - """private, do not call directly.""" - return _libwebp.wrap_WebPEncodeLosslessRGBA(rgb, unused1, unused2, width, height, stride) - -def wrap_WebPEncodeLosslessBGRA(rgb, unused1, unused2, width, height, stride): - """private, do not call directly.""" - return _libwebp.wrap_WebPEncodeLosslessBGRA(rgb, unused1, unused2, width, height, stride) - -_UNUSED = 1 - - -def WebPEncodeRGB(rgb, width, height, stride, quality_factor): - """WebPEncodeRGB(uint8_t rgb, int width, int height, int stride, float quality_factor) -> lossy_webp""" - webp = wrap_WebPEncodeRGB( - rgb, _UNUSED, _UNUSED, width, height, stride, quality_factor) - if len(webp[0]) == 0: - return None - return webp[0] - - -def WebPEncodeRGBA(rgb, width, height, stride, quality_factor): - """WebPEncodeRGBA(uint8_t rgb, int width, int height, int stride, float quality_factor) -> lossy_webp""" - webp = wrap_WebPEncodeRGBA( - rgb, _UNUSED, _UNUSED, width, height, stride, quality_factor) - if len(webp[0]) == 0: - return None - return webp[0] - - -def WebPEncodeBGR(rgb, width, height, stride, quality_factor): - """WebPEncodeBGR(uint8_t rgb, int width, int height, int stride, float quality_factor) -> lossy_webp""" - webp = wrap_WebPEncodeBGR( - rgb, _UNUSED, _UNUSED, width, height, stride, quality_factor) - if len(webp[0]) == 0: - return None - return webp[0] - - -def WebPEncodeBGRA(rgb, width, height, stride, quality_factor): - """WebPEncodeBGRA(uint8_t rgb, int width, int height, int stride, float quality_factor) -> lossy_webp""" - webp = wrap_WebPEncodeBGRA( - rgb, _UNUSED, _UNUSED, width, height, stride, quality_factor) - if len(webp[0]) == 0: - return None - return webp[0] - - -def WebPEncodeLosslessRGB(rgb, width, height, stride): - """WebPEncodeLosslessRGB(uint8_t rgb, int width, int height, int stride) -> lossless_webp""" - webp = wrap_WebPEncodeLosslessRGB(rgb, _UNUSED, _UNUSED, width, height, stride) - if len(webp[0]) == 0: - return None - return webp[0] - - -def WebPEncodeLosslessRGBA(rgb, width, height, stride): - """WebPEncodeLosslessRGBA(uint8_t rgb, int width, int height, int stride) -> lossless_webp""" - webp = wrap_WebPEncodeLosslessRGBA(rgb, _UNUSED, _UNUSED, width, height, stride) - if len(webp[0]) == 0: - return None - return webp[0] - - -def WebPEncodeLosslessBGR(rgb, width, height, stride): - """WebPEncodeLosslessBGR(uint8_t rgb, int width, int height, int stride) -> lossless_webp""" - webp = wrap_WebPEncodeLosslessBGR(rgb, _UNUSED, _UNUSED, width, height, stride) - if len(webp[0]) == 0: - return None - return webp[0] - - -def WebPEncodeLosslessBGRA(rgb, width, height, stride): - """WebPEncodeLosslessBGRA(uint8_t rgb, int width, int height, int stride) -> lossless_webp""" - webp = wrap_WebPEncodeLosslessBGRA(rgb, _UNUSED, _UNUSED, width, height, stride) - if len(webp[0]) == 0: - return None - return webp[0] - -# This file is compatible with both classic and new-style classes. - - diff --git a/libwebp/swig/libwebp.swig b/libwebp/swig/libwebp.swig deleted file mode 100644 index ca382981..00000000 --- a/libwebp/swig/libwebp.swig +++ /dev/null @@ -1,438 +0,0 @@ -// Copyright 2011 Google Inc. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the COPYING file in the root of the source -// tree. An additional intellectual property rights grant can be found -// in the file PATENTS. All contributing project authors may -// be found in the AUTHORS file in the root of the source tree. -// ----------------------------------------------------------------------------- -// -// libwebp swig interface definition -// -// Author: James Zern (jzern@google.com) - -/* - Go bindings: - $ swig -go \ - -outdir . \ - -o libwebp_go_wrap.c libwebp.swig - - Java bindings: - $ mkdir -p java/com/google/webp - $ swig -java \ - -package com.google.webp \ - -outdir java/com/google/webp \ - -o libwebp_java_wrap.c libwebp.swig - - Python bindings: - $ swig -python \ - -outdir . \ - -o libwebp_python_wrap.c libwebp.swig -*/ - -#ifdef SWIGPYTHON -%module(package="com.google.webp") libwebp -%begin %{ -#define SWIG_PYTHON_STRICT_BYTE_CHAR -%} -#else -%module libwebp -#endif /* SWIGPYTHON */ - -%include "constraints.i" -%include "typemaps.i" - -#ifdef SWIGGO -%apply (char* STRING, size_t LENGTH) { (const uint8_t* data, size_t data_size) } - -%rename(wrapped_WebPGetInfo) WebPGetInfo(const uint8_t* data, size_t data_size, - int* width, int* height); -#endif /* SWIGGO */ - -#ifdef SWIGJAVA -%include "arrays_java.i"; -%include "enums.swg" /*NB: requires JDK-1.5+ - See: http://www.swig.org/Doc1.3/Java.html#enumerations */ - -// map uint8_t* such that a byte[] is used -%{ -#include "webp/types.h" -%} -// from arrays_java.i (signed char) -JAVA_ARRAYS_DECL(uint8_t, jbyte, Byte, Uint8) -JAVA_ARRAYS_IMPL(uint8_t, jbyte, Byte, Uint8) -JAVA_ARRAYS_TYPEMAPS(uint8_t, byte, jbyte, Uint8, "[B") -%apply uint8_t[] { uint8_t* } -#endif /* SWIGJAVA */ - -#ifdef SWIGPYTHON -%apply (char* STRING, size_t LENGTH) { (const uint8_t* data, size_t data_size) } -%typemap(out) uint8_t* { - $result = PyString_FromStringAndSize( - (const char*)$1, - ($1 == NULL) ? 0 : ReturnedBufferSize("$symname", arg3, arg4)); -} - -%typemap (in) const uint8_t* rgb (Py_buffer rgb_buffer) { - // NB: with Python < 2.6 the old style buffer protocol may be used: - // Py_ssize_t unused; - // PyObject_AsReadBuffer($input, (const void**)(&$1), &unused); - if (!PyObject_CheckBuffer($input)) { - SWIG_exception_fail(SWIG_TypeError, - "in method '$symname', argument $argnum" - " does not support the buffer interface"); - } - if (PyObject_GetBuffer($input, &rgb_buffer, PyBUF_SIMPLE)) { - SWIG_exception_fail(SWIG_RuntimeError, - "in method '$symname', unable to get buffer view"); - } - $1 = ($1_ltype)rgb_buffer.buf; -} - -%typemap(freearg) const uint8_t* rgb { - PyBuffer_Release(&rgb_buffer$argnum); -} - -%define DECODE_AUTODOC(func) -%feature("autodoc", #func "(uint8_t data) -> (rgb, width, height)") func; -%enddef - -%feature("autodoc", "1"); -DECODE_AUTODOC(WebPDecodeRGB); -DECODE_AUTODOC(WebPDecodeRGBA); -DECODE_AUTODOC(WebPDecodeARGB); -DECODE_AUTODOC(WebPDecodeBGR); -DECODE_AUTODOC(WebPDecodeBGRA); -%feature("autodoc", "WebPGetInfo(uint8_t data) -> (width, height)") WebPGetInfo; -#endif /* SWIGPYTHON */ - -//------------------------------------------------------------------------------ -// Decoder specific - -%apply int* OUTPUT { int* width, int* height } - -int WebPGetDecoderVersion(void); -int WebPGetInfo(const uint8_t* data, size_t data_size, - int* width, int* height); - -#if defined(SWIGJAVA) || defined(SWIGPYTHON) - -// free the buffer returned by these functions after copying into -// the native type -%newobject WebPDecodeRGB; -%newobject WebPDecodeRGBA; -%newobject WebPDecodeARGB; -%newobject WebPDecodeBGR; -%newobject WebPDecodeBGRA; -%typemap(newfree) uint8_t* "free($1);" - -uint8_t* WebPDecodeRGB(const uint8_t* data, size_t data_size, - int* width, int* height); -uint8_t* WebPDecodeRGBA(const uint8_t* data, size_t data_size, - int* width, int* height); -uint8_t* WebPDecodeARGB(const uint8_t* data, size_t data_size, - int* width, int* height); -uint8_t* WebPDecodeBGR(const uint8_t* data, size_t data_size, - int* width, int* height); -uint8_t* WebPDecodeBGRA(const uint8_t* data, size_t data_size, - int* width, int* height); - -#endif /* SWIGJAVA || SWIGPYTHON */ - -//------------------------------------------------------------------------------ -// Encoder specific - -#if defined(SWIGJAVA) || defined(SWIGPYTHON) - -int WebPGetEncoderVersion(void); - -#endif /* SWIGJAVA || SWIGPYTHON */ - -//------------------------------------------------------------------------------ -// Wrapper code additions - -%{ -#include "webp/decode.h" -#include "webp/encode.h" -%} - -#ifdef SWIGJAVA -%{ -#define FillMeInAsSizeCannotBeDeterminedAutomatically \ - (result ? (jint)ReturnedBufferSize(__FUNCTION__, arg3, arg4) : 0) -%} -#endif /* SWIGJAVA */ - -#if defined(SWIGJAVA) || defined(SWIGPYTHON) -%{ -static size_t ReturnedBufferSize( - const char* function, int* width, int* height) { - static const struct sizemap { - const char* function; - int size_multiplier; - } size_map[] = { -#ifdef SWIGJAVA - { "Java_com_google_webp_libwebpJNI_WebPDecodeRGB", 3 }, - { "Java_com_google_webp_libwebpJNI_WebPDecodeRGBA", 4 }, - { "Java_com_google_webp_libwebpJNI_WebPDecodeARGB", 4 }, - { "Java_com_google_webp_libwebpJNI_WebPDecodeBGR", 3 }, - { "Java_com_google_webp_libwebpJNI_WebPDecodeBGRA", 4 }, - { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeRGB", 1 }, - { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeBGR", 1 }, - { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeRGBA", 1 }, - { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeBGRA", 1 }, - { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeLosslessRGB", 1 }, - { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeLosslessBGR", 1 }, - { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeLosslessRGBA", 1 }, - { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeLosslessBGRA", 1 }, -#endif -#ifdef SWIGPYTHON - { "WebPDecodeRGB", 3 }, - { "WebPDecodeRGBA", 4 }, - { "WebPDecodeARGB", 4 }, - { "WebPDecodeBGR", 3 }, - { "WebPDecodeBGRA", 4 }, - { "wrap_WebPEncodeRGB", 1 }, - { "wrap_WebPEncodeBGR", 1 }, - { "wrap_WebPEncodeRGBA", 1 }, - { "wrap_WebPEncodeBGRA", 1 }, - { "wrap_WebPEncodeLosslessRGB", 1 }, - { "wrap_WebPEncodeLosslessBGR", 1 }, - { "wrap_WebPEncodeLosslessRGBA", 1 }, - { "wrap_WebPEncodeLosslessBGRA", 1 }, -#endif - { NULL, 0 } - }; - const struct sizemap* p; - size_t size = 0; - - for (p = size_map; p->function; ++p) { - if (!strcmp(function, p->function)) { - size = *width * *height * p->size_multiplier; - break; - } - } - - return size; -} -%} - -%{ -typedef size_t (*WebPEncodeFunction)(const uint8_t* rgb, - int width, int height, int stride, - float quality_factor, uint8_t** output); -typedef size_t (*WebPEncodeLosslessFunction)(const uint8_t* rgb, - int width, int height, int stride, - uint8_t** output); - -static uint8_t* EncodeLossy(const uint8_t* rgb, - int width, int height, int stride, - float quality_factor, - WebPEncodeFunction encfn, - int* output_size, int* unused) { - uint8_t* output = NULL; - const size_t image_size = - encfn(rgb, width, height, stride, quality_factor, &output); - // the values of following two will be interpreted by ReturnedBufferSize() - // as 'width' and 'height' in the size calculation. - *output_size = image_size; - *unused = 1; - return image_size ? output : NULL; -} - -static uint8_t* EncodeLossless(const uint8_t* rgb, - int width, int height, int stride, - WebPEncodeLosslessFunction encfn, - int* output_size, int* unused) { - uint8_t* output = NULL; - const size_t image_size = encfn(rgb, width, height, stride, &output); - // the values of the following two will be interpreted by - // ReturnedBufferSize() as 'width' and 'height' in the size calculation. - *output_size = image_size; - *unused = 1; - return image_size ? output : NULL; -} -%} - -#endif /* SWIGJAVA || SWIGPYTHON */ - -//------------------------------------------------------------------------------ -// libwebp/encode wrapper functions - -#if defined(SWIGJAVA) || defined(SWIGPYTHON) - -%apply int* INPUT { int* unused1, int* unused2 } -%apply int* OUTPUT { int* output_size } - -// free the buffer returned by these functions after copying into -// the native type -%newobject wrap_WebPEncodeRGB; -%newobject wrap_WebPEncodeBGR; -%newobject wrap_WebPEncodeRGBA; -%newobject wrap_WebPEncodeBGRA; -%newobject wrap_WebPEncodeLosslessRGB; -%newobject wrap_WebPEncodeLosslessBGR; -%newobject wrap_WebPEncodeLosslessRGBA; -%newobject wrap_WebPEncodeLosslessBGRA; - -#ifdef SWIGJAVA -// There's no reason to call these directly -%javamethodmodifiers wrap_WebPEncodeRGB "private"; -%javamethodmodifiers wrap_WebPEncodeBGR "private"; -%javamethodmodifiers wrap_WebPEncodeRGBA "private"; -%javamethodmodifiers wrap_WebPEncodeBGRA "private"; -%javamethodmodifiers wrap_WebPEncodeLosslessRGB "private"; -%javamethodmodifiers wrap_WebPEncodeLosslessBGR "private"; -%javamethodmodifiers wrap_WebPEncodeLosslessRGBA "private"; -%javamethodmodifiers wrap_WebPEncodeLosslessBGRA "private"; -#endif /* SWIGJAVA */ - -#ifdef SWIGPYTHON -// This autodoc will serve as a catch-all for wrap_*. -%feature("autodoc", "private, do not call directly."); -#endif - -%inline %{ -// Changes the return type of WebPEncode* to more closely match Decode*. -// This also makes it easier to wrap the output buffer in a native type rather -// than dealing with the return pointer. -// The additional parameters are to allow reuse of ReturnedBufferSize(), -// unused2 and output_size will be used in this case. -#define LOSSY_WRAPPER(FUNC) \ - static uint8_t* wrap_##FUNC( \ - const uint8_t* rgb, int* unused1, int* unused2, int* output_size, \ - int width, int height, int stride, float quality_factor) { \ - return EncodeLossy(rgb, width, height, stride, quality_factor, \ - FUNC, output_size, unused2); \ - } \ - -LOSSY_WRAPPER(WebPEncodeRGB) -LOSSY_WRAPPER(WebPEncodeBGR) -LOSSY_WRAPPER(WebPEncodeRGBA) -LOSSY_WRAPPER(WebPEncodeBGRA) - -#undef LOSSY_WRAPPER - -#define LOSSLESS_WRAPPER(FUNC) \ - static uint8_t* wrap_##FUNC( \ - const uint8_t* rgb, int* unused1, int* unused2, int* output_size, \ - int width, int height, int stride) { \ - return EncodeLossless(rgb, width, height, stride, \ - FUNC, output_size, unused2); \ - } \ - -LOSSLESS_WRAPPER(WebPEncodeLosslessRGB) -LOSSLESS_WRAPPER(WebPEncodeLosslessBGR) -LOSSLESS_WRAPPER(WebPEncodeLosslessRGBA) -LOSSLESS_WRAPPER(WebPEncodeLosslessBGRA) - -#undef LOSSLESS_WRAPPER - -%} - -#endif /* SWIGJAVA || SWIGPYTHON */ - -//------------------------------------------------------------------------------ -// Language specific - -#ifdef SWIGGO -%insert(go_wrapper) %{ - -// WebPGetInfo has 2 output parameters, provide a version in the more natural -// go idiom: -func WebPGetInfo(webp []byte) (ok bool, width int, height int) { - w := []int{0} - h := []int{0} - ok = Wrapped_WebPGetInfo(string(webp), w, h) != 0 - width = w[0] - height = h[0] - return -} - -%} -#endif /* SWIGGO */ - -#ifdef SWIGJAVA -%{ -/* Work around broken gcj jni.h */ -#ifdef __GCJ_JNI_H__ -# undef JNIEXPORT -# define JNIEXPORT -# undef JNICALL -# define JNICALL -#endif -%} - -%pragma(java) modulecode=%{ - private static final int UNUSED = 1; - private static int outputSize[] = { 0 }; -%} - - -%define CALL_ENCODE_LOSSY_WRAPPER(func) -%pragma(java) modulecode=%{ - public static byte[] func( - byte[] rgb, int width, int height, int stride, float quality_factor) { - return wrap_##func( - rgb, UNUSED, UNUSED, outputSize, width, height, stride, quality_factor); - } -%} -%enddef - -%define CALL_ENCODE_LOSSLESS_WRAPPER(func) -%pragma(java) modulecode=%{ - public static byte[] func( - byte[] rgb, int width, int height, int stride) { - return wrap_##func( - rgb, UNUSED, UNUSED, outputSize, width, height, stride); - } -%} -%enddef - -CALL_ENCODE_LOSSY_WRAPPER(WebPEncodeRGB) -CALL_ENCODE_LOSSY_WRAPPER(WebPEncodeRGBA) -CALL_ENCODE_LOSSY_WRAPPER(WebPEncodeBGR) -CALL_ENCODE_LOSSY_WRAPPER(WebPEncodeBGRA) -CALL_ENCODE_LOSSLESS_WRAPPER(WebPEncodeLosslessRGB) -CALL_ENCODE_LOSSLESS_WRAPPER(WebPEncodeLosslessRGBA) -CALL_ENCODE_LOSSLESS_WRAPPER(WebPEncodeLosslessBGR) -CALL_ENCODE_LOSSLESS_WRAPPER(WebPEncodeLosslessBGRA) -#endif /* SWIGJAVA */ - -#ifdef SWIGPYTHON -%pythoncode %{ -_UNUSED = 1 -%} - -%define CALL_ENCODE_LOSSY_WRAPPER(func) -%pythoncode %{ -def func(rgb, width, height, stride, quality_factor): - """func(uint8_t rgb, int width, int height, int stride, float quality_factor) -> lossy_webp""" - webp = wrap_##func( - rgb, _UNUSED, _UNUSED, width, height, stride, quality_factor) - if len(webp[0]) == 0: - return None - return webp[0] -%} -%enddef - -%define CALL_ENCODE_LOSSLESS_WRAPPER(func) -%pythoncode %{ -def func(rgb, width, height, stride): - """func(uint8_t rgb, int width, int height, int stride) -> lossless_webp""" - webp = wrap_##func(rgb, _UNUSED, _UNUSED, width, height, stride) - if len(webp[0]) == 0: - return None - return webp[0] -%} -%enddef - -CALL_ENCODE_LOSSY_WRAPPER(WebPEncodeRGB) -CALL_ENCODE_LOSSY_WRAPPER(WebPEncodeRGBA) -CALL_ENCODE_LOSSY_WRAPPER(WebPEncodeBGR) -CALL_ENCODE_LOSSY_WRAPPER(WebPEncodeBGRA) -CALL_ENCODE_LOSSLESS_WRAPPER(WebPEncodeLosslessRGB) -CALL_ENCODE_LOSSLESS_WRAPPER(WebPEncodeLosslessRGBA) -CALL_ENCODE_LOSSLESS_WRAPPER(WebPEncodeLosslessBGR) -CALL_ENCODE_LOSSLESS_WRAPPER(WebPEncodeLosslessBGRA) -#endif /* SWIGPYTHON */ diff --git a/libwebp/swig/libwebp_gc.c b/libwebp/swig/libwebp_gc.c deleted file mode 100644 index 308b7f83..00000000 --- a/libwebp/swig/libwebp_gc.c +++ /dev/null @@ -1,52 +0,0 @@ -/* ---------------------------------------------------------------------------- - * This file was automatically generated by SWIG (http://www.swig.org). - * Version 2.0.10 - * - * This file is not intended to be easily readable and contains a number of - * coding conventions designed to improve portability and efficiency. Do not make - * changes to this file unless you know what you are doing--modify the SWIG - * interface file instead. - * ----------------------------------------------------------------------------- */ - -/* This file should be compiled with 6c/8c. */ -#pragma dynimport _ _ "libwebp_go.so" - -#include "runtime.h" -#include "cgocall.h" - -#ifdef _64BIT -#define SWIG_PARM_SIZE 8 -#else -#define SWIG_PARM_SIZE 4 -#endif - -#pragma dynimport _wrap_WebPGetDecoderVersion _wrap_WebPGetDecoderVersion "" -extern void (*_wrap_WebPGetDecoderVersion)(void*); -static void (*x_wrap_WebPGetDecoderVersion)(void*) = _wrap_WebPGetDecoderVersion; - -void -·WebPGetDecoderVersion(struct { - uint8 x[SWIG_PARM_SIZE]; -} p) - -{ - runtime·cgocall(x_wrap_WebPGetDecoderVersion, &p); -} - - - -#pragma dynimport _wrap_wrapped_WebPGetInfo _wrap_wrapped_WebPGetInfo "" -extern void (*_wrap_wrapped_WebPGetInfo)(void*); -static void (*x_wrap_wrapped_WebPGetInfo)(void*) = _wrap_wrapped_WebPGetInfo; - -void -·Wrapped_WebPGetInfo(struct { - uint8 x[(2 * SWIG_PARM_SIZE) + (3 * SWIG_PARM_SIZE) + (3 * SWIG_PARM_SIZE) + SWIG_PARM_SIZE]; -} p) - -{ - runtime·cgocall(x_wrap_wrapped_WebPGetInfo, &p); -} - - - diff --git a/libwebp/swig/libwebp_go_wrap.c b/libwebp/swig/libwebp_go_wrap.c deleted file mode 100644 index 351d523f..00000000 --- a/libwebp/swig/libwebp_go_wrap.c +++ /dev/null @@ -1,274 +0,0 @@ -/* ---------------------------------------------------------------------------- - * This file was automatically generated by SWIG (http://www.swig.org). - * Version 2.0.10 - * - * This file is not intended to be easily readable and contains a number of - * coding conventions designed to improve portability and efficiency. Do not make - * changes to this file unless you know what you are doing--modify the SWIG - * interface file instead. - * ----------------------------------------------------------------------------- */ -#define SWIGMODULE libwebp -/* ----------------------------------------------------------------------------- - * This section contains generic SWIG labels for method/variable - * declarations/attributes, and other compiler dependent labels. - * ----------------------------------------------------------------------------- */ - -/* template workaround for compilers that cannot correctly implement the C++ standard */ -#ifndef SWIGTEMPLATEDISAMBIGUATOR -# if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x560) -# define SWIGTEMPLATEDISAMBIGUATOR template -# elif defined(__HP_aCC) -/* Needed even with `aCC -AA' when `aCC -V' reports HP ANSI C++ B3910B A.03.55 */ -/* If we find a maximum version that requires this, the test would be __HP_aCC <= 35500 for A.03.55 */ -# define SWIGTEMPLATEDISAMBIGUATOR template -# else -# define SWIGTEMPLATEDISAMBIGUATOR -# endif -#endif - -/* inline attribute */ -#ifndef SWIGINLINE -# if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__)) -# define SWIGINLINE inline -# else -# define SWIGINLINE -# endif -#endif - -/* attribute recognised by some compilers to avoid 'unused' warnings */ -#ifndef SWIGUNUSED -# if defined(__GNUC__) -# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) -# define SWIGUNUSED __attribute__ ((__unused__)) -# else -# define SWIGUNUSED -# endif -# elif defined(__ICC) -# define SWIGUNUSED __attribute__ ((__unused__)) -# else -# define SWIGUNUSED -# endif -#endif - -#ifndef SWIG_MSC_UNSUPPRESS_4505 -# if defined(_MSC_VER) -# pragma warning(disable : 4505) /* unreferenced local function has been removed */ -# endif -#endif - -#ifndef SWIGUNUSEDPARM -# ifdef __cplusplus -# define SWIGUNUSEDPARM(p) -# else -# define SWIGUNUSEDPARM(p) p SWIGUNUSED -# endif -#endif - -/* internal SWIG method */ -#ifndef SWIGINTERN -# define SWIGINTERN static SWIGUNUSED -#endif - -/* internal inline SWIG method */ -#ifndef SWIGINTERNINLINE -# define SWIGINTERNINLINE SWIGINTERN SWIGINLINE -#endif - -/* exporting methods */ -#if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) -# ifndef GCC_HASCLASSVISIBILITY -# define GCC_HASCLASSVISIBILITY -# endif -#endif - -#ifndef SWIGEXPORT -# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) -# if defined(STATIC_LINKED) -# define SWIGEXPORT -# else -# define SWIGEXPORT __declspec(dllexport) -# endif -# else -# if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY) -# define SWIGEXPORT __attribute__ ((visibility("default"))) -# else -# define SWIGEXPORT -# endif -# endif -#endif - -/* calling conventions for Windows */ -#ifndef SWIGSTDCALL -# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) -# define SWIGSTDCALL __stdcall -# else -# define SWIGSTDCALL -# endif -#endif - -/* Deal with Microsoft's attempt at deprecating C standard runtime functions */ -#if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) -# define _CRT_SECURE_NO_DEPRECATE -#endif - -/* Deal with Microsoft's attempt at deprecating methods in the standard C++ library */ -#if !defined(SWIG_NO_SCL_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_SCL_SECURE_NO_DEPRECATE) -# define _SCL_SECURE_NO_DEPRECATE -#endif - - - -#include -#include -#include -#include -#include - - - -typedef long long intgo; -typedef unsigned long long uintgo; - - - -typedef struct { char *p; intgo n; } _gostring_; -typedef struct { void* array; intgo len; intgo cap; } _goslice_; - - - - -#define swiggo_size_assert_eq(x, y, name) typedef char name[(x-y)*(x-y)*-2+1]; -#define swiggo_size_assert(t, n) swiggo_size_assert_eq(sizeof(t), n, swiggo_sizeof_##t##_is_not_##n) - -swiggo_size_assert(char, 1) -swiggo_size_assert(short, 2) -swiggo_size_assert(int, 4) -typedef long long swiggo_long_long; -swiggo_size_assert(swiggo_long_long, 8) -swiggo_size_assert(float, 4) -swiggo_size_assert(double, 8) - -#ifdef __cplusplus -extern "C" { -#endif -extern void crosscall2(void (*fn)(void *, int), void *, int); -extern void _cgo_allocate(void *, int); -extern void _cgo_panic(void *, int); -#ifdef __cplusplus -} -#endif - -static void *_swig_goallocate(size_t len) { - struct { - size_t len; - void *ret; - } a; - a.len = len; - crosscall2(_cgo_allocate, &a, (int) sizeof a); - return a.ret; -} - -static void _swig_gopanic(const char *p) { - struct { - const char *p; - } a; - a.p = p; - crosscall2(_cgo_panic, &a, (int) sizeof a); -} - - - - -static _gostring_ _swig_makegostring(const char *p, size_t l) { - _gostring_ ret; - ret.p = (char*)_swig_goallocate(l + 1); - memcpy(ret.p, p, l); - ret.n = l; - return ret; -} - -#define SWIG_contract_assert(expr, msg) \ - if (!(expr)) { _swig_gopanic(msg); } else - - -#define SWIG_exception(code, msg) _swig_gopanic(msg) - - -#include "webp/decode.h" -#include "webp/encode.h" - -#ifdef __cplusplus -extern "C" { -#endif - -void -_wrap_WebPGetDecoderVersion(void *swig_v) -{ - int result; - - struct swigargs { - long : 0; - intgo result; - } *swig_a = (struct swigargs *) swig_v; - - - result = (int)WebPGetDecoderVersion(); - swig_a->result = result; -} - - -void -_wrap_wrapped_WebPGetInfo(void *swig_v) -{ - uint8_t *arg1 = (uint8_t *) 0 ; - size_t arg2 ; - int *arg3 = (int *) 0 ; - int *arg4 = (int *) 0 ; - int temp3 ; - int temp4 ; - int result; - - struct swigargs { - _gostring_ arg1; - _goslice_ arg3; - _goslice_ arg4; - long : 0; - intgo result; - } *swig_a = (struct swigargs *) swig_v; - - - arg1 = (uint8_t *)swig_a->arg1.p; - arg2 = (size_t)swig_a->arg1.n; - - { - if (swig_a->arg3.len == 0) { - _swig_gopanic("array must contain at least 1 element"); - } - arg3 = &temp3; - } - { - if (swig_a->arg4.len == 0) { - _swig_gopanic("array must contain at least 1 element"); - } - arg4 = &temp4; - } - - result = (int)WebPGetInfo((uint8_t const *)arg1,arg2,arg3,arg4); - swig_a->result = result; - { - int* a = (int *) swig_a->arg3.array; - a[0] = temp3; - } - { - int* a = (int *) swig_a->arg4.array; - a[0] = temp4; - } - - -} - - -#ifdef __cplusplus -} -#endif - diff --git a/libwebp/swig/libwebp_java_wrap.c b/libwebp/swig/libwebp_java_wrap.c deleted file mode 100644 index c8d4b133..00000000 --- a/libwebp/swig/libwebp_java_wrap.c +++ /dev/null @@ -1,1765 +0,0 @@ -/* ---------------------------------------------------------------------------- - * This file was automatically generated by SWIG (http://www.swig.org). - * Version 2.0.4 - * - * This file is not intended to be easily readable and contains a number of - * coding conventions designed to improve portability and efficiency. Do not make - * changes to this file unless you know what you are doing--modify the SWIG - * interface file instead. - * ----------------------------------------------------------------------------- */ - -#define SWIGJAVA - -/* ----------------------------------------------------------------------------- - * This section contains generic SWIG labels for method/variable - * declarations/attributes, and other compiler dependent labels. - * ----------------------------------------------------------------------------- */ - -/* template workaround for compilers that cannot correctly implement the C++ standard */ -#ifndef SWIGTEMPLATEDISAMBIGUATOR -# if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x560) -# define SWIGTEMPLATEDISAMBIGUATOR template -# elif defined(__HP_aCC) -/* Needed even with `aCC -AA' when `aCC -V' reports HP ANSI C++ B3910B A.03.55 */ -/* If we find a maximum version that requires this, the test would be __HP_aCC <= 35500 for A.03.55 */ -# define SWIGTEMPLATEDISAMBIGUATOR template -# else -# define SWIGTEMPLATEDISAMBIGUATOR -# endif -#endif - -/* inline attribute */ -#ifndef SWIGINLINE -# if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__)) -# define SWIGINLINE inline -# else -# define SWIGINLINE -# endif -#endif - -/* attribute recognised by some compilers to avoid 'unused' warnings */ -#ifndef SWIGUNUSED -# if defined(__GNUC__) -# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) -# define SWIGUNUSED __attribute__ ((__unused__)) -# else -# define SWIGUNUSED -# endif -# elif defined(__ICC) -# define SWIGUNUSED __attribute__ ((__unused__)) -# else -# define SWIGUNUSED -# endif -#endif - -#ifndef SWIG_MSC_UNSUPPRESS_4505 -# if defined(_MSC_VER) -# pragma warning(disable : 4505) /* unreferenced local function has been removed */ -# endif -#endif - -#ifndef SWIGUNUSEDPARM -# ifdef __cplusplus -# define SWIGUNUSEDPARM(p) -# else -# define SWIGUNUSEDPARM(p) p SWIGUNUSED -# endif -#endif - -/* internal SWIG method */ -#ifndef SWIGINTERN -# define SWIGINTERN static SWIGUNUSED -#endif - -/* internal inline SWIG method */ -#ifndef SWIGINTERNINLINE -# define SWIGINTERNINLINE SWIGINTERN SWIGINLINE -#endif - -/* exporting methods */ -#if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) -# ifndef GCC_HASCLASSVISIBILITY -# define GCC_HASCLASSVISIBILITY -# endif -#endif - -#ifndef SWIGEXPORT -# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) -# if defined(STATIC_LINKED) -# define SWIGEXPORT -# else -# define SWIGEXPORT __declspec(dllexport) -# endif -# else -# if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY) -# define SWIGEXPORT __attribute__ ((visibility("default"))) -# else -# define SWIGEXPORT -# endif -# endif -#endif - -/* calling conventions for Windows */ -#ifndef SWIGSTDCALL -# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) -# define SWIGSTDCALL __stdcall -# else -# define SWIGSTDCALL -# endif -#endif - -/* Deal with Microsoft's attempt at deprecating C standard runtime functions */ -#if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) -# define _CRT_SECURE_NO_DEPRECATE -#endif - -/* Deal with Microsoft's attempt at deprecating methods in the standard C++ library */ -#if !defined(SWIG_NO_SCL_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_SCL_SECURE_NO_DEPRECATE) -# define _SCL_SECURE_NO_DEPRECATE -#endif - - - -/* Fix for jlong on some versions of gcc on Windows */ -#if defined(__GNUC__) && !defined(__INTEL_COMPILER) - typedef long long __int64; -#endif - -/* Fix for jlong on 64-bit x86 Solaris */ -#if defined(__x86_64) -# ifdef _LP64 -# undef _LP64 -# endif -#endif - -#include -#include -#include - - -/* Support for throwing Java exceptions */ -typedef enum { - SWIG_JavaOutOfMemoryError = 1, - SWIG_JavaIOException, - SWIG_JavaRuntimeException, - SWIG_JavaIndexOutOfBoundsException, - SWIG_JavaArithmeticException, - SWIG_JavaIllegalArgumentException, - SWIG_JavaNullPointerException, - SWIG_JavaDirectorPureVirtual, - SWIG_JavaUnknownError -} SWIG_JavaExceptionCodes; - -typedef struct { - SWIG_JavaExceptionCodes code; - const char *java_exception; -} SWIG_JavaExceptions_t; - - -static void SWIGUNUSED SWIG_JavaThrowException(JNIEnv *jenv, SWIG_JavaExceptionCodes code, const char *msg) { - jclass excep; - static const SWIG_JavaExceptions_t java_exceptions[] = { - { SWIG_JavaOutOfMemoryError, "java/lang/OutOfMemoryError" }, - { SWIG_JavaIOException, "java/io/IOException" }, - { SWIG_JavaRuntimeException, "java/lang/RuntimeException" }, - { SWIG_JavaIndexOutOfBoundsException, "java/lang/IndexOutOfBoundsException" }, - { SWIG_JavaArithmeticException, "java/lang/ArithmeticException" }, - { SWIG_JavaIllegalArgumentException, "java/lang/IllegalArgumentException" }, - { SWIG_JavaNullPointerException, "java/lang/NullPointerException" }, - { SWIG_JavaDirectorPureVirtual, "java/lang/RuntimeException" }, - { SWIG_JavaUnknownError, "java/lang/UnknownError" }, - { (SWIG_JavaExceptionCodes)0, "java/lang/UnknownError" } - }; - const SWIG_JavaExceptions_t *except_ptr = java_exceptions; - - while (except_ptr->code != code && except_ptr->code) - except_ptr++; - - (*jenv)->ExceptionClear(jenv); - excep = (*jenv)->FindClass(jenv, except_ptr->java_exception); - if (excep) - (*jenv)->ThrowNew(jenv, excep, msg); -} - - -/* Contract support */ - -#define SWIG_contract_assert(nullreturn, expr, msg) if (!(expr)) {SWIG_JavaThrowException(jenv, SWIG_JavaIllegalArgumentException, msg); return nullreturn; } else - -/* Errors in SWIG */ -#define SWIG_UnknownError -1 -#define SWIG_IOError -2 -#define SWIG_RuntimeError -3 -#define SWIG_IndexError -4 -#define SWIG_TypeError -5 -#define SWIG_DivisionByZero -6 -#define SWIG_OverflowError -7 -#define SWIG_SyntaxError -8 -#define SWIG_ValueError -9 -#define SWIG_SystemError -10 -#define SWIG_AttributeError -11 -#define SWIG_MemoryError -12 -#define SWIG_NullReferenceError -13 - - - - -SWIGINTERN void SWIG_JavaException(JNIEnv *jenv, int code, const char *msg) { - SWIG_JavaExceptionCodes exception_code = SWIG_JavaUnknownError; - switch(code) { - case SWIG_MemoryError: - exception_code = SWIG_JavaOutOfMemoryError; - break; - case SWIG_IOError: - exception_code = SWIG_JavaIOException; - break; - case SWIG_SystemError: - case SWIG_RuntimeError: - exception_code = SWIG_JavaRuntimeException; - break; - case SWIG_OverflowError: - case SWIG_IndexError: - exception_code = SWIG_JavaIndexOutOfBoundsException; - break; - case SWIG_DivisionByZero: - exception_code = SWIG_JavaArithmeticException; - break; - case SWIG_SyntaxError: - case SWIG_ValueError: - case SWIG_TypeError: - exception_code = SWIG_JavaIllegalArgumentException; - break; - case SWIG_UnknownError: - default: - exception_code = SWIG_JavaUnknownError; - break; - } - SWIG_JavaThrowException(jenv, exception_code, msg); -} - - -#if defined(SWIG_NOINCLUDE) || defined(SWIG_NOARRAYS) - - -int SWIG_JavaArrayInSchar (JNIEnv *jenv, jbyte **jarr, signed char **carr, jbyteArray input); -void SWIG_JavaArrayArgoutSchar (JNIEnv *jenv, jbyte *jarr, signed char *carr, jbyteArray input); -jbyteArray SWIG_JavaArrayOutSchar (JNIEnv *jenv, signed char *result, jsize sz); - - -int SWIG_JavaArrayInUchar (JNIEnv *jenv, jshort **jarr, unsigned char **carr, jshortArray input); -void SWIG_JavaArrayArgoutUchar (JNIEnv *jenv, jshort *jarr, unsigned char *carr, jshortArray input); -jshortArray SWIG_JavaArrayOutUchar (JNIEnv *jenv, unsigned char *result, jsize sz); - - -int SWIG_JavaArrayInShort (JNIEnv *jenv, jshort **jarr, short **carr, jshortArray input); -void SWIG_JavaArrayArgoutShort (JNIEnv *jenv, jshort *jarr, short *carr, jshortArray input); -jshortArray SWIG_JavaArrayOutShort (JNIEnv *jenv, short *result, jsize sz); - - -int SWIG_JavaArrayInUshort (JNIEnv *jenv, jint **jarr, unsigned short **carr, jintArray input); -void SWIG_JavaArrayArgoutUshort (JNIEnv *jenv, jint *jarr, unsigned short *carr, jintArray input); -jintArray SWIG_JavaArrayOutUshort (JNIEnv *jenv, unsigned short *result, jsize sz); - - -int SWIG_JavaArrayInInt (JNIEnv *jenv, jint **jarr, int **carr, jintArray input); -void SWIG_JavaArrayArgoutInt (JNIEnv *jenv, jint *jarr, int *carr, jintArray input); -jintArray SWIG_JavaArrayOutInt (JNIEnv *jenv, int *result, jsize sz); - - -int SWIG_JavaArrayInUint (JNIEnv *jenv, jlong **jarr, unsigned int **carr, jlongArray input); -void SWIG_JavaArrayArgoutUint (JNIEnv *jenv, jlong *jarr, unsigned int *carr, jlongArray input); -jlongArray SWIG_JavaArrayOutUint (JNIEnv *jenv, unsigned int *result, jsize sz); - - -int SWIG_JavaArrayInLong (JNIEnv *jenv, jint **jarr, long **carr, jintArray input); -void SWIG_JavaArrayArgoutLong (JNIEnv *jenv, jint *jarr, long *carr, jintArray input); -jintArray SWIG_JavaArrayOutLong (JNIEnv *jenv, long *result, jsize sz); - - -int SWIG_JavaArrayInUlong (JNIEnv *jenv, jlong **jarr, unsigned long **carr, jlongArray input); -void SWIG_JavaArrayArgoutUlong (JNIEnv *jenv, jlong *jarr, unsigned long *carr, jlongArray input); -jlongArray SWIG_JavaArrayOutUlong (JNIEnv *jenv, unsigned long *result, jsize sz); - - -int SWIG_JavaArrayInLonglong (JNIEnv *jenv, jlong **jarr, jlong **carr, jlongArray input); -void SWIG_JavaArrayArgoutLonglong (JNIEnv *jenv, jlong *jarr, jlong *carr, jlongArray input); -jlongArray SWIG_JavaArrayOutLonglong (JNIEnv *jenv, jlong *result, jsize sz); - - -int SWIG_JavaArrayInFloat (JNIEnv *jenv, jfloat **jarr, float **carr, jfloatArray input); -void SWIG_JavaArrayArgoutFloat (JNIEnv *jenv, jfloat *jarr, float *carr, jfloatArray input); -jfloatArray SWIG_JavaArrayOutFloat (JNIEnv *jenv, float *result, jsize sz); - - -int SWIG_JavaArrayInDouble (JNIEnv *jenv, jdouble **jarr, double **carr, jdoubleArray input); -void SWIG_JavaArrayArgoutDouble (JNIEnv *jenv, jdouble *jarr, double *carr, jdoubleArray input); -jdoubleArray SWIG_JavaArrayOutDouble (JNIEnv *jenv, double *result, jsize sz); - - -#else - - -/* signed char[] support */ -int SWIG_JavaArrayInSchar (JNIEnv *jenv, jbyte **jarr, signed char **carr, jbyteArray input) { - int i; - jsize sz; - if (!input) { - SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null array"); - return 0; - } - sz = (*jenv)->GetArrayLength(jenv, input); - *jarr = (*jenv)->GetByteArrayElements(jenv, input, 0); - if (!*jarr) - return 0; - *carr = (signed char*) calloc(sz, sizeof(signed char)); - if (!*carr) { - SWIG_JavaThrowException(jenv, SWIG_JavaOutOfMemoryError, "array memory allocation failed"); - return 0; - } - for (i=0; iGetArrayLength(jenv, input); - for (i=0; iReleaseByteArrayElements(jenv, input, jarr, 0); -} - -jbyteArray SWIG_JavaArrayOutSchar (JNIEnv *jenv, signed char *result, jsize sz) { - jbyte *arr; - int i; - jbyteArray jresult = (*jenv)->NewByteArray(jenv, sz); - if (!jresult) - return NULL; - arr = (*jenv)->GetByteArrayElements(jenv, jresult, 0); - if (!arr) - return NULL; - for (i=0; iReleaseByteArrayElements(jenv, jresult, arr, 0); - return jresult; -} - - -/* unsigned char[] support */ -int SWIG_JavaArrayInUchar (JNIEnv *jenv, jshort **jarr, unsigned char **carr, jshortArray input) { - int i; - jsize sz; - if (!input) { - SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null array"); - return 0; - } - sz = (*jenv)->GetArrayLength(jenv, input); - *jarr = (*jenv)->GetShortArrayElements(jenv, input, 0); - if (!*jarr) - return 0; - *carr = (unsigned char*) calloc(sz, sizeof(unsigned char)); - if (!*carr) { - SWIG_JavaThrowException(jenv, SWIG_JavaOutOfMemoryError, "array memory allocation failed"); - return 0; - } - for (i=0; iGetArrayLength(jenv, input); - for (i=0; iReleaseShortArrayElements(jenv, input, jarr, 0); -} - -jshortArray SWIG_JavaArrayOutUchar (JNIEnv *jenv, unsigned char *result, jsize sz) { - jshort *arr; - int i; - jshortArray jresult = (*jenv)->NewShortArray(jenv, sz); - if (!jresult) - return NULL; - arr = (*jenv)->GetShortArrayElements(jenv, jresult, 0); - if (!arr) - return NULL; - for (i=0; iReleaseShortArrayElements(jenv, jresult, arr, 0); - return jresult; -} - - -/* short[] support */ -int SWIG_JavaArrayInShort (JNIEnv *jenv, jshort **jarr, short **carr, jshortArray input) { - int i; - jsize sz; - if (!input) { - SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null array"); - return 0; - } - sz = (*jenv)->GetArrayLength(jenv, input); - *jarr = (*jenv)->GetShortArrayElements(jenv, input, 0); - if (!*jarr) - return 0; - *carr = (short*) calloc(sz, sizeof(short)); - if (!*carr) { - SWIG_JavaThrowException(jenv, SWIG_JavaOutOfMemoryError, "array memory allocation failed"); - return 0; - } - for (i=0; iGetArrayLength(jenv, input); - for (i=0; iReleaseShortArrayElements(jenv, input, jarr, 0); -} - -jshortArray SWIG_JavaArrayOutShort (JNIEnv *jenv, short *result, jsize sz) { - jshort *arr; - int i; - jshortArray jresult = (*jenv)->NewShortArray(jenv, sz); - if (!jresult) - return NULL; - arr = (*jenv)->GetShortArrayElements(jenv, jresult, 0); - if (!arr) - return NULL; - for (i=0; iReleaseShortArrayElements(jenv, jresult, arr, 0); - return jresult; -} - - -/* unsigned short[] support */ -int SWIG_JavaArrayInUshort (JNIEnv *jenv, jint **jarr, unsigned short **carr, jintArray input) { - int i; - jsize sz; - if (!input) { - SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null array"); - return 0; - } - sz = (*jenv)->GetArrayLength(jenv, input); - *jarr = (*jenv)->GetIntArrayElements(jenv, input, 0); - if (!*jarr) - return 0; - *carr = (unsigned short*) calloc(sz, sizeof(unsigned short)); - if (!*carr) { - SWIG_JavaThrowException(jenv, SWIG_JavaOutOfMemoryError, "array memory allocation failed"); - return 0; - } - for (i=0; iGetArrayLength(jenv, input); - for (i=0; iReleaseIntArrayElements(jenv, input, jarr, 0); -} - -jintArray SWIG_JavaArrayOutUshort (JNIEnv *jenv, unsigned short *result, jsize sz) { - jint *arr; - int i; - jintArray jresult = (*jenv)->NewIntArray(jenv, sz); - if (!jresult) - return NULL; - arr = (*jenv)->GetIntArrayElements(jenv, jresult, 0); - if (!arr) - return NULL; - for (i=0; iReleaseIntArrayElements(jenv, jresult, arr, 0); - return jresult; -} - - -/* int[] support */ -int SWIG_JavaArrayInInt (JNIEnv *jenv, jint **jarr, int **carr, jintArray input) { - int i; - jsize sz; - if (!input) { - SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null array"); - return 0; - } - sz = (*jenv)->GetArrayLength(jenv, input); - *jarr = (*jenv)->GetIntArrayElements(jenv, input, 0); - if (!*jarr) - return 0; - *carr = (int*) calloc(sz, sizeof(int)); - if (!*carr) { - SWIG_JavaThrowException(jenv, SWIG_JavaOutOfMemoryError, "array memory allocation failed"); - return 0; - } - for (i=0; iGetArrayLength(jenv, input); - for (i=0; iReleaseIntArrayElements(jenv, input, jarr, 0); -} - -jintArray SWIG_JavaArrayOutInt (JNIEnv *jenv, int *result, jsize sz) { - jint *arr; - int i; - jintArray jresult = (*jenv)->NewIntArray(jenv, sz); - if (!jresult) - return NULL; - arr = (*jenv)->GetIntArrayElements(jenv, jresult, 0); - if (!arr) - return NULL; - for (i=0; iReleaseIntArrayElements(jenv, jresult, arr, 0); - return jresult; -} - - -/* unsigned int[] support */ -int SWIG_JavaArrayInUint (JNIEnv *jenv, jlong **jarr, unsigned int **carr, jlongArray input) { - int i; - jsize sz; - if (!input) { - SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null array"); - return 0; - } - sz = (*jenv)->GetArrayLength(jenv, input); - *jarr = (*jenv)->GetLongArrayElements(jenv, input, 0); - if (!*jarr) - return 0; - *carr = (unsigned int*) calloc(sz, sizeof(unsigned int)); - if (!*carr) { - SWIG_JavaThrowException(jenv, SWIG_JavaOutOfMemoryError, "array memory allocation failed"); - return 0; - } - for (i=0; iGetArrayLength(jenv, input); - for (i=0; iReleaseLongArrayElements(jenv, input, jarr, 0); -} - -jlongArray SWIG_JavaArrayOutUint (JNIEnv *jenv, unsigned int *result, jsize sz) { - jlong *arr; - int i; - jlongArray jresult = (*jenv)->NewLongArray(jenv, sz); - if (!jresult) - return NULL; - arr = (*jenv)->GetLongArrayElements(jenv, jresult, 0); - if (!arr) - return NULL; - for (i=0; iReleaseLongArrayElements(jenv, jresult, arr, 0); - return jresult; -} - - -/* long[] support */ -int SWIG_JavaArrayInLong (JNIEnv *jenv, jint **jarr, long **carr, jintArray input) { - int i; - jsize sz; - if (!input) { - SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null array"); - return 0; - } - sz = (*jenv)->GetArrayLength(jenv, input); - *jarr = (*jenv)->GetIntArrayElements(jenv, input, 0); - if (!*jarr) - return 0; - *carr = (long*) calloc(sz, sizeof(long)); - if (!*carr) { - SWIG_JavaThrowException(jenv, SWIG_JavaOutOfMemoryError, "array memory allocation failed"); - return 0; - } - for (i=0; iGetArrayLength(jenv, input); - for (i=0; iReleaseIntArrayElements(jenv, input, jarr, 0); -} - -jintArray SWIG_JavaArrayOutLong (JNIEnv *jenv, long *result, jsize sz) { - jint *arr; - int i; - jintArray jresult = (*jenv)->NewIntArray(jenv, sz); - if (!jresult) - return NULL; - arr = (*jenv)->GetIntArrayElements(jenv, jresult, 0); - if (!arr) - return NULL; - for (i=0; iReleaseIntArrayElements(jenv, jresult, arr, 0); - return jresult; -} - - -/* unsigned long[] support */ -int SWIG_JavaArrayInUlong (JNIEnv *jenv, jlong **jarr, unsigned long **carr, jlongArray input) { - int i; - jsize sz; - if (!input) { - SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null array"); - return 0; - } - sz = (*jenv)->GetArrayLength(jenv, input); - *jarr = (*jenv)->GetLongArrayElements(jenv, input, 0); - if (!*jarr) - return 0; - *carr = (unsigned long*) calloc(sz, sizeof(unsigned long)); - if (!*carr) { - SWIG_JavaThrowException(jenv, SWIG_JavaOutOfMemoryError, "array memory allocation failed"); - return 0; - } - for (i=0; iGetArrayLength(jenv, input); - for (i=0; iReleaseLongArrayElements(jenv, input, jarr, 0); -} - -jlongArray SWIG_JavaArrayOutUlong (JNIEnv *jenv, unsigned long *result, jsize sz) { - jlong *arr; - int i; - jlongArray jresult = (*jenv)->NewLongArray(jenv, sz); - if (!jresult) - return NULL; - arr = (*jenv)->GetLongArrayElements(jenv, jresult, 0); - if (!arr) - return NULL; - for (i=0; iReleaseLongArrayElements(jenv, jresult, arr, 0); - return jresult; -} - - -/* jlong[] support */ -int SWIG_JavaArrayInLonglong (JNIEnv *jenv, jlong **jarr, jlong **carr, jlongArray input) { - int i; - jsize sz; - if (!input) { - SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null array"); - return 0; - } - sz = (*jenv)->GetArrayLength(jenv, input); - *jarr = (*jenv)->GetLongArrayElements(jenv, input, 0); - if (!*jarr) - return 0; - *carr = (jlong*) calloc(sz, sizeof(jlong)); - if (!*carr) { - SWIG_JavaThrowException(jenv, SWIG_JavaOutOfMemoryError, "array memory allocation failed"); - return 0; - } - for (i=0; iGetArrayLength(jenv, input); - for (i=0; iReleaseLongArrayElements(jenv, input, jarr, 0); -} - -jlongArray SWIG_JavaArrayOutLonglong (JNIEnv *jenv, jlong *result, jsize sz) { - jlong *arr; - int i; - jlongArray jresult = (*jenv)->NewLongArray(jenv, sz); - if (!jresult) - return NULL; - arr = (*jenv)->GetLongArrayElements(jenv, jresult, 0); - if (!arr) - return NULL; - for (i=0; iReleaseLongArrayElements(jenv, jresult, arr, 0); - return jresult; -} - - -/* float[] support */ -int SWIG_JavaArrayInFloat (JNIEnv *jenv, jfloat **jarr, float **carr, jfloatArray input) { - int i; - jsize sz; - if (!input) { - SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null array"); - return 0; - } - sz = (*jenv)->GetArrayLength(jenv, input); - *jarr = (*jenv)->GetFloatArrayElements(jenv, input, 0); - if (!*jarr) - return 0; - *carr = (float*) calloc(sz, sizeof(float)); - if (!*carr) { - SWIG_JavaThrowException(jenv, SWIG_JavaOutOfMemoryError, "array memory allocation failed"); - return 0; - } - for (i=0; iGetArrayLength(jenv, input); - for (i=0; iReleaseFloatArrayElements(jenv, input, jarr, 0); -} - -jfloatArray SWIG_JavaArrayOutFloat (JNIEnv *jenv, float *result, jsize sz) { - jfloat *arr; - int i; - jfloatArray jresult = (*jenv)->NewFloatArray(jenv, sz); - if (!jresult) - return NULL; - arr = (*jenv)->GetFloatArrayElements(jenv, jresult, 0); - if (!arr) - return NULL; - for (i=0; iReleaseFloatArrayElements(jenv, jresult, arr, 0); - return jresult; -} - - -/* double[] support */ -int SWIG_JavaArrayInDouble (JNIEnv *jenv, jdouble **jarr, double **carr, jdoubleArray input) { - int i; - jsize sz; - if (!input) { - SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null array"); - return 0; - } - sz = (*jenv)->GetArrayLength(jenv, input); - *jarr = (*jenv)->GetDoubleArrayElements(jenv, input, 0); - if (!*jarr) - return 0; - *carr = (double*) calloc(sz, sizeof(double)); - if (!*carr) { - SWIG_JavaThrowException(jenv, SWIG_JavaOutOfMemoryError, "array memory allocation failed"); - return 0; - } - for (i=0; iGetArrayLength(jenv, input); - for (i=0; iReleaseDoubleArrayElements(jenv, input, jarr, 0); -} - -jdoubleArray SWIG_JavaArrayOutDouble (JNIEnv *jenv, double *result, jsize sz) { - jdouble *arr; - int i; - jdoubleArray jresult = (*jenv)->NewDoubleArray(jenv, sz); - if (!jresult) - return NULL; - arr = (*jenv)->GetDoubleArrayElements(jenv, jresult, 0); - if (!arr) - return NULL; - for (i=0; iReleaseDoubleArrayElements(jenv, jresult, arr, 0); - return jresult; -} - - -#endif - - -#include "webp/types.h" - - -int SWIG_JavaArrayInUint8 (JNIEnv *jenv, jbyte **jarr, uint8_t **carr, jbyteArray input); -void SWIG_JavaArrayArgoutUint8 (JNIEnv *jenv, jbyte *jarr, uint8_t *carr, jbyteArray input); -jbyteArray SWIG_JavaArrayOutUint8 (JNIEnv *jenv, uint8_t *result, jsize sz); - - -/* uint8_t[] support */ -int SWIG_JavaArrayInUint8 (JNIEnv *jenv, jbyte **jarr, uint8_t **carr, jbyteArray input) { - int i; - jsize sz; - if (!input) { - SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null array"); - return 0; - } - sz = (*jenv)->GetArrayLength(jenv, input); - *jarr = (*jenv)->GetByteArrayElements(jenv, input, 0); - if (!*jarr) - return 0; - *carr = (uint8_t*) calloc(sz, sizeof(uint8_t)); - if (!*carr) { - SWIG_JavaThrowException(jenv, SWIG_JavaOutOfMemoryError, "array memory allocation failed"); - return 0; - } - for (i=0; iGetArrayLength(jenv, input); - for (i=0; iReleaseByteArrayElements(jenv, input, jarr, 0); -} - -jbyteArray SWIG_JavaArrayOutUint8 (JNIEnv *jenv, uint8_t *result, jsize sz) { - jbyte *arr; - int i; - jbyteArray jresult = (*jenv)->NewByteArray(jenv, sz); - if (!jresult) - return NULL; - arr = (*jenv)->GetByteArrayElements(jenv, jresult, 0); - if (!arr) - return NULL; - for (i=0; iReleaseByteArrayElements(jenv, jresult, arr, 0); - return jresult; -} - - -#include "webp/decode.h" -#include "webp/encode.h" - - -#define FillMeInAsSizeCannotBeDeterminedAutomatically \ - (result ? (jint)ReturnedBufferSize(__FUNCTION__, arg3, arg4) : 0) - - -static size_t ReturnedBufferSize( - const char* function, int* width, int* height) { - static const struct sizemap { - const char* function; - int size_multiplier; - } size_map[] = { -#ifdef SWIGJAVA - { "Java_com_google_webp_libwebpJNI_WebPDecodeRGB", 3 }, - { "Java_com_google_webp_libwebpJNI_WebPDecodeRGBA", 4 }, - { "Java_com_google_webp_libwebpJNI_WebPDecodeARGB", 4 }, - { "Java_com_google_webp_libwebpJNI_WebPDecodeBGR", 3 }, - { "Java_com_google_webp_libwebpJNI_WebPDecodeBGRA", 4 }, - { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeRGB", 1 }, - { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeBGR", 1 }, - { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeRGBA", 1 }, - { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeBGRA", 1 }, - { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeLosslessRGB", 1 }, - { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeLosslessBGR", 1 }, - { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeLosslessRGBA", 1 }, - { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeLosslessBGRA", 1 }, -#endif -#ifdef SWIGPYTHON - { "WebPDecodeRGB", 3 }, - { "WebPDecodeRGBA", 4 }, - { "WebPDecodeARGB", 4 }, - { "WebPDecodeBGR", 3 }, - { "WebPDecodeBGRA", 4 }, - { "wrap_WebPEncodeRGB", 1 }, - { "wrap_WebPEncodeBGR", 1 }, - { "wrap_WebPEncodeRGBA", 1 }, - { "wrap_WebPEncodeBGRA", 1 }, - { "wrap_WebPEncodeLosslessRGB", 1 }, - { "wrap_WebPEncodeLosslessBGR", 1 }, - { "wrap_WebPEncodeLosslessRGBA", 1 }, - { "wrap_WebPEncodeLosslessBGRA", 1 }, -#endif - { NULL, 0 } - }; - const struct sizemap* p; - size_t size = 0; - - for (p = size_map; p->function; ++p) { - if (!strcmp(function, p->function)) { - size = *width * *height * p->size_multiplier; - break; - } - } - - return size; -} - - -typedef size_t (*WebPEncodeFunction)(const uint8_t* rgb, - int width, int height, int stride, - float quality_factor, uint8_t** output); -typedef size_t (*WebPEncodeLosslessFunction)(const uint8_t* rgb, - int width, int height, int stride, - uint8_t** output); - -static uint8_t* EncodeLossy(const uint8_t* rgb, - int width, int height, int stride, - float quality_factor, - WebPEncodeFunction encfn, - int* output_size, int* unused) { - uint8_t* output = NULL; - const size_t image_size = - encfn(rgb, width, height, stride, quality_factor, &output); - // the values of following two will be interpreted by ReturnedBufferSize() - // as 'width' and 'height' in the size calculation. - *output_size = image_size; - *unused = 1; - return image_size ? output : NULL; -} - -static uint8_t* EncodeLossless(const uint8_t* rgb, - int width, int height, int stride, - WebPEncodeLosslessFunction encfn, - int* output_size, int* unused) { - uint8_t* output = NULL; - const size_t image_size = encfn(rgb, width, height, stride, &output); - // the values of the following two will be interpreted by - // ReturnedBufferSize() as 'width' and 'height' in the size calculation. - *output_size = image_size; - *unused = 1; - return image_size ? output : NULL; -} - - -// Changes the return type of WebPEncode* to more closely match Decode*. -// This also makes it easier to wrap the output buffer in a native type rather -// than dealing with the return pointer. -// The additional parameters are to allow reuse of ReturnedBufferSize(), -// unused2 and output_size will be used in this case. -#define LOSSY_WRAPPER(FUNC) \ - static uint8_t* wrap_##FUNC( \ - const uint8_t* rgb, int* unused1, int* unused2, int* output_size, \ - int width, int height, int stride, float quality_factor) { \ - return EncodeLossy(rgb, width, height, stride, quality_factor, \ - FUNC, output_size, unused2); \ - } \ - -LOSSY_WRAPPER(WebPEncodeRGB) -LOSSY_WRAPPER(WebPEncodeBGR) -LOSSY_WRAPPER(WebPEncodeRGBA) -LOSSY_WRAPPER(WebPEncodeBGRA) - -#undef LOSSY_WRAPPER - -#define LOSSLESS_WRAPPER(FUNC) \ - static uint8_t* wrap_##FUNC( \ - const uint8_t* rgb, int* unused1, int* unused2, int* output_size, \ - int width, int height, int stride) { \ - return EncodeLossless(rgb, width, height, stride, \ - FUNC, output_size, unused2); \ - } \ - -LOSSLESS_WRAPPER(WebPEncodeLosslessRGB) -LOSSLESS_WRAPPER(WebPEncodeLosslessBGR) -LOSSLESS_WRAPPER(WebPEncodeLosslessRGBA) -LOSSLESS_WRAPPER(WebPEncodeLosslessBGRA) - -#undef LOSSLESS_WRAPPER - - - -/* Work around broken gcj jni.h */ -#ifdef __GCJ_JNI_H__ -# undef JNIEXPORT -# define JNIEXPORT -# undef JNICALL -# define JNICALL -#endif - - -#ifdef __cplusplus -extern "C" { -#endif - -SWIGEXPORT jint JNICALL Java_com_google_webp_libwebpJNI_WebPGetDecoderVersion(JNIEnv *jenv, jclass jcls) { - jint jresult = 0 ; - int result; - - (void)jenv; - (void)jcls; - result = (int)WebPGetDecoderVersion(); - jresult = (jint)result; - return jresult; -} - - -SWIGEXPORT jint JNICALL Java_com_google_webp_libwebpJNI_WebPGetInfo(JNIEnv *jenv, jclass jcls, jbyteArray jarg1, jlong jarg2, jintArray jarg3, jintArray jarg4) { - jint jresult = 0 ; - uint8_t *arg1 = (uint8_t *) 0 ; - size_t arg2 ; - int *arg3 = (int *) 0 ; - int *arg4 = (int *) 0 ; - jbyte *jarr1 ; - int temp3 ; - int temp4 ; - int result; - - (void)jenv; - (void)jcls; - if (!SWIG_JavaArrayInUint8(jenv, &jarr1, &arg1, jarg1)) return 0; - arg2 = (size_t)jarg2; - { - if (!jarg3) { - SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null"); - return 0; - } - if ((*jenv)->GetArrayLength(jenv, jarg3) == 0) { - SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element"); - return 0; - } - arg3 = &temp3; - } - { - if (!jarg4) { - SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null"); - return 0; - } - if ((*jenv)->GetArrayLength(jenv, jarg4) == 0) { - SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element"); - return 0; - } - arg4 = &temp4; - } - result = (int)WebPGetInfo((uint8_t const *)arg1,arg2,arg3,arg4); - jresult = (jint)result; - SWIG_JavaArrayArgoutUint8(jenv, jarr1, arg1, jarg1); - { - jint jvalue = (jint)temp3; - (*jenv)->SetIntArrayRegion(jenv, jarg3, 0, 1, &jvalue); - } - { - jint jvalue = (jint)temp4; - (*jenv)->SetIntArrayRegion(jenv, jarg4, 0, 1, &jvalue); - } - free(arg1); - - - return jresult; -} - - -SWIGEXPORT jbyteArray JNICALL Java_com_google_webp_libwebpJNI_WebPDecodeRGB(JNIEnv *jenv, jclass jcls, jbyteArray jarg1, jlong jarg2, jintArray jarg3, jintArray jarg4) { - jbyteArray jresult = 0 ; - uint8_t *arg1 = (uint8_t *) 0 ; - size_t arg2 ; - int *arg3 = (int *) 0 ; - int *arg4 = (int *) 0 ; - jbyte *jarr1 ; - int temp3 ; - int temp4 ; - uint8_t *result = 0 ; - - (void)jenv; - (void)jcls; - if (!SWIG_JavaArrayInUint8(jenv, &jarr1, &arg1, jarg1)) return 0; - arg2 = (size_t)jarg2; - { - if (!jarg3) { - SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null"); - return 0; - } - if ((*jenv)->GetArrayLength(jenv, jarg3) == 0) { - SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element"); - return 0; - } - arg3 = &temp3; - } - { - if (!jarg4) { - SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null"); - return 0; - } - if ((*jenv)->GetArrayLength(jenv, jarg4) == 0) { - SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element"); - return 0; - } - arg4 = &temp4; - } - result = (uint8_t *)WebPDecodeRGB((uint8_t const *)arg1,arg2,arg3,arg4); - jresult = SWIG_JavaArrayOutUint8(jenv, result, FillMeInAsSizeCannotBeDeterminedAutomatically); - SWIG_JavaArrayArgoutUint8(jenv, jarr1, arg1, jarg1); - { - jint jvalue = (jint)temp3; - (*jenv)->SetIntArrayRegion(jenv, jarg3, 0, 1, &jvalue); - } - { - jint jvalue = (jint)temp4; - (*jenv)->SetIntArrayRegion(jenv, jarg4, 0, 1, &jvalue); - } - free(arg1); - - - free(result); - return jresult; -} - - -SWIGEXPORT jbyteArray JNICALL Java_com_google_webp_libwebpJNI_WebPDecodeRGBA(JNIEnv *jenv, jclass jcls, jbyteArray jarg1, jlong jarg2, jintArray jarg3, jintArray jarg4) { - jbyteArray jresult = 0 ; - uint8_t *arg1 = (uint8_t *) 0 ; - size_t arg2 ; - int *arg3 = (int *) 0 ; - int *arg4 = (int *) 0 ; - jbyte *jarr1 ; - int temp3 ; - int temp4 ; - uint8_t *result = 0 ; - - (void)jenv; - (void)jcls; - if (!SWIG_JavaArrayInUint8(jenv, &jarr1, &arg1, jarg1)) return 0; - arg2 = (size_t)jarg2; - { - if (!jarg3) { - SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null"); - return 0; - } - if ((*jenv)->GetArrayLength(jenv, jarg3) == 0) { - SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element"); - return 0; - } - arg3 = &temp3; - } - { - if (!jarg4) { - SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null"); - return 0; - } - if ((*jenv)->GetArrayLength(jenv, jarg4) == 0) { - SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element"); - return 0; - } - arg4 = &temp4; - } - result = (uint8_t *)WebPDecodeRGBA((uint8_t const *)arg1,arg2,arg3,arg4); - jresult = SWIG_JavaArrayOutUint8(jenv, result, FillMeInAsSizeCannotBeDeterminedAutomatically); - SWIG_JavaArrayArgoutUint8(jenv, jarr1, arg1, jarg1); - { - jint jvalue = (jint)temp3; - (*jenv)->SetIntArrayRegion(jenv, jarg3, 0, 1, &jvalue); - } - { - jint jvalue = (jint)temp4; - (*jenv)->SetIntArrayRegion(jenv, jarg4, 0, 1, &jvalue); - } - free(arg1); - - - free(result); - return jresult; -} - - -SWIGEXPORT jbyteArray JNICALL Java_com_google_webp_libwebpJNI_WebPDecodeARGB(JNIEnv *jenv, jclass jcls, jbyteArray jarg1, jlong jarg2, jintArray jarg3, jintArray jarg4) { - jbyteArray jresult = 0 ; - uint8_t *arg1 = (uint8_t *) 0 ; - size_t arg2 ; - int *arg3 = (int *) 0 ; - int *arg4 = (int *) 0 ; - jbyte *jarr1 ; - int temp3 ; - int temp4 ; - uint8_t *result = 0 ; - - (void)jenv; - (void)jcls; - if (!SWIG_JavaArrayInUint8(jenv, &jarr1, &arg1, jarg1)) return 0; - arg2 = (size_t)jarg2; - { - if (!jarg3) { - SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null"); - return 0; - } - if ((*jenv)->GetArrayLength(jenv, jarg3) == 0) { - SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element"); - return 0; - } - arg3 = &temp3; - } - { - if (!jarg4) { - SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null"); - return 0; - } - if ((*jenv)->GetArrayLength(jenv, jarg4) == 0) { - SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element"); - return 0; - } - arg4 = &temp4; - } - result = (uint8_t *)WebPDecodeARGB((uint8_t const *)arg1,arg2,arg3,arg4); - jresult = SWIG_JavaArrayOutUint8(jenv, result, FillMeInAsSizeCannotBeDeterminedAutomatically); - SWIG_JavaArrayArgoutUint8(jenv, jarr1, arg1, jarg1); - { - jint jvalue = (jint)temp3; - (*jenv)->SetIntArrayRegion(jenv, jarg3, 0, 1, &jvalue); - } - { - jint jvalue = (jint)temp4; - (*jenv)->SetIntArrayRegion(jenv, jarg4, 0, 1, &jvalue); - } - free(arg1); - - - free(result); - return jresult; -} - - -SWIGEXPORT jbyteArray JNICALL Java_com_google_webp_libwebpJNI_WebPDecodeBGR(JNIEnv *jenv, jclass jcls, jbyteArray jarg1, jlong jarg2, jintArray jarg3, jintArray jarg4) { - jbyteArray jresult = 0 ; - uint8_t *arg1 = (uint8_t *) 0 ; - size_t arg2 ; - int *arg3 = (int *) 0 ; - int *arg4 = (int *) 0 ; - jbyte *jarr1 ; - int temp3 ; - int temp4 ; - uint8_t *result = 0 ; - - (void)jenv; - (void)jcls; - if (!SWIG_JavaArrayInUint8(jenv, &jarr1, &arg1, jarg1)) return 0; - arg2 = (size_t)jarg2; - { - if (!jarg3) { - SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null"); - return 0; - } - if ((*jenv)->GetArrayLength(jenv, jarg3) == 0) { - SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element"); - return 0; - } - arg3 = &temp3; - } - { - if (!jarg4) { - SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null"); - return 0; - } - if ((*jenv)->GetArrayLength(jenv, jarg4) == 0) { - SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element"); - return 0; - } - arg4 = &temp4; - } - result = (uint8_t *)WebPDecodeBGR((uint8_t const *)arg1,arg2,arg3,arg4); - jresult = SWIG_JavaArrayOutUint8(jenv, result, FillMeInAsSizeCannotBeDeterminedAutomatically); - SWIG_JavaArrayArgoutUint8(jenv, jarr1, arg1, jarg1); - { - jint jvalue = (jint)temp3; - (*jenv)->SetIntArrayRegion(jenv, jarg3, 0, 1, &jvalue); - } - { - jint jvalue = (jint)temp4; - (*jenv)->SetIntArrayRegion(jenv, jarg4, 0, 1, &jvalue); - } - free(arg1); - - - free(result); - return jresult; -} - - -SWIGEXPORT jbyteArray JNICALL Java_com_google_webp_libwebpJNI_WebPDecodeBGRA(JNIEnv *jenv, jclass jcls, jbyteArray jarg1, jlong jarg2, jintArray jarg3, jintArray jarg4) { - jbyteArray jresult = 0 ; - uint8_t *arg1 = (uint8_t *) 0 ; - size_t arg2 ; - int *arg3 = (int *) 0 ; - int *arg4 = (int *) 0 ; - jbyte *jarr1 ; - int temp3 ; - int temp4 ; - uint8_t *result = 0 ; - - (void)jenv; - (void)jcls; - if (!SWIG_JavaArrayInUint8(jenv, &jarr1, &arg1, jarg1)) return 0; - arg2 = (size_t)jarg2; - { - if (!jarg3) { - SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null"); - return 0; - } - if ((*jenv)->GetArrayLength(jenv, jarg3) == 0) { - SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element"); - return 0; - } - arg3 = &temp3; - } - { - if (!jarg4) { - SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null"); - return 0; - } - if ((*jenv)->GetArrayLength(jenv, jarg4) == 0) { - SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element"); - return 0; - } - arg4 = &temp4; - } - result = (uint8_t *)WebPDecodeBGRA((uint8_t const *)arg1,arg2,arg3,arg4); - jresult = SWIG_JavaArrayOutUint8(jenv, result, FillMeInAsSizeCannotBeDeterminedAutomatically); - SWIG_JavaArrayArgoutUint8(jenv, jarr1, arg1, jarg1); - { - jint jvalue = (jint)temp3; - (*jenv)->SetIntArrayRegion(jenv, jarg3, 0, 1, &jvalue); - } - { - jint jvalue = (jint)temp4; - (*jenv)->SetIntArrayRegion(jenv, jarg4, 0, 1, &jvalue); - } - free(arg1); - - - free(result); - return jresult; -} - - -SWIGEXPORT jint JNICALL Java_com_google_webp_libwebpJNI_WebPGetEncoderVersion(JNIEnv *jenv, jclass jcls) { - jint jresult = 0 ; - int result; - - (void)jenv; - (void)jcls; - result = (int)WebPGetEncoderVersion(); - jresult = (jint)result; - return jresult; -} - - -SWIGEXPORT jbyteArray JNICALL Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeRGB(JNIEnv *jenv, jclass jcls, jbyteArray jarg1, jint jarg2, jint jarg3, jintArray jarg4, jint jarg5, jint jarg6, jint jarg7, jfloat jarg8) { - jbyteArray jresult = 0 ; - uint8_t *arg1 = (uint8_t *) 0 ; - int *arg2 = (int *) 0 ; - int *arg3 = (int *) 0 ; - int *arg4 = (int *) 0 ; - int arg5 ; - int arg6 ; - int arg7 ; - float arg8 ; - jbyte *jarr1 ; - int temp4 ; - uint8_t *result = 0 ; - - (void)jenv; - (void)jcls; - if (!SWIG_JavaArrayInUint8(jenv, &jarr1, &arg1, jarg1)) return 0; - arg2 = (int *)&jarg2; - arg3 = (int *)&jarg3; - { - if (!jarg4) { - SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null"); - return 0; - } - if ((*jenv)->GetArrayLength(jenv, jarg4) == 0) { - SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element"); - return 0; - } - arg4 = &temp4; - } - arg5 = (int)jarg5; - arg6 = (int)jarg6; - arg7 = (int)jarg7; - arg8 = (float)jarg8; - result = (uint8_t *)wrap_WebPEncodeRGB((uint8_t const *)arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8); - jresult = SWIG_JavaArrayOutUint8(jenv, result, FillMeInAsSizeCannotBeDeterminedAutomatically); - SWIG_JavaArrayArgoutUint8(jenv, jarr1, arg1, jarg1); - { - jint jvalue = (jint)temp4; - (*jenv)->SetIntArrayRegion(jenv, jarg4, 0, 1, &jvalue); - } - free(arg1); - - - - free(result); - return jresult; -} - - -SWIGEXPORT jbyteArray JNICALL Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeBGR(JNIEnv *jenv, jclass jcls, jbyteArray jarg1, jint jarg2, jint jarg3, jintArray jarg4, jint jarg5, jint jarg6, jint jarg7, jfloat jarg8) { - jbyteArray jresult = 0 ; - uint8_t *arg1 = (uint8_t *) 0 ; - int *arg2 = (int *) 0 ; - int *arg3 = (int *) 0 ; - int *arg4 = (int *) 0 ; - int arg5 ; - int arg6 ; - int arg7 ; - float arg8 ; - jbyte *jarr1 ; - int temp4 ; - uint8_t *result = 0 ; - - (void)jenv; - (void)jcls; - if (!SWIG_JavaArrayInUint8(jenv, &jarr1, &arg1, jarg1)) return 0; - arg2 = (int *)&jarg2; - arg3 = (int *)&jarg3; - { - if (!jarg4) { - SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null"); - return 0; - } - if ((*jenv)->GetArrayLength(jenv, jarg4) == 0) { - SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element"); - return 0; - } - arg4 = &temp4; - } - arg5 = (int)jarg5; - arg6 = (int)jarg6; - arg7 = (int)jarg7; - arg8 = (float)jarg8; - result = (uint8_t *)wrap_WebPEncodeBGR((uint8_t const *)arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8); - jresult = SWIG_JavaArrayOutUint8(jenv, result, FillMeInAsSizeCannotBeDeterminedAutomatically); - SWIG_JavaArrayArgoutUint8(jenv, jarr1, arg1, jarg1); - { - jint jvalue = (jint)temp4; - (*jenv)->SetIntArrayRegion(jenv, jarg4, 0, 1, &jvalue); - } - free(arg1); - - - - free(result); - return jresult; -} - - -SWIGEXPORT jbyteArray JNICALL Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeRGBA(JNIEnv *jenv, jclass jcls, jbyteArray jarg1, jint jarg2, jint jarg3, jintArray jarg4, jint jarg5, jint jarg6, jint jarg7, jfloat jarg8) { - jbyteArray jresult = 0 ; - uint8_t *arg1 = (uint8_t *) 0 ; - int *arg2 = (int *) 0 ; - int *arg3 = (int *) 0 ; - int *arg4 = (int *) 0 ; - int arg5 ; - int arg6 ; - int arg7 ; - float arg8 ; - jbyte *jarr1 ; - int temp4 ; - uint8_t *result = 0 ; - - (void)jenv; - (void)jcls; - if (!SWIG_JavaArrayInUint8(jenv, &jarr1, &arg1, jarg1)) return 0; - arg2 = (int *)&jarg2; - arg3 = (int *)&jarg3; - { - if (!jarg4) { - SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null"); - return 0; - } - if ((*jenv)->GetArrayLength(jenv, jarg4) == 0) { - SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element"); - return 0; - } - arg4 = &temp4; - } - arg5 = (int)jarg5; - arg6 = (int)jarg6; - arg7 = (int)jarg7; - arg8 = (float)jarg8; - result = (uint8_t *)wrap_WebPEncodeRGBA((uint8_t const *)arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8); - jresult = SWIG_JavaArrayOutUint8(jenv, result, FillMeInAsSizeCannotBeDeterminedAutomatically); - SWIG_JavaArrayArgoutUint8(jenv, jarr1, arg1, jarg1); - { - jint jvalue = (jint)temp4; - (*jenv)->SetIntArrayRegion(jenv, jarg4, 0, 1, &jvalue); - } - free(arg1); - - - - free(result); - return jresult; -} - - -SWIGEXPORT jbyteArray JNICALL Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeBGRA(JNIEnv *jenv, jclass jcls, jbyteArray jarg1, jint jarg2, jint jarg3, jintArray jarg4, jint jarg5, jint jarg6, jint jarg7, jfloat jarg8) { - jbyteArray jresult = 0 ; - uint8_t *arg1 = (uint8_t *) 0 ; - int *arg2 = (int *) 0 ; - int *arg3 = (int *) 0 ; - int *arg4 = (int *) 0 ; - int arg5 ; - int arg6 ; - int arg7 ; - float arg8 ; - jbyte *jarr1 ; - int temp4 ; - uint8_t *result = 0 ; - - (void)jenv; - (void)jcls; - if (!SWIG_JavaArrayInUint8(jenv, &jarr1, &arg1, jarg1)) return 0; - arg2 = (int *)&jarg2; - arg3 = (int *)&jarg3; - { - if (!jarg4) { - SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null"); - return 0; - } - if ((*jenv)->GetArrayLength(jenv, jarg4) == 0) { - SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element"); - return 0; - } - arg4 = &temp4; - } - arg5 = (int)jarg5; - arg6 = (int)jarg6; - arg7 = (int)jarg7; - arg8 = (float)jarg8; - result = (uint8_t *)wrap_WebPEncodeBGRA((uint8_t const *)arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8); - jresult = SWIG_JavaArrayOutUint8(jenv, result, FillMeInAsSizeCannotBeDeterminedAutomatically); - SWIG_JavaArrayArgoutUint8(jenv, jarr1, arg1, jarg1); - { - jint jvalue = (jint)temp4; - (*jenv)->SetIntArrayRegion(jenv, jarg4, 0, 1, &jvalue); - } - free(arg1); - - - - free(result); - return jresult; -} - - -SWIGEXPORT jbyteArray JNICALL Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeLosslessRGB(JNIEnv *jenv, jclass jcls, jbyteArray jarg1, jint jarg2, jint jarg3, jintArray jarg4, jint jarg5, jint jarg6, jint jarg7) { - jbyteArray jresult = 0 ; - uint8_t *arg1 = (uint8_t *) 0 ; - int *arg2 = (int *) 0 ; - int *arg3 = (int *) 0 ; - int *arg4 = (int *) 0 ; - int arg5 ; - int arg6 ; - int arg7 ; - jbyte *jarr1 ; - int temp4 ; - uint8_t *result = 0 ; - - (void)jenv; - (void)jcls; - if (!SWIG_JavaArrayInUint8(jenv, &jarr1, &arg1, jarg1)) return 0; - arg2 = (int *)&jarg2; - arg3 = (int *)&jarg3; - { - if (!jarg4) { - SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null"); - return 0; - } - if ((*jenv)->GetArrayLength(jenv, jarg4) == 0) { - SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element"); - return 0; - } - arg4 = &temp4; - } - arg5 = (int)jarg5; - arg6 = (int)jarg6; - arg7 = (int)jarg7; - result = (uint8_t *)wrap_WebPEncodeLosslessRGB((uint8_t const *)arg1,arg2,arg3,arg4,arg5,arg6,arg7); - jresult = SWIG_JavaArrayOutUint8(jenv, result, FillMeInAsSizeCannotBeDeterminedAutomatically); - SWIG_JavaArrayArgoutUint8(jenv, jarr1, arg1, jarg1); - { - jint jvalue = (jint)temp4; - (*jenv)->SetIntArrayRegion(jenv, jarg4, 0, 1, &jvalue); - } - free(arg1); - - - - free(result); - return jresult; -} - - -SWIGEXPORT jbyteArray JNICALL Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeLosslessBGR(JNIEnv *jenv, jclass jcls, jbyteArray jarg1, jint jarg2, jint jarg3, jintArray jarg4, jint jarg5, jint jarg6, jint jarg7) { - jbyteArray jresult = 0 ; - uint8_t *arg1 = (uint8_t *) 0 ; - int *arg2 = (int *) 0 ; - int *arg3 = (int *) 0 ; - int *arg4 = (int *) 0 ; - int arg5 ; - int arg6 ; - int arg7 ; - jbyte *jarr1 ; - int temp4 ; - uint8_t *result = 0 ; - - (void)jenv; - (void)jcls; - if (!SWIG_JavaArrayInUint8(jenv, &jarr1, &arg1, jarg1)) return 0; - arg2 = (int *)&jarg2; - arg3 = (int *)&jarg3; - { - if (!jarg4) { - SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null"); - return 0; - } - if ((*jenv)->GetArrayLength(jenv, jarg4) == 0) { - SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element"); - return 0; - } - arg4 = &temp4; - } - arg5 = (int)jarg5; - arg6 = (int)jarg6; - arg7 = (int)jarg7; - result = (uint8_t *)wrap_WebPEncodeLosslessBGR((uint8_t const *)arg1,arg2,arg3,arg4,arg5,arg6,arg7); - jresult = SWIG_JavaArrayOutUint8(jenv, result, FillMeInAsSizeCannotBeDeterminedAutomatically); - SWIG_JavaArrayArgoutUint8(jenv, jarr1, arg1, jarg1); - { - jint jvalue = (jint)temp4; - (*jenv)->SetIntArrayRegion(jenv, jarg4, 0, 1, &jvalue); - } - free(arg1); - - - - free(result); - return jresult; -} - - -SWIGEXPORT jbyteArray JNICALL Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeLosslessRGBA(JNIEnv *jenv, jclass jcls, jbyteArray jarg1, jint jarg2, jint jarg3, jintArray jarg4, jint jarg5, jint jarg6, jint jarg7) { - jbyteArray jresult = 0 ; - uint8_t *arg1 = (uint8_t *) 0 ; - int *arg2 = (int *) 0 ; - int *arg3 = (int *) 0 ; - int *arg4 = (int *) 0 ; - int arg5 ; - int arg6 ; - int arg7 ; - jbyte *jarr1 ; - int temp4 ; - uint8_t *result = 0 ; - - (void)jenv; - (void)jcls; - if (!SWIG_JavaArrayInUint8(jenv, &jarr1, &arg1, jarg1)) return 0; - arg2 = (int *)&jarg2; - arg3 = (int *)&jarg3; - { - if (!jarg4) { - SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null"); - return 0; - } - if ((*jenv)->GetArrayLength(jenv, jarg4) == 0) { - SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element"); - return 0; - } - arg4 = &temp4; - } - arg5 = (int)jarg5; - arg6 = (int)jarg6; - arg7 = (int)jarg7; - result = (uint8_t *)wrap_WebPEncodeLosslessRGBA((uint8_t const *)arg1,arg2,arg3,arg4,arg5,arg6,arg7); - jresult = SWIG_JavaArrayOutUint8(jenv, result, FillMeInAsSizeCannotBeDeterminedAutomatically); - SWIG_JavaArrayArgoutUint8(jenv, jarr1, arg1, jarg1); - { - jint jvalue = (jint)temp4; - (*jenv)->SetIntArrayRegion(jenv, jarg4, 0, 1, &jvalue); - } - free(arg1); - - - - free(result); - return jresult; -} - - -SWIGEXPORT jbyteArray JNICALL Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeLosslessBGRA(JNIEnv *jenv, jclass jcls, jbyteArray jarg1, jint jarg2, jint jarg3, jintArray jarg4, jint jarg5, jint jarg6, jint jarg7) { - jbyteArray jresult = 0 ; - uint8_t *arg1 = (uint8_t *) 0 ; - int *arg2 = (int *) 0 ; - int *arg3 = (int *) 0 ; - int *arg4 = (int *) 0 ; - int arg5 ; - int arg6 ; - int arg7 ; - jbyte *jarr1 ; - int temp4 ; - uint8_t *result = 0 ; - - (void)jenv; - (void)jcls; - if (!SWIG_JavaArrayInUint8(jenv, &jarr1, &arg1, jarg1)) return 0; - arg2 = (int *)&jarg2; - arg3 = (int *)&jarg3; - { - if (!jarg4) { - SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null"); - return 0; - } - if ((*jenv)->GetArrayLength(jenv, jarg4) == 0) { - SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element"); - return 0; - } - arg4 = &temp4; - } - arg5 = (int)jarg5; - arg6 = (int)jarg6; - arg7 = (int)jarg7; - result = (uint8_t *)wrap_WebPEncodeLosslessBGRA((uint8_t const *)arg1,arg2,arg3,arg4,arg5,arg6,arg7); - jresult = SWIG_JavaArrayOutUint8(jenv, result, FillMeInAsSizeCannotBeDeterminedAutomatically); - SWIG_JavaArrayArgoutUint8(jenv, jarr1, arg1, jarg1); - { - jint jvalue = (jint)temp4; - (*jenv)->SetIntArrayRegion(jenv, jarg4, 0, 1, &jvalue); - } - free(arg1); - - - - free(result); - return jresult; -} - - -#ifdef __cplusplus -} -#endif - diff --git a/libwebp/swig/libwebp_python_wrap.c b/libwebp/swig/libwebp_python_wrap.c deleted file mode 100644 index 3aa27285..00000000 --- a/libwebp/swig/libwebp_python_wrap.c +++ /dev/null @@ -1,5628 +0,0 @@ -/* ---------------------------------------------------------------------------- - * This file was automatically generated by SWIG (http://www.swig.org). - * Version 3.0.12 - * - * This file is not intended to be easily readable and contains a number of - * coding conventions designed to improve portability and efficiency. Do not make - * changes to this file unless you know what you are doing--modify the SWIG - * interface file instead. - * ----------------------------------------------------------------------------- */ - -#define SWIG_PYTHON_STRICT_BYTE_CHAR - - - -#ifndef SWIGPYTHON -#define SWIGPYTHON -#endif - -#define SWIG_PYTHON_DIRECTOR_NO_VTABLE - -/* ----------------------------------------------------------------------------- - * This section contains generic SWIG labels for method/variable - * declarations/attributes, and other compiler dependent labels. - * ----------------------------------------------------------------------------- */ - -/* template workaround for compilers that cannot correctly implement the C++ standard */ -#ifndef SWIGTEMPLATEDISAMBIGUATOR -# if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x560) -# define SWIGTEMPLATEDISAMBIGUATOR template -# elif defined(__HP_aCC) -/* Needed even with `aCC -AA' when `aCC -V' reports HP ANSI C++ B3910B A.03.55 */ -/* If we find a maximum version that requires this, the test would be __HP_aCC <= 35500 for A.03.55 */ -# define SWIGTEMPLATEDISAMBIGUATOR template -# else -# define SWIGTEMPLATEDISAMBIGUATOR -# endif -#endif - -/* inline attribute */ -#ifndef SWIGINLINE -# if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__)) -# define SWIGINLINE inline -# else -# define SWIGINLINE -# endif -#endif - -/* attribute recognised by some compilers to avoid 'unused' warnings */ -#ifndef SWIGUNUSED -# if defined(__GNUC__) -# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) -# define SWIGUNUSED __attribute__ ((__unused__)) -# else -# define SWIGUNUSED -# endif -# elif defined(__ICC) -# define SWIGUNUSED __attribute__ ((__unused__)) -# else -# define SWIGUNUSED -# endif -#endif - -#ifndef SWIG_MSC_UNSUPPRESS_4505 -# if defined(_MSC_VER) -# pragma warning(disable : 4505) /* unreferenced local function has been removed */ -# endif -#endif - -#ifndef SWIGUNUSEDPARM -# ifdef __cplusplus -# define SWIGUNUSEDPARM(p) -# else -# define SWIGUNUSEDPARM(p) p SWIGUNUSED -# endif -#endif - -/* internal SWIG method */ -#ifndef SWIGINTERN -# define SWIGINTERN static SWIGUNUSED -#endif - -/* internal inline SWIG method */ -#ifndef SWIGINTERNINLINE -# define SWIGINTERNINLINE SWIGINTERN SWIGINLINE -#endif - -/* exporting methods */ -#if defined(__GNUC__) -# if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) -# ifndef GCC_HASCLASSVISIBILITY -# define GCC_HASCLASSVISIBILITY -# endif -# endif -#endif - -#ifndef SWIGEXPORT -# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) -# if defined(STATIC_LINKED) -# define SWIGEXPORT -# else -# define SWIGEXPORT __declspec(dllexport) -# endif -# else -# if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY) -# define SWIGEXPORT __attribute__ ((visibility("default"))) -# else -# define SWIGEXPORT -# endif -# endif -#endif - -/* calling conventions for Windows */ -#ifndef SWIGSTDCALL -# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) -# define SWIGSTDCALL __stdcall -# else -# define SWIGSTDCALL -# endif -#endif - -/* Deal with Microsoft's attempt at deprecating C standard runtime functions */ -#if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) -# define _CRT_SECURE_NO_DEPRECATE -#endif - -/* Deal with Microsoft's attempt at deprecating methods in the standard C++ library */ -#if !defined(SWIG_NO_SCL_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_SCL_SECURE_NO_DEPRECATE) -# define _SCL_SECURE_NO_DEPRECATE -#endif - -/* Deal with Apple's deprecated 'AssertMacros.h' from Carbon-framework */ -#if defined(__APPLE__) && !defined(__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES) -# define __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES 0 -#endif - -/* Intel's compiler complains if a variable which was never initialised is - * cast to void, which is a common idiom which we use to indicate that we - * are aware a variable isn't used. So we just silence that warning. - * See: https://github.com/swig/swig/issues/192 for more discussion. - */ -#ifdef __INTEL_COMPILER -# pragma warning disable 592 -#endif - - -#if defined(_DEBUG) && defined(SWIG_PYTHON_INTERPRETER_NO_DEBUG) -/* Use debug wrappers with the Python release dll */ -# undef _DEBUG -# include -# define _DEBUG -#else -# include -#endif - -/* ----------------------------------------------------------------------------- - * swigrun.swg - * - * This file contains generic C API SWIG runtime support for pointer - * type checking. - * ----------------------------------------------------------------------------- */ - -/* This should only be incremented when either the layout of swig_type_info changes, - or for whatever reason, the runtime changes incompatibly */ -#define SWIG_RUNTIME_VERSION "4" - -/* define SWIG_TYPE_TABLE_NAME as "SWIG_TYPE_TABLE" */ -#ifdef SWIG_TYPE_TABLE -# define SWIG_QUOTE_STRING(x) #x -# define SWIG_EXPAND_AND_QUOTE_STRING(x) SWIG_QUOTE_STRING(x) -# define SWIG_TYPE_TABLE_NAME SWIG_EXPAND_AND_QUOTE_STRING(SWIG_TYPE_TABLE) -#else -# define SWIG_TYPE_TABLE_NAME -#endif - -/* - You can use the SWIGRUNTIME and SWIGRUNTIMEINLINE macros for - creating a static or dynamic library from the SWIG runtime code. - In 99.9% of the cases, SWIG just needs to declare them as 'static'. - - But only do this if strictly necessary, ie, if you have problems - with your compiler or suchlike. -*/ - -#ifndef SWIGRUNTIME -# define SWIGRUNTIME SWIGINTERN -#endif - -#ifndef SWIGRUNTIMEINLINE -# define SWIGRUNTIMEINLINE SWIGRUNTIME SWIGINLINE -#endif - -/* Generic buffer size */ -#ifndef SWIG_BUFFER_SIZE -# define SWIG_BUFFER_SIZE 1024 -#endif - -/* Flags for pointer conversions */ -#define SWIG_POINTER_DISOWN 0x1 -#define SWIG_CAST_NEW_MEMORY 0x2 - -/* Flags for new pointer objects */ -#define SWIG_POINTER_OWN 0x1 - - -/* - Flags/methods for returning states. - - The SWIG conversion methods, as ConvertPtr, return an integer - that tells if the conversion was successful or not. And if not, - an error code can be returned (see swigerrors.swg for the codes). - - Use the following macros/flags to set or process the returning - states. - - In old versions of SWIG, code such as the following was usually written: - - if (SWIG_ConvertPtr(obj,vptr,ty.flags) != -1) { - // success code - } else { - //fail code - } - - Now you can be more explicit: - - int res = SWIG_ConvertPtr(obj,vptr,ty.flags); - if (SWIG_IsOK(res)) { - // success code - } else { - // fail code - } - - which is the same really, but now you can also do - - Type *ptr; - int res = SWIG_ConvertPtr(obj,(void **)(&ptr),ty.flags); - if (SWIG_IsOK(res)) { - // success code - if (SWIG_IsNewObj(res) { - ... - delete *ptr; - } else { - ... - } - } else { - // fail code - } - - I.e., now SWIG_ConvertPtr can return new objects and you can - identify the case and take care of the deallocation. Of course that - also requires SWIG_ConvertPtr to return new result values, such as - - int SWIG_ConvertPtr(obj, ptr,...) { - if () { - if () { - *ptr = ; - return SWIG_NEWOBJ; - } else { - *ptr = ; - return SWIG_OLDOBJ; - } - } else { - return SWIG_BADOBJ; - } - } - - Of course, returning the plain '0(success)/-1(fail)' still works, but you can be - more explicit by returning SWIG_BADOBJ, SWIG_ERROR or any of the - SWIG errors code. - - Finally, if the SWIG_CASTRANK_MODE is enabled, the result code - allows to return the 'cast rank', for example, if you have this - - int food(double) - int fooi(int); - - and you call - - food(1) // cast rank '1' (1 -> 1.0) - fooi(1) // cast rank '0' - - just use the SWIG_AddCast()/SWIG_CheckState() -*/ - -#define SWIG_OK (0) -#define SWIG_ERROR (-1) -#define SWIG_IsOK(r) (r >= 0) -#define SWIG_ArgError(r) ((r != SWIG_ERROR) ? r : SWIG_TypeError) - -/* The CastRankLimit says how many bits are used for the cast rank */ -#define SWIG_CASTRANKLIMIT (1 << 8) -/* The NewMask denotes the object was created (using new/malloc) */ -#define SWIG_NEWOBJMASK (SWIG_CASTRANKLIMIT << 1) -/* The TmpMask is for in/out typemaps that use temporal objects */ -#define SWIG_TMPOBJMASK (SWIG_NEWOBJMASK << 1) -/* Simple returning values */ -#define SWIG_BADOBJ (SWIG_ERROR) -#define SWIG_OLDOBJ (SWIG_OK) -#define SWIG_NEWOBJ (SWIG_OK | SWIG_NEWOBJMASK) -#define SWIG_TMPOBJ (SWIG_OK | SWIG_TMPOBJMASK) -/* Check, add and del mask methods */ -#define SWIG_AddNewMask(r) (SWIG_IsOK(r) ? (r | SWIG_NEWOBJMASK) : r) -#define SWIG_DelNewMask(r) (SWIG_IsOK(r) ? (r & ~SWIG_NEWOBJMASK) : r) -#define SWIG_IsNewObj(r) (SWIG_IsOK(r) && (r & SWIG_NEWOBJMASK)) -#define SWIG_AddTmpMask(r) (SWIG_IsOK(r) ? (r | SWIG_TMPOBJMASK) : r) -#define SWIG_DelTmpMask(r) (SWIG_IsOK(r) ? (r & ~SWIG_TMPOBJMASK) : r) -#define SWIG_IsTmpObj(r) (SWIG_IsOK(r) && (r & SWIG_TMPOBJMASK)) - -/* Cast-Rank Mode */ -#if defined(SWIG_CASTRANK_MODE) -# ifndef SWIG_TypeRank -# define SWIG_TypeRank unsigned long -# endif -# ifndef SWIG_MAXCASTRANK /* Default cast allowed */ -# define SWIG_MAXCASTRANK (2) -# endif -# define SWIG_CASTRANKMASK ((SWIG_CASTRANKLIMIT) -1) -# define SWIG_CastRank(r) (r & SWIG_CASTRANKMASK) -SWIGINTERNINLINE int SWIG_AddCast(int r) { - return SWIG_IsOK(r) ? ((SWIG_CastRank(r) < SWIG_MAXCASTRANK) ? (r + 1) : SWIG_ERROR) : r; -} -SWIGINTERNINLINE int SWIG_CheckState(int r) { - return SWIG_IsOK(r) ? SWIG_CastRank(r) + 1 : 0; -} -#else /* no cast-rank mode */ -# define SWIG_AddCast(r) (r) -# define SWIG_CheckState(r) (SWIG_IsOK(r) ? 1 : 0) -#endif - - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef void *(*swig_converter_func)(void *, int *); -typedef struct swig_type_info *(*swig_dycast_func)(void **); - -/* Structure to store information on one type */ -typedef struct swig_type_info { - const char *name; /* mangled name of this type */ - const char *str; /* human readable name of this type */ - swig_dycast_func dcast; /* dynamic cast function down a hierarchy */ - struct swig_cast_info *cast; /* linked list of types that can cast into this type */ - void *clientdata; /* language specific type data */ - int owndata; /* flag if the structure owns the clientdata */ -} swig_type_info; - -/* Structure to store a type and conversion function used for casting */ -typedef struct swig_cast_info { - swig_type_info *type; /* pointer to type that is equivalent to this type */ - swig_converter_func converter; /* function to cast the void pointers */ - struct swig_cast_info *next; /* pointer to next cast in linked list */ - struct swig_cast_info *prev; /* pointer to the previous cast */ -} swig_cast_info; - -/* Structure used to store module information - * Each module generates one structure like this, and the runtime collects - * all of these structures and stores them in a circularly linked list.*/ -typedef struct swig_module_info { - swig_type_info **types; /* Array of pointers to swig_type_info structures that are in this module */ - size_t size; /* Number of types in this module */ - struct swig_module_info *next; /* Pointer to next element in circularly linked list */ - swig_type_info **type_initial; /* Array of initially generated type structures */ - swig_cast_info **cast_initial; /* Array of initially generated casting structures */ - void *clientdata; /* Language specific module data */ -} swig_module_info; - -/* - Compare two type names skipping the space characters, therefore - "char*" == "char *" and "Class" == "Class", etc. - - Return 0 when the two name types are equivalent, as in - strncmp, but skipping ' '. -*/ -SWIGRUNTIME int -SWIG_TypeNameComp(const char *f1, const char *l1, - const char *f2, const char *l2) { - for (;(f1 != l1) && (f2 != l2); ++f1, ++f2) { - while ((*f1 == ' ') && (f1 != l1)) ++f1; - while ((*f2 == ' ') && (f2 != l2)) ++f2; - if (*f1 != *f2) return (*f1 > *f2) ? 1 : -1; - } - return (int)((l1 - f1) - (l2 - f2)); -} - -/* - Check type equivalence in a name list like ||... - Return 0 if equal, -1 if nb < tb, 1 if nb > tb -*/ -SWIGRUNTIME int -SWIG_TypeCmp(const char *nb, const char *tb) { - int equiv = 1; - const char* te = tb + strlen(tb); - const char* ne = nb; - while (equiv != 0 && *ne) { - for (nb = ne; *ne; ++ne) { - if (*ne == '|') break; - } - equiv = SWIG_TypeNameComp(nb, ne, tb, te); - if (*ne) ++ne; - } - return equiv; -} - -/* - Check type equivalence in a name list like ||... - Return 0 if not equal, 1 if equal -*/ -SWIGRUNTIME int -SWIG_TypeEquiv(const char *nb, const char *tb) { - return SWIG_TypeCmp(nb, tb) == 0 ? 1 : 0; -} - -/* - Check the typename -*/ -SWIGRUNTIME swig_cast_info * -SWIG_TypeCheck(const char *c, swig_type_info *ty) { - if (ty) { - swig_cast_info *iter = ty->cast; - while (iter) { - if (strcmp(iter->type->name, c) == 0) { - if (iter == ty->cast) - return iter; - /* Move iter to the top of the linked list */ - iter->prev->next = iter->next; - if (iter->next) - iter->next->prev = iter->prev; - iter->next = ty->cast; - iter->prev = 0; - if (ty->cast) ty->cast->prev = iter; - ty->cast = iter; - return iter; - } - iter = iter->next; - } - } - return 0; -} - -/* - Identical to SWIG_TypeCheck, except strcmp is replaced with a pointer comparison -*/ -SWIGRUNTIME swig_cast_info * -SWIG_TypeCheckStruct(swig_type_info *from, swig_type_info *ty) { - if (ty) { - swig_cast_info *iter = ty->cast; - while (iter) { - if (iter->type == from) { - if (iter == ty->cast) - return iter; - /* Move iter to the top of the linked list */ - iter->prev->next = iter->next; - if (iter->next) - iter->next->prev = iter->prev; - iter->next = ty->cast; - iter->prev = 0; - if (ty->cast) ty->cast->prev = iter; - ty->cast = iter; - return iter; - } - iter = iter->next; - } - } - return 0; -} - -/* - Cast a pointer up an inheritance hierarchy -*/ -SWIGRUNTIMEINLINE void * -SWIG_TypeCast(swig_cast_info *ty, void *ptr, int *newmemory) { - return ((!ty) || (!ty->converter)) ? ptr : (*ty->converter)(ptr, newmemory); -} - -/* - Dynamic pointer casting. Down an inheritance hierarchy -*/ -SWIGRUNTIME swig_type_info * -SWIG_TypeDynamicCast(swig_type_info *ty, void **ptr) { - swig_type_info *lastty = ty; - if (!ty || !ty->dcast) return ty; - while (ty && (ty->dcast)) { - ty = (*ty->dcast)(ptr); - if (ty) lastty = ty; - } - return lastty; -} - -/* - Return the name associated with this type -*/ -SWIGRUNTIMEINLINE const char * -SWIG_TypeName(const swig_type_info *ty) { - return ty->name; -} - -/* - Return the pretty name associated with this type, - that is an unmangled type name in a form presentable to the user. -*/ -SWIGRUNTIME const char * -SWIG_TypePrettyName(const swig_type_info *type) { - /* The "str" field contains the equivalent pretty names of the - type, separated by vertical-bar characters. We choose - to print the last name, as it is often (?) the most - specific. */ - if (!type) return NULL; - if (type->str != NULL) { - const char *last_name = type->str; - const char *s; - for (s = type->str; *s; s++) - if (*s == '|') last_name = s+1; - return last_name; - } - else - return type->name; -} - -/* - Set the clientdata field for a type -*/ -SWIGRUNTIME void -SWIG_TypeClientData(swig_type_info *ti, void *clientdata) { - swig_cast_info *cast = ti->cast; - /* if (ti->clientdata == clientdata) return; */ - ti->clientdata = clientdata; - - while (cast) { - if (!cast->converter) { - swig_type_info *tc = cast->type; - if (!tc->clientdata) { - SWIG_TypeClientData(tc, clientdata); - } - } - cast = cast->next; - } -} -SWIGRUNTIME void -SWIG_TypeNewClientData(swig_type_info *ti, void *clientdata) { - SWIG_TypeClientData(ti, clientdata); - ti->owndata = 1; -} - -/* - Search for a swig_type_info structure only by mangled name - Search is a O(log #types) - - We start searching at module start, and finish searching when start == end. - Note: if start == end at the beginning of the function, we go all the way around - the circular list. -*/ -SWIGRUNTIME swig_type_info * -SWIG_MangledTypeQueryModule(swig_module_info *start, - swig_module_info *end, - const char *name) { - swig_module_info *iter = start; - do { - if (iter->size) { - size_t l = 0; - size_t r = iter->size - 1; - do { - /* since l+r >= 0, we can (>> 1) instead (/ 2) */ - size_t i = (l + r) >> 1; - const char *iname = iter->types[i]->name; - if (iname) { - int compare = strcmp(name, iname); - if (compare == 0) { - return iter->types[i]; - } else if (compare < 0) { - if (i) { - r = i - 1; - } else { - break; - } - } else if (compare > 0) { - l = i + 1; - } - } else { - break; /* should never happen */ - } - } while (l <= r); - } - iter = iter->next; - } while (iter != end); - return 0; -} - -/* - Search for a swig_type_info structure for either a mangled name or a human readable name. - It first searches the mangled names of the types, which is a O(log #types) - If a type is not found it then searches the human readable names, which is O(#types). - - We start searching at module start, and finish searching when start == end. - Note: if start == end at the beginning of the function, we go all the way around - the circular list. -*/ -SWIGRUNTIME swig_type_info * -SWIG_TypeQueryModule(swig_module_info *start, - swig_module_info *end, - const char *name) { - /* STEP 1: Search the name field using binary search */ - swig_type_info *ret = SWIG_MangledTypeQueryModule(start, end, name); - if (ret) { - return ret; - } else { - /* STEP 2: If the type hasn't been found, do a complete search - of the str field (the human readable name) */ - swig_module_info *iter = start; - do { - size_t i = 0; - for (; i < iter->size; ++i) { - if (iter->types[i]->str && (SWIG_TypeEquiv(iter->types[i]->str, name))) - return iter->types[i]; - } - iter = iter->next; - } while (iter != end); - } - - /* neither found a match */ - return 0; -} - -/* - Pack binary data into a string -*/ -SWIGRUNTIME char * -SWIG_PackData(char *c, void *ptr, size_t sz) { - static const char hex[17] = "0123456789abcdef"; - const unsigned char *u = (unsigned char *) ptr; - const unsigned char *eu = u + sz; - for (; u != eu; ++u) { - unsigned char uu = *u; - *(c++) = hex[(uu & 0xf0) >> 4]; - *(c++) = hex[uu & 0xf]; - } - return c; -} - -/* - Unpack binary data from a string -*/ -SWIGRUNTIME const char * -SWIG_UnpackData(const char *c, void *ptr, size_t sz) { - unsigned char *u = (unsigned char *) ptr; - const unsigned char *eu = u + sz; - for (; u != eu; ++u) { - char d = *(c++); - unsigned char uu; - if ((d >= '0') && (d <= '9')) - uu = (unsigned char)((d - '0') << 4); - else if ((d >= 'a') && (d <= 'f')) - uu = (unsigned char)((d - ('a'-10)) << 4); - else - return (char *) 0; - d = *(c++); - if ((d >= '0') && (d <= '9')) - uu |= (unsigned char)(d - '0'); - else if ((d >= 'a') && (d <= 'f')) - uu |= (unsigned char)(d - ('a'-10)); - else - return (char *) 0; - *u = uu; - } - return c; -} - -/* - Pack 'void *' into a string buffer. -*/ -SWIGRUNTIME char * -SWIG_PackVoidPtr(char *buff, void *ptr, const char *name, size_t bsz) { - char *r = buff; - if ((2*sizeof(void *) + 2) > bsz) return 0; - *(r++) = '_'; - r = SWIG_PackData(r,&ptr,sizeof(void *)); - if (strlen(name) + 1 > (bsz - (r - buff))) return 0; - strcpy(r,name); - return buff; -} - -SWIGRUNTIME const char * -SWIG_UnpackVoidPtr(const char *c, void **ptr, const char *name) { - if (*c != '_') { - if (strcmp(c,"NULL") == 0) { - *ptr = (void *) 0; - return name; - } else { - return 0; - } - } - return SWIG_UnpackData(++c,ptr,sizeof(void *)); -} - -SWIGRUNTIME char * -SWIG_PackDataName(char *buff, void *ptr, size_t sz, const char *name, size_t bsz) { - char *r = buff; - size_t lname = (name ? strlen(name) : 0); - if ((2*sz + 2 + lname) > bsz) return 0; - *(r++) = '_'; - r = SWIG_PackData(r,ptr,sz); - if (lname) { - strncpy(r,name,lname+1); - } else { - *r = 0; - } - return buff; -} - -SWIGRUNTIME const char * -SWIG_UnpackDataName(const char *c, void *ptr, size_t sz, const char *name) { - if (*c != '_') { - if (strcmp(c,"NULL") == 0) { - memset(ptr,0,sz); - return name; - } else { - return 0; - } - } - return SWIG_UnpackData(++c,ptr,sz); -} - -#ifdef __cplusplus -} -#endif - -/* Errors in SWIG */ -#define SWIG_UnknownError -1 -#define SWIG_IOError -2 -#define SWIG_RuntimeError -3 -#define SWIG_IndexError -4 -#define SWIG_TypeError -5 -#define SWIG_DivisionByZero -6 -#define SWIG_OverflowError -7 -#define SWIG_SyntaxError -8 -#define SWIG_ValueError -9 -#define SWIG_SystemError -10 -#define SWIG_AttributeError -11 -#define SWIG_MemoryError -12 -#define SWIG_NullReferenceError -13 - - - -/* Compatibility macros for Python 3 */ -#if PY_VERSION_HEX >= 0x03000000 - -#define PyClass_Check(obj) PyObject_IsInstance(obj, (PyObject *)&PyType_Type) -#define PyInt_Check(x) PyLong_Check(x) -#define PyInt_AsLong(x) PyLong_AsLong(x) -#define PyInt_FromLong(x) PyLong_FromLong(x) -#define PyInt_FromSize_t(x) PyLong_FromSize_t(x) -#define PyString_Check(name) PyBytes_Check(name) -#define PyString_FromString(x) PyUnicode_FromString(x) -#define PyString_FromStringAndSize(x, y) PyBytes_FromStringAndSize(x, y) -#define PyString_Format(fmt, args) PyUnicode_Format(fmt, args) -#define PyString_AsString(str) PyBytes_AsString(str) -#define PyString_Size(str) PyBytes_Size(str) -#define PyString_InternFromString(key) PyUnicode_InternFromString(key) -#define Py_TPFLAGS_HAVE_CLASS Py_TPFLAGS_BASETYPE -#define PyString_AS_STRING(x) PyUnicode_AS_STRING(x) -#define _PyLong_FromSsize_t(x) PyLong_FromSsize_t(x) - -#endif - -#ifndef Py_TYPE -# define Py_TYPE(op) ((op)->ob_type) -#endif - -/* SWIG APIs for compatibility of both Python 2 & 3 */ - -#if PY_VERSION_HEX >= 0x03000000 -# define SWIG_Python_str_FromFormat PyUnicode_FromFormat -#else -# define SWIG_Python_str_FromFormat PyString_FromFormat -#endif - - -/* Warning: This function will allocate a new string in Python 3, - * so please call SWIG_Python_str_DelForPy3(x) to free the space. - */ -SWIGINTERN char* -SWIG_Python_str_AsChar(PyObject *str) -{ -#if PY_VERSION_HEX >= 0x03000000 - char *cstr; - char *newstr; - Py_ssize_t len; - str = PyUnicode_AsUTF8String(str); - PyBytes_AsStringAndSize(str, &cstr, &len); - newstr = (char *) malloc(len+1); - memcpy(newstr, cstr, len+1); - Py_XDECREF(str); - return newstr; -#else - return PyString_AsString(str); -#endif -} - -#if PY_VERSION_HEX >= 0x03000000 -# define SWIG_Python_str_DelForPy3(x) free( (void*) (x) ) -#else -# define SWIG_Python_str_DelForPy3(x) -#endif - - -SWIGINTERN PyObject* -SWIG_Python_str_FromChar(const char *c) -{ -#if PY_VERSION_HEX >= 0x03000000 - return PyUnicode_FromString(c); -#else - return PyString_FromString(c); -#endif -} - -/* Add PyOS_snprintf for old Pythons */ -#if PY_VERSION_HEX < 0x02020000 -# if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WATCOM) -# define PyOS_snprintf _snprintf -# else -# define PyOS_snprintf snprintf -# endif -#endif - -/* A crude PyString_FromFormat implementation for old Pythons */ -#if PY_VERSION_HEX < 0x02020000 - -#ifndef SWIG_PYBUFFER_SIZE -# define SWIG_PYBUFFER_SIZE 1024 -#endif - -static PyObject * -PyString_FromFormat(const char *fmt, ...) { - va_list ap; - char buf[SWIG_PYBUFFER_SIZE * 2]; - int res; - va_start(ap, fmt); - res = vsnprintf(buf, sizeof(buf), fmt, ap); - va_end(ap); - return (res < 0 || res >= (int)sizeof(buf)) ? 0 : PyString_FromString(buf); -} -#endif - -#ifndef PyObject_DEL -# define PyObject_DEL PyObject_Del -#endif - -/* A crude PyExc_StopIteration exception for old Pythons */ -#if PY_VERSION_HEX < 0x02020000 -# ifndef PyExc_StopIteration -# define PyExc_StopIteration PyExc_RuntimeError -# endif -# ifndef PyObject_GenericGetAttr -# define PyObject_GenericGetAttr 0 -# endif -#endif - -/* Py_NotImplemented is defined in 2.1 and up. */ -#if PY_VERSION_HEX < 0x02010000 -# ifndef Py_NotImplemented -# define Py_NotImplemented PyExc_RuntimeError -# endif -#endif - -/* A crude PyString_AsStringAndSize implementation for old Pythons */ -#if PY_VERSION_HEX < 0x02010000 -# ifndef PyString_AsStringAndSize -# define PyString_AsStringAndSize(obj, s, len) {*s = PyString_AsString(obj); *len = *s ? strlen(*s) : 0;} -# endif -#endif - -/* PySequence_Size for old Pythons */ -#if PY_VERSION_HEX < 0x02000000 -# ifndef PySequence_Size -# define PySequence_Size PySequence_Length -# endif -#endif - -/* PyBool_FromLong for old Pythons */ -#if PY_VERSION_HEX < 0x02030000 -static -PyObject *PyBool_FromLong(long ok) -{ - PyObject *result = ok ? Py_True : Py_False; - Py_INCREF(result); - return result; -} -#endif - -/* Py_ssize_t for old Pythons */ -/* This code is as recommended by: */ -/* http://www.python.org/dev/peps/pep-0353/#conversion-guidelines */ -#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) -typedef int Py_ssize_t; -# define PY_SSIZE_T_MAX INT_MAX -# define PY_SSIZE_T_MIN INT_MIN -typedef inquiry lenfunc; -typedef intargfunc ssizeargfunc; -typedef intintargfunc ssizessizeargfunc; -typedef intobjargproc ssizeobjargproc; -typedef intintobjargproc ssizessizeobjargproc; -typedef getreadbufferproc readbufferproc; -typedef getwritebufferproc writebufferproc; -typedef getsegcountproc segcountproc; -typedef getcharbufferproc charbufferproc; -static long PyNumber_AsSsize_t (PyObject *x, void *SWIGUNUSEDPARM(exc)) -{ - long result = 0; - PyObject *i = PyNumber_Int(x); - if (i) { - result = PyInt_AsLong(i); - Py_DECREF(i); - } - return result; -} -#endif - -#if PY_VERSION_HEX < 0x02050000 -#define PyInt_FromSize_t(x) PyInt_FromLong((long)x) -#endif - -#if PY_VERSION_HEX < 0x02040000 -#define Py_VISIT(op) \ - do { \ - if (op) { \ - int vret = visit((op), arg); \ - if (vret) \ - return vret; \ - } \ - } while (0) -#endif - -#if PY_VERSION_HEX < 0x02030000 -typedef struct { - PyTypeObject type; - PyNumberMethods as_number; - PyMappingMethods as_mapping; - PySequenceMethods as_sequence; - PyBufferProcs as_buffer; - PyObject *name, *slots; -} PyHeapTypeObject; -#endif - -#if PY_VERSION_HEX < 0x02030000 -typedef destructor freefunc; -#endif - -#if ((PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 6) || \ - (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION > 0) || \ - (PY_MAJOR_VERSION > 3)) -# define SWIGPY_USE_CAPSULE -# define SWIGPY_CAPSULE_NAME ((char*)"swig_runtime_data" SWIG_RUNTIME_VERSION ".type_pointer_capsule" SWIG_TYPE_TABLE_NAME) -#endif - -#if PY_VERSION_HEX < 0x03020000 -#define PyDescr_TYPE(x) (((PyDescrObject *)(x))->d_type) -#define PyDescr_NAME(x) (((PyDescrObject *)(x))->d_name) -#define Py_hash_t long -#endif - -/* ----------------------------------------------------------------------------- - * error manipulation - * ----------------------------------------------------------------------------- */ - -SWIGRUNTIME PyObject* -SWIG_Python_ErrorType(int code) { - PyObject* type = 0; - switch(code) { - case SWIG_MemoryError: - type = PyExc_MemoryError; - break; - case SWIG_IOError: - type = PyExc_IOError; - break; - case SWIG_RuntimeError: - type = PyExc_RuntimeError; - break; - case SWIG_IndexError: - type = PyExc_IndexError; - break; - case SWIG_TypeError: - type = PyExc_TypeError; - break; - case SWIG_DivisionByZero: - type = PyExc_ZeroDivisionError; - break; - case SWIG_OverflowError: - type = PyExc_OverflowError; - break; - case SWIG_SyntaxError: - type = PyExc_SyntaxError; - break; - case SWIG_ValueError: - type = PyExc_ValueError; - break; - case SWIG_SystemError: - type = PyExc_SystemError; - break; - case SWIG_AttributeError: - type = PyExc_AttributeError; - break; - default: - type = PyExc_RuntimeError; - } - return type; -} - - -SWIGRUNTIME void -SWIG_Python_AddErrorMsg(const char* mesg) -{ - PyObject *type = 0; - PyObject *value = 0; - PyObject *traceback = 0; - - if (PyErr_Occurred()) PyErr_Fetch(&type, &value, &traceback); - if (value) { - char *tmp; - PyObject *old_str = PyObject_Str(value); - PyErr_Clear(); - Py_XINCREF(type); - - PyErr_Format(type, "%s %s", tmp = SWIG_Python_str_AsChar(old_str), mesg); - SWIG_Python_str_DelForPy3(tmp); - Py_DECREF(old_str); - Py_DECREF(value); - } else { - PyErr_SetString(PyExc_RuntimeError, mesg); - } -} - -#if defined(SWIG_PYTHON_NO_THREADS) -# if defined(SWIG_PYTHON_THREADS) -# undef SWIG_PYTHON_THREADS -# endif -#endif -#if defined(SWIG_PYTHON_THREADS) /* Threading support is enabled */ -# if !defined(SWIG_PYTHON_USE_GIL) && !defined(SWIG_PYTHON_NO_USE_GIL) -# if (PY_VERSION_HEX >= 0x02030000) /* For 2.3 or later, use the PyGILState calls */ -# define SWIG_PYTHON_USE_GIL -# endif -# endif -# if defined(SWIG_PYTHON_USE_GIL) /* Use PyGILState threads calls */ -# ifndef SWIG_PYTHON_INITIALIZE_THREADS -# define SWIG_PYTHON_INITIALIZE_THREADS PyEval_InitThreads() -# endif -# ifdef __cplusplus /* C++ code */ - class SWIG_Python_Thread_Block { - bool status; - PyGILState_STATE state; - public: - void end() { if (status) { PyGILState_Release(state); status = false;} } - SWIG_Python_Thread_Block() : status(true), state(PyGILState_Ensure()) {} - ~SWIG_Python_Thread_Block() { end(); } - }; - class SWIG_Python_Thread_Allow { - bool status; - PyThreadState *save; - public: - void end() { if (status) { PyEval_RestoreThread(save); status = false; }} - SWIG_Python_Thread_Allow() : status(true), save(PyEval_SaveThread()) {} - ~SWIG_Python_Thread_Allow() { end(); } - }; -# define SWIG_PYTHON_THREAD_BEGIN_BLOCK SWIG_Python_Thread_Block _swig_thread_block -# define SWIG_PYTHON_THREAD_END_BLOCK _swig_thread_block.end() -# define SWIG_PYTHON_THREAD_BEGIN_ALLOW SWIG_Python_Thread_Allow _swig_thread_allow -# define SWIG_PYTHON_THREAD_END_ALLOW _swig_thread_allow.end() -# else /* C code */ -# define SWIG_PYTHON_THREAD_BEGIN_BLOCK PyGILState_STATE _swig_thread_block = PyGILState_Ensure() -# define SWIG_PYTHON_THREAD_END_BLOCK PyGILState_Release(_swig_thread_block) -# define SWIG_PYTHON_THREAD_BEGIN_ALLOW PyThreadState *_swig_thread_allow = PyEval_SaveThread() -# define SWIG_PYTHON_THREAD_END_ALLOW PyEval_RestoreThread(_swig_thread_allow) -# endif -# else /* Old thread way, not implemented, user must provide it */ -# if !defined(SWIG_PYTHON_INITIALIZE_THREADS) -# define SWIG_PYTHON_INITIALIZE_THREADS -# endif -# if !defined(SWIG_PYTHON_THREAD_BEGIN_BLOCK) -# define SWIG_PYTHON_THREAD_BEGIN_BLOCK -# endif -# if !defined(SWIG_PYTHON_THREAD_END_BLOCK) -# define SWIG_PYTHON_THREAD_END_BLOCK -# endif -# if !defined(SWIG_PYTHON_THREAD_BEGIN_ALLOW) -# define SWIG_PYTHON_THREAD_BEGIN_ALLOW -# endif -# if !defined(SWIG_PYTHON_THREAD_END_ALLOW) -# define SWIG_PYTHON_THREAD_END_ALLOW -# endif -# endif -#else /* No thread support */ -# define SWIG_PYTHON_INITIALIZE_THREADS -# define SWIG_PYTHON_THREAD_BEGIN_BLOCK -# define SWIG_PYTHON_THREAD_END_BLOCK -# define SWIG_PYTHON_THREAD_BEGIN_ALLOW -# define SWIG_PYTHON_THREAD_END_ALLOW -#endif - -/* ----------------------------------------------------------------------------- - * Python API portion that goes into the runtime - * ----------------------------------------------------------------------------- */ - -#ifdef __cplusplus -extern "C" { -#endif - -/* ----------------------------------------------------------------------------- - * Constant declarations - * ----------------------------------------------------------------------------- */ - -/* Constant Types */ -#define SWIG_PY_POINTER 4 -#define SWIG_PY_BINARY 5 - -/* Constant information structure */ -typedef struct swig_const_info { - int type; - char *name; - long lvalue; - double dvalue; - void *pvalue; - swig_type_info **ptype; -} swig_const_info; - - -/* ----------------------------------------------------------------------------- - * Wrapper of PyInstanceMethod_New() used in Python 3 - * It is exported to the generated module, used for -fastproxy - * ----------------------------------------------------------------------------- */ -#if PY_VERSION_HEX >= 0x03000000 -SWIGRUNTIME PyObject* SWIG_PyInstanceMethod_New(PyObject *SWIGUNUSEDPARM(self), PyObject *func) -{ - return PyInstanceMethod_New(func); -} -#else -SWIGRUNTIME PyObject* SWIG_PyInstanceMethod_New(PyObject *SWIGUNUSEDPARM(self), PyObject *SWIGUNUSEDPARM(func)) -{ - return NULL; -} -#endif - -#ifdef __cplusplus -} -#endif - - -/* ----------------------------------------------------------------------------- - * pyrun.swg - * - * This file contains the runtime support for Python modules - * and includes code for managing global variables and pointer - * type checking. - * - * ----------------------------------------------------------------------------- */ - -/* Common SWIG API */ - -/* for raw pointers */ -#define SWIG_Python_ConvertPtr(obj, pptr, type, flags) SWIG_Python_ConvertPtrAndOwn(obj, pptr, type, flags, 0) -#define SWIG_ConvertPtr(obj, pptr, type, flags) SWIG_Python_ConvertPtr(obj, pptr, type, flags) -#define SWIG_ConvertPtrAndOwn(obj,pptr,type,flags,own) SWIG_Python_ConvertPtrAndOwn(obj, pptr, type, flags, own) - -#ifdef SWIGPYTHON_BUILTIN -#define SWIG_NewPointerObj(ptr, type, flags) SWIG_Python_NewPointerObj(self, ptr, type, flags) -#else -#define SWIG_NewPointerObj(ptr, type, flags) SWIG_Python_NewPointerObj(NULL, ptr, type, flags) -#endif - -#define SWIG_InternalNewPointerObj(ptr, type, flags) SWIG_Python_NewPointerObj(NULL, ptr, type, flags) - -#define SWIG_CheckImplicit(ty) SWIG_Python_CheckImplicit(ty) -#define SWIG_AcquirePtr(ptr, src) SWIG_Python_AcquirePtr(ptr, src) -#define swig_owntype int - -/* for raw packed data */ -#define SWIG_ConvertPacked(obj, ptr, sz, ty) SWIG_Python_ConvertPacked(obj, ptr, sz, ty) -#define SWIG_NewPackedObj(ptr, sz, type) SWIG_Python_NewPackedObj(ptr, sz, type) - -/* for class or struct pointers */ -#define SWIG_ConvertInstance(obj, pptr, type, flags) SWIG_ConvertPtr(obj, pptr, type, flags) -#define SWIG_NewInstanceObj(ptr, type, flags) SWIG_NewPointerObj(ptr, type, flags) - -/* for C or C++ function pointers */ -#define SWIG_ConvertFunctionPtr(obj, pptr, type) SWIG_Python_ConvertFunctionPtr(obj, pptr, type) -#define SWIG_NewFunctionPtrObj(ptr, type) SWIG_Python_NewPointerObj(NULL, ptr, type, 0) - -/* for C++ member pointers, ie, member methods */ -#define SWIG_ConvertMember(obj, ptr, sz, ty) SWIG_Python_ConvertPacked(obj, ptr, sz, ty) -#define SWIG_NewMemberObj(ptr, sz, type) SWIG_Python_NewPackedObj(ptr, sz, type) - - -/* Runtime API */ - -#define SWIG_GetModule(clientdata) SWIG_Python_GetModule(clientdata) -#define SWIG_SetModule(clientdata, pointer) SWIG_Python_SetModule(pointer) -#define SWIG_NewClientData(obj) SwigPyClientData_New(obj) - -#define SWIG_SetErrorObj SWIG_Python_SetErrorObj -#define SWIG_SetErrorMsg SWIG_Python_SetErrorMsg -#define SWIG_ErrorType(code) SWIG_Python_ErrorType(code) -#define SWIG_Error(code, msg) SWIG_Python_SetErrorMsg(SWIG_ErrorType(code), msg) -#define SWIG_fail goto fail - - -/* Runtime API implementation */ - -/* Error manipulation */ - -SWIGINTERN void -SWIG_Python_SetErrorObj(PyObject *errtype, PyObject *obj) { - SWIG_PYTHON_THREAD_BEGIN_BLOCK; - PyErr_SetObject(errtype, obj); - Py_DECREF(obj); - SWIG_PYTHON_THREAD_END_BLOCK; -} - -SWIGINTERN void -SWIG_Python_SetErrorMsg(PyObject *errtype, const char *msg) { - SWIG_PYTHON_THREAD_BEGIN_BLOCK; - PyErr_SetString(errtype, msg); - SWIG_PYTHON_THREAD_END_BLOCK; -} - -#define SWIG_Python_Raise(obj, type, desc) SWIG_Python_SetErrorObj(SWIG_Python_ExceptionType(desc), obj) - -/* Set a constant value */ - -#if defined(SWIGPYTHON_BUILTIN) - -SWIGINTERN void -SwigPyBuiltin_AddPublicSymbol(PyObject *seq, const char *key) { - PyObject *s = PyString_InternFromString(key); - PyList_Append(seq, s); - Py_DECREF(s); -} - -SWIGINTERN void -SWIG_Python_SetConstant(PyObject *d, PyObject *public_interface, const char *name, PyObject *obj) { -#if PY_VERSION_HEX < 0x02030000 - PyDict_SetItemString(d, (char *)name, obj); -#else - PyDict_SetItemString(d, name, obj); -#endif - Py_DECREF(obj); - if (public_interface) - SwigPyBuiltin_AddPublicSymbol(public_interface, name); -} - -#else - -SWIGINTERN void -SWIG_Python_SetConstant(PyObject *d, const char *name, PyObject *obj) { -#if PY_VERSION_HEX < 0x02030000 - PyDict_SetItemString(d, (char *)name, obj); -#else - PyDict_SetItemString(d, name, obj); -#endif - Py_DECREF(obj); -} - -#endif - -/* Append a value to the result obj */ - -SWIGINTERN PyObject* -SWIG_Python_AppendOutput(PyObject* result, PyObject* obj) { -#if !defined(SWIG_PYTHON_OUTPUT_TUPLE) - if (!result) { - result = obj; - } else if (result == Py_None) { - Py_DECREF(result); - result = obj; - } else { - if (!PyList_Check(result)) { - PyObject *o2 = result; - result = PyList_New(1); - PyList_SetItem(result, 0, o2); - } - PyList_Append(result,obj); - Py_DECREF(obj); - } - return result; -#else - PyObject* o2; - PyObject* o3; - if (!result) { - result = obj; - } else if (result == Py_None) { - Py_DECREF(result); - result = obj; - } else { - if (!PyTuple_Check(result)) { - o2 = result; - result = PyTuple_New(1); - PyTuple_SET_ITEM(result, 0, o2); - } - o3 = PyTuple_New(1); - PyTuple_SET_ITEM(o3, 0, obj); - o2 = result; - result = PySequence_Concat(o2, o3); - Py_DECREF(o2); - Py_DECREF(o3); - } - return result; -#endif -} - -/* Unpack the argument tuple */ - -SWIGINTERN Py_ssize_t -SWIG_Python_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t max, PyObject **objs) -{ - if (!args) { - if (!min && !max) { - return 1; - } else { - PyErr_Format(PyExc_TypeError, "%s expected %s%d arguments, got none", - name, (min == max ? "" : "at least "), (int)min); - return 0; - } - } - if (!PyTuple_Check(args)) { - if (min <= 1 && max >= 1) { - Py_ssize_t i; - objs[0] = args; - for (i = 1; i < max; ++i) { - objs[i] = 0; - } - return 2; - } - PyErr_SetString(PyExc_SystemError, "UnpackTuple() argument list is not a tuple"); - return 0; - } else { - Py_ssize_t l = PyTuple_GET_SIZE(args); - if (l < min) { - PyErr_Format(PyExc_TypeError, "%s expected %s%d arguments, got %d", - name, (min == max ? "" : "at least "), (int)min, (int)l); - return 0; - } else if (l > max) { - PyErr_Format(PyExc_TypeError, "%s expected %s%d arguments, got %d", - name, (min == max ? "" : "at most "), (int)max, (int)l); - return 0; - } else { - Py_ssize_t i; - for (i = 0; i < l; ++i) { - objs[i] = PyTuple_GET_ITEM(args, i); - } - for (; l < max; ++l) { - objs[l] = 0; - } - return i + 1; - } - } -} - -/* A functor is a function object with one single object argument */ -#if PY_VERSION_HEX >= 0x02020000 -#define SWIG_Python_CallFunctor(functor, obj) PyObject_CallFunctionObjArgs(functor, obj, NULL); -#else -#define SWIG_Python_CallFunctor(functor, obj) PyObject_CallFunction(functor, "O", obj); -#endif - -/* - Helper for static pointer initialization for both C and C++ code, for example - static PyObject *SWIG_STATIC_POINTER(MyVar) = NewSomething(...); -*/ -#ifdef __cplusplus -#define SWIG_STATIC_POINTER(var) var -#else -#define SWIG_STATIC_POINTER(var) var = 0; if (!var) var -#endif - -/* ----------------------------------------------------------------------------- - * Pointer declarations - * ----------------------------------------------------------------------------- */ - -/* Flags for new pointer objects */ -#define SWIG_POINTER_NOSHADOW (SWIG_POINTER_OWN << 1) -#define SWIG_POINTER_NEW (SWIG_POINTER_NOSHADOW | SWIG_POINTER_OWN) - -#define SWIG_POINTER_IMPLICIT_CONV (SWIG_POINTER_DISOWN << 1) - -#define SWIG_BUILTIN_TP_INIT (SWIG_POINTER_OWN << 2) -#define SWIG_BUILTIN_INIT (SWIG_BUILTIN_TP_INIT | SWIG_POINTER_OWN) - -#ifdef __cplusplus -extern "C" { -#endif - -/* How to access Py_None */ -#if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) -# ifndef SWIG_PYTHON_NO_BUILD_NONE -# ifndef SWIG_PYTHON_BUILD_NONE -# define SWIG_PYTHON_BUILD_NONE -# endif -# endif -#endif - -#ifdef SWIG_PYTHON_BUILD_NONE -# ifdef Py_None -# undef Py_None -# define Py_None SWIG_Py_None() -# endif -SWIGRUNTIMEINLINE PyObject * -_SWIG_Py_None(void) -{ - PyObject *none = Py_BuildValue((char*)""); - Py_DECREF(none); - return none; -} -SWIGRUNTIME PyObject * -SWIG_Py_None(void) -{ - static PyObject *SWIG_STATIC_POINTER(none) = _SWIG_Py_None(); - return none; -} -#endif - -/* The python void return value */ - -SWIGRUNTIMEINLINE PyObject * -SWIG_Py_Void(void) -{ - PyObject *none = Py_None; - Py_INCREF(none); - return none; -} - -/* SwigPyClientData */ - -typedef struct { - PyObject *klass; - PyObject *newraw; - PyObject *newargs; - PyObject *destroy; - int delargs; - int implicitconv; - PyTypeObject *pytype; -} SwigPyClientData; - -SWIGRUNTIMEINLINE int -SWIG_Python_CheckImplicit(swig_type_info *ty) -{ - SwigPyClientData *data = (SwigPyClientData *)ty->clientdata; - return data ? data->implicitconv : 0; -} - -SWIGRUNTIMEINLINE PyObject * -SWIG_Python_ExceptionType(swig_type_info *desc) { - SwigPyClientData *data = desc ? (SwigPyClientData *) desc->clientdata : 0; - PyObject *klass = data ? data->klass : 0; - return (klass ? klass : PyExc_RuntimeError); -} - - -SWIGRUNTIME SwigPyClientData * -SwigPyClientData_New(PyObject* obj) -{ - if (!obj) { - return 0; - } else { - SwigPyClientData *data = (SwigPyClientData *)malloc(sizeof(SwigPyClientData)); - /* the klass element */ - data->klass = obj; - Py_INCREF(data->klass); - /* the newraw method and newargs arguments used to create a new raw instance */ - if (PyClass_Check(obj)) { - data->newraw = 0; - data->newargs = obj; - Py_INCREF(obj); - } else { -#if (PY_VERSION_HEX < 0x02020000) - data->newraw = 0; -#else - data->newraw = PyObject_GetAttrString(data->klass, (char *)"__new__"); -#endif - if (data->newraw) { - Py_INCREF(data->newraw); - data->newargs = PyTuple_New(1); - PyTuple_SetItem(data->newargs, 0, obj); - } else { - data->newargs = obj; - } - Py_INCREF(data->newargs); - } - /* the destroy method, aka as the C++ delete method */ - data->destroy = PyObject_GetAttrString(data->klass, (char *)"__swig_destroy__"); - if (PyErr_Occurred()) { - PyErr_Clear(); - data->destroy = 0; - } - if (data->destroy) { - int flags; - Py_INCREF(data->destroy); - flags = PyCFunction_GET_FLAGS(data->destroy); -#ifdef METH_O - data->delargs = !(flags & (METH_O)); -#else - data->delargs = 0; -#endif - } else { - data->delargs = 0; - } - data->implicitconv = 0; - data->pytype = 0; - return data; - } -} - -SWIGRUNTIME void -SwigPyClientData_Del(SwigPyClientData *data) { - Py_XDECREF(data->newraw); - Py_XDECREF(data->newargs); - Py_XDECREF(data->destroy); -} - -/* =============== SwigPyObject =====================*/ - -typedef struct { - PyObject_HEAD - void *ptr; - swig_type_info *ty; - int own; - PyObject *next; -#ifdef SWIGPYTHON_BUILTIN - PyObject *dict; -#endif -} SwigPyObject; - - -#ifdef SWIGPYTHON_BUILTIN - -SWIGRUNTIME PyObject * -SwigPyObject_get___dict__(PyObject *v, PyObject *SWIGUNUSEDPARM(args)) -{ - SwigPyObject *sobj = (SwigPyObject *)v; - - if (!sobj->dict) - sobj->dict = PyDict_New(); - - Py_INCREF(sobj->dict); - return sobj->dict; -} - -#endif - -SWIGRUNTIME PyObject * -SwigPyObject_long(SwigPyObject *v) -{ - return PyLong_FromVoidPtr(v->ptr); -} - -SWIGRUNTIME PyObject * -SwigPyObject_format(const char* fmt, SwigPyObject *v) -{ - PyObject *res = NULL; - PyObject *args = PyTuple_New(1); - if (args) { - if (PyTuple_SetItem(args, 0, SwigPyObject_long(v)) == 0) { - PyObject *ofmt = SWIG_Python_str_FromChar(fmt); - if (ofmt) { -#if PY_VERSION_HEX >= 0x03000000 - res = PyUnicode_Format(ofmt,args); -#else - res = PyString_Format(ofmt,args); -#endif - Py_DECREF(ofmt); - } - Py_DECREF(args); - } - } - return res; -} - -SWIGRUNTIME PyObject * -SwigPyObject_oct(SwigPyObject *v) -{ - return SwigPyObject_format("%o",v); -} - -SWIGRUNTIME PyObject * -SwigPyObject_hex(SwigPyObject *v) -{ - return SwigPyObject_format("%x",v); -} - -SWIGRUNTIME PyObject * -#ifdef METH_NOARGS -SwigPyObject_repr(SwigPyObject *v) -#else -SwigPyObject_repr(SwigPyObject *v, PyObject *args) -#endif -{ - const char *name = SWIG_TypePrettyName(v->ty); - PyObject *repr = SWIG_Python_str_FromFormat("", (name ? name : "unknown"), (void *)v); - if (v->next) { -# ifdef METH_NOARGS - PyObject *nrep = SwigPyObject_repr((SwigPyObject *)v->next); -# else - PyObject *nrep = SwigPyObject_repr((SwigPyObject *)v->next, args); -# endif -# if PY_VERSION_HEX >= 0x03000000 - PyObject *joined = PyUnicode_Concat(repr, nrep); - Py_DecRef(repr); - Py_DecRef(nrep); - repr = joined; -# else - PyString_ConcatAndDel(&repr,nrep); -# endif - } - return repr; -} - -/* We need a version taking two PyObject* parameters so it's a valid - * PyCFunction to use in swigobject_methods[]. */ -SWIGRUNTIME PyObject * -SwigPyObject_repr2(PyObject *v, PyObject *SWIGUNUSEDPARM(args)) -{ - return SwigPyObject_repr((SwigPyObject*)v); -} - -SWIGRUNTIME int -SwigPyObject_compare(SwigPyObject *v, SwigPyObject *w) -{ - void *i = v->ptr; - void *j = w->ptr; - return (i < j) ? -1 : ((i > j) ? 1 : 0); -} - -/* Added for Python 3.x, would it also be useful for Python 2.x? */ -SWIGRUNTIME PyObject* -SwigPyObject_richcompare(SwigPyObject *v, SwigPyObject *w, int op) -{ - PyObject* res; - if( op != Py_EQ && op != Py_NE ) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - res = PyBool_FromLong( (SwigPyObject_compare(v, w)==0) == (op == Py_EQ) ? 1 : 0); - return res; -} - - -SWIGRUNTIME PyTypeObject* SwigPyObject_TypeOnce(void); - -#ifdef SWIGPYTHON_BUILTIN -static swig_type_info *SwigPyObject_stype = 0; -SWIGRUNTIME PyTypeObject* -SwigPyObject_type(void) { - SwigPyClientData *cd; - assert(SwigPyObject_stype); - cd = (SwigPyClientData*) SwigPyObject_stype->clientdata; - assert(cd); - assert(cd->pytype); - return cd->pytype; -} -#else -SWIGRUNTIME PyTypeObject* -SwigPyObject_type(void) { - static PyTypeObject *SWIG_STATIC_POINTER(type) = SwigPyObject_TypeOnce(); - return type; -} -#endif - -SWIGRUNTIMEINLINE int -SwigPyObject_Check(PyObject *op) { -#ifdef SWIGPYTHON_BUILTIN - PyTypeObject *target_tp = SwigPyObject_type(); - if (PyType_IsSubtype(op->ob_type, target_tp)) - return 1; - return (strcmp(op->ob_type->tp_name, "SwigPyObject") == 0); -#else - return (Py_TYPE(op) == SwigPyObject_type()) - || (strcmp(Py_TYPE(op)->tp_name,"SwigPyObject") == 0); -#endif -} - -SWIGRUNTIME PyObject * -SwigPyObject_New(void *ptr, swig_type_info *ty, int own); - -SWIGRUNTIME void -SwigPyObject_dealloc(PyObject *v) -{ - SwigPyObject *sobj = (SwigPyObject *) v; - PyObject *next = sobj->next; - if (sobj->own == SWIG_POINTER_OWN) { - swig_type_info *ty = sobj->ty; - SwigPyClientData *data = ty ? (SwigPyClientData *) ty->clientdata : 0; - PyObject *destroy = data ? data->destroy : 0; - if (destroy) { - /* destroy is always a VARARGS method */ - PyObject *res; - - /* PyObject_CallFunction() has the potential to silently drop - the active active exception. In cases of unnamed temporary - variable or where we just finished iterating over a generator - StopIteration will be active right now, and this needs to - remain true upon return from SwigPyObject_dealloc. So save - and restore. */ - - PyObject *val = NULL, *type = NULL, *tb = NULL; - PyErr_Fetch(&val, &type, &tb); - - if (data->delargs) { - /* we need to create a temporary object to carry the destroy operation */ - PyObject *tmp = SwigPyObject_New(sobj->ptr, ty, 0); - res = SWIG_Python_CallFunctor(destroy, tmp); - Py_DECREF(tmp); - } else { - PyCFunction meth = PyCFunction_GET_FUNCTION(destroy); - PyObject *mself = PyCFunction_GET_SELF(destroy); - res = ((*meth)(mself, v)); - } - if (!res) - PyErr_WriteUnraisable(destroy); - - PyErr_Restore(val, type, tb); - - Py_XDECREF(res); - } -#if !defined(SWIG_PYTHON_SILENT_MEMLEAK) - else { - const char *name = SWIG_TypePrettyName(ty); - printf("swig/python detected a memory leak of type '%s', no destructor found.\n", (name ? name : "unknown")); - } -#endif - } - Py_XDECREF(next); - PyObject_DEL(v); -} - -SWIGRUNTIME PyObject* -SwigPyObject_append(PyObject* v, PyObject* next) -{ - SwigPyObject *sobj = (SwigPyObject *) v; -#ifndef METH_O - PyObject *tmp = 0; - if (!PyArg_ParseTuple(next,(char *)"O:append", &tmp)) return NULL; - next = tmp; -#endif - if (!SwigPyObject_Check(next)) { - PyErr_SetString(PyExc_TypeError, "Attempt to append a non SwigPyObject"); - return NULL; - } - sobj->next = next; - Py_INCREF(next); - return SWIG_Py_Void(); -} - -SWIGRUNTIME PyObject* -SwigPyObject_next(PyObject* v, PyObject *SWIGUNUSEDPARM(args)) -{ - SwigPyObject *sobj = (SwigPyObject *) v; - if (sobj->next) { - Py_INCREF(sobj->next); - return sobj->next; - } else { - return SWIG_Py_Void(); - } -} - -SWIGINTERN PyObject* -#ifdef METH_NOARGS -SwigPyObject_disown(PyObject *v) -#else -SwigPyObject_disown(PyObject* v, PyObject *SWIGUNUSEDPARM(args)) -#endif -{ - SwigPyObject *sobj = (SwigPyObject *)v; - sobj->own = 0; - return SWIG_Py_Void(); -} - -SWIGINTERN PyObject* -#ifdef METH_NOARGS -SwigPyObject_acquire(PyObject *v) -#else -SwigPyObject_acquire(PyObject* v, PyObject *SWIGUNUSEDPARM(args)) -#endif -{ - SwigPyObject *sobj = (SwigPyObject *)v; - sobj->own = SWIG_POINTER_OWN; - return SWIG_Py_Void(); -} - -#ifdef METH_NOARGS -static PyObject* -SwigPyObject_disown2(PyObject* v, PyObject *SWIGUNUSEDPARM(args)) -{ - return SwigPyObject_disown(v); -} - -static PyObject* -SwigPyObject_acquire2(PyObject* v, PyObject *SWIGUNUSEDPARM(args)) -{ - return SwigPyObject_acquire(v); -} -#endif - -SWIGINTERN PyObject* -SwigPyObject_own(PyObject *v, PyObject *args) -{ - PyObject *val = 0; -#if (PY_VERSION_HEX < 0x02020000) - if (!PyArg_ParseTuple(args,(char *)"|O:own",&val)) -#elif (PY_VERSION_HEX < 0x02050000) - if (!PyArg_UnpackTuple(args, (char *)"own", 0, 1, &val)) -#else - if (!PyArg_UnpackTuple(args, "own", 0, 1, &val)) -#endif - { - return NULL; - } - else - { - SwigPyObject *sobj = (SwigPyObject *)v; - PyObject *obj = PyBool_FromLong(sobj->own); - if (val) { -#ifdef METH_NOARGS - if (PyObject_IsTrue(val)) { - SwigPyObject_acquire(v); - } else { - SwigPyObject_disown(v); - } -#else - if (PyObject_IsTrue(val)) { - SwigPyObject_acquire(v,args); - } else { - SwigPyObject_disown(v,args); - } -#endif - } - return obj; - } -} - -#ifdef METH_O -static PyMethodDef -swigobject_methods[] = { - {(char *)"disown", (PyCFunction)SwigPyObject_disown2, METH_NOARGS, (char *)"releases ownership of the pointer"}, - {(char *)"acquire", (PyCFunction)SwigPyObject_acquire2,METH_NOARGS, (char *)"acquires ownership of the pointer"}, - {(char *)"own", (PyCFunction)SwigPyObject_own, METH_VARARGS, (char *)"returns/sets ownership of the pointer"}, - {(char *)"append", (PyCFunction)SwigPyObject_append, METH_O, (char *)"appends another 'this' object"}, - {(char *)"next", (PyCFunction)SwigPyObject_next, METH_NOARGS, (char *)"returns the next 'this' object"}, - {(char *)"__repr__",(PyCFunction)SwigPyObject_repr2, METH_NOARGS, (char *)"returns object representation"}, - {0, 0, 0, 0} -}; -#else -static PyMethodDef -swigobject_methods[] = { - {(char *)"disown", (PyCFunction)SwigPyObject_disown, METH_VARARGS, (char *)"releases ownership of the pointer"}, - {(char *)"acquire", (PyCFunction)SwigPyObject_acquire, METH_VARARGS, (char *)"acquires ownership of the pointer"}, - {(char *)"own", (PyCFunction)SwigPyObject_own, METH_VARARGS, (char *)"returns/sets ownership of the pointer"}, - {(char *)"append", (PyCFunction)SwigPyObject_append, METH_VARARGS, (char *)"appends another 'this' object"}, - {(char *)"next", (PyCFunction)SwigPyObject_next, METH_VARARGS, (char *)"returns the next 'this' object"}, - {(char *)"__repr__",(PyCFunction)SwigPyObject_repr, METH_VARARGS, (char *)"returns object representation"}, - {0, 0, 0, 0} -}; -#endif - -#if PY_VERSION_HEX < 0x02020000 -SWIGINTERN PyObject * -SwigPyObject_getattr(SwigPyObject *sobj,char *name) -{ - return Py_FindMethod(swigobject_methods, (PyObject *)sobj, name); -} -#endif - -SWIGRUNTIME PyTypeObject* -SwigPyObject_TypeOnce(void) { - static char swigobject_doc[] = "Swig object carries a C/C++ instance pointer"; - - static PyNumberMethods SwigPyObject_as_number = { - (binaryfunc)0, /*nb_add*/ - (binaryfunc)0, /*nb_subtract*/ - (binaryfunc)0, /*nb_multiply*/ - /* nb_divide removed in Python 3 */ -#if PY_VERSION_HEX < 0x03000000 - (binaryfunc)0, /*nb_divide*/ -#endif - (binaryfunc)0, /*nb_remainder*/ - (binaryfunc)0, /*nb_divmod*/ - (ternaryfunc)0,/*nb_power*/ - (unaryfunc)0, /*nb_negative*/ - (unaryfunc)0, /*nb_positive*/ - (unaryfunc)0, /*nb_absolute*/ - (inquiry)0, /*nb_nonzero*/ - 0, /*nb_invert*/ - 0, /*nb_lshift*/ - 0, /*nb_rshift*/ - 0, /*nb_and*/ - 0, /*nb_xor*/ - 0, /*nb_or*/ -#if PY_VERSION_HEX < 0x03000000 - 0, /*nb_coerce*/ -#endif - (unaryfunc)SwigPyObject_long, /*nb_int*/ -#if PY_VERSION_HEX < 0x03000000 - (unaryfunc)SwigPyObject_long, /*nb_long*/ -#else - 0, /*nb_reserved*/ -#endif - (unaryfunc)0, /*nb_float*/ -#if PY_VERSION_HEX < 0x03000000 - (unaryfunc)SwigPyObject_oct, /*nb_oct*/ - (unaryfunc)SwigPyObject_hex, /*nb_hex*/ -#endif -#if PY_VERSION_HEX >= 0x03050000 /* 3.5 */ - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_inplace_matrix_multiply */ -#elif PY_VERSION_HEX >= 0x03000000 /* 3.0 */ - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_index, nb_inplace_divide removed */ -#elif PY_VERSION_HEX >= 0x02050000 /* 2.5.0 */ - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_index */ -#elif PY_VERSION_HEX >= 0x02020000 /* 2.2.0 */ - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_inplace_true_divide */ -#elif PY_VERSION_HEX >= 0x02000000 /* 2.0.0 */ - 0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_inplace_or */ -#endif - }; - - static PyTypeObject swigpyobject_type; - static int type_init = 0; - if (!type_init) { - const PyTypeObject tmp = { -#if PY_VERSION_HEX >= 0x03000000 - PyVarObject_HEAD_INIT(NULL, 0) -#else - PyObject_HEAD_INIT(NULL) - 0, /* ob_size */ -#endif - (char *)"SwigPyObject", /* tp_name */ - sizeof(SwigPyObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)SwigPyObject_dealloc, /* tp_dealloc */ - 0, /* tp_print */ -#if PY_VERSION_HEX < 0x02020000 - (getattrfunc)SwigPyObject_getattr, /* tp_getattr */ -#else - (getattrfunc)0, /* tp_getattr */ -#endif - (setattrfunc)0, /* tp_setattr */ -#if PY_VERSION_HEX >= 0x03000000 - 0, /* tp_reserved in 3.0.1, tp_compare in 3.0.0 but not used */ -#else - (cmpfunc)SwigPyObject_compare, /* tp_compare */ -#endif - (reprfunc)SwigPyObject_repr, /* tp_repr */ - &SwigPyObject_as_number, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - (hashfunc)0, /* tp_hash */ - (ternaryfunc)0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - swigobject_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - (richcmpfunc)SwigPyObject_richcompare,/* tp_richcompare */ - 0, /* tp_weaklistoffset */ -#if PY_VERSION_HEX >= 0x02020000 - 0, /* tp_iter */ - 0, /* tp_iternext */ - swigobject_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - 0, /* tp_new */ - 0, /* tp_free */ - 0, /* tp_is_gc */ - 0, /* tp_bases */ - 0, /* tp_mro */ - 0, /* tp_cache */ - 0, /* tp_subclasses */ - 0, /* tp_weaklist */ -#endif -#if PY_VERSION_HEX >= 0x02030000 - 0, /* tp_del */ -#endif -#if PY_VERSION_HEX >= 0x02060000 - 0, /* tp_version_tag */ -#endif -#if PY_VERSION_HEX >= 0x03040000 - 0, /* tp_finalize */ -#endif -#ifdef COUNT_ALLOCS - 0, /* tp_allocs */ - 0, /* tp_frees */ - 0, /* tp_maxalloc */ -#if PY_VERSION_HEX >= 0x02050000 - 0, /* tp_prev */ -#endif - 0 /* tp_next */ -#endif - }; - swigpyobject_type = tmp; - type_init = 1; -#if PY_VERSION_HEX < 0x02020000 - swigpyobject_type.ob_type = &PyType_Type; -#else - if (PyType_Ready(&swigpyobject_type) < 0) - return NULL; -#endif - } - return &swigpyobject_type; -} - -SWIGRUNTIME PyObject * -SwigPyObject_New(void *ptr, swig_type_info *ty, int own) -{ - SwigPyObject *sobj = PyObject_NEW(SwigPyObject, SwigPyObject_type()); - if (sobj) { - sobj->ptr = ptr; - sobj->ty = ty; - sobj->own = own; - sobj->next = 0; - } - return (PyObject *)sobj; -} - -/* ----------------------------------------------------------------------------- - * Implements a simple Swig Packed type, and use it instead of string - * ----------------------------------------------------------------------------- */ - -typedef struct { - PyObject_HEAD - void *pack; - swig_type_info *ty; - size_t size; -} SwigPyPacked; - -SWIGRUNTIME int -SwigPyPacked_print(SwigPyPacked *v, FILE *fp, int SWIGUNUSEDPARM(flags)) -{ - char result[SWIG_BUFFER_SIZE]; - fputs("pack, v->size, 0, sizeof(result))) { - fputs("at ", fp); - fputs(result, fp); - } - fputs(v->ty->name,fp); - fputs(">", fp); - return 0; -} - -SWIGRUNTIME PyObject * -SwigPyPacked_repr(SwigPyPacked *v) -{ - char result[SWIG_BUFFER_SIZE]; - if (SWIG_PackDataName(result, v->pack, v->size, 0, sizeof(result))) { - return SWIG_Python_str_FromFormat("", result, v->ty->name); - } else { - return SWIG_Python_str_FromFormat("", v->ty->name); - } -} - -SWIGRUNTIME PyObject * -SwigPyPacked_str(SwigPyPacked *v) -{ - char result[SWIG_BUFFER_SIZE]; - if (SWIG_PackDataName(result, v->pack, v->size, 0, sizeof(result))){ - return SWIG_Python_str_FromFormat("%s%s", result, v->ty->name); - } else { - return SWIG_Python_str_FromChar(v->ty->name); - } -} - -SWIGRUNTIME int -SwigPyPacked_compare(SwigPyPacked *v, SwigPyPacked *w) -{ - size_t i = v->size; - size_t j = w->size; - int s = (i < j) ? -1 : ((i > j) ? 1 : 0); - return s ? s : strncmp((char *)v->pack, (char *)w->pack, 2*v->size); -} - -SWIGRUNTIME PyTypeObject* SwigPyPacked_TypeOnce(void); - -SWIGRUNTIME PyTypeObject* -SwigPyPacked_type(void) { - static PyTypeObject *SWIG_STATIC_POINTER(type) = SwigPyPacked_TypeOnce(); - return type; -} - -SWIGRUNTIMEINLINE int -SwigPyPacked_Check(PyObject *op) { - return ((op)->ob_type == SwigPyPacked_TypeOnce()) - || (strcmp((op)->ob_type->tp_name,"SwigPyPacked") == 0); -} - -SWIGRUNTIME void -SwigPyPacked_dealloc(PyObject *v) -{ - if (SwigPyPacked_Check(v)) { - SwigPyPacked *sobj = (SwigPyPacked *) v; - free(sobj->pack); - } - PyObject_DEL(v); -} - -SWIGRUNTIME PyTypeObject* -SwigPyPacked_TypeOnce(void) { - static char swigpacked_doc[] = "Swig object carries a C/C++ instance pointer"; - static PyTypeObject swigpypacked_type; - static int type_init = 0; - if (!type_init) { - const PyTypeObject tmp = { -#if PY_VERSION_HEX>=0x03000000 - PyVarObject_HEAD_INIT(NULL, 0) -#else - PyObject_HEAD_INIT(NULL) - 0, /* ob_size */ -#endif - (char *)"SwigPyPacked", /* tp_name */ - sizeof(SwigPyPacked), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)SwigPyPacked_dealloc, /* tp_dealloc */ - (printfunc)SwigPyPacked_print, /* tp_print */ - (getattrfunc)0, /* tp_getattr */ - (setattrfunc)0, /* tp_setattr */ -#if PY_VERSION_HEX>=0x03000000 - 0, /* tp_reserved in 3.0.1 */ -#else - (cmpfunc)SwigPyPacked_compare, /* tp_compare */ -#endif - (reprfunc)SwigPyPacked_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - (hashfunc)0, /* tp_hash */ - (ternaryfunc)0, /* tp_call */ - (reprfunc)SwigPyPacked_str, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - swigpacked_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ -#if PY_VERSION_HEX >= 0x02020000 - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - 0, /* tp_new */ - 0, /* tp_free */ - 0, /* tp_is_gc */ - 0, /* tp_bases */ - 0, /* tp_mro */ - 0, /* tp_cache */ - 0, /* tp_subclasses */ - 0, /* tp_weaklist */ -#endif -#if PY_VERSION_HEX >= 0x02030000 - 0, /* tp_del */ -#endif -#if PY_VERSION_HEX >= 0x02060000 - 0, /* tp_version_tag */ -#endif -#if PY_VERSION_HEX >= 0x03040000 - 0, /* tp_finalize */ -#endif -#ifdef COUNT_ALLOCS - 0, /* tp_allocs */ - 0, /* tp_frees */ - 0, /* tp_maxalloc */ -#if PY_VERSION_HEX >= 0x02050000 - 0, /* tp_prev */ -#endif - 0 /* tp_next */ -#endif - }; - swigpypacked_type = tmp; - type_init = 1; -#if PY_VERSION_HEX < 0x02020000 - swigpypacked_type.ob_type = &PyType_Type; -#else - if (PyType_Ready(&swigpypacked_type) < 0) - return NULL; -#endif - } - return &swigpypacked_type; -} - -SWIGRUNTIME PyObject * -SwigPyPacked_New(void *ptr, size_t size, swig_type_info *ty) -{ - SwigPyPacked *sobj = PyObject_NEW(SwigPyPacked, SwigPyPacked_type()); - if (sobj) { - void *pack = malloc(size); - if (pack) { - memcpy(pack, ptr, size); - sobj->pack = pack; - sobj->ty = ty; - sobj->size = size; - } else { - PyObject_DEL((PyObject *) sobj); - sobj = 0; - } - } - return (PyObject *) sobj; -} - -SWIGRUNTIME swig_type_info * -SwigPyPacked_UnpackData(PyObject *obj, void *ptr, size_t size) -{ - if (SwigPyPacked_Check(obj)) { - SwigPyPacked *sobj = (SwigPyPacked *)obj; - if (sobj->size != size) return 0; - memcpy(ptr, sobj->pack, size); - return sobj->ty; - } else { - return 0; - } -} - -/* ----------------------------------------------------------------------------- - * pointers/data manipulation - * ----------------------------------------------------------------------------- */ - -SWIGRUNTIMEINLINE PyObject * -_SWIG_This(void) -{ - return SWIG_Python_str_FromChar("this"); -} - -static PyObject *swig_this = NULL; - -SWIGRUNTIME PyObject * -SWIG_This(void) -{ - if (swig_this == NULL) - swig_this = _SWIG_This(); - return swig_this; -} - -/* #define SWIG_PYTHON_SLOW_GETSET_THIS */ - -/* TODO: I don't know how to implement the fast getset in Python 3 right now */ -#if PY_VERSION_HEX>=0x03000000 -#define SWIG_PYTHON_SLOW_GETSET_THIS -#endif - -SWIGRUNTIME SwigPyObject * -SWIG_Python_GetSwigThis(PyObject *pyobj) -{ - PyObject *obj; - - if (SwigPyObject_Check(pyobj)) - return (SwigPyObject *) pyobj; - -#ifdef SWIGPYTHON_BUILTIN - (void)obj; -# ifdef PyWeakref_CheckProxy - if (PyWeakref_CheckProxy(pyobj)) { - pyobj = PyWeakref_GET_OBJECT(pyobj); - if (pyobj && SwigPyObject_Check(pyobj)) - return (SwigPyObject*) pyobj; - } -# endif - return NULL; -#else - - obj = 0; - -#if (!defined(SWIG_PYTHON_SLOW_GETSET_THIS) && (PY_VERSION_HEX >= 0x02030000)) - if (PyInstance_Check(pyobj)) { - obj = _PyInstance_Lookup(pyobj, SWIG_This()); - } else { - PyObject **dictptr = _PyObject_GetDictPtr(pyobj); - if (dictptr != NULL) { - PyObject *dict = *dictptr; - obj = dict ? PyDict_GetItem(dict, SWIG_This()) : 0; - } else { -#ifdef PyWeakref_CheckProxy - if (PyWeakref_CheckProxy(pyobj)) { - PyObject *wobj = PyWeakref_GET_OBJECT(pyobj); - return wobj ? SWIG_Python_GetSwigThis(wobj) : 0; - } -#endif - obj = PyObject_GetAttr(pyobj,SWIG_This()); - if (obj) { - Py_DECREF(obj); - } else { - if (PyErr_Occurred()) PyErr_Clear(); - return 0; - } - } - } -#else - obj = PyObject_GetAttr(pyobj,SWIG_This()); - if (obj) { - Py_DECREF(obj); - } else { - if (PyErr_Occurred()) PyErr_Clear(); - return 0; - } -#endif - if (obj && !SwigPyObject_Check(obj)) { - /* a PyObject is called 'this', try to get the 'real this' - SwigPyObject from it */ - return SWIG_Python_GetSwigThis(obj); - } - return (SwigPyObject *)obj; -#endif -} - -/* Acquire a pointer value */ - -SWIGRUNTIME int -SWIG_Python_AcquirePtr(PyObject *obj, int own) { - if (own == SWIG_POINTER_OWN) { - SwigPyObject *sobj = SWIG_Python_GetSwigThis(obj); - if (sobj) { - int oldown = sobj->own; - sobj->own = own; - return oldown; - } - } - return 0; -} - -/* Convert a pointer value */ - -SWIGRUNTIME int -SWIG_Python_ConvertPtrAndOwn(PyObject *obj, void **ptr, swig_type_info *ty, int flags, int *own) { - int res; - SwigPyObject *sobj; - int implicit_conv = (flags & SWIG_POINTER_IMPLICIT_CONV) != 0; - - if (!obj) - return SWIG_ERROR; - if (obj == Py_None && !implicit_conv) { - if (ptr) - *ptr = 0; - return SWIG_OK; - } - - res = SWIG_ERROR; - - sobj = SWIG_Python_GetSwigThis(obj); - if (own) - *own = 0; - while (sobj) { - void *vptr = sobj->ptr; - if (ty) { - swig_type_info *to = sobj->ty; - if (to == ty) { - /* no type cast needed */ - if (ptr) *ptr = vptr; - break; - } else { - swig_cast_info *tc = SWIG_TypeCheck(to->name,ty); - if (!tc) { - sobj = (SwigPyObject *)sobj->next; - } else { - if (ptr) { - int newmemory = 0; - *ptr = SWIG_TypeCast(tc,vptr,&newmemory); - if (newmemory == SWIG_CAST_NEW_MEMORY) { - assert(own); /* badly formed typemap which will lead to a memory leak - it must set and use own to delete *ptr */ - if (own) - *own = *own | SWIG_CAST_NEW_MEMORY; - } - } - break; - } - } - } else { - if (ptr) *ptr = vptr; - break; - } - } - if (sobj) { - if (own) - *own = *own | sobj->own; - if (flags & SWIG_POINTER_DISOWN) { - sobj->own = 0; - } - res = SWIG_OK; - } else { - if (implicit_conv) { - SwigPyClientData *data = ty ? (SwigPyClientData *) ty->clientdata : 0; - if (data && !data->implicitconv) { - PyObject *klass = data->klass; - if (klass) { - PyObject *impconv; - data->implicitconv = 1; /* avoid recursion and call 'explicit' constructors*/ - impconv = SWIG_Python_CallFunctor(klass, obj); - data->implicitconv = 0; - if (PyErr_Occurred()) { - PyErr_Clear(); - impconv = 0; - } - if (impconv) { - SwigPyObject *iobj = SWIG_Python_GetSwigThis(impconv); - if (iobj) { - void *vptr; - res = SWIG_Python_ConvertPtrAndOwn((PyObject*)iobj, &vptr, ty, 0, 0); - if (SWIG_IsOK(res)) { - if (ptr) { - *ptr = vptr; - /* transfer the ownership to 'ptr' */ - iobj->own = 0; - res = SWIG_AddCast(res); - res = SWIG_AddNewMask(res); - } else { - res = SWIG_AddCast(res); - } - } - } - Py_DECREF(impconv); - } - } - } - } - if (!SWIG_IsOK(res) && obj == Py_None) { - if (ptr) - *ptr = 0; - if (PyErr_Occurred()) - PyErr_Clear(); - res = SWIG_OK; - } - } - return res; -} - -/* Convert a function ptr value */ - -SWIGRUNTIME int -SWIG_Python_ConvertFunctionPtr(PyObject *obj, void **ptr, swig_type_info *ty) { - if (!PyCFunction_Check(obj)) { - return SWIG_ConvertPtr(obj, ptr, ty, 0); - } else { - void *vptr = 0; - - /* here we get the method pointer for callbacks */ - const char *doc = (((PyCFunctionObject *)obj) -> m_ml -> ml_doc); - const char *desc = doc ? strstr(doc, "swig_ptr: ") : 0; - if (desc) - desc = ty ? SWIG_UnpackVoidPtr(desc + 10, &vptr, ty->name) : 0; - if (!desc) - return SWIG_ERROR; - if (ty) { - swig_cast_info *tc = SWIG_TypeCheck(desc,ty); - if (tc) { - int newmemory = 0; - *ptr = SWIG_TypeCast(tc,vptr,&newmemory); - assert(!newmemory); /* newmemory handling not yet implemented */ - } else { - return SWIG_ERROR; - } - } else { - *ptr = vptr; - } - return SWIG_OK; - } -} - -/* Convert a packed value value */ - -SWIGRUNTIME int -SWIG_Python_ConvertPacked(PyObject *obj, void *ptr, size_t sz, swig_type_info *ty) { - swig_type_info *to = SwigPyPacked_UnpackData(obj, ptr, sz); - if (!to) return SWIG_ERROR; - if (ty) { - if (to != ty) { - /* check type cast? */ - swig_cast_info *tc = SWIG_TypeCheck(to->name,ty); - if (!tc) return SWIG_ERROR; - } - } - return SWIG_OK; -} - -/* ----------------------------------------------------------------------------- - * Create a new pointer object - * ----------------------------------------------------------------------------- */ - -/* - Create a new instance object, without calling __init__, and set the - 'this' attribute. -*/ - -SWIGRUNTIME PyObject* -SWIG_Python_NewShadowInstance(SwigPyClientData *data, PyObject *swig_this) -{ -#if (PY_VERSION_HEX >= 0x02020000) - PyObject *inst = 0; - PyObject *newraw = data->newraw; - if (newraw) { - inst = PyObject_Call(newraw, data->newargs, NULL); - if (inst) { -#if !defined(SWIG_PYTHON_SLOW_GETSET_THIS) - PyObject **dictptr = _PyObject_GetDictPtr(inst); - if (dictptr != NULL) { - PyObject *dict = *dictptr; - if (dict == NULL) { - dict = PyDict_New(); - *dictptr = dict; - PyDict_SetItem(dict, SWIG_This(), swig_this); - } - } -#else - PyObject *key = SWIG_This(); - PyObject_SetAttr(inst, key, swig_this); -#endif - } - } else { -#if PY_VERSION_HEX >= 0x03000000 - inst = ((PyTypeObject*) data->newargs)->tp_new((PyTypeObject*) data->newargs, Py_None, Py_None); - if (inst) { - PyObject_SetAttr(inst, SWIG_This(), swig_this); - Py_TYPE(inst)->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG; - } -#else - PyObject *dict = PyDict_New(); - if (dict) { - PyDict_SetItem(dict, SWIG_This(), swig_this); - inst = PyInstance_NewRaw(data->newargs, dict); - Py_DECREF(dict); - } -#endif - } - return inst; -#else -#if (PY_VERSION_HEX >= 0x02010000) - PyObject *inst = 0; - PyObject *dict = PyDict_New(); - if (dict) { - PyDict_SetItem(dict, SWIG_This(), swig_this); - inst = PyInstance_NewRaw(data->newargs, dict); - Py_DECREF(dict); - } - return (PyObject *) inst; -#else - PyInstanceObject *inst = PyObject_NEW(PyInstanceObject, &PyInstance_Type); - if (inst == NULL) { - return NULL; - } - inst->in_class = (PyClassObject *)data->newargs; - Py_INCREF(inst->in_class); - inst->in_dict = PyDict_New(); - if (inst->in_dict == NULL) { - Py_DECREF(inst); - return NULL; - } -#ifdef Py_TPFLAGS_HAVE_WEAKREFS - inst->in_weakreflist = NULL; -#endif -#ifdef Py_TPFLAGS_GC - PyObject_GC_Init(inst); -#endif - PyDict_SetItem(inst->in_dict, SWIG_This(), swig_this); - return (PyObject *) inst; -#endif -#endif -} - -SWIGRUNTIME void -SWIG_Python_SetSwigThis(PyObject *inst, PyObject *swig_this) -{ - PyObject *dict; -#if (PY_VERSION_HEX >= 0x02020000) && !defined(SWIG_PYTHON_SLOW_GETSET_THIS) - PyObject **dictptr = _PyObject_GetDictPtr(inst); - if (dictptr != NULL) { - dict = *dictptr; - if (dict == NULL) { - dict = PyDict_New(); - *dictptr = dict; - } - PyDict_SetItem(dict, SWIG_This(), swig_this); - return; - } -#endif - dict = PyObject_GetAttrString(inst, (char*)"__dict__"); - PyDict_SetItem(dict, SWIG_This(), swig_this); - Py_DECREF(dict); -} - - -SWIGINTERN PyObject * -SWIG_Python_InitShadowInstance(PyObject *args) { - PyObject *obj[2]; - if (!SWIG_Python_UnpackTuple(args, "swiginit", 2, 2, obj)) { - return NULL; - } else { - SwigPyObject *sthis = SWIG_Python_GetSwigThis(obj[0]); - if (sthis) { - SwigPyObject_append((PyObject*) sthis, obj[1]); - } else { - SWIG_Python_SetSwigThis(obj[0], obj[1]); - } - return SWIG_Py_Void(); - } -} - -/* Create a new pointer object */ - -SWIGRUNTIME PyObject * -SWIG_Python_NewPointerObj(PyObject *self, void *ptr, swig_type_info *type, int flags) { - SwigPyClientData *clientdata; - PyObject * robj; - int own; - - if (!ptr) - return SWIG_Py_Void(); - - clientdata = type ? (SwigPyClientData *)(type->clientdata) : 0; - own = (flags & SWIG_POINTER_OWN) ? SWIG_POINTER_OWN : 0; - if (clientdata && clientdata->pytype) { - SwigPyObject *newobj; - if (flags & SWIG_BUILTIN_TP_INIT) { - newobj = (SwigPyObject*) self; - if (newobj->ptr) { - PyObject *next_self = clientdata->pytype->tp_alloc(clientdata->pytype, 0); - while (newobj->next) - newobj = (SwigPyObject *) newobj->next; - newobj->next = next_self; - newobj = (SwigPyObject *)next_self; -#ifdef SWIGPYTHON_BUILTIN - newobj->dict = 0; -#endif - } - } else { - newobj = PyObject_New(SwigPyObject, clientdata->pytype); -#ifdef SWIGPYTHON_BUILTIN - newobj->dict = 0; -#endif - } - if (newobj) { - newobj->ptr = ptr; - newobj->ty = type; - newobj->own = own; - newobj->next = 0; - return (PyObject*) newobj; - } - return SWIG_Py_Void(); - } - - assert(!(flags & SWIG_BUILTIN_TP_INIT)); - - robj = SwigPyObject_New(ptr, type, own); - if (robj && clientdata && !(flags & SWIG_POINTER_NOSHADOW)) { - PyObject *inst = SWIG_Python_NewShadowInstance(clientdata, robj); - Py_DECREF(robj); - robj = inst; - } - return robj; -} - -/* Create a new packed object */ - -SWIGRUNTIMEINLINE PyObject * -SWIG_Python_NewPackedObj(void *ptr, size_t sz, swig_type_info *type) { - return ptr ? SwigPyPacked_New((void *) ptr, sz, type) : SWIG_Py_Void(); -} - -/* -----------------------------------------------------------------------------* - * Get type list - * -----------------------------------------------------------------------------*/ - -#ifdef SWIG_LINK_RUNTIME -void *SWIG_ReturnGlobalTypeList(void *); -#endif - -SWIGRUNTIME swig_module_info * -SWIG_Python_GetModule(void *SWIGUNUSEDPARM(clientdata)) { - static void *type_pointer = (void *)0; - /* first check if module already created */ - if (!type_pointer) { -#ifdef SWIG_LINK_RUNTIME - type_pointer = SWIG_ReturnGlobalTypeList((void *)0); -#else -# ifdef SWIGPY_USE_CAPSULE - type_pointer = PyCapsule_Import(SWIGPY_CAPSULE_NAME, 0); -# else - type_pointer = PyCObject_Import((char*)"swig_runtime_data" SWIG_RUNTIME_VERSION, - (char*)"type_pointer" SWIG_TYPE_TABLE_NAME); -# endif - if (PyErr_Occurred()) { - PyErr_Clear(); - type_pointer = (void *)0; - } -#endif - } - return (swig_module_info *) type_pointer; -} - -#if PY_MAJOR_VERSION < 2 -/* PyModule_AddObject function was introduced in Python 2.0. The following function - is copied out of Python/modsupport.c in python version 2.3.4 */ -SWIGINTERN int -PyModule_AddObject(PyObject *m, char *name, PyObject *o) -{ - PyObject *dict; - if (!PyModule_Check(m)) { - PyErr_SetString(PyExc_TypeError, "PyModule_AddObject() needs module as first arg"); - return SWIG_ERROR; - } - if (!o) { - PyErr_SetString(PyExc_TypeError, "PyModule_AddObject() needs non-NULL value"); - return SWIG_ERROR; - } - - dict = PyModule_GetDict(m); - if (dict == NULL) { - /* Internal error -- modules must have a dict! */ - PyErr_Format(PyExc_SystemError, "module '%s' has no __dict__", - PyModule_GetName(m)); - return SWIG_ERROR; - } - if (PyDict_SetItemString(dict, name, o)) - return SWIG_ERROR; - Py_DECREF(o); - return SWIG_OK; -} -#endif - -SWIGRUNTIME void -#ifdef SWIGPY_USE_CAPSULE -SWIG_Python_DestroyModule(PyObject *obj) -#else -SWIG_Python_DestroyModule(void *vptr) -#endif -{ -#ifdef SWIGPY_USE_CAPSULE - swig_module_info *swig_module = (swig_module_info *) PyCapsule_GetPointer(obj, SWIGPY_CAPSULE_NAME); -#else - swig_module_info *swig_module = (swig_module_info *) vptr; -#endif - swig_type_info **types = swig_module->types; - size_t i; - for (i =0; i < swig_module->size; ++i) { - swig_type_info *ty = types[i]; - if (ty->owndata) { - SwigPyClientData *data = (SwigPyClientData *) ty->clientdata; - if (data) SwigPyClientData_Del(data); - } - } - Py_DECREF(SWIG_This()); - swig_this = NULL; -} - -SWIGRUNTIME void -SWIG_Python_SetModule(swig_module_info *swig_module) { -#if PY_VERSION_HEX >= 0x03000000 - /* Add a placeholder module object into sys.modules */ - PyObject *module = PyImport_AddModule((char*)"swig_runtime_data" SWIG_RUNTIME_VERSION); -#else - static PyMethodDef swig_empty_runtime_method_table[] = { {NULL, NULL, 0, NULL} }; /* Sentinel */ - PyObject *module = Py_InitModule((char*)"swig_runtime_data" SWIG_RUNTIME_VERSION, swig_empty_runtime_method_table); -#endif -#ifdef SWIGPY_USE_CAPSULE - PyObject *pointer = PyCapsule_New((void *) swig_module, SWIGPY_CAPSULE_NAME, SWIG_Python_DestroyModule); - if (pointer && module) { - PyModule_AddObject(module, (char*)"type_pointer_capsule" SWIG_TYPE_TABLE_NAME, pointer); - } else { - Py_XDECREF(pointer); - } -#else - PyObject *pointer = PyCObject_FromVoidPtr((void *) swig_module, SWIG_Python_DestroyModule); - if (pointer && module) { - PyModule_AddObject(module, (char*)"type_pointer" SWIG_TYPE_TABLE_NAME, pointer); - } else { - Py_XDECREF(pointer); - } -#endif -} - -/* The python cached type query */ -SWIGRUNTIME PyObject * -SWIG_Python_TypeCache(void) { - static PyObject *SWIG_STATIC_POINTER(cache) = PyDict_New(); - return cache; -} - -SWIGRUNTIME swig_type_info * -SWIG_Python_TypeQuery(const char *type) -{ - PyObject *cache = SWIG_Python_TypeCache(); - PyObject *key = SWIG_Python_str_FromChar(type); - PyObject *obj = PyDict_GetItem(cache, key); - swig_type_info *descriptor; - if (obj) { -#ifdef SWIGPY_USE_CAPSULE - descriptor = (swig_type_info *) PyCapsule_GetPointer(obj, NULL); -#else - descriptor = (swig_type_info *) PyCObject_AsVoidPtr(obj); -#endif - } else { - swig_module_info *swig_module = SWIG_GetModule(0); - descriptor = SWIG_TypeQueryModule(swig_module, swig_module, type); - if (descriptor) { -#ifdef SWIGPY_USE_CAPSULE - obj = PyCapsule_New((void*) descriptor, NULL, NULL); -#else - obj = PyCObject_FromVoidPtr(descriptor, NULL); -#endif - PyDict_SetItem(cache, key, obj); - Py_DECREF(obj); - } - } - Py_DECREF(key); - return descriptor; -} - -/* - For backward compatibility only -*/ -#define SWIG_POINTER_EXCEPTION 0 -#define SWIG_arg_fail(arg) SWIG_Python_ArgFail(arg) -#define SWIG_MustGetPtr(p, type, argnum, flags) SWIG_Python_MustGetPtr(p, type, argnum, flags) - -SWIGRUNTIME int -SWIG_Python_AddErrMesg(const char* mesg, int infront) -{ - if (PyErr_Occurred()) { - PyObject *type = 0; - PyObject *value = 0; - PyObject *traceback = 0; - PyErr_Fetch(&type, &value, &traceback); - if (value) { - char *tmp; - PyObject *old_str = PyObject_Str(value); - Py_XINCREF(type); - PyErr_Clear(); - if (infront) { - PyErr_Format(type, "%s %s", mesg, tmp = SWIG_Python_str_AsChar(old_str)); - } else { - PyErr_Format(type, "%s %s", tmp = SWIG_Python_str_AsChar(old_str), mesg); - } - SWIG_Python_str_DelForPy3(tmp); - Py_DECREF(old_str); - } - return 1; - } else { - return 0; - } -} - -SWIGRUNTIME int -SWIG_Python_ArgFail(int argnum) -{ - if (PyErr_Occurred()) { - /* add information about failing argument */ - char mesg[256]; - PyOS_snprintf(mesg, sizeof(mesg), "argument number %d:", argnum); - return SWIG_Python_AddErrMesg(mesg, 1); - } else { - return 0; - } -} - -SWIGRUNTIMEINLINE const char * -SwigPyObject_GetDesc(PyObject *self) -{ - SwigPyObject *v = (SwigPyObject *)self; - swig_type_info *ty = v ? v->ty : 0; - return ty ? ty->str : ""; -} - -SWIGRUNTIME void -SWIG_Python_TypeError(const char *type, PyObject *obj) -{ - if (type) { -#if defined(SWIG_COBJECT_TYPES) - if (obj && SwigPyObject_Check(obj)) { - const char *otype = (const char *) SwigPyObject_GetDesc(obj); - if (otype) { - PyErr_Format(PyExc_TypeError, "a '%s' is expected, 'SwigPyObject(%s)' is received", - type, otype); - return; - } - } else -#endif - { - const char *otype = (obj ? obj->ob_type->tp_name : 0); - if (otype) { - PyObject *str = PyObject_Str(obj); - const char *cstr = str ? SWIG_Python_str_AsChar(str) : 0; - if (cstr) { - PyErr_Format(PyExc_TypeError, "a '%s' is expected, '%s(%s)' is received", - type, otype, cstr); - SWIG_Python_str_DelForPy3(cstr); - } else { - PyErr_Format(PyExc_TypeError, "a '%s' is expected, '%s' is received", - type, otype); - } - Py_XDECREF(str); - return; - } - } - PyErr_Format(PyExc_TypeError, "a '%s' is expected", type); - } else { - PyErr_Format(PyExc_TypeError, "unexpected type is received"); - } -} - - -/* Convert a pointer value, signal an exception on a type mismatch */ -SWIGRUNTIME void * -SWIG_Python_MustGetPtr(PyObject *obj, swig_type_info *ty, int SWIGUNUSEDPARM(argnum), int flags) { - void *result; - if (SWIG_Python_ConvertPtr(obj, &result, ty, flags) == -1) { - PyErr_Clear(); -#if SWIG_POINTER_EXCEPTION - if (flags) { - SWIG_Python_TypeError(SWIG_TypePrettyName(ty), obj); - SWIG_Python_ArgFail(argnum); - } -#endif - } - return result; -} - -#ifdef SWIGPYTHON_BUILTIN -SWIGRUNTIME int -SWIG_Python_NonDynamicSetAttr(PyObject *obj, PyObject *name, PyObject *value) { - PyTypeObject *tp = obj->ob_type; - PyObject *descr; - PyObject *encoded_name; - descrsetfunc f; - int res = -1; - -# ifdef Py_USING_UNICODE - if (PyString_Check(name)) { - name = PyUnicode_Decode(PyString_AsString(name), PyString_Size(name), NULL, NULL); - if (!name) - return -1; - } else if (!PyUnicode_Check(name)) -# else - if (!PyString_Check(name)) -# endif - { - PyErr_Format(PyExc_TypeError, "attribute name must be string, not '%.200s'", name->ob_type->tp_name); - return -1; - } else { - Py_INCREF(name); - } - - if (!tp->tp_dict) { - if (PyType_Ready(tp) < 0) - goto done; - } - - descr = _PyType_Lookup(tp, name); - f = NULL; - if (descr != NULL) - f = descr->ob_type->tp_descr_set; - if (!f) { - if (PyString_Check(name)) { - encoded_name = name; - Py_INCREF(name); - } else { - encoded_name = PyUnicode_AsUTF8String(name); - } - PyErr_Format(PyExc_AttributeError, "'%.100s' object has no attribute '%.200s'", tp->tp_name, PyString_AsString(encoded_name)); - Py_DECREF(encoded_name); - } else { - res = f(descr, obj, value); - } - - done: - Py_DECREF(name); - return res; -} -#endif - - -#ifdef __cplusplus -} -#endif - - - -#define SWIG_exception_fail(code, msg) do { SWIG_Error(code, msg); SWIG_fail; } while(0) - -#define SWIG_contract_assert(expr, msg) if (!(expr)) { SWIG_Error(SWIG_RuntimeError, msg); SWIG_fail; } else - - - - #define SWIG_exception(code, msg) do { SWIG_Error(code, msg); SWIG_fail;; } while(0) - - -/* -------- TYPES TABLE (BEGIN) -------- */ - -#define SWIGTYPE_p_char swig_types[0] -#define SWIGTYPE_p_int swig_types[1] -#define SWIGTYPE_p_uint8_t swig_types[2] -static swig_type_info *swig_types[4]; -static swig_module_info swig_module = {swig_types, 3, 0, 0, 0, 0}; -#define SWIG_TypeQuery(name) SWIG_TypeQueryModule(&swig_module, &swig_module, name) -#define SWIG_MangledTypeQuery(name) SWIG_MangledTypeQueryModule(&swig_module, &swig_module, name) - -/* -------- TYPES TABLE (END) -------- */ - -#if (PY_VERSION_HEX <= 0x02000000) -# if !defined(SWIG_PYTHON_CLASSIC) -# error "This python version requires swig to be run with the '-classic' option" -# endif -#endif - -/*----------------------------------------------- - @(target):= _libwebp.so - ------------------------------------------------*/ -#if PY_VERSION_HEX >= 0x03000000 -# define SWIG_init PyInit__libwebp - -#else -# define SWIG_init init_libwebp - -#endif -#define SWIG_name "_libwebp" - -#define SWIGVERSION 0x030012 -#define SWIG_VERSION SWIGVERSION - - -#define SWIG_as_voidptr(a) (void *)((const void *)(a)) -#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) - - -SWIGINTERNINLINE PyObject* - SWIG_From_int (int value) -{ - return PyInt_FromLong((long) value); -} - - -SWIGINTERN swig_type_info* -SWIG_pchar_descriptor(void) -{ - static int init = 0; - static swig_type_info* info = 0; - if (!init) { - info = SWIG_TypeQuery("_p_char"); - init = 1; - } - return info; -} - - -SWIGINTERN int -SWIG_AsCharPtrAndSize(PyObject *obj, char** cptr, size_t* psize, int *alloc) -{ -#if PY_VERSION_HEX>=0x03000000 -#if defined(SWIG_PYTHON_STRICT_BYTE_CHAR) - if (PyBytes_Check(obj)) -#else - if (PyUnicode_Check(obj)) -#endif -#else - if (PyString_Check(obj)) -#endif - { - char *cstr; Py_ssize_t len; -#if PY_VERSION_HEX>=0x03000000 -#if !defined(SWIG_PYTHON_STRICT_BYTE_CHAR) - if (!alloc && cptr) { - /* We can't allow converting without allocation, since the internal - representation of string in Python 3 is UCS-2/UCS-4 but we require - a UTF-8 representation. - TODO(bhy) More detailed explanation */ - return SWIG_RuntimeError; - } - obj = PyUnicode_AsUTF8String(obj); - if(alloc) *alloc = SWIG_NEWOBJ; -#endif - PyBytes_AsStringAndSize(obj, &cstr, &len); -#else - PyString_AsStringAndSize(obj, &cstr, &len); -#endif - if (cptr) { - if (alloc) { - /* - In python the user should not be able to modify the inner - string representation. To warranty that, if you define - SWIG_PYTHON_SAFE_CSTRINGS, a new/copy of the python string - buffer is always returned. - - The default behavior is just to return the pointer value, - so, be careful. - */ -#if defined(SWIG_PYTHON_SAFE_CSTRINGS) - if (*alloc != SWIG_OLDOBJ) -#else - if (*alloc == SWIG_NEWOBJ) -#endif - { - *cptr = (char *)memcpy(malloc((len + 1)*sizeof(char)), cstr, sizeof(char)*(len + 1)); - *alloc = SWIG_NEWOBJ; - } else { - *cptr = cstr; - *alloc = SWIG_OLDOBJ; - } - } else { -#if PY_VERSION_HEX>=0x03000000 -#if defined(SWIG_PYTHON_STRICT_BYTE_CHAR) - *cptr = PyBytes_AsString(obj); -#else - assert(0); /* Should never reach here with Unicode strings in Python 3 */ -#endif -#else - *cptr = SWIG_Python_str_AsChar(obj); -#endif - } - } - if (psize) *psize = len + 1; -#if PY_VERSION_HEX>=0x03000000 && !defined(SWIG_PYTHON_STRICT_BYTE_CHAR) - Py_XDECREF(obj); -#endif - return SWIG_OK; - } else { -#if defined(SWIG_PYTHON_2_UNICODE) -#if defined(SWIG_PYTHON_STRICT_BYTE_CHAR) -#error "Cannot use both SWIG_PYTHON_2_UNICODE and SWIG_PYTHON_STRICT_BYTE_CHAR at once" -#endif -#if PY_VERSION_HEX<0x03000000 - if (PyUnicode_Check(obj)) { - char *cstr; Py_ssize_t len; - if (!alloc && cptr) { - return SWIG_RuntimeError; - } - obj = PyUnicode_AsUTF8String(obj); - if (PyString_AsStringAndSize(obj, &cstr, &len) != -1) { - if (cptr) { - if (alloc) *alloc = SWIG_NEWOBJ; - *cptr = (char *)memcpy(malloc((len + 1)*sizeof(char)), cstr, sizeof(char)*(len + 1)); - } - if (psize) *psize = len + 1; - - Py_XDECREF(obj); - return SWIG_OK; - } else { - Py_XDECREF(obj); - } - } -#endif -#endif - - swig_type_info* pchar_descriptor = SWIG_pchar_descriptor(); - if (pchar_descriptor) { - void* vptr = 0; - if (SWIG_ConvertPtr(obj, &vptr, pchar_descriptor, 0) == SWIG_OK) { - if (cptr) *cptr = (char *) vptr; - if (psize) *psize = vptr ? (strlen((char *)vptr) + 1) : 0; - if (alloc) *alloc = SWIG_OLDOBJ; - return SWIG_OK; - } - } - } - return SWIG_TypeError; -} - - -SWIGINTERN int -SWIG_AsVal_double (PyObject *obj, double *val) -{ - int res = SWIG_TypeError; - if (PyFloat_Check(obj)) { - if (val) *val = PyFloat_AsDouble(obj); - return SWIG_OK; -#if PY_VERSION_HEX < 0x03000000 - } else if (PyInt_Check(obj)) { - if (val) *val = (double) PyInt_AsLong(obj); - return SWIG_OK; -#endif - } else if (PyLong_Check(obj)) { - double v = PyLong_AsDouble(obj); - if (!PyErr_Occurred()) { - if (val) *val = v; - return SWIG_OK; - } else { - PyErr_Clear(); - } - } -#ifdef SWIG_PYTHON_CAST_MODE - { - int dispatch = 0; - double d = PyFloat_AsDouble(obj); - if (!PyErr_Occurred()) { - if (val) *val = d; - return SWIG_AddCast(SWIG_OK); - } else { - PyErr_Clear(); - } - if (!dispatch) { - long v = PyLong_AsLong(obj); - if (!PyErr_Occurred()) { - if (val) *val = v; - return SWIG_AddCast(SWIG_AddCast(SWIG_OK)); - } else { - PyErr_Clear(); - } - } - } -#endif - return res; -} - - -#include - - -#include - - -SWIGINTERNINLINE int -SWIG_CanCastAsInteger(double *d, double min, double max) { - double x = *d; - if ((min <= x && x <= max)) { - double fx = floor(x); - double cx = ceil(x); - double rd = ((x - fx) < 0.5) ? fx : cx; /* simple rint */ - if ((errno == EDOM) || (errno == ERANGE)) { - errno = 0; - } else { - double summ, reps, diff; - if (rd < x) { - diff = x - rd; - } else if (rd > x) { - diff = rd - x; - } else { - return 1; - } - summ = rd + x; - reps = diff/summ; - if (reps < 8*DBL_EPSILON) { - *d = rd; - return 1; - } - } - } - return 0; -} - - -SWIGINTERN int -SWIG_AsVal_unsigned_SS_long (PyObject *obj, unsigned long *val) -{ -#if PY_VERSION_HEX < 0x03000000 - if (PyInt_Check(obj)) { - long v = PyInt_AsLong(obj); - if (v >= 0) { - if (val) *val = v; - return SWIG_OK; - } else { - return SWIG_OverflowError; - } - } else -#endif - if (PyLong_Check(obj)) { - unsigned long v = PyLong_AsUnsignedLong(obj); - if (!PyErr_Occurred()) { - if (val) *val = v; - return SWIG_OK; - } else { - PyErr_Clear(); - return SWIG_OverflowError; - } - } -#ifdef SWIG_PYTHON_CAST_MODE - { - int dispatch = 0; - unsigned long v = PyLong_AsUnsignedLong(obj); - if (!PyErr_Occurred()) { - if (val) *val = v; - return SWIG_AddCast(SWIG_OK); - } else { - PyErr_Clear(); - } - if (!dispatch) { - double d; - int res = SWIG_AddCast(SWIG_AsVal_double (obj,&d)); - if (SWIG_IsOK(res) && SWIG_CanCastAsInteger(&d, 0, ULONG_MAX)) { - if (val) *val = (unsigned long)(d); - return res; - } - } - } -#endif - return SWIG_TypeError; -} - - -#include -#if !defined(SWIG_NO_LLONG_MAX) -# if !defined(LLONG_MAX) && defined(__GNUC__) && defined (__LONG_LONG_MAX__) -# define LLONG_MAX __LONG_LONG_MAX__ -# define LLONG_MIN (-LLONG_MAX - 1LL) -# define ULLONG_MAX (LLONG_MAX * 2ULL + 1ULL) -# endif -#endif - - -#if defined(LLONG_MAX) && !defined(SWIG_LONG_LONG_AVAILABLE) -# define SWIG_LONG_LONG_AVAILABLE -#endif - - -#ifdef SWIG_LONG_LONG_AVAILABLE -SWIGINTERN int -SWIG_AsVal_unsigned_SS_long_SS_long (PyObject *obj, unsigned long long *val) -{ - int res = SWIG_TypeError; - if (PyLong_Check(obj)) { - unsigned long long v = PyLong_AsUnsignedLongLong(obj); - if (!PyErr_Occurred()) { - if (val) *val = v; - return SWIG_OK; - } else { - PyErr_Clear(); - res = SWIG_OverflowError; - } - } else { - unsigned long v; - res = SWIG_AsVal_unsigned_SS_long (obj,&v); - if (SWIG_IsOK(res)) { - if (val) *val = v; - return res; - } - } -#ifdef SWIG_PYTHON_CAST_MODE - { - const double mant_max = 1LL << DBL_MANT_DIG; - double d; - res = SWIG_AsVal_double (obj,&d); - if (SWIG_IsOK(res) && !SWIG_CanCastAsInteger(&d, 0, mant_max)) - return SWIG_OverflowError; - if (SWIG_IsOK(res) && SWIG_CanCastAsInteger(&d, 0, mant_max)) { - if (val) *val = (unsigned long long)(d); - return SWIG_AddCast(res); - } - res = SWIG_TypeError; - } -#endif - return res; -} -#endif - - -SWIGINTERNINLINE int -SWIG_AsVal_size_t (PyObject * obj, size_t *val) -{ - int res = SWIG_TypeError; -#ifdef SWIG_LONG_LONG_AVAILABLE - if (sizeof(size_t) <= sizeof(unsigned long)) { -#endif - unsigned long v; - res = SWIG_AsVal_unsigned_SS_long (obj, val ? &v : 0); - if (SWIG_IsOK(res) && val) *val = (size_t)(v); -#ifdef SWIG_LONG_LONG_AVAILABLE - } else if (sizeof(size_t) <= sizeof(unsigned long long)) { - unsigned long long v; - res = SWIG_AsVal_unsigned_SS_long_SS_long (obj, val ? &v : 0); - if (SWIG_IsOK(res) && val) *val = (size_t)(v); - } -#endif - return res; -} - - -#include "webp/decode.h" -#include "webp/encode.h" - - -static size_t ReturnedBufferSize( - const char* function, int* width, int* height) { - static const struct sizemap { - const char* function; - int size_multiplier; - } size_map[] = { -#ifdef SWIGJAVA - { "Java_com_google_webp_libwebpJNI_WebPDecodeRGB", 3 }, - { "Java_com_google_webp_libwebpJNI_WebPDecodeRGBA", 4 }, - { "Java_com_google_webp_libwebpJNI_WebPDecodeARGB", 4 }, - { "Java_com_google_webp_libwebpJNI_WebPDecodeBGR", 3 }, - { "Java_com_google_webp_libwebpJNI_WebPDecodeBGRA", 4 }, - { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeRGB", 1 }, - { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeBGR", 1 }, - { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeRGBA", 1 }, - { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeBGRA", 1 }, - { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeLosslessRGB", 1 }, - { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeLosslessBGR", 1 }, - { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeLosslessRGBA", 1 }, - { "Java_com_google_webp_libwebpJNI_wrap_1WebPEncodeLosslessBGRA", 1 }, -#endif -#ifdef SWIGPYTHON - { "WebPDecodeRGB", 3 }, - { "WebPDecodeRGBA", 4 }, - { "WebPDecodeARGB", 4 }, - { "WebPDecodeBGR", 3 }, - { "WebPDecodeBGRA", 4 }, - { "wrap_WebPEncodeRGB", 1 }, - { "wrap_WebPEncodeBGR", 1 }, - { "wrap_WebPEncodeRGBA", 1 }, - { "wrap_WebPEncodeBGRA", 1 }, - { "wrap_WebPEncodeLosslessRGB", 1 }, - { "wrap_WebPEncodeLosslessBGR", 1 }, - { "wrap_WebPEncodeLosslessRGBA", 1 }, - { "wrap_WebPEncodeLosslessBGRA", 1 }, -#endif - { NULL, 0 } - }; - const struct sizemap* p; - size_t size = 0; - - for (p = size_map; p->function; ++p) { - if (!strcmp(function, p->function)) { - size = *width * *height * p->size_multiplier; - break; - } - } - - return size; -} - - -typedef size_t (*WebPEncodeFunction)(const uint8_t* rgb, - int width, int height, int stride, - float quality_factor, uint8_t** output); -typedef size_t (*WebPEncodeLosslessFunction)(const uint8_t* rgb, - int width, int height, int stride, - uint8_t** output); - -static uint8_t* EncodeLossy(const uint8_t* rgb, - int width, int height, int stride, - float quality_factor, - WebPEncodeFunction encfn, - int* output_size, int* unused) { - uint8_t* output = NULL; - const size_t image_size = - encfn(rgb, width, height, stride, quality_factor, &output); - // the values of following two will be interpreted by ReturnedBufferSize() - // as 'width' and 'height' in the size calculation. - *output_size = image_size; - *unused = 1; - return image_size ? output : NULL; -} - -static uint8_t* EncodeLossless(const uint8_t* rgb, - int width, int height, int stride, - WebPEncodeLosslessFunction encfn, - int* output_size, int* unused) { - uint8_t* output = NULL; - const size_t image_size = encfn(rgb, width, height, stride, &output); - // the values of the following two will be interpreted by - // ReturnedBufferSize() as 'width' and 'height' in the size calculation. - *output_size = image_size; - *unused = 1; - return image_size ? output : NULL; -} - - -// Changes the return type of WebPEncode* to more closely match Decode*. -// This also makes it easier to wrap the output buffer in a native type rather -// than dealing with the return pointer. -// The additional parameters are to allow reuse of ReturnedBufferSize(), -// unused2 and output_size will be used in this case. -#define LOSSY_WRAPPER(FUNC) \ - static uint8_t* wrap_##FUNC( \ - const uint8_t* rgb, int* unused1, int* unused2, int* output_size, \ - int width, int height, int stride, float quality_factor) { \ - return EncodeLossy(rgb, width, height, stride, quality_factor, \ - FUNC, output_size, unused2); \ - } \ - -LOSSY_WRAPPER(WebPEncodeRGB) -LOSSY_WRAPPER(WebPEncodeBGR) -LOSSY_WRAPPER(WebPEncodeRGBA) -LOSSY_WRAPPER(WebPEncodeBGRA) - -#undef LOSSY_WRAPPER - -#define LOSSLESS_WRAPPER(FUNC) \ - static uint8_t* wrap_##FUNC( \ - const uint8_t* rgb, int* unused1, int* unused2, int* output_size, \ - int width, int height, int stride) { \ - return EncodeLossless(rgb, width, height, stride, \ - FUNC, output_size, unused2); \ - } \ - -LOSSLESS_WRAPPER(WebPEncodeLosslessRGB) -LOSSLESS_WRAPPER(WebPEncodeLosslessBGR) -LOSSLESS_WRAPPER(WebPEncodeLosslessRGBA) -LOSSLESS_WRAPPER(WebPEncodeLosslessBGRA) - -#undef LOSSLESS_WRAPPER - - - -SWIGINTERN int -SWIG_AsVal_long (PyObject *obj, long* val) -{ -#if PY_VERSION_HEX < 0x03000000 - if (PyInt_Check(obj)) { - if (val) *val = PyInt_AsLong(obj); - return SWIG_OK; - } else -#endif - if (PyLong_Check(obj)) { - long v = PyLong_AsLong(obj); - if (!PyErr_Occurred()) { - if (val) *val = v; - return SWIG_OK; - } else { - PyErr_Clear(); - return SWIG_OverflowError; - } - } -#ifdef SWIG_PYTHON_CAST_MODE - { - int dispatch = 0; - long v = PyInt_AsLong(obj); - if (!PyErr_Occurred()) { - if (val) *val = v; - return SWIG_AddCast(SWIG_OK); - } else { - PyErr_Clear(); - } - if (!dispatch) { - double d; - int res = SWIG_AddCast(SWIG_AsVal_double (obj,&d)); - if (SWIG_IsOK(res) && SWIG_CanCastAsInteger(&d, LONG_MIN, LONG_MAX)) { - if (val) *val = (long)(d); - return res; - } - } - } -#endif - return SWIG_TypeError; -} - - -SWIGINTERN int -SWIG_AsVal_int (PyObject * obj, int *val) -{ - long v; - int res = SWIG_AsVal_long (obj, &v); - if (SWIG_IsOK(res)) { - if ((v < INT_MIN || v > INT_MAX)) { - return SWIG_OverflowError; - } else { - if (val) *val = (int)(v); - } - } - return res; -} - - -/* Getting isfinite working pre C99 across multiple platforms is non-trivial. Users can provide SWIG_isfinite on older platforms. */ -#ifndef SWIG_isfinite -/* isfinite() is a macro for C99 */ -# if defined(isfinite) -# define SWIG_isfinite(X) (isfinite(X)) -# elif defined __cplusplus && __cplusplus >= 201103L -/* Use a template so that this works whether isfinite() is std::isfinite() or - * in the global namespace. The reality seems to vary between compiler - * versions. - * - * Make sure namespace std exists to avoid compiler warnings. - * - * extern "C++" is required as this fragment can end up inside an extern "C" { } block - */ -namespace std { } -extern "C++" template -inline int SWIG_isfinite_func(T x) { - using namespace std; - return isfinite(x); -} -# define SWIG_isfinite(X) (SWIG_isfinite_func(X)) -# elif defined(_MSC_VER) -# define SWIG_isfinite(X) (_finite(X)) -# elif defined(__sun) && defined(__SVR4) -# include -# define SWIG_isfinite(X) (finite(X)) -# endif -#endif - - -/* Accept infinite as a valid float value unless we are unable to check if a value is finite */ -#ifdef SWIG_isfinite -# define SWIG_Float_Overflow_Check(X) ((X < -FLT_MAX || X > FLT_MAX) && SWIG_isfinite(X)) -#else -# define SWIG_Float_Overflow_Check(X) ((X < -FLT_MAX || X > FLT_MAX)) -#endif - - -SWIGINTERN int -SWIG_AsVal_float (PyObject * obj, float *val) -{ - double v; - int res = SWIG_AsVal_double (obj, &v); - if (SWIG_IsOK(res)) { - if (SWIG_Float_Overflow_Check(v)) { - return SWIG_OverflowError; - } else { - if (val) *val = (float)(v); - } - } - return res; -} - -#ifdef __cplusplus -extern "C" { -#endif -SWIGINTERN PyObject *_wrap_WebPGetDecoderVersion(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - PyObject *resultobj = 0; - int result; - - if (!PyArg_ParseTuple(args,(char *)":WebPGetDecoderVersion")) SWIG_fail; - result = (int)WebPGetDecoderVersion(); - resultobj = SWIG_From_int((int)(result)); - return resultobj; -fail: - return NULL; -} - - -SWIGINTERN PyObject *_wrap_WebPGetInfo(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - PyObject *resultobj = 0; - uint8_t *arg1 = (uint8_t *) 0 ; - size_t arg2 ; - int *arg3 = (int *) 0 ; - int *arg4 = (int *) 0 ; - int res1 ; - char *buf1 = 0 ; - size_t size1 = 0 ; - int alloc1 = 0 ; - int temp3 ; - int res3 = SWIG_TMPOBJ ; - int temp4 ; - int res4 = SWIG_TMPOBJ ; - PyObject * obj0 = 0 ; - int result; - - arg3 = &temp3; - arg4 = &temp4; - if (!PyArg_ParseTuple(args,(char *)"O:WebPGetInfo",&obj0)) SWIG_fail; - res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, &size1, &alloc1); - if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "WebPGetInfo" "', argument " "1"" of type '" "uint8_t const *""'"); - } - arg1 = (uint8_t *)(buf1); - arg2 = (size_t)(size1 - 1); - result = (int)WebPGetInfo((uint8_t const *)arg1,arg2,arg3,arg4); - resultobj = SWIG_From_int((int)(result)); - if (SWIG_IsTmpObj(res3)) { - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg3))); - } else { - int new_flags = SWIG_IsNewObj(res3) ? (SWIG_POINTER_OWN | 0 ) : 0 ; - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg3), SWIGTYPE_p_int, new_flags)); - } - if (SWIG_IsTmpObj(res4)) { - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg4))); - } else { - int new_flags = SWIG_IsNewObj(res4) ? (SWIG_POINTER_OWN | 0 ) : 0 ; - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg4), SWIGTYPE_p_int, new_flags)); - } - if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); - return resultobj; -fail: - if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); - return NULL; -} - - -SWIGINTERN PyObject *_wrap_WebPDecodeRGB(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - PyObject *resultobj = 0; - uint8_t *arg1 = (uint8_t *) 0 ; - size_t arg2 ; - int *arg3 = (int *) 0 ; - int *arg4 = (int *) 0 ; - int res1 ; - char *buf1 = 0 ; - size_t size1 = 0 ; - int alloc1 = 0 ; - int temp3 ; - int res3 = SWIG_TMPOBJ ; - int temp4 ; - int res4 = SWIG_TMPOBJ ; - PyObject * obj0 = 0 ; - uint8_t *result = 0 ; - - arg3 = &temp3; - arg4 = &temp4; - if (!PyArg_ParseTuple(args,(char *)"O:WebPDecodeRGB",&obj0)) SWIG_fail; - res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, &size1, &alloc1); - if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "WebPDecodeRGB" "', argument " "1"" of type '" "uint8_t const *""'"); - } - arg1 = (uint8_t *)(buf1); - arg2 = (size_t)(size1 - 1); - result = (uint8_t *)WebPDecodeRGB((uint8_t const *)arg1,arg2,arg3,arg4); - { - resultobj = PyString_FromStringAndSize( - (const char*)result, - (result == NULL) ? 0 : ReturnedBufferSize("WebPDecodeRGB", arg3, arg4)); - } - if (SWIG_IsTmpObj(res3)) { - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg3))); - } else { - int new_flags = SWIG_IsNewObj(res3) ? (SWIG_POINTER_OWN | 0 ) : 0 ; - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg3), SWIGTYPE_p_int, new_flags)); - } - if (SWIG_IsTmpObj(res4)) { - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg4))); - } else { - int new_flags = SWIG_IsNewObj(res4) ? (SWIG_POINTER_OWN | 0 ) : 0 ; - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg4), SWIGTYPE_p_int, new_flags)); - } - if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); - free(result); - return resultobj; -fail: - if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); - return NULL; -} - - -SWIGINTERN PyObject *_wrap_WebPDecodeRGBA(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - PyObject *resultobj = 0; - uint8_t *arg1 = (uint8_t *) 0 ; - size_t arg2 ; - int *arg3 = (int *) 0 ; - int *arg4 = (int *) 0 ; - int res1 ; - char *buf1 = 0 ; - size_t size1 = 0 ; - int alloc1 = 0 ; - int temp3 ; - int res3 = SWIG_TMPOBJ ; - int temp4 ; - int res4 = SWIG_TMPOBJ ; - PyObject * obj0 = 0 ; - uint8_t *result = 0 ; - - arg3 = &temp3; - arg4 = &temp4; - if (!PyArg_ParseTuple(args,(char *)"O:WebPDecodeRGBA",&obj0)) SWIG_fail; - res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, &size1, &alloc1); - if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "WebPDecodeRGBA" "', argument " "1"" of type '" "uint8_t const *""'"); - } - arg1 = (uint8_t *)(buf1); - arg2 = (size_t)(size1 - 1); - result = (uint8_t *)WebPDecodeRGBA((uint8_t const *)arg1,arg2,arg3,arg4); - { - resultobj = PyString_FromStringAndSize( - (const char*)result, - (result == NULL) ? 0 : ReturnedBufferSize("WebPDecodeRGBA", arg3, arg4)); - } - if (SWIG_IsTmpObj(res3)) { - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg3))); - } else { - int new_flags = SWIG_IsNewObj(res3) ? (SWIG_POINTER_OWN | 0 ) : 0 ; - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg3), SWIGTYPE_p_int, new_flags)); - } - if (SWIG_IsTmpObj(res4)) { - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg4))); - } else { - int new_flags = SWIG_IsNewObj(res4) ? (SWIG_POINTER_OWN | 0 ) : 0 ; - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg4), SWIGTYPE_p_int, new_flags)); - } - if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); - free(result); - return resultobj; -fail: - if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); - return NULL; -} - - -SWIGINTERN PyObject *_wrap_WebPDecodeARGB(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - PyObject *resultobj = 0; - uint8_t *arg1 = (uint8_t *) 0 ; - size_t arg2 ; - int *arg3 = (int *) 0 ; - int *arg4 = (int *) 0 ; - int res1 ; - char *buf1 = 0 ; - size_t size1 = 0 ; - int alloc1 = 0 ; - int temp3 ; - int res3 = SWIG_TMPOBJ ; - int temp4 ; - int res4 = SWIG_TMPOBJ ; - PyObject * obj0 = 0 ; - uint8_t *result = 0 ; - - arg3 = &temp3; - arg4 = &temp4; - if (!PyArg_ParseTuple(args,(char *)"O:WebPDecodeARGB",&obj0)) SWIG_fail; - res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, &size1, &alloc1); - if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "WebPDecodeARGB" "', argument " "1"" of type '" "uint8_t const *""'"); - } - arg1 = (uint8_t *)(buf1); - arg2 = (size_t)(size1 - 1); - result = (uint8_t *)WebPDecodeARGB((uint8_t const *)arg1,arg2,arg3,arg4); - { - resultobj = PyString_FromStringAndSize( - (const char*)result, - (result == NULL) ? 0 : ReturnedBufferSize("WebPDecodeARGB", arg3, arg4)); - } - if (SWIG_IsTmpObj(res3)) { - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg3))); - } else { - int new_flags = SWIG_IsNewObj(res3) ? (SWIG_POINTER_OWN | 0 ) : 0 ; - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg3), SWIGTYPE_p_int, new_flags)); - } - if (SWIG_IsTmpObj(res4)) { - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg4))); - } else { - int new_flags = SWIG_IsNewObj(res4) ? (SWIG_POINTER_OWN | 0 ) : 0 ; - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg4), SWIGTYPE_p_int, new_flags)); - } - if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); - free(result); - return resultobj; -fail: - if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); - return NULL; -} - - -SWIGINTERN PyObject *_wrap_WebPDecodeBGR(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - PyObject *resultobj = 0; - uint8_t *arg1 = (uint8_t *) 0 ; - size_t arg2 ; - int *arg3 = (int *) 0 ; - int *arg4 = (int *) 0 ; - int res1 ; - char *buf1 = 0 ; - size_t size1 = 0 ; - int alloc1 = 0 ; - int temp3 ; - int res3 = SWIG_TMPOBJ ; - int temp4 ; - int res4 = SWIG_TMPOBJ ; - PyObject * obj0 = 0 ; - uint8_t *result = 0 ; - - arg3 = &temp3; - arg4 = &temp4; - if (!PyArg_ParseTuple(args,(char *)"O:WebPDecodeBGR",&obj0)) SWIG_fail; - res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, &size1, &alloc1); - if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "WebPDecodeBGR" "', argument " "1"" of type '" "uint8_t const *""'"); - } - arg1 = (uint8_t *)(buf1); - arg2 = (size_t)(size1 - 1); - result = (uint8_t *)WebPDecodeBGR((uint8_t const *)arg1,arg2,arg3,arg4); - { - resultobj = PyString_FromStringAndSize( - (const char*)result, - (result == NULL) ? 0 : ReturnedBufferSize("WebPDecodeBGR", arg3, arg4)); - } - if (SWIG_IsTmpObj(res3)) { - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg3))); - } else { - int new_flags = SWIG_IsNewObj(res3) ? (SWIG_POINTER_OWN | 0 ) : 0 ; - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg3), SWIGTYPE_p_int, new_flags)); - } - if (SWIG_IsTmpObj(res4)) { - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg4))); - } else { - int new_flags = SWIG_IsNewObj(res4) ? (SWIG_POINTER_OWN | 0 ) : 0 ; - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg4), SWIGTYPE_p_int, new_flags)); - } - if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); - free(result); - return resultobj; -fail: - if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); - return NULL; -} - - -SWIGINTERN PyObject *_wrap_WebPDecodeBGRA(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - PyObject *resultobj = 0; - uint8_t *arg1 = (uint8_t *) 0 ; - size_t arg2 ; - int *arg3 = (int *) 0 ; - int *arg4 = (int *) 0 ; - int res1 ; - char *buf1 = 0 ; - size_t size1 = 0 ; - int alloc1 = 0 ; - int temp3 ; - int res3 = SWIG_TMPOBJ ; - int temp4 ; - int res4 = SWIG_TMPOBJ ; - PyObject * obj0 = 0 ; - uint8_t *result = 0 ; - - arg3 = &temp3; - arg4 = &temp4; - if (!PyArg_ParseTuple(args,(char *)"O:WebPDecodeBGRA",&obj0)) SWIG_fail; - res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, &size1, &alloc1); - if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "WebPDecodeBGRA" "', argument " "1"" of type '" "uint8_t const *""'"); - } - arg1 = (uint8_t *)(buf1); - arg2 = (size_t)(size1 - 1); - result = (uint8_t *)WebPDecodeBGRA((uint8_t const *)arg1,arg2,arg3,arg4); - { - resultobj = PyString_FromStringAndSize( - (const char*)result, - (result == NULL) ? 0 : ReturnedBufferSize("WebPDecodeBGRA", arg3, arg4)); - } - if (SWIG_IsTmpObj(res3)) { - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg3))); - } else { - int new_flags = SWIG_IsNewObj(res3) ? (SWIG_POINTER_OWN | 0 ) : 0 ; - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg3), SWIGTYPE_p_int, new_flags)); - } - if (SWIG_IsTmpObj(res4)) { - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg4))); - } else { - int new_flags = SWIG_IsNewObj(res4) ? (SWIG_POINTER_OWN | 0 ) : 0 ; - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg4), SWIGTYPE_p_int, new_flags)); - } - if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); - free(result); - return resultobj; -fail: - if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); - return NULL; -} - - -SWIGINTERN PyObject *_wrap_WebPGetEncoderVersion(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - PyObject *resultobj = 0; - int result; - - if (!PyArg_ParseTuple(args,(char *)":WebPGetEncoderVersion")) SWIG_fail; - result = (int)WebPGetEncoderVersion(); - resultobj = SWIG_From_int((int)(result)); - return resultobj; -fail: - return NULL; -} - - -SWIGINTERN PyObject *_wrap_wrap_WebPEncodeRGB(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - PyObject *resultobj = 0; - uint8_t *arg1 = (uint8_t *) 0 ; - int *arg2 = (int *) 0 ; - int *arg3 = (int *) 0 ; - int *arg4 = (int *) 0 ; - int arg5 ; - int arg6 ; - int arg7 ; - float arg8 ; - Py_buffer rgb_buffer1 ; - int temp2 ; - int res2 = 0 ; - int temp3 ; - int res3 = 0 ; - int temp4 ; - int res4 = SWIG_TMPOBJ ; - int val5 ; - int ecode5 = 0 ; - int val6 ; - int ecode6 = 0 ; - int val7 ; - int ecode7 = 0 ; - float val8 ; - int ecode8 = 0 ; - PyObject * obj0 = 0 ; - PyObject * obj1 = 0 ; - PyObject * obj2 = 0 ; - PyObject * obj3 = 0 ; - PyObject * obj4 = 0 ; - PyObject * obj5 = 0 ; - PyObject * obj6 = 0 ; - uint8_t *result = 0 ; - - arg4 = &temp4; - if (!PyArg_ParseTuple(args,(char *)"OOOOOOO:wrap_WebPEncodeRGB",&obj0,&obj1,&obj2,&obj3,&obj4,&obj5,&obj6)) SWIG_fail; - { - // NB: with Python < 2.6 the old style buffer protocol may be used: - // Py_ssize_t unused; - // PyObject_AsReadBuffer(obj0, (const void**)(&arg1), &unused); - if (!PyObject_CheckBuffer(obj0)) { - SWIG_exception_fail(SWIG_TypeError, - "in method 'wrap_WebPEncodeRGB', argument 1" - " does not support the buffer interface"); - } - if (PyObject_GetBuffer(obj0, &rgb_buffer1, PyBUF_SIMPLE)) { - SWIG_exception_fail(SWIG_RuntimeError, - "in method 'wrap_WebPEncodeRGB', unable to get buffer view"); - } - arg1 = (uint8_t *)rgb_buffer1.buf; - } - if (!(SWIG_IsOK((res2 = SWIG_ConvertPtr(obj1,SWIG_as_voidptrptr(&arg2),SWIGTYPE_p_int,0))))) { - int val; - int ecode = SWIG_AsVal_int(obj1, &val); - if (!SWIG_IsOK(ecode)) { - SWIG_exception_fail(SWIG_ArgError(ecode), "in method '" "wrap_WebPEncodeRGB" "', argument " "2"" of type '" "int""'"); - } - temp2 = (int)(val); - arg2 = &temp2; - res2 = SWIG_AddTmpMask(ecode); - } - if (!(SWIG_IsOK((res3 = SWIG_ConvertPtr(obj2,SWIG_as_voidptrptr(&arg3),SWIGTYPE_p_int,0))))) { - int val; - int ecode = SWIG_AsVal_int(obj2, &val); - if (!SWIG_IsOK(ecode)) { - SWIG_exception_fail(SWIG_ArgError(ecode), "in method '" "wrap_WebPEncodeRGB" "', argument " "3"" of type '" "int""'"); - } - temp3 = (int)(val); - arg3 = &temp3; - res3 = SWIG_AddTmpMask(ecode); - } - ecode5 = SWIG_AsVal_int(obj3, &val5); - if (!SWIG_IsOK(ecode5)) { - SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "wrap_WebPEncodeRGB" "', argument " "5"" of type '" "int""'"); - } - arg5 = (int)(val5); - ecode6 = SWIG_AsVal_int(obj4, &val6); - if (!SWIG_IsOK(ecode6)) { - SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "wrap_WebPEncodeRGB" "', argument " "6"" of type '" "int""'"); - } - arg6 = (int)(val6); - ecode7 = SWIG_AsVal_int(obj5, &val7); - if (!SWIG_IsOK(ecode7)) { - SWIG_exception_fail(SWIG_ArgError(ecode7), "in method '" "wrap_WebPEncodeRGB" "', argument " "7"" of type '" "int""'"); - } - arg7 = (int)(val7); - ecode8 = SWIG_AsVal_float(obj6, &val8); - if (!SWIG_IsOK(ecode8)) { - SWIG_exception_fail(SWIG_ArgError(ecode8), "in method '" "wrap_WebPEncodeRGB" "', argument " "8"" of type '" "float""'"); - } - arg8 = (float)(val8); - result = (uint8_t *)wrap_WebPEncodeRGB((uint8_t const *)arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8); - { - resultobj = PyString_FromStringAndSize( - (const char*)result, - (result == NULL) ? 0 : ReturnedBufferSize("wrap_WebPEncodeRGB", arg3, arg4)); - } - if (SWIG_IsTmpObj(res4)) { - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg4))); - } else { - int new_flags = SWIG_IsNewObj(res4) ? (SWIG_POINTER_OWN | 0 ) : 0 ; - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg4), SWIGTYPE_p_int, new_flags)); - } - { - PyBuffer_Release(&rgb_buffer1); - } - if (SWIG_IsNewObj(res2)) free((char*)arg2); - if (SWIG_IsNewObj(res3)) free((char*)arg3); - free(result); - return resultobj; -fail: - { - PyBuffer_Release(&rgb_buffer1); - } - if (SWIG_IsNewObj(res2)) free((char*)arg2); - if (SWIG_IsNewObj(res3)) free((char*)arg3); - return NULL; -} - - -SWIGINTERN PyObject *_wrap_wrap_WebPEncodeBGR(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - PyObject *resultobj = 0; - uint8_t *arg1 = (uint8_t *) 0 ; - int *arg2 = (int *) 0 ; - int *arg3 = (int *) 0 ; - int *arg4 = (int *) 0 ; - int arg5 ; - int arg6 ; - int arg7 ; - float arg8 ; - Py_buffer rgb_buffer1 ; - int temp2 ; - int res2 = 0 ; - int temp3 ; - int res3 = 0 ; - int temp4 ; - int res4 = SWIG_TMPOBJ ; - int val5 ; - int ecode5 = 0 ; - int val6 ; - int ecode6 = 0 ; - int val7 ; - int ecode7 = 0 ; - float val8 ; - int ecode8 = 0 ; - PyObject * obj0 = 0 ; - PyObject * obj1 = 0 ; - PyObject * obj2 = 0 ; - PyObject * obj3 = 0 ; - PyObject * obj4 = 0 ; - PyObject * obj5 = 0 ; - PyObject * obj6 = 0 ; - uint8_t *result = 0 ; - - arg4 = &temp4; - if (!PyArg_ParseTuple(args,(char *)"OOOOOOO:wrap_WebPEncodeBGR",&obj0,&obj1,&obj2,&obj3,&obj4,&obj5,&obj6)) SWIG_fail; - { - // NB: with Python < 2.6 the old style buffer protocol may be used: - // Py_ssize_t unused; - // PyObject_AsReadBuffer(obj0, (const void**)(&arg1), &unused); - if (!PyObject_CheckBuffer(obj0)) { - SWIG_exception_fail(SWIG_TypeError, - "in method 'wrap_WebPEncodeBGR', argument 1" - " does not support the buffer interface"); - } - if (PyObject_GetBuffer(obj0, &rgb_buffer1, PyBUF_SIMPLE)) { - SWIG_exception_fail(SWIG_RuntimeError, - "in method 'wrap_WebPEncodeBGR', unable to get buffer view"); - } - arg1 = (uint8_t *)rgb_buffer1.buf; - } - if (!(SWIG_IsOK((res2 = SWIG_ConvertPtr(obj1,SWIG_as_voidptrptr(&arg2),SWIGTYPE_p_int,0))))) { - int val; - int ecode = SWIG_AsVal_int(obj1, &val); - if (!SWIG_IsOK(ecode)) { - SWIG_exception_fail(SWIG_ArgError(ecode), "in method '" "wrap_WebPEncodeBGR" "', argument " "2"" of type '" "int""'"); - } - temp2 = (int)(val); - arg2 = &temp2; - res2 = SWIG_AddTmpMask(ecode); - } - if (!(SWIG_IsOK((res3 = SWIG_ConvertPtr(obj2,SWIG_as_voidptrptr(&arg3),SWIGTYPE_p_int,0))))) { - int val; - int ecode = SWIG_AsVal_int(obj2, &val); - if (!SWIG_IsOK(ecode)) { - SWIG_exception_fail(SWIG_ArgError(ecode), "in method '" "wrap_WebPEncodeBGR" "', argument " "3"" of type '" "int""'"); - } - temp3 = (int)(val); - arg3 = &temp3; - res3 = SWIG_AddTmpMask(ecode); - } - ecode5 = SWIG_AsVal_int(obj3, &val5); - if (!SWIG_IsOK(ecode5)) { - SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "wrap_WebPEncodeBGR" "', argument " "5"" of type '" "int""'"); - } - arg5 = (int)(val5); - ecode6 = SWIG_AsVal_int(obj4, &val6); - if (!SWIG_IsOK(ecode6)) { - SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "wrap_WebPEncodeBGR" "', argument " "6"" of type '" "int""'"); - } - arg6 = (int)(val6); - ecode7 = SWIG_AsVal_int(obj5, &val7); - if (!SWIG_IsOK(ecode7)) { - SWIG_exception_fail(SWIG_ArgError(ecode7), "in method '" "wrap_WebPEncodeBGR" "', argument " "7"" of type '" "int""'"); - } - arg7 = (int)(val7); - ecode8 = SWIG_AsVal_float(obj6, &val8); - if (!SWIG_IsOK(ecode8)) { - SWIG_exception_fail(SWIG_ArgError(ecode8), "in method '" "wrap_WebPEncodeBGR" "', argument " "8"" of type '" "float""'"); - } - arg8 = (float)(val8); - result = (uint8_t *)wrap_WebPEncodeBGR((uint8_t const *)arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8); - { - resultobj = PyString_FromStringAndSize( - (const char*)result, - (result == NULL) ? 0 : ReturnedBufferSize("wrap_WebPEncodeBGR", arg3, arg4)); - } - if (SWIG_IsTmpObj(res4)) { - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg4))); - } else { - int new_flags = SWIG_IsNewObj(res4) ? (SWIG_POINTER_OWN | 0 ) : 0 ; - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg4), SWIGTYPE_p_int, new_flags)); - } - { - PyBuffer_Release(&rgb_buffer1); - } - if (SWIG_IsNewObj(res2)) free((char*)arg2); - if (SWIG_IsNewObj(res3)) free((char*)arg3); - free(result); - return resultobj; -fail: - { - PyBuffer_Release(&rgb_buffer1); - } - if (SWIG_IsNewObj(res2)) free((char*)arg2); - if (SWIG_IsNewObj(res3)) free((char*)arg3); - return NULL; -} - - -SWIGINTERN PyObject *_wrap_wrap_WebPEncodeRGBA(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - PyObject *resultobj = 0; - uint8_t *arg1 = (uint8_t *) 0 ; - int *arg2 = (int *) 0 ; - int *arg3 = (int *) 0 ; - int *arg4 = (int *) 0 ; - int arg5 ; - int arg6 ; - int arg7 ; - float arg8 ; - Py_buffer rgb_buffer1 ; - int temp2 ; - int res2 = 0 ; - int temp3 ; - int res3 = 0 ; - int temp4 ; - int res4 = SWIG_TMPOBJ ; - int val5 ; - int ecode5 = 0 ; - int val6 ; - int ecode6 = 0 ; - int val7 ; - int ecode7 = 0 ; - float val8 ; - int ecode8 = 0 ; - PyObject * obj0 = 0 ; - PyObject * obj1 = 0 ; - PyObject * obj2 = 0 ; - PyObject * obj3 = 0 ; - PyObject * obj4 = 0 ; - PyObject * obj5 = 0 ; - PyObject * obj6 = 0 ; - uint8_t *result = 0 ; - - arg4 = &temp4; - if (!PyArg_ParseTuple(args,(char *)"OOOOOOO:wrap_WebPEncodeRGBA",&obj0,&obj1,&obj2,&obj3,&obj4,&obj5,&obj6)) SWIG_fail; - { - // NB: with Python < 2.6 the old style buffer protocol may be used: - // Py_ssize_t unused; - // PyObject_AsReadBuffer(obj0, (const void**)(&arg1), &unused); - if (!PyObject_CheckBuffer(obj0)) { - SWIG_exception_fail(SWIG_TypeError, - "in method 'wrap_WebPEncodeRGBA', argument 1" - " does not support the buffer interface"); - } - if (PyObject_GetBuffer(obj0, &rgb_buffer1, PyBUF_SIMPLE)) { - SWIG_exception_fail(SWIG_RuntimeError, - "in method 'wrap_WebPEncodeRGBA', unable to get buffer view"); - } - arg1 = (uint8_t *)rgb_buffer1.buf; - } - if (!(SWIG_IsOK((res2 = SWIG_ConvertPtr(obj1,SWIG_as_voidptrptr(&arg2),SWIGTYPE_p_int,0))))) { - int val; - int ecode = SWIG_AsVal_int(obj1, &val); - if (!SWIG_IsOK(ecode)) { - SWIG_exception_fail(SWIG_ArgError(ecode), "in method '" "wrap_WebPEncodeRGBA" "', argument " "2"" of type '" "int""'"); - } - temp2 = (int)(val); - arg2 = &temp2; - res2 = SWIG_AddTmpMask(ecode); - } - if (!(SWIG_IsOK((res3 = SWIG_ConvertPtr(obj2,SWIG_as_voidptrptr(&arg3),SWIGTYPE_p_int,0))))) { - int val; - int ecode = SWIG_AsVal_int(obj2, &val); - if (!SWIG_IsOK(ecode)) { - SWIG_exception_fail(SWIG_ArgError(ecode), "in method '" "wrap_WebPEncodeRGBA" "', argument " "3"" of type '" "int""'"); - } - temp3 = (int)(val); - arg3 = &temp3; - res3 = SWIG_AddTmpMask(ecode); - } - ecode5 = SWIG_AsVal_int(obj3, &val5); - if (!SWIG_IsOK(ecode5)) { - SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "wrap_WebPEncodeRGBA" "', argument " "5"" of type '" "int""'"); - } - arg5 = (int)(val5); - ecode6 = SWIG_AsVal_int(obj4, &val6); - if (!SWIG_IsOK(ecode6)) { - SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "wrap_WebPEncodeRGBA" "', argument " "6"" of type '" "int""'"); - } - arg6 = (int)(val6); - ecode7 = SWIG_AsVal_int(obj5, &val7); - if (!SWIG_IsOK(ecode7)) { - SWIG_exception_fail(SWIG_ArgError(ecode7), "in method '" "wrap_WebPEncodeRGBA" "', argument " "7"" of type '" "int""'"); - } - arg7 = (int)(val7); - ecode8 = SWIG_AsVal_float(obj6, &val8); - if (!SWIG_IsOK(ecode8)) { - SWIG_exception_fail(SWIG_ArgError(ecode8), "in method '" "wrap_WebPEncodeRGBA" "', argument " "8"" of type '" "float""'"); - } - arg8 = (float)(val8); - result = (uint8_t *)wrap_WebPEncodeRGBA((uint8_t const *)arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8); - { - resultobj = PyString_FromStringAndSize( - (const char*)result, - (result == NULL) ? 0 : ReturnedBufferSize("wrap_WebPEncodeRGBA", arg3, arg4)); - } - if (SWIG_IsTmpObj(res4)) { - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg4))); - } else { - int new_flags = SWIG_IsNewObj(res4) ? (SWIG_POINTER_OWN | 0 ) : 0 ; - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg4), SWIGTYPE_p_int, new_flags)); - } - { - PyBuffer_Release(&rgb_buffer1); - } - if (SWIG_IsNewObj(res2)) free((char*)arg2); - if (SWIG_IsNewObj(res3)) free((char*)arg3); - free(result); - return resultobj; -fail: - { - PyBuffer_Release(&rgb_buffer1); - } - if (SWIG_IsNewObj(res2)) free((char*)arg2); - if (SWIG_IsNewObj(res3)) free((char*)arg3); - return NULL; -} - - -SWIGINTERN PyObject *_wrap_wrap_WebPEncodeBGRA(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - PyObject *resultobj = 0; - uint8_t *arg1 = (uint8_t *) 0 ; - int *arg2 = (int *) 0 ; - int *arg3 = (int *) 0 ; - int *arg4 = (int *) 0 ; - int arg5 ; - int arg6 ; - int arg7 ; - float arg8 ; - Py_buffer rgb_buffer1 ; - int temp2 ; - int res2 = 0 ; - int temp3 ; - int res3 = 0 ; - int temp4 ; - int res4 = SWIG_TMPOBJ ; - int val5 ; - int ecode5 = 0 ; - int val6 ; - int ecode6 = 0 ; - int val7 ; - int ecode7 = 0 ; - float val8 ; - int ecode8 = 0 ; - PyObject * obj0 = 0 ; - PyObject * obj1 = 0 ; - PyObject * obj2 = 0 ; - PyObject * obj3 = 0 ; - PyObject * obj4 = 0 ; - PyObject * obj5 = 0 ; - PyObject * obj6 = 0 ; - uint8_t *result = 0 ; - - arg4 = &temp4; - if (!PyArg_ParseTuple(args,(char *)"OOOOOOO:wrap_WebPEncodeBGRA",&obj0,&obj1,&obj2,&obj3,&obj4,&obj5,&obj6)) SWIG_fail; - { - // NB: with Python < 2.6 the old style buffer protocol may be used: - // Py_ssize_t unused; - // PyObject_AsReadBuffer(obj0, (const void**)(&arg1), &unused); - if (!PyObject_CheckBuffer(obj0)) { - SWIG_exception_fail(SWIG_TypeError, - "in method 'wrap_WebPEncodeBGRA', argument 1" - " does not support the buffer interface"); - } - if (PyObject_GetBuffer(obj0, &rgb_buffer1, PyBUF_SIMPLE)) { - SWIG_exception_fail(SWIG_RuntimeError, - "in method 'wrap_WebPEncodeBGRA', unable to get buffer view"); - } - arg1 = (uint8_t *)rgb_buffer1.buf; - } - if (!(SWIG_IsOK((res2 = SWIG_ConvertPtr(obj1,SWIG_as_voidptrptr(&arg2),SWIGTYPE_p_int,0))))) { - int val; - int ecode = SWIG_AsVal_int(obj1, &val); - if (!SWIG_IsOK(ecode)) { - SWIG_exception_fail(SWIG_ArgError(ecode), "in method '" "wrap_WebPEncodeBGRA" "', argument " "2"" of type '" "int""'"); - } - temp2 = (int)(val); - arg2 = &temp2; - res2 = SWIG_AddTmpMask(ecode); - } - if (!(SWIG_IsOK((res3 = SWIG_ConvertPtr(obj2,SWIG_as_voidptrptr(&arg3),SWIGTYPE_p_int,0))))) { - int val; - int ecode = SWIG_AsVal_int(obj2, &val); - if (!SWIG_IsOK(ecode)) { - SWIG_exception_fail(SWIG_ArgError(ecode), "in method '" "wrap_WebPEncodeBGRA" "', argument " "3"" of type '" "int""'"); - } - temp3 = (int)(val); - arg3 = &temp3; - res3 = SWIG_AddTmpMask(ecode); - } - ecode5 = SWIG_AsVal_int(obj3, &val5); - if (!SWIG_IsOK(ecode5)) { - SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "wrap_WebPEncodeBGRA" "', argument " "5"" of type '" "int""'"); - } - arg5 = (int)(val5); - ecode6 = SWIG_AsVal_int(obj4, &val6); - if (!SWIG_IsOK(ecode6)) { - SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "wrap_WebPEncodeBGRA" "', argument " "6"" of type '" "int""'"); - } - arg6 = (int)(val6); - ecode7 = SWIG_AsVal_int(obj5, &val7); - if (!SWIG_IsOK(ecode7)) { - SWIG_exception_fail(SWIG_ArgError(ecode7), "in method '" "wrap_WebPEncodeBGRA" "', argument " "7"" of type '" "int""'"); - } - arg7 = (int)(val7); - ecode8 = SWIG_AsVal_float(obj6, &val8); - if (!SWIG_IsOK(ecode8)) { - SWIG_exception_fail(SWIG_ArgError(ecode8), "in method '" "wrap_WebPEncodeBGRA" "', argument " "8"" of type '" "float""'"); - } - arg8 = (float)(val8); - result = (uint8_t *)wrap_WebPEncodeBGRA((uint8_t const *)arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8); - { - resultobj = PyString_FromStringAndSize( - (const char*)result, - (result == NULL) ? 0 : ReturnedBufferSize("wrap_WebPEncodeBGRA", arg3, arg4)); - } - if (SWIG_IsTmpObj(res4)) { - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg4))); - } else { - int new_flags = SWIG_IsNewObj(res4) ? (SWIG_POINTER_OWN | 0 ) : 0 ; - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg4), SWIGTYPE_p_int, new_flags)); - } - { - PyBuffer_Release(&rgb_buffer1); - } - if (SWIG_IsNewObj(res2)) free((char*)arg2); - if (SWIG_IsNewObj(res3)) free((char*)arg3); - free(result); - return resultobj; -fail: - { - PyBuffer_Release(&rgb_buffer1); - } - if (SWIG_IsNewObj(res2)) free((char*)arg2); - if (SWIG_IsNewObj(res3)) free((char*)arg3); - return NULL; -} - - -SWIGINTERN PyObject *_wrap_wrap_WebPEncodeLosslessRGB(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - PyObject *resultobj = 0; - uint8_t *arg1 = (uint8_t *) 0 ; - int *arg2 = (int *) 0 ; - int *arg3 = (int *) 0 ; - int *arg4 = (int *) 0 ; - int arg5 ; - int arg6 ; - int arg7 ; - Py_buffer rgb_buffer1 ; - int temp2 ; - int res2 = 0 ; - int temp3 ; - int res3 = 0 ; - int temp4 ; - int res4 = SWIG_TMPOBJ ; - int val5 ; - int ecode5 = 0 ; - int val6 ; - int ecode6 = 0 ; - int val7 ; - int ecode7 = 0 ; - PyObject * obj0 = 0 ; - PyObject * obj1 = 0 ; - PyObject * obj2 = 0 ; - PyObject * obj3 = 0 ; - PyObject * obj4 = 0 ; - PyObject * obj5 = 0 ; - uint8_t *result = 0 ; - - arg4 = &temp4; - if (!PyArg_ParseTuple(args,(char *)"OOOOOO:wrap_WebPEncodeLosslessRGB",&obj0,&obj1,&obj2,&obj3,&obj4,&obj5)) SWIG_fail; - { - // NB: with Python < 2.6 the old style buffer protocol may be used: - // Py_ssize_t unused; - // PyObject_AsReadBuffer(obj0, (const void**)(&arg1), &unused); - if (!PyObject_CheckBuffer(obj0)) { - SWIG_exception_fail(SWIG_TypeError, - "in method 'wrap_WebPEncodeLosslessRGB', argument 1" - " does not support the buffer interface"); - } - if (PyObject_GetBuffer(obj0, &rgb_buffer1, PyBUF_SIMPLE)) { - SWIG_exception_fail(SWIG_RuntimeError, - "in method 'wrap_WebPEncodeLosslessRGB', unable to get buffer view"); - } - arg1 = (uint8_t *)rgb_buffer1.buf; - } - if (!(SWIG_IsOK((res2 = SWIG_ConvertPtr(obj1,SWIG_as_voidptrptr(&arg2),SWIGTYPE_p_int,0))))) { - int val; - int ecode = SWIG_AsVal_int(obj1, &val); - if (!SWIG_IsOK(ecode)) { - SWIG_exception_fail(SWIG_ArgError(ecode), "in method '" "wrap_WebPEncodeLosslessRGB" "', argument " "2"" of type '" "int""'"); - } - temp2 = (int)(val); - arg2 = &temp2; - res2 = SWIG_AddTmpMask(ecode); - } - if (!(SWIG_IsOK((res3 = SWIG_ConvertPtr(obj2,SWIG_as_voidptrptr(&arg3),SWIGTYPE_p_int,0))))) { - int val; - int ecode = SWIG_AsVal_int(obj2, &val); - if (!SWIG_IsOK(ecode)) { - SWIG_exception_fail(SWIG_ArgError(ecode), "in method '" "wrap_WebPEncodeLosslessRGB" "', argument " "3"" of type '" "int""'"); - } - temp3 = (int)(val); - arg3 = &temp3; - res3 = SWIG_AddTmpMask(ecode); - } - ecode5 = SWIG_AsVal_int(obj3, &val5); - if (!SWIG_IsOK(ecode5)) { - SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "wrap_WebPEncodeLosslessRGB" "', argument " "5"" of type '" "int""'"); - } - arg5 = (int)(val5); - ecode6 = SWIG_AsVal_int(obj4, &val6); - if (!SWIG_IsOK(ecode6)) { - SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "wrap_WebPEncodeLosslessRGB" "', argument " "6"" of type '" "int""'"); - } - arg6 = (int)(val6); - ecode7 = SWIG_AsVal_int(obj5, &val7); - if (!SWIG_IsOK(ecode7)) { - SWIG_exception_fail(SWIG_ArgError(ecode7), "in method '" "wrap_WebPEncodeLosslessRGB" "', argument " "7"" of type '" "int""'"); - } - arg7 = (int)(val7); - result = (uint8_t *)wrap_WebPEncodeLosslessRGB((uint8_t const *)arg1,arg2,arg3,arg4,arg5,arg6,arg7); - { - resultobj = PyString_FromStringAndSize( - (const char*)result, - (result == NULL) ? 0 : ReturnedBufferSize("wrap_WebPEncodeLosslessRGB", arg3, arg4)); - } - if (SWIG_IsTmpObj(res4)) { - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg4))); - } else { - int new_flags = SWIG_IsNewObj(res4) ? (SWIG_POINTER_OWN | 0 ) : 0 ; - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg4), SWIGTYPE_p_int, new_flags)); - } - { - PyBuffer_Release(&rgb_buffer1); - } - if (SWIG_IsNewObj(res2)) free((char*)arg2); - if (SWIG_IsNewObj(res3)) free((char*)arg3); - free(result); - return resultobj; -fail: - { - PyBuffer_Release(&rgb_buffer1); - } - if (SWIG_IsNewObj(res2)) free((char*)arg2); - if (SWIG_IsNewObj(res3)) free((char*)arg3); - return NULL; -} - - -SWIGINTERN PyObject *_wrap_wrap_WebPEncodeLosslessBGR(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - PyObject *resultobj = 0; - uint8_t *arg1 = (uint8_t *) 0 ; - int *arg2 = (int *) 0 ; - int *arg3 = (int *) 0 ; - int *arg4 = (int *) 0 ; - int arg5 ; - int arg6 ; - int arg7 ; - Py_buffer rgb_buffer1 ; - int temp2 ; - int res2 = 0 ; - int temp3 ; - int res3 = 0 ; - int temp4 ; - int res4 = SWIG_TMPOBJ ; - int val5 ; - int ecode5 = 0 ; - int val6 ; - int ecode6 = 0 ; - int val7 ; - int ecode7 = 0 ; - PyObject * obj0 = 0 ; - PyObject * obj1 = 0 ; - PyObject * obj2 = 0 ; - PyObject * obj3 = 0 ; - PyObject * obj4 = 0 ; - PyObject * obj5 = 0 ; - uint8_t *result = 0 ; - - arg4 = &temp4; - if (!PyArg_ParseTuple(args,(char *)"OOOOOO:wrap_WebPEncodeLosslessBGR",&obj0,&obj1,&obj2,&obj3,&obj4,&obj5)) SWIG_fail; - { - // NB: with Python < 2.6 the old style buffer protocol may be used: - // Py_ssize_t unused; - // PyObject_AsReadBuffer(obj0, (const void**)(&arg1), &unused); - if (!PyObject_CheckBuffer(obj0)) { - SWIG_exception_fail(SWIG_TypeError, - "in method 'wrap_WebPEncodeLosslessBGR', argument 1" - " does not support the buffer interface"); - } - if (PyObject_GetBuffer(obj0, &rgb_buffer1, PyBUF_SIMPLE)) { - SWIG_exception_fail(SWIG_RuntimeError, - "in method 'wrap_WebPEncodeLosslessBGR', unable to get buffer view"); - } - arg1 = (uint8_t *)rgb_buffer1.buf; - } - if (!(SWIG_IsOK((res2 = SWIG_ConvertPtr(obj1,SWIG_as_voidptrptr(&arg2),SWIGTYPE_p_int,0))))) { - int val; - int ecode = SWIG_AsVal_int(obj1, &val); - if (!SWIG_IsOK(ecode)) { - SWIG_exception_fail(SWIG_ArgError(ecode), "in method '" "wrap_WebPEncodeLosslessBGR" "', argument " "2"" of type '" "int""'"); - } - temp2 = (int)(val); - arg2 = &temp2; - res2 = SWIG_AddTmpMask(ecode); - } - if (!(SWIG_IsOK((res3 = SWIG_ConvertPtr(obj2,SWIG_as_voidptrptr(&arg3),SWIGTYPE_p_int,0))))) { - int val; - int ecode = SWIG_AsVal_int(obj2, &val); - if (!SWIG_IsOK(ecode)) { - SWIG_exception_fail(SWIG_ArgError(ecode), "in method '" "wrap_WebPEncodeLosslessBGR" "', argument " "3"" of type '" "int""'"); - } - temp3 = (int)(val); - arg3 = &temp3; - res3 = SWIG_AddTmpMask(ecode); - } - ecode5 = SWIG_AsVal_int(obj3, &val5); - if (!SWIG_IsOK(ecode5)) { - SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "wrap_WebPEncodeLosslessBGR" "', argument " "5"" of type '" "int""'"); - } - arg5 = (int)(val5); - ecode6 = SWIG_AsVal_int(obj4, &val6); - if (!SWIG_IsOK(ecode6)) { - SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "wrap_WebPEncodeLosslessBGR" "', argument " "6"" of type '" "int""'"); - } - arg6 = (int)(val6); - ecode7 = SWIG_AsVal_int(obj5, &val7); - if (!SWIG_IsOK(ecode7)) { - SWIG_exception_fail(SWIG_ArgError(ecode7), "in method '" "wrap_WebPEncodeLosslessBGR" "', argument " "7"" of type '" "int""'"); - } - arg7 = (int)(val7); - result = (uint8_t *)wrap_WebPEncodeLosslessBGR((uint8_t const *)arg1,arg2,arg3,arg4,arg5,arg6,arg7); - { - resultobj = PyString_FromStringAndSize( - (const char*)result, - (result == NULL) ? 0 : ReturnedBufferSize("wrap_WebPEncodeLosslessBGR", arg3, arg4)); - } - if (SWIG_IsTmpObj(res4)) { - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg4))); - } else { - int new_flags = SWIG_IsNewObj(res4) ? (SWIG_POINTER_OWN | 0 ) : 0 ; - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg4), SWIGTYPE_p_int, new_flags)); - } - { - PyBuffer_Release(&rgb_buffer1); - } - if (SWIG_IsNewObj(res2)) free((char*)arg2); - if (SWIG_IsNewObj(res3)) free((char*)arg3); - free(result); - return resultobj; -fail: - { - PyBuffer_Release(&rgb_buffer1); - } - if (SWIG_IsNewObj(res2)) free((char*)arg2); - if (SWIG_IsNewObj(res3)) free((char*)arg3); - return NULL; -} - - -SWIGINTERN PyObject *_wrap_wrap_WebPEncodeLosslessRGBA(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - PyObject *resultobj = 0; - uint8_t *arg1 = (uint8_t *) 0 ; - int *arg2 = (int *) 0 ; - int *arg3 = (int *) 0 ; - int *arg4 = (int *) 0 ; - int arg5 ; - int arg6 ; - int arg7 ; - Py_buffer rgb_buffer1 ; - int temp2 ; - int res2 = 0 ; - int temp3 ; - int res3 = 0 ; - int temp4 ; - int res4 = SWIG_TMPOBJ ; - int val5 ; - int ecode5 = 0 ; - int val6 ; - int ecode6 = 0 ; - int val7 ; - int ecode7 = 0 ; - PyObject * obj0 = 0 ; - PyObject * obj1 = 0 ; - PyObject * obj2 = 0 ; - PyObject * obj3 = 0 ; - PyObject * obj4 = 0 ; - PyObject * obj5 = 0 ; - uint8_t *result = 0 ; - - arg4 = &temp4; - if (!PyArg_ParseTuple(args,(char *)"OOOOOO:wrap_WebPEncodeLosslessRGBA",&obj0,&obj1,&obj2,&obj3,&obj4,&obj5)) SWIG_fail; - { - // NB: with Python < 2.6 the old style buffer protocol may be used: - // Py_ssize_t unused; - // PyObject_AsReadBuffer(obj0, (const void**)(&arg1), &unused); - if (!PyObject_CheckBuffer(obj0)) { - SWIG_exception_fail(SWIG_TypeError, - "in method 'wrap_WebPEncodeLosslessRGBA', argument 1" - " does not support the buffer interface"); - } - if (PyObject_GetBuffer(obj0, &rgb_buffer1, PyBUF_SIMPLE)) { - SWIG_exception_fail(SWIG_RuntimeError, - "in method 'wrap_WebPEncodeLosslessRGBA', unable to get buffer view"); - } - arg1 = (uint8_t *)rgb_buffer1.buf; - } - if (!(SWIG_IsOK((res2 = SWIG_ConvertPtr(obj1,SWIG_as_voidptrptr(&arg2),SWIGTYPE_p_int,0))))) { - int val; - int ecode = SWIG_AsVal_int(obj1, &val); - if (!SWIG_IsOK(ecode)) { - SWIG_exception_fail(SWIG_ArgError(ecode), "in method '" "wrap_WebPEncodeLosslessRGBA" "', argument " "2"" of type '" "int""'"); - } - temp2 = (int)(val); - arg2 = &temp2; - res2 = SWIG_AddTmpMask(ecode); - } - if (!(SWIG_IsOK((res3 = SWIG_ConvertPtr(obj2,SWIG_as_voidptrptr(&arg3),SWIGTYPE_p_int,0))))) { - int val; - int ecode = SWIG_AsVal_int(obj2, &val); - if (!SWIG_IsOK(ecode)) { - SWIG_exception_fail(SWIG_ArgError(ecode), "in method '" "wrap_WebPEncodeLosslessRGBA" "', argument " "3"" of type '" "int""'"); - } - temp3 = (int)(val); - arg3 = &temp3; - res3 = SWIG_AddTmpMask(ecode); - } - ecode5 = SWIG_AsVal_int(obj3, &val5); - if (!SWIG_IsOK(ecode5)) { - SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "wrap_WebPEncodeLosslessRGBA" "', argument " "5"" of type '" "int""'"); - } - arg5 = (int)(val5); - ecode6 = SWIG_AsVal_int(obj4, &val6); - if (!SWIG_IsOK(ecode6)) { - SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "wrap_WebPEncodeLosslessRGBA" "', argument " "6"" of type '" "int""'"); - } - arg6 = (int)(val6); - ecode7 = SWIG_AsVal_int(obj5, &val7); - if (!SWIG_IsOK(ecode7)) { - SWIG_exception_fail(SWIG_ArgError(ecode7), "in method '" "wrap_WebPEncodeLosslessRGBA" "', argument " "7"" of type '" "int""'"); - } - arg7 = (int)(val7); - result = (uint8_t *)wrap_WebPEncodeLosslessRGBA((uint8_t const *)arg1,arg2,arg3,arg4,arg5,arg6,arg7); - { - resultobj = PyString_FromStringAndSize( - (const char*)result, - (result == NULL) ? 0 : ReturnedBufferSize("wrap_WebPEncodeLosslessRGBA", arg3, arg4)); - } - if (SWIG_IsTmpObj(res4)) { - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg4))); - } else { - int new_flags = SWIG_IsNewObj(res4) ? (SWIG_POINTER_OWN | 0 ) : 0 ; - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg4), SWIGTYPE_p_int, new_flags)); - } - { - PyBuffer_Release(&rgb_buffer1); - } - if (SWIG_IsNewObj(res2)) free((char*)arg2); - if (SWIG_IsNewObj(res3)) free((char*)arg3); - free(result); - return resultobj; -fail: - { - PyBuffer_Release(&rgb_buffer1); - } - if (SWIG_IsNewObj(res2)) free((char*)arg2); - if (SWIG_IsNewObj(res3)) free((char*)arg3); - return NULL; -} - - -SWIGINTERN PyObject *_wrap_wrap_WebPEncodeLosslessBGRA(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - PyObject *resultobj = 0; - uint8_t *arg1 = (uint8_t *) 0 ; - int *arg2 = (int *) 0 ; - int *arg3 = (int *) 0 ; - int *arg4 = (int *) 0 ; - int arg5 ; - int arg6 ; - int arg7 ; - Py_buffer rgb_buffer1 ; - int temp2 ; - int res2 = 0 ; - int temp3 ; - int res3 = 0 ; - int temp4 ; - int res4 = SWIG_TMPOBJ ; - int val5 ; - int ecode5 = 0 ; - int val6 ; - int ecode6 = 0 ; - int val7 ; - int ecode7 = 0 ; - PyObject * obj0 = 0 ; - PyObject * obj1 = 0 ; - PyObject * obj2 = 0 ; - PyObject * obj3 = 0 ; - PyObject * obj4 = 0 ; - PyObject * obj5 = 0 ; - uint8_t *result = 0 ; - - arg4 = &temp4; - if (!PyArg_ParseTuple(args,(char *)"OOOOOO:wrap_WebPEncodeLosslessBGRA",&obj0,&obj1,&obj2,&obj3,&obj4,&obj5)) SWIG_fail; - { - // NB: with Python < 2.6 the old style buffer protocol may be used: - // Py_ssize_t unused; - // PyObject_AsReadBuffer(obj0, (const void**)(&arg1), &unused); - if (!PyObject_CheckBuffer(obj0)) { - SWIG_exception_fail(SWIG_TypeError, - "in method 'wrap_WebPEncodeLosslessBGRA', argument 1" - " does not support the buffer interface"); - } - if (PyObject_GetBuffer(obj0, &rgb_buffer1, PyBUF_SIMPLE)) { - SWIG_exception_fail(SWIG_RuntimeError, - "in method 'wrap_WebPEncodeLosslessBGRA', unable to get buffer view"); - } - arg1 = (uint8_t *)rgb_buffer1.buf; - } - if (!(SWIG_IsOK((res2 = SWIG_ConvertPtr(obj1,SWIG_as_voidptrptr(&arg2),SWIGTYPE_p_int,0))))) { - int val; - int ecode = SWIG_AsVal_int(obj1, &val); - if (!SWIG_IsOK(ecode)) { - SWIG_exception_fail(SWIG_ArgError(ecode), "in method '" "wrap_WebPEncodeLosslessBGRA" "', argument " "2"" of type '" "int""'"); - } - temp2 = (int)(val); - arg2 = &temp2; - res2 = SWIG_AddTmpMask(ecode); - } - if (!(SWIG_IsOK((res3 = SWIG_ConvertPtr(obj2,SWIG_as_voidptrptr(&arg3),SWIGTYPE_p_int,0))))) { - int val; - int ecode = SWIG_AsVal_int(obj2, &val); - if (!SWIG_IsOK(ecode)) { - SWIG_exception_fail(SWIG_ArgError(ecode), "in method '" "wrap_WebPEncodeLosslessBGRA" "', argument " "3"" of type '" "int""'"); - } - temp3 = (int)(val); - arg3 = &temp3; - res3 = SWIG_AddTmpMask(ecode); - } - ecode5 = SWIG_AsVal_int(obj3, &val5); - if (!SWIG_IsOK(ecode5)) { - SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "wrap_WebPEncodeLosslessBGRA" "', argument " "5"" of type '" "int""'"); - } - arg5 = (int)(val5); - ecode6 = SWIG_AsVal_int(obj4, &val6); - if (!SWIG_IsOK(ecode6)) { - SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "wrap_WebPEncodeLosslessBGRA" "', argument " "6"" of type '" "int""'"); - } - arg6 = (int)(val6); - ecode7 = SWIG_AsVal_int(obj5, &val7); - if (!SWIG_IsOK(ecode7)) { - SWIG_exception_fail(SWIG_ArgError(ecode7), "in method '" "wrap_WebPEncodeLosslessBGRA" "', argument " "7"" of type '" "int""'"); - } - arg7 = (int)(val7); - result = (uint8_t *)wrap_WebPEncodeLosslessBGRA((uint8_t const *)arg1,arg2,arg3,arg4,arg5,arg6,arg7); - { - resultobj = PyString_FromStringAndSize( - (const char*)result, - (result == NULL) ? 0 : ReturnedBufferSize("wrap_WebPEncodeLosslessBGRA", arg3, arg4)); - } - if (SWIG_IsTmpObj(res4)) { - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg4))); - } else { - int new_flags = SWIG_IsNewObj(res4) ? (SWIG_POINTER_OWN | 0 ) : 0 ; - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg4), SWIGTYPE_p_int, new_flags)); - } - { - PyBuffer_Release(&rgb_buffer1); - } - if (SWIG_IsNewObj(res2)) free((char*)arg2); - if (SWIG_IsNewObj(res3)) free((char*)arg3); - free(result); - return resultobj; -fail: - { - PyBuffer_Release(&rgb_buffer1); - } - if (SWIG_IsNewObj(res2)) free((char*)arg2); - if (SWIG_IsNewObj(res3)) free((char*)arg3); - return NULL; -} - - -static PyMethodDef SwigMethods[] = { - { "SWIG_PyInstanceMethod_New", SWIG_PyInstanceMethod_New, METH_O, NULL}, - { "WebPGetDecoderVersion", _wrap_WebPGetDecoderVersion, METH_VARARGS, (char *)"WebPGetDecoderVersion() -> int"}, - { "WebPGetInfo", _wrap_WebPGetInfo, METH_VARARGS, (char *)"WebPGetInfo(uint8_t data) -> (width, height)"}, - { "WebPDecodeRGB", _wrap_WebPDecodeRGB, METH_VARARGS, (char *)"WebPDecodeRGB(uint8_t data) -> (rgb, width, height)"}, - { "WebPDecodeRGBA", _wrap_WebPDecodeRGBA, METH_VARARGS, (char *)"WebPDecodeRGBA(uint8_t data) -> (rgb, width, height)"}, - { "WebPDecodeARGB", _wrap_WebPDecodeARGB, METH_VARARGS, (char *)"WebPDecodeARGB(uint8_t data) -> (rgb, width, height)"}, - { "WebPDecodeBGR", _wrap_WebPDecodeBGR, METH_VARARGS, (char *)"WebPDecodeBGR(uint8_t data) -> (rgb, width, height)"}, - { "WebPDecodeBGRA", _wrap_WebPDecodeBGRA, METH_VARARGS, (char *)"WebPDecodeBGRA(uint8_t data) -> (rgb, width, height)"}, - { "WebPGetEncoderVersion", _wrap_WebPGetEncoderVersion, METH_VARARGS, (char *)"WebPGetEncoderVersion() -> int"}, - { "wrap_WebPEncodeRGB", _wrap_wrap_WebPEncodeRGB, METH_VARARGS, (char *)"private, do not call directly."}, - { "wrap_WebPEncodeBGR", _wrap_wrap_WebPEncodeBGR, METH_VARARGS, (char *)"private, do not call directly."}, - { "wrap_WebPEncodeRGBA", _wrap_wrap_WebPEncodeRGBA, METH_VARARGS, (char *)"private, do not call directly."}, - { "wrap_WebPEncodeBGRA", _wrap_wrap_WebPEncodeBGRA, METH_VARARGS, (char *)"private, do not call directly."}, - { "wrap_WebPEncodeLosslessRGB", _wrap_wrap_WebPEncodeLosslessRGB, METH_VARARGS, (char *)"private, do not call directly."}, - { "wrap_WebPEncodeLosslessBGR", _wrap_wrap_WebPEncodeLosslessBGR, METH_VARARGS, (char *)"private, do not call directly."}, - { "wrap_WebPEncodeLosslessRGBA", _wrap_wrap_WebPEncodeLosslessRGBA, METH_VARARGS, (char *)"private, do not call directly."}, - { "wrap_WebPEncodeLosslessBGRA", _wrap_wrap_WebPEncodeLosslessBGRA, METH_VARARGS, (char *)"private, do not call directly."}, - { NULL, NULL, 0, NULL } -}; - - -/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */ - -static swig_type_info _swigt__p_char = {"_p_char", "char *", 0, 0, (void*)0, 0}; -static swig_type_info _swigt__p_int = {"_p_int", "int *", 0, 0, (void*)0, 0}; -static swig_type_info _swigt__p_uint8_t = {"_p_uint8_t", "uint8_t *", 0, 0, (void*)0, 0}; - -static swig_type_info *swig_type_initial[] = { - &_swigt__p_char, - &_swigt__p_int, - &_swigt__p_uint8_t, -}; - -static swig_cast_info _swigc__p_char[] = { {&_swigt__p_char, 0, 0, 0},{0, 0, 0, 0}}; -static swig_cast_info _swigc__p_int[] = { {&_swigt__p_int, 0, 0, 0},{0, 0, 0, 0}}; -static swig_cast_info _swigc__p_uint8_t[] = { {&_swigt__p_uint8_t, 0, 0, 0},{0, 0, 0, 0}}; - -static swig_cast_info *swig_cast_initial[] = { - _swigc__p_char, - _swigc__p_int, - _swigc__p_uint8_t, -}; - - -/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (END) -------- */ - -static swig_const_info swig_const_table[] = { -{0, 0, 0, 0.0, 0, 0}}; - -#ifdef __cplusplus -} -#endif -/* ----------------------------------------------------------------------------- - * Type initialization: - * This problem is tough by the requirement that no dynamic - * memory is used. Also, since swig_type_info structures store pointers to - * swig_cast_info structures and swig_cast_info structures store pointers back - * to swig_type_info structures, we need some lookup code at initialization. - * The idea is that swig generates all the structures that are needed. - * The runtime then collects these partially filled structures. - * The SWIG_InitializeModule function takes these initial arrays out of - * swig_module, and does all the lookup, filling in the swig_module.types - * array with the correct data and linking the correct swig_cast_info - * structures together. - * - * The generated swig_type_info structures are assigned statically to an initial - * array. We just loop through that array, and handle each type individually. - * First we lookup if this type has been already loaded, and if so, use the - * loaded structure instead of the generated one. Then we have to fill in the - * cast linked list. The cast data is initially stored in something like a - * two-dimensional array. Each row corresponds to a type (there are the same - * number of rows as there are in the swig_type_initial array). Each entry in - * a column is one of the swig_cast_info structures for that type. - * The cast_initial array is actually an array of arrays, because each row has - * a variable number of columns. So to actually build the cast linked list, - * we find the array of casts associated with the type, and loop through it - * adding the casts to the list. The one last trick we need to do is making - * sure the type pointer in the swig_cast_info struct is correct. - * - * First off, we lookup the cast->type name to see if it is already loaded. - * There are three cases to handle: - * 1) If the cast->type has already been loaded AND the type we are adding - * casting info to has not been loaded (it is in this module), THEN we - * replace the cast->type pointer with the type pointer that has already - * been loaded. - * 2) If BOTH types (the one we are adding casting info to, and the - * cast->type) are loaded, THEN the cast info has already been loaded by - * the previous module so we just ignore it. - * 3) Finally, if cast->type has not already been loaded, then we add that - * swig_cast_info to the linked list (because the cast->type) pointer will - * be correct. - * ----------------------------------------------------------------------------- */ - -#ifdef __cplusplus -extern "C" { -#if 0 -} /* c-mode */ -#endif -#endif - -#if 0 -#define SWIGRUNTIME_DEBUG -#endif - - -SWIGRUNTIME void -SWIG_InitializeModule(void *clientdata) { - size_t i; - swig_module_info *module_head, *iter; - int init; - - /* check to see if the circular list has been setup, if not, set it up */ - if (swig_module.next==0) { - /* Initialize the swig_module */ - swig_module.type_initial = swig_type_initial; - swig_module.cast_initial = swig_cast_initial; - swig_module.next = &swig_module; - init = 1; - } else { - init = 0; - } - - /* Try and load any already created modules */ - module_head = SWIG_GetModule(clientdata); - if (!module_head) { - /* This is the first module loaded for this interpreter */ - /* so set the swig module into the interpreter */ - SWIG_SetModule(clientdata, &swig_module); - } else { - /* the interpreter has loaded a SWIG module, but has it loaded this one? */ - iter=module_head; - do { - if (iter==&swig_module) { - /* Our module is already in the list, so there's nothing more to do. */ - return; - } - iter=iter->next; - } while (iter!= module_head); - - /* otherwise we must add our module into the list */ - swig_module.next = module_head->next; - module_head->next = &swig_module; - } - - /* When multiple interpreters are used, a module could have already been initialized in - a different interpreter, but not yet have a pointer in this interpreter. - In this case, we do not want to continue adding types... everything should be - set up already */ - if (init == 0) return; - - /* Now work on filling in swig_module.types */ -#ifdef SWIGRUNTIME_DEBUG - printf("SWIG_InitializeModule: size %d\n", swig_module.size); -#endif - for (i = 0; i < swig_module.size; ++i) { - swig_type_info *type = 0; - swig_type_info *ret; - swig_cast_info *cast; - -#ifdef SWIGRUNTIME_DEBUG - printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name); -#endif - - /* if there is another module already loaded */ - if (swig_module.next != &swig_module) { - type = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, swig_module.type_initial[i]->name); - } - if (type) { - /* Overwrite clientdata field */ -#ifdef SWIGRUNTIME_DEBUG - printf("SWIG_InitializeModule: found type %s\n", type->name); -#endif - if (swig_module.type_initial[i]->clientdata) { - type->clientdata = swig_module.type_initial[i]->clientdata; -#ifdef SWIGRUNTIME_DEBUG - printf("SWIG_InitializeModule: found and overwrite type %s \n", type->name); -#endif - } - } else { - type = swig_module.type_initial[i]; - } - - /* Insert casting types */ - cast = swig_module.cast_initial[i]; - while (cast->type) { - /* Don't need to add information already in the list */ - ret = 0; -#ifdef SWIGRUNTIME_DEBUG - printf("SWIG_InitializeModule: look cast %s\n", cast->type->name); -#endif - if (swig_module.next != &swig_module) { - ret = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, cast->type->name); -#ifdef SWIGRUNTIME_DEBUG - if (ret) printf("SWIG_InitializeModule: found cast %s\n", ret->name); -#endif - } - if (ret) { - if (type == swig_module.type_initial[i]) { -#ifdef SWIGRUNTIME_DEBUG - printf("SWIG_InitializeModule: skip old type %s\n", ret->name); -#endif - cast->type = ret; - ret = 0; - } else { - /* Check for casting already in the list */ - swig_cast_info *ocast = SWIG_TypeCheck(ret->name, type); -#ifdef SWIGRUNTIME_DEBUG - if (ocast) printf("SWIG_InitializeModule: skip old cast %s\n", ret->name); -#endif - if (!ocast) ret = 0; - } - } - - if (!ret) { -#ifdef SWIGRUNTIME_DEBUG - printf("SWIG_InitializeModule: adding cast %s\n", cast->type->name); -#endif - if (type->cast) { - type->cast->prev = cast; - cast->next = type->cast; - } - type->cast = cast; - } - cast++; - } - /* Set entry in modules->types array equal to the type */ - swig_module.types[i] = type; - } - swig_module.types[i] = 0; - -#ifdef SWIGRUNTIME_DEBUG - printf("**** SWIG_InitializeModule: Cast List ******\n"); - for (i = 0; i < swig_module.size; ++i) { - int j = 0; - swig_cast_info *cast = swig_module.cast_initial[i]; - printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name); - while (cast->type) { - printf("SWIG_InitializeModule: cast type %s\n", cast->type->name); - cast++; - ++j; - } - printf("---- Total casts: %d\n",j); - } - printf("**** SWIG_InitializeModule: Cast List ******\n"); -#endif -} - -/* This function will propagate the clientdata field of type to -* any new swig_type_info structures that have been added into the list -* of equivalent types. It is like calling -* SWIG_TypeClientData(type, clientdata) a second time. -*/ -SWIGRUNTIME void -SWIG_PropagateClientData(void) { - size_t i; - swig_cast_info *equiv; - static int init_run = 0; - - if (init_run) return; - init_run = 1; - - for (i = 0; i < swig_module.size; i++) { - if (swig_module.types[i]->clientdata) { - equiv = swig_module.types[i]->cast; - while (equiv) { - if (!equiv->converter) { - if (equiv->type && !equiv->type->clientdata) - SWIG_TypeClientData(equiv->type, swig_module.types[i]->clientdata); - } - equiv = equiv->next; - } - } - } -} - -#ifdef __cplusplus -#if 0 -{ - /* c-mode */ -#endif -} -#endif - - - -#ifdef __cplusplus -extern "C" { -#endif - - /* Python-specific SWIG API */ -#define SWIG_newvarlink() SWIG_Python_newvarlink() -#define SWIG_addvarlink(p, name, get_attr, set_attr) SWIG_Python_addvarlink(p, name, get_attr, set_attr) -#define SWIG_InstallConstants(d, constants) SWIG_Python_InstallConstants(d, constants) - - /* ----------------------------------------------------------------------------- - * global variable support code. - * ----------------------------------------------------------------------------- */ - - typedef struct swig_globalvar { - char *name; /* Name of global variable */ - PyObject *(*get_attr)(void); /* Return the current value */ - int (*set_attr)(PyObject *); /* Set the value */ - struct swig_globalvar *next; - } swig_globalvar; - - typedef struct swig_varlinkobject { - PyObject_HEAD - swig_globalvar *vars; - } swig_varlinkobject; - - SWIGINTERN PyObject * - swig_varlink_repr(swig_varlinkobject *SWIGUNUSEDPARM(v)) { -#if PY_VERSION_HEX >= 0x03000000 - return PyUnicode_InternFromString(""); -#else - return PyString_FromString(""); -#endif - } - - SWIGINTERN PyObject * - swig_varlink_str(swig_varlinkobject *v) { -#if PY_VERSION_HEX >= 0x03000000 - PyObject *str = PyUnicode_InternFromString("("); - PyObject *tail; - PyObject *joined; - swig_globalvar *var; - for (var = v->vars; var; var=var->next) { - tail = PyUnicode_FromString(var->name); - joined = PyUnicode_Concat(str, tail); - Py_DecRef(str); - Py_DecRef(tail); - str = joined; - if (var->next) { - tail = PyUnicode_InternFromString(", "); - joined = PyUnicode_Concat(str, tail); - Py_DecRef(str); - Py_DecRef(tail); - str = joined; - } - } - tail = PyUnicode_InternFromString(")"); - joined = PyUnicode_Concat(str, tail); - Py_DecRef(str); - Py_DecRef(tail); - str = joined; -#else - PyObject *str = PyString_FromString("("); - swig_globalvar *var; - for (var = v->vars; var; var=var->next) { - PyString_ConcatAndDel(&str,PyString_FromString(var->name)); - if (var->next) PyString_ConcatAndDel(&str,PyString_FromString(", ")); - } - PyString_ConcatAndDel(&str,PyString_FromString(")")); -#endif - return str; - } - - SWIGINTERN int - swig_varlink_print(swig_varlinkobject *v, FILE *fp, int SWIGUNUSEDPARM(flags)) { - char *tmp; - PyObject *str = swig_varlink_str(v); - fprintf(fp,"Swig global variables "); - fprintf(fp,"%s\n", tmp = SWIG_Python_str_AsChar(str)); - SWIG_Python_str_DelForPy3(tmp); - Py_DECREF(str); - return 0; - } - - SWIGINTERN void - swig_varlink_dealloc(swig_varlinkobject *v) { - swig_globalvar *var = v->vars; - while (var) { - swig_globalvar *n = var->next; - free(var->name); - free(var); - var = n; - } - } - - SWIGINTERN PyObject * - swig_varlink_getattr(swig_varlinkobject *v, char *n) { - PyObject *res = NULL; - swig_globalvar *var = v->vars; - while (var) { - if (strcmp(var->name,n) == 0) { - res = (*var->get_attr)(); - break; - } - var = var->next; - } - if (res == NULL && !PyErr_Occurred()) { - PyErr_Format(PyExc_AttributeError, "Unknown C global variable '%s'", n); - } - return res; - } - - SWIGINTERN int - swig_varlink_setattr(swig_varlinkobject *v, char *n, PyObject *p) { - int res = 1; - swig_globalvar *var = v->vars; - while (var) { - if (strcmp(var->name,n) == 0) { - res = (*var->set_attr)(p); - break; - } - var = var->next; - } - if (res == 1 && !PyErr_Occurred()) { - PyErr_Format(PyExc_AttributeError, "Unknown C global variable '%s'", n); - } - return res; - } - - SWIGINTERN PyTypeObject* - swig_varlink_type(void) { - static char varlink__doc__[] = "Swig var link object"; - static PyTypeObject varlink_type; - static int type_init = 0; - if (!type_init) { - const PyTypeObject tmp = { -#if PY_VERSION_HEX >= 0x03000000 - PyVarObject_HEAD_INIT(NULL, 0) -#else - PyObject_HEAD_INIT(NULL) - 0, /* ob_size */ -#endif - (char *)"swigvarlink", /* tp_name */ - sizeof(swig_varlinkobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor) swig_varlink_dealloc, /* tp_dealloc */ - (printfunc) swig_varlink_print, /* tp_print */ - (getattrfunc) swig_varlink_getattr, /* tp_getattr */ - (setattrfunc) swig_varlink_setattr, /* tp_setattr */ - 0, /* tp_compare */ - (reprfunc) swig_varlink_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - (reprfunc) swig_varlink_str, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - 0, /* tp_flags */ - varlink__doc__, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ -#if PY_VERSION_HEX >= 0x02020000 - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* tp_iter -> tp_weaklist */ -#endif -#if PY_VERSION_HEX >= 0x02030000 - 0, /* tp_del */ -#endif -#if PY_VERSION_HEX >= 0x02060000 - 0, /* tp_version_tag */ -#endif -#if PY_VERSION_HEX >= 0x03040000 - 0, /* tp_finalize */ -#endif -#ifdef COUNT_ALLOCS - 0, /* tp_allocs */ - 0, /* tp_frees */ - 0, /* tp_maxalloc */ -#if PY_VERSION_HEX >= 0x02050000 - 0, /* tp_prev */ -#endif - 0 /* tp_next */ -#endif - }; - varlink_type = tmp; - type_init = 1; -#if PY_VERSION_HEX < 0x02020000 - varlink_type.ob_type = &PyType_Type; -#else - if (PyType_Ready(&varlink_type) < 0) - return NULL; -#endif - } - return &varlink_type; - } - - /* Create a variable linking object for use later */ - SWIGINTERN PyObject * - SWIG_Python_newvarlink(void) { - swig_varlinkobject *result = PyObject_NEW(swig_varlinkobject, swig_varlink_type()); - if (result) { - result->vars = 0; - } - return ((PyObject*) result); - } - - SWIGINTERN void - SWIG_Python_addvarlink(PyObject *p, char *name, PyObject *(*get_attr)(void), int (*set_attr)(PyObject *p)) { - swig_varlinkobject *v = (swig_varlinkobject *) p; - swig_globalvar *gv = (swig_globalvar *) malloc(sizeof(swig_globalvar)); - if (gv) { - size_t size = strlen(name)+1; - gv->name = (char *)malloc(size); - if (gv->name) { - strncpy(gv->name,name,size); - gv->get_attr = get_attr; - gv->set_attr = set_attr; - gv->next = v->vars; - } - } - v->vars = gv; - } - - SWIGINTERN PyObject * - SWIG_globals(void) { - static PyObject *_SWIG_globals = 0; - if (!_SWIG_globals) _SWIG_globals = SWIG_newvarlink(); - return _SWIG_globals; - } - - /* ----------------------------------------------------------------------------- - * constants/methods manipulation - * ----------------------------------------------------------------------------- */ - - /* Install Constants */ - SWIGINTERN void - SWIG_Python_InstallConstants(PyObject *d, swig_const_info constants[]) { - PyObject *obj = 0; - size_t i; - for (i = 0; constants[i].type; ++i) { - switch(constants[i].type) { - case SWIG_PY_POINTER: - obj = SWIG_InternalNewPointerObj(constants[i].pvalue, *(constants[i]).ptype,0); - break; - case SWIG_PY_BINARY: - obj = SWIG_NewPackedObj(constants[i].pvalue, constants[i].lvalue, *(constants[i].ptype)); - break; - default: - obj = 0; - break; - } - if (obj) { - PyDict_SetItemString(d, constants[i].name, obj); - Py_DECREF(obj); - } - } - } - - /* -----------------------------------------------------------------------------*/ - /* Fix SwigMethods to carry the callback ptrs when needed */ - /* -----------------------------------------------------------------------------*/ - - SWIGINTERN void - SWIG_Python_FixMethods(PyMethodDef *methods, - swig_const_info *const_table, - swig_type_info **types, - swig_type_info **types_initial) { - size_t i; - for (i = 0; methods[i].ml_name; ++i) { - const char *c = methods[i].ml_doc; - if (!c) continue; - c = strstr(c, "swig_ptr: "); - if (c) { - int j; - swig_const_info *ci = 0; - const char *name = c + 10; - for (j = 0; const_table[j].type; ++j) { - if (strncmp(const_table[j].name, name, - strlen(const_table[j].name)) == 0) { - ci = &(const_table[j]); - break; - } - } - if (ci) { - void *ptr = (ci->type == SWIG_PY_POINTER) ? ci->pvalue : 0; - if (ptr) { - size_t shift = (ci->ptype) - types; - swig_type_info *ty = types_initial[shift]; - size_t ldoc = (c - methods[i].ml_doc); - size_t lptr = strlen(ty->name)+2*sizeof(void*)+2; - char *ndoc = (char*)malloc(ldoc + lptr + 10); - if (ndoc) { - char *buff = ndoc; - memcpy(buff, methods[i].ml_doc, ldoc); - buff += ldoc; - memcpy(buff, "swig_ptr: ", 10); - buff += 10; - SWIG_PackVoidPtr(buff, ptr, ty->name, lptr); - methods[i].ml_doc = ndoc; - } - } - } - } - } - } - -#ifdef __cplusplus -} -#endif - -/* -----------------------------------------------------------------------------* - * Partial Init method - * -----------------------------------------------------------------------------*/ - -#ifdef __cplusplus -extern "C" -#endif - -SWIGEXPORT -#if PY_VERSION_HEX >= 0x03000000 -PyObject* -#else -void -#endif -SWIG_init(void) { - PyObject *m, *d, *md; -#if PY_VERSION_HEX >= 0x03000000 - static struct PyModuleDef SWIG_module = { -# if PY_VERSION_HEX >= 0x03020000 - PyModuleDef_HEAD_INIT, -# else - { - PyObject_HEAD_INIT(NULL) - NULL, /* m_init */ - 0, /* m_index */ - NULL, /* m_copy */ - }, -# endif - (char *) SWIG_name, - NULL, - -1, - SwigMethods, - NULL, - NULL, - NULL, - NULL - }; -#endif - -#if defined(SWIGPYTHON_BUILTIN) - static SwigPyClientData SwigPyObject_clientdata = { - 0, 0, 0, 0, 0, 0, 0 - }; - static PyGetSetDef this_getset_def = { - (char *)"this", &SwigPyBuiltin_ThisClosure, NULL, NULL, NULL - }; - static SwigPyGetSet thisown_getset_closure = { - SwigPyObject_own, - SwigPyObject_own - }; - static PyGetSetDef thisown_getset_def = { - (char *)"thisown", SwigPyBuiltin_GetterClosure, SwigPyBuiltin_SetterClosure, NULL, &thisown_getset_closure - }; - PyTypeObject *builtin_pytype; - int builtin_base_count; - swig_type_info *builtin_basetype; - PyObject *tuple; - PyGetSetDescrObject *static_getset; - PyTypeObject *metatype; - PyTypeObject *swigpyobject; - SwigPyClientData *cd; - PyObject *public_interface, *public_symbol; - PyObject *this_descr; - PyObject *thisown_descr; - PyObject *self = 0; - int i; - - (void)builtin_pytype; - (void)builtin_base_count; - (void)builtin_basetype; - (void)tuple; - (void)static_getset; - (void)self; - - /* Metaclass is used to implement static member variables */ - metatype = SwigPyObjectType(); - assert(metatype); -#endif - - /* Fix SwigMethods to carry the callback ptrs when needed */ - SWIG_Python_FixMethods(SwigMethods, swig_const_table, swig_types, swig_type_initial); - -#if PY_VERSION_HEX >= 0x03000000 - m = PyModule_Create(&SWIG_module); -#else - m = Py_InitModule((char *) SWIG_name, SwigMethods); -#endif - - md = d = PyModule_GetDict(m); - (void)md; - - SWIG_InitializeModule(0); - -#ifdef SWIGPYTHON_BUILTIN - swigpyobject = SwigPyObject_TypeOnce(); - - SwigPyObject_stype = SWIG_MangledTypeQuery("_p_SwigPyObject"); - assert(SwigPyObject_stype); - cd = (SwigPyClientData*) SwigPyObject_stype->clientdata; - if (!cd) { - SwigPyObject_stype->clientdata = &SwigPyObject_clientdata; - SwigPyObject_clientdata.pytype = swigpyobject; - } else if (swigpyobject->tp_basicsize != cd->pytype->tp_basicsize) { - PyErr_SetString(PyExc_RuntimeError, "Import error: attempted to load two incompatible swig-generated modules."); -# if PY_VERSION_HEX >= 0x03000000 - return NULL; -# else - return; -# endif - } - - /* All objects have a 'this' attribute */ - this_descr = PyDescr_NewGetSet(SwigPyObject_type(), &this_getset_def); - (void)this_descr; - - /* All objects have a 'thisown' attribute */ - thisown_descr = PyDescr_NewGetSet(SwigPyObject_type(), &thisown_getset_def); - (void)thisown_descr; - - public_interface = PyList_New(0); - public_symbol = 0; - (void)public_symbol; - - PyDict_SetItemString(md, "__all__", public_interface); - Py_DECREF(public_interface); - for (i = 0; SwigMethods[i].ml_name != NULL; ++i) - SwigPyBuiltin_AddPublicSymbol(public_interface, SwigMethods[i].ml_name); - for (i = 0; swig_const_table[i].name != 0; ++i) - SwigPyBuiltin_AddPublicSymbol(public_interface, swig_const_table[i].name); -#endif - - SWIG_InstallConstants(d,swig_const_table); - -#if PY_VERSION_HEX >= 0x03000000 - return m; -#else - return; -#endif -} - diff --git a/libwebp/swig/setup.py b/libwebp/swig/setup.py deleted file mode 100644 index 3a3bfe19..00000000 --- a/libwebp/swig/setup.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/python - -"""distutils script for libwebp python module.""" - -from distutils.core import setup -from distutils.extension import Extension -import os -import shutil -import tempfile - -tmpdir = tempfile.mkdtemp() -package = "com.google.webp" -package_path = os.path.join(tmpdir, *package.split(".")) -os.makedirs(package_path) - -# Create __init_.py files along the package path. -initpy_path = tmpdir -for d in package.split("."): - initpy_path = os.path.join(initpy_path, d) - open(os.path.join(initpy_path, "__init__.py"), "w").close() - -shutil.copy2("libwebp.py", package_path) -setup(name="libwebp", - version="0.0", - description="libwebp python wrapper", - long_description="Provides access to 'simple' libwebp decode interface", - license="BSD", - url="http://developers.google.com/speed/webp", - ext_package=package, - ext_modules=[Extension("_libwebp", - ["libwebp_python_wrap.c"], - libraries=["webp"], - ), - ], - package_dir={"": tmpdir}, - packages=["com", "com.google", "com.google.webp"], - py_modules=[package + ".libwebp"], - ) - -shutil.rmtree(tmpdir) diff --git a/libwebp/tests/README.md b/libwebp/tests/README.md deleted file mode 100644 index 91daba26..00000000 --- a/libwebp/tests/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# Tests - -This is a collection of tests for the libwebp libraries, currently covering -fuzzing through the APIs. Additional test vector coverage can be found at: -https://chromium.googlesource.com/webm/libwebp-test-data - -## Building - -### Fuzzers - -Follow the [build instructions](../doc/building.md) for libwebp, optionally -adding build flags for various sanitizers (e.g., -fsanitize=address). - -`fuzzer/makefile.unix` can then be used to compile the fuzzer targets: - -```shell -$ make -C fuzzer -f makefile.unix -``` diff --git a/libwebp/tests/fuzzer/advanced_api_fuzzer.c b/libwebp/tests/fuzzer/advanced_api_fuzzer.c deleted file mode 100644 index 22c689bb..00000000 --- a/libwebp/tests/fuzzer/advanced_api_fuzzer.c +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright 2018 Google Inc. -// -// 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. -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include - -#include "./fuzz_utils.h" -#include "src/utils/rescaler_utils.h" -#include "src/webp/decode.h" - -int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) { - WebPDecoderConfig config; - if (!WebPInitDecoderConfig(&config)) return 0; - if (WebPGetFeatures(data, size, &config.input) != VP8_STATUS_OK) return 0; - if ((size_t)config.input.width * config.input.height > kFuzzPxLimit) return 0; - - // Using two independent criteria ensures that all combinations of options - // can reach each path at the decoding stage, with meaningful differences. - - const uint8_t value = FuzzHash(data, size); - const float factor = value / 255.f; // 0-1 - - config.options.flip = value & 1; - config.options.bypass_filtering = value & 2; - config.options.no_fancy_upsampling = value & 4; - config.options.use_threads = value & 8; - if (size & 1) { - config.options.use_cropping = 1; - config.options.crop_width = (int)(config.input.width * (1 - factor)); - config.options.crop_height = (int)(config.input.height * (1 - factor)); - config.options.crop_left = config.input.width - config.options.crop_width; - config.options.crop_top = config.input.height - config.options.crop_height; - } - if (size & 2) { - int strength = (int)(factor * 100); - config.options.dithering_strength = strength; - config.options.alpha_dithering_strength = 100 - strength; - } - if (size & 4) { - config.options.use_scaling = 1; - config.options.scaled_width = (int)(config.input.width * factor * 2); - config.options.scaled_height = (int)(config.input.height * factor * 2); - } - -#if defined(WEBP_REDUCE_CSP) - config.output.colorspace = (value & 1) - ? ((value & 2) ? MODE_RGBA : MODE_BGRA) - : ((value & 2) ? MODE_rgbA : MODE_bgrA); -#else - config.output.colorspace = (WEBP_CSP_MODE)(value % MODE_LAST); -#endif // WEBP_REDUCE_CSP - - for (int i = 0; i < 2; ++i) { - if (i == 1) { - // Use the bitstream data to generate extreme ranges for the options. An - // alternative approach would be to use a custom corpus containing webp - // files prepended with sizeof(config.options) zeroes to allow the fuzzer - // to modify these independently. - const int data_offset = 50; - if (data_offset + sizeof(config.options) >= size) break; - memcpy(&config.options, data + data_offset, sizeof(config.options)); - - // Skip easily avoidable out-of-memory fuzzing errors. - if (config.options.use_scaling) { - int scaled_width = config.options.scaled_width; - int scaled_height = config.options.scaled_height; - if (WebPRescalerGetScaledDimensions(config.input.width, - config.input.height, &scaled_width, - &scaled_height)) { - size_t fuzz_px_limit = kFuzzPxLimit; - if (scaled_width != config.input.width || - scaled_height != config.input.height) { - // Using the WebPRescalerImport internally can significantly slow - // down the execution. Avoid timeouts due to that. - fuzz_px_limit /= 2; - } - // A big output canvas can lead to out-of-memory and timeout issues, - // but a big internal working buffer can too. Also, rescaling from a - // very wide input image to a very tall canvas can be as slow as - // decoding a huge number of pixels. Avoid timeouts due to these. - const uint64_t max_num_operations = - (uint64_t)Max(scaled_width, config.input.width) * - Max(scaled_height, config.input.height); - if (max_num_operations > fuzz_px_limit) { - break; - } - } - } - } - if (size % 3) { - // Decodes incrementally in chunks of increasing size. - WebPIDecoder* idec = WebPIDecode(NULL, 0, &config); - if (!idec) return 0; - VP8StatusCode status; - if (size & 8) { - size_t available_size = value + 1; - while (1) { - if (available_size > size) available_size = size; - status = WebPIUpdate(idec, data, available_size); - if (status != VP8_STATUS_SUSPENDED || available_size == size) break; - available_size *= 2; - } - } else { - // WebPIAppend expects new data and its size with each call. - // Implemented here by simply advancing the pointer into data. - const uint8_t* new_data = data; - size_t new_size = value + 1; - while (1) { - if (new_data + new_size > data + size) { - new_size = data + size - new_data; - } - status = WebPIAppend(idec, new_data, new_size); - if (status != VP8_STATUS_SUSPENDED || new_size == 0) break; - new_data += new_size; - new_size *= 2; - } - } - WebPIDelete(idec); - } else { - (void)WebPDecode(data, size, &config); - } - - WebPFreeDecBuffer(&config.output); - } - return 0; -} diff --git a/libwebp/tests/fuzzer/animation_api_fuzzer.c b/libwebp/tests/fuzzer/animation_api_fuzzer.c deleted file mode 100644 index 187ed24e..00000000 --- a/libwebp/tests/fuzzer/animation_api_fuzzer.c +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2018 Google Inc. -// -// 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. -// -//////////////////////////////////////////////////////////////////////////////// - -#include "./fuzz_utils.h" -#include "src/webp/decode.h" -#include "src/webp/demux.h" -#include "src/webp/mux_types.h" - -int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) { - WebPData webp_data; - WebPDataInit(&webp_data); - webp_data.size = size; - webp_data.bytes = data; - - // WebPAnimDecoderNew uses WebPDemux internally to calloc canvas size. - WebPDemuxer* const demux = WebPDemux(&webp_data); - if (!demux) return 0; - const uint32_t cw = WebPDemuxGetI(demux, WEBP_FF_CANVAS_WIDTH); - const uint32_t ch = WebPDemuxGetI(demux, WEBP_FF_CANVAS_HEIGHT); - if ((size_t)cw * ch > kFuzzPxLimit) { - WebPDemuxDelete(demux); - return 0; - } - - // In addition to canvas size, check each frame separately. - WebPIterator iter; - for (int i = 0; i < kFuzzFrameLimit; i++) { - if (!WebPDemuxGetFrame(demux, i + 1, &iter)) break; - int w, h; - if (WebPGetInfo(iter.fragment.bytes, iter.fragment.size, &w, &h)) { - if ((size_t)w * h > kFuzzPxLimit) { // image size of the frame payload - WebPDemuxReleaseIterator(&iter); - WebPDemuxDelete(demux); - return 0; - } - } - } - - WebPDemuxReleaseIterator(&iter); - WebPDemuxDelete(demux); - - WebPAnimDecoderOptions dec_options; - if (!WebPAnimDecoderOptionsInit(&dec_options)) return 0; - - dec_options.use_threads = size & 1; - // Animations only support 4 (of 12) modes. - dec_options.color_mode = (WEBP_CSP_MODE)(size % MODE_LAST); - if (dec_options.color_mode != MODE_BGRA && - dec_options.color_mode != MODE_rgbA && - dec_options.color_mode != MODE_bgrA) { - dec_options.color_mode = MODE_RGBA; - } - - WebPAnimDecoder* dec = WebPAnimDecoderNew(&webp_data, &dec_options); - if (!dec) return 0; - - for (int i = 0; i < kFuzzFrameLimit; i++) { - uint8_t* buf; - int timestamp; - if (!WebPAnimDecoderGetNext(dec, &buf, ×tamp)) break; - } - - WebPAnimDecoderDelete(dec); - return 0; -} diff --git a/libwebp/tests/fuzzer/animdecoder_fuzzer.cc b/libwebp/tests/fuzzer/animdecoder_fuzzer.cc deleted file mode 100644 index c3ea4758..00000000 --- a/libwebp/tests/fuzzer/animdecoder_fuzzer.cc +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2020 Google Inc. -// -// 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. -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include - -#include "imageio/imageio_util.h" -#include "src/webp/decode.h" -#include "src/webp/demux.h" -#include "src/webp/mux_types.h" - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - // WebPAnimDecoderGetInfo() is too late to check the canvas size as - // WebPAnimDecoderNew() will handle the allocations. - const size_t kMaxNumBytes = 2684354560; // RSS (resident set size) limit. - const size_t kMaxNumPixels = kMaxNumBytes / 4; // At most ARGB. - const size_t kMaxNumPixelsSafe = kMaxNumPixels / 2; // Allow one buffer copy. - WebPBitstreamFeatures features; - if (WebPGetFeatures(data, size, &features) == VP8_STATUS_OK) { - if (!ImgIoUtilCheckSizeArgumentsOverflow(features.width * 4, - features.height) || - static_cast(features.width) * features.height > - kMaxNumPixelsSafe) { - return 0; - } - } - - // decode everything as an animation - WebPData webp_data = {data, size}; - WebPAnimDecoder* const dec = WebPAnimDecoderNew(&webp_data, nullptr); - if (dec == nullptr) return 0; - - WebPAnimInfo info; - if (!WebPAnimDecoderGetInfo(dec, &info)) goto End; - if (!ImgIoUtilCheckSizeArgumentsOverflow(info.canvas_width * 4, - info.canvas_height)) { - goto End; - } - - while (WebPAnimDecoderHasMoreFrames(dec)) { - uint8_t* buf; - int timestamp; - if (!WebPAnimDecoderGetNext(dec, &buf, ×tamp)) break; - } -End: - WebPAnimDecoderDelete(dec); - return 0; -} diff --git a/libwebp/tests/fuzzer/animencoder_fuzzer.cc b/libwebp/tests/fuzzer/animencoder_fuzzer.cc deleted file mode 100644 index ef6ec1e4..00000000 --- a/libwebp/tests/fuzzer/animencoder_fuzzer.cc +++ /dev/null @@ -1,188 +0,0 @@ -// Copyright 2018 Google Inc. -// -// 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. -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include - -#include "./fuzz_utils.h" -#include "src/webp/encode.h" -#include "src/webp/mux.h" - -namespace { - -const VP8CPUInfo default_VP8GetCPUInfo = VP8GetCPUInfo; - -int AddFrame(WebPAnimEncoder** const enc, - const WebPAnimEncoderOptions& anim_config, int* const width, - int* const height, int timestamp_ms, const uint8_t data[], - size_t size, uint32_t* const bit_pos) { - if (enc == nullptr || width == nullptr || height == nullptr) { - fprintf(stderr, "NULL parameters.\n"); - if (enc != nullptr) WebPAnimEncoderDelete(*enc); - abort(); - } - - // Init the source picture. - WebPPicture pic; - if (!WebPPictureInit(&pic)) { - fprintf(stderr, "WebPPictureInit failed.\n"); - WebPAnimEncoderDelete(*enc); - abort(); - } - pic.use_argb = Extract(1, data, size, bit_pos); - - // Read the source picture. - if (!ExtractSourcePicture(&pic, data, size, bit_pos)) { - const WebPEncodingError error_code = pic.error_code; - WebPAnimEncoderDelete(*enc); - WebPPictureFree(&pic); - if (error_code == VP8_ENC_ERROR_OUT_OF_MEMORY) return 0; - fprintf(stderr, "Can't read input image. Error code: %d\n", error_code); - abort(); - } - - // Crop and scale. - if (*enc == nullptr) { // First frame will set canvas width and height. - if (!ExtractAndCropOrScale(&pic, data, size, bit_pos)) { - const WebPEncodingError error_code = pic.error_code; - WebPPictureFree(&pic); - if (error_code == VP8_ENC_ERROR_OUT_OF_MEMORY) return 0; - fprintf(stderr, "ExtractAndCropOrScale failed. Error code: %d\n", - error_code); - abort(); - } - } else { // Other frames will be resized to the first frame's dimensions. - if (!WebPPictureRescale(&pic, *width, *height)) { - const WebPEncodingError error_code = pic.error_code; - WebPAnimEncoderDelete(*enc); - WebPPictureFree(&pic); - if (error_code == VP8_ENC_ERROR_OUT_OF_MEMORY) return 0; - fprintf(stderr, - "WebPPictureRescale failed. Size: %d,%d. Error code: %d\n", - *width, *height, error_code); - abort(); - } - } - - // Create encoder if it doesn't exist. - if (*enc == nullptr) { - *width = pic.width; - *height = pic.height; - *enc = WebPAnimEncoderNew(*width, *height, &anim_config); - if (*enc == nullptr) { - WebPPictureFree(&pic); - return 0; - } - } - - // Create frame encoding config. - WebPConfig config; - if (!ExtractWebPConfig(&config, data, size, bit_pos)) { - fprintf(stderr, "ExtractWebPConfig failed.\n"); - WebPAnimEncoderDelete(*enc); - WebPPictureFree(&pic); - abort(); - } - // Skip slow settings on big images, it's likely to timeout. - if (pic.width * pic.height > 32 * 32) { - config.method = (config.method > 4) ? 4 : config.method; - config.quality = (config.quality > 99.0f) ? 99.0f : config.quality; - config.alpha_quality = - (config.alpha_quality > 99) ? 99 : config.alpha_quality; - } - - // Encode. - if (!WebPAnimEncoderAdd(*enc, &pic, timestamp_ms, &config)) { - const WebPEncodingError error_code = pic.error_code; - WebPAnimEncoderDelete(*enc); - WebPPictureFree(&pic); - // Tolerate failures when running under the nallocfuzz engine as - // WebPAnimEncoderAdd() may fail due to memory allocation errors outside of - // the encoder; in muxer functions that return booleans for instance. - if (error_code == VP8_ENC_ERROR_OUT_OF_MEMORY || - error_code == VP8_ENC_ERROR_BAD_WRITE || - getenv("NALLOC_FUZZ_VERSION") != nullptr) { - return 0; - } - fprintf(stderr, "WebPEncode failed. Error code: %d\n", error_code); - abort(); - } - - WebPPictureFree(&pic); - return 1; -} - -} // namespace - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) { - WebPAnimEncoder* enc = nullptr; - int width = 0, height = 0, timestamp_ms = 0; - uint32_t bit_pos = 0; - - ExtractAndDisableOptimizations(default_VP8GetCPUInfo, data, size, &bit_pos); - - // Extract a configuration from the packed bits. - WebPAnimEncoderOptions anim_config; - if (!WebPAnimEncoderOptionsInit(&anim_config)) { - fprintf(stderr, "WebPAnimEncoderOptionsInit failed.\n"); - abort(); - } - anim_config.minimize_size = Extract(1, data, size, &bit_pos); - anim_config.kmax = Extract(15, data, size, &bit_pos); - const int min_kmin = (anim_config.kmax > 1) ? (anim_config.kmax / 2) : 0; - const int max_kmin = (anim_config.kmax > 1) ? (anim_config.kmax - 1) : 0; - anim_config.kmin = - min_kmin + Extract((uint32_t)(max_kmin - min_kmin), data, size, &bit_pos); - anim_config.allow_mixed = Extract(1, data, size, &bit_pos); - anim_config.verbose = 0; - - const int nb_frames = 1 + Extract(15, data, size, &bit_pos); - - // For each frame. - for (int i = 0; i < nb_frames; ++i) { - if (!AddFrame(&enc, anim_config, &width, &height, timestamp_ms, data, size, - &bit_pos)) { - return 0; - } - - timestamp_ms += (1 << (2 + Extract(15, data, size, &bit_pos))) + - Extract(1, data, size, &bit_pos); // [1..131073], arbitrary - } - - // Assemble. - if (!WebPAnimEncoderAdd(enc, nullptr, timestamp_ms, nullptr)) { - fprintf(stderr, "Last WebPAnimEncoderAdd failed: %s.\n", - WebPAnimEncoderGetError(enc)); - WebPAnimEncoderDelete(enc); - abort(); - } - WebPData webp_data; - WebPDataInit(&webp_data); - // Tolerate failures when running under the nallocfuzz engine as allocations - // during assembly may fail. - if (!WebPAnimEncoderAssemble(enc, &webp_data) && - getenv("NALLOC_FUZZ_VERSION") == nullptr) { - fprintf(stderr, "WebPAnimEncoderAssemble failed: %s.\n", - WebPAnimEncoderGetError(enc)); - WebPAnimEncoderDelete(enc); - WebPDataClear(&webp_data); - abort(); - } - - WebPAnimEncoderDelete(enc); - WebPDataClear(&webp_data); - return 0; -} diff --git a/libwebp/tests/fuzzer/enc_dec_fuzzer.cc b/libwebp/tests/fuzzer/enc_dec_fuzzer.cc deleted file mode 100644 index c5d46ae0..00000000 --- a/libwebp/tests/fuzzer/enc_dec_fuzzer.cc +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2018 Google Inc. -// -// 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. -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include - -#include "./fuzz_utils.h" -#include "src/webp/decode.h" -#include "src/webp/encode.h" - -namespace { - -const VP8CPUInfo default_VP8GetCPUInfo = VP8GetCPUInfo; - -} // namespace - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) { - uint32_t bit_pos = 0; - - ExtractAndDisableOptimizations(default_VP8GetCPUInfo, data, size, &bit_pos); - - // Init the source picture. - WebPPicture pic; - if (!WebPPictureInit(&pic)) { - fprintf(stderr, "WebPPictureInit failed.\n"); - abort(); - } - pic.use_argb = Extract(1, data, size, &bit_pos); - - // Read the source picture. - if (!ExtractSourcePicture(&pic, data, size, &bit_pos)) { - const WebPEncodingError error_code = pic.error_code; - WebPPictureFree(&pic); - if (error_code == VP8_ENC_ERROR_OUT_OF_MEMORY) return 0; - fprintf(stderr, "Can't read input image. Error code: %d\n", error_code); - abort(); - } - - // Crop and scale. - if (!ExtractAndCropOrScale(&pic, data, size, &bit_pos)) { - const WebPEncodingError error_code = pic.error_code; - WebPPictureFree(&pic); - if (error_code == VP8_ENC_ERROR_OUT_OF_MEMORY) return 0; - fprintf(stderr, "ExtractAndCropOrScale failed. Error code: %d\n", - error_code); - abort(); - } - - // Extract a configuration from the packed bits. - WebPConfig config; - if (!ExtractWebPConfig(&config, data, size, &bit_pos)) { - fprintf(stderr, "ExtractWebPConfig failed.\n"); - abort(); - } - // Skip slow settings on big images, it's likely to timeout. - if (pic.width * pic.height > 32 * 32) { - if (config.lossless) { - if (config.quality > 99.0f && config.method >= 5) { - config.quality = 99.0f; - config.method = 5; - } - } else { - if (config.quality > 99.0f && config.method == 6) { - config.quality = 99.0f; - } - } - if (config.alpha_quality == 100 && config.method == 6) { - config.alpha_quality = 99; - } - } - - // Encode. - WebPMemoryWriter memory_writer; - WebPMemoryWriterInit(&memory_writer); - pic.writer = WebPMemoryWrite; - pic.custom_ptr = &memory_writer; - if (!WebPEncode(&config, &pic)) { - const WebPEncodingError error_code = pic.error_code; - WebPMemoryWriterClear(&memory_writer); - WebPPictureFree(&pic); - if (error_code == VP8_ENC_ERROR_OUT_OF_MEMORY || - error_code == VP8_ENC_ERROR_BAD_WRITE) { - return 0; - } - fprintf(stderr, "WebPEncode failed. Error code: %d\n", error_code); - abort(); - } - - // Try decoding the result. - const uint8_t* const out_data = memory_writer.mem; - const size_t out_size = memory_writer.size; - WebPDecoderConfig dec_config; - if (!WebPInitDecoderConfig(&dec_config)) { - fprintf(stderr, "WebPInitDecoderConfig failed.\n"); - WebPMemoryWriterClear(&memory_writer); - WebPPictureFree(&pic); - abort(); - } - - dec_config.output.colorspace = MODE_BGRA; - const VP8StatusCode status = WebPDecode(out_data, out_size, &dec_config); - if ((status != VP8_STATUS_OK && status != VP8_STATUS_OUT_OF_MEMORY && - status != VP8_STATUS_USER_ABORT) || - (status == VP8_STATUS_OK && (dec_config.output.width != pic.width || - dec_config.output.height != pic.height))) { - fprintf(stderr, "WebPDecode failed. status: %d.\n", status); - WebPFreeDecBuffer(&dec_config.output); - WebPMemoryWriterClear(&memory_writer); - WebPPictureFree(&pic); - abort(); - } - - if (status == VP8_STATUS_OK) { - const uint8_t* const rgba = dec_config.output.u.RGBA.rgba; - const int w = dec_config.output.width; - const int h = dec_config.output.height; - - // Compare the results if exact encoding. - if (pic.use_argb && config.lossless && config.near_lossless == 100) { - const uint32_t* src1 = (const uint32_t*)rgba; - const uint32_t* src2 = pic.argb; - for (int y = 0; y < h; ++y, src1 += w, src2 += pic.argb_stride) { - for (int x = 0; x < w; ++x) { - uint32_t v1 = src1[x], v2 = src2[x]; - if (!config.exact) { - if ((v1 & 0xff000000u) == 0 || (v2 & 0xff000000u) == 0) { - // Only keep alpha for comparison of fully transparent area. - v1 &= 0xff000000u; - v2 &= 0xff000000u; - } - } - if (v1 != v2) { - fprintf(stderr, "Lossless compression failed pixel-exactness.\n"); - WebPFreeDecBuffer(&dec_config.output); - WebPMemoryWriterClear(&memory_writer); - WebPPictureFree(&pic); - abort(); - } - } - } - } - } - - WebPFreeDecBuffer(&dec_config.output); - WebPMemoryWriterClear(&memory_writer); - WebPPictureFree(&pic); - return 0; -} diff --git a/libwebp/tests/fuzzer/fuzz.dict b/libwebp/tests/fuzzer/fuzz.dict deleted file mode 100644 index 627c72e7..00000000 --- a/libwebp/tests/fuzzer/fuzz.dict +++ /dev/null @@ -1,17 +0,0 @@ -# https://developers.google.com/speed/webp/docs/riff_container - -# FourCC -"ALPH" -"ANIM" -"ANMF" -"EXIF" -"ICCP" -"RIFF" -"VP8 " -"VP8L" -"VP8X" -"WEBP" -"XMP " - -# VP8 signature -"\x9D\x01\x2A" diff --git a/libwebp/tests/fuzzer/fuzz_utils.h b/libwebp/tests/fuzzer/fuzz_utils.h deleted file mode 100644 index c3fc366d..00000000 --- a/libwebp/tests/fuzzer/fuzz_utils.h +++ /dev/null @@ -1,223 +0,0 @@ -// Copyright 2018 Google Inc. -// -// 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. -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef WEBP_TESTS_FUZZER_FUZZ_UTILS_H_ -#define WEBP_TESTS_FUZZER_FUZZ_UTILS_H_ - -#include -#include - -#include "./img_alpha.h" -#include "./img_grid.h" -#include "./img_peak.h" -#include "src/dsp/dsp.h" -#include "src/webp/encode.h" - -//------------------------------------------------------------------------------ -// Arbitrary limits to prevent OOM, timeout, or slow execution. - -// The decoded image size, and for animations additionally the canvas size. -// Enabling some sanitizers slow down runtime significantly. -// Use a very low threshold in this case to avoid timeouts. -#if defined(__SANITIZE_ADDRESS__) // GCC -static const size_t kFuzzPxLimit = 1024 * 1024 / 10; -#elif !defined(__has_feature) // Clang -static const size_t kFuzzPxLimit = 1024 * 1024; -#elif __has_feature(address_sanitizer) || __has_feature(memory_sanitizer) -static const size_t kFuzzPxLimit = 1024 * 1024 / 18; -#else -static const size_t kFuzzPxLimit = 1024 * 1024; -#endif - -// Demuxed or decoded animation frames. -static const int kFuzzFrameLimit = 3; - -// Reads and sums (up to) 128 spread-out bytes. -static WEBP_INLINE uint8_t FuzzHash(const uint8_t* const data, size_t size) { - uint8_t value = 0; - size_t incr = size / 128; - if (!incr) incr = 1; - for (size_t i = 0; i < size; i += incr) value += data[i]; - return value; -} - -//------------------------------------------------------------------------------ -// Extract an integer in [0, max_value]. - -static WEBP_INLINE uint32_t Extract(uint32_t max_value, - const uint8_t data[], size_t size, - uint32_t* const bit_pos) { - uint32_t v = 0; - uint32_t range = 1; - while (*bit_pos < 8 * size && range <= max_value) { - const uint8_t mask = 1u << (*bit_pos & 7); - v = (v << 1) | !!(data[*bit_pos >> 3] & mask); - range <<= 1; - ++*bit_pos; - } - return v % (max_value + 1); -} - -//------------------------------------------------------------------------------ -// Some functions to override VP8GetCPUInfo and disable some optimizations. - -#ifdef __cplusplus -extern "C" VP8CPUInfo VP8GetCPUInfo; -#else -extern VP8CPUInfo VP8GetCPUInfo; -#endif -static VP8CPUInfo GetCPUInfo; - -static WEBP_INLINE int GetCPUInfoNoSSE41(CPUFeature feature) { - if (feature == kSSE4_1 || feature == kAVX) return 0; - return GetCPUInfo(feature); -} - -static WEBP_INLINE int GetCPUInfoNoAVX(CPUFeature feature) { - if (feature == kAVX) return 0; - return GetCPUInfo(feature); -} - -static WEBP_INLINE int GetCPUInfoForceSlowSSSE3(CPUFeature feature) { - if (feature == kSlowSSSE3 && GetCPUInfo(kSSE3)) { - return 1; // we have SSE3 -> force SlowSSSE3 - } - return GetCPUInfo(feature); -} - -static WEBP_INLINE int GetCPUInfoOnlyC(CPUFeature feature) { - (void)feature; - return 0; -} - -static WEBP_INLINE void ExtractAndDisableOptimizations( - VP8CPUInfo default_VP8GetCPUInfo, const uint8_t data[], size_t size, - uint32_t* const bit_pos) { - GetCPUInfo = default_VP8GetCPUInfo; - const VP8CPUInfo kVP8CPUInfos[5] = {GetCPUInfoOnlyC, GetCPUInfoForceSlowSSSE3, - GetCPUInfoNoSSE41, GetCPUInfoNoAVX, - GetCPUInfo}; - int VP8GetCPUInfo_index = Extract(4, data, size, bit_pos); - VP8GetCPUInfo = kVP8CPUInfos[VP8GetCPUInfo_index]; -} - -//------------------------------------------------------------------------------ - -static WEBP_INLINE int ExtractWebPConfig(WebPConfig* const config, - const uint8_t data[], size_t size, - uint32_t* const bit_pos) { - if (config == NULL || !WebPConfigInit(config)) return 0; - config->lossless = Extract(1, data, size, bit_pos); - config->quality = Extract(100, data, size, bit_pos); - config->method = Extract(6, data, size, bit_pos); - config->image_hint = - (WebPImageHint)Extract(WEBP_HINT_LAST - 1, data, size, bit_pos); - config->segments = 1 + Extract(3, data, size, bit_pos); - config->sns_strength = Extract(100, data, size, bit_pos); - config->filter_strength = Extract(100, data, size, bit_pos); - config->filter_sharpness = Extract(7, data, size, bit_pos); - config->filter_type = Extract(1, data, size, bit_pos); - config->autofilter = Extract(1, data, size, bit_pos); - config->alpha_compression = Extract(1, data, size, bit_pos); - config->alpha_filtering = Extract(2, data, size, bit_pos); - config->alpha_quality = Extract(100, data, size, bit_pos); - config->pass = 1 + Extract(9, data, size, bit_pos); - config->show_compressed = 1; - config->preprocessing = Extract(2, data, size, bit_pos); - config->partitions = Extract(3, data, size, bit_pos); - config->partition_limit = 10 * Extract(10, data, size, bit_pos); - config->emulate_jpeg_size = Extract(1, data, size, bit_pos); - config->thread_level = Extract(1, data, size, bit_pos); - config->low_memory = Extract(1, data, size, bit_pos); - config->near_lossless = 20 * Extract(5, data, size, bit_pos); - config->exact = Extract(1, data, size, bit_pos); - config->use_delta_palette = Extract(1, data, size, bit_pos); - config->use_sharp_yuv = Extract(1, data, size, bit_pos); - return WebPValidateConfig(config); -} - -//------------------------------------------------------------------------------ - -static WEBP_INLINE int ExtractSourcePicture(WebPPicture* const pic, - const uint8_t data[], size_t size, - uint32_t* const bit_pos) { - if (pic == NULL) return 0; - - // Pick a source picture. - const uint8_t* kImagesData[] = { - kImgAlphaData, - kImgGridData, - kImgPeakData - }; - const int kImagesWidth[] = { - kImgAlphaWidth, - kImgGridWidth, - kImgPeakWidth - }; - const int kImagesHeight[] = { - kImgAlphaHeight, - kImgGridHeight, - kImgPeakHeight - }; - const size_t kNbImages = sizeof(kImagesData) / sizeof(kImagesData[0]); - const size_t image_index = Extract(kNbImages - 1, data, size, bit_pos); - const uint8_t* const image_data = kImagesData[image_index]; - pic->width = kImagesWidth[image_index]; - pic->height = kImagesHeight[image_index]; - pic->argb_stride = pic->width * 4 * sizeof(uint8_t); - - // Read the bytes. - return WebPPictureImportRGBA(pic, image_data, pic->argb_stride); -} - -//------------------------------------------------------------------------------ - -static WEBP_INLINE int Max(int a, int b) { return ((a < b) ? b : a); } - -static WEBP_INLINE int ExtractAndCropOrScale(WebPPicture* const pic, - const uint8_t data[], size_t size, - uint32_t* const bit_pos) { - if (pic == NULL) return 0; -#if !defined(WEBP_REDUCE_SIZE) - const int alter_input = Extract(1, data, size, bit_pos); - const int crop_or_scale = Extract(1, data, size, bit_pos); - const int width_ratio = 1 + Extract(7, data, size, bit_pos); - const int height_ratio = 1 + Extract(7, data, size, bit_pos); - if (alter_input) { - if (crop_or_scale) { - const uint32_t left_ratio = 1 + Extract(7, data, size, bit_pos); - const uint32_t top_ratio = 1 + Extract(7, data, size, bit_pos); - const int cropped_width = Max(1, pic->width / width_ratio); - const int cropped_height = Max(1, pic->height / height_ratio); - const int cropped_left = (pic->width - cropped_width) / left_ratio; - const int cropped_top = (pic->height - cropped_height) / top_ratio; - return WebPPictureCrop(pic, cropped_left, cropped_top, cropped_width, - cropped_height); - } else { - const int scaled_width = 1 + (pic->width * width_ratio) / 8; - const int scaled_height = 1 + (pic->height * height_ratio) / 8; - return WebPPictureRescale(pic, scaled_width, scaled_height); - } - } -#else // defined(WEBP_REDUCE_SIZE) - (void)data; - (void)size; - (void)bit_pos; -#endif // !defined(WEBP_REDUCE_SIZE) - return 1; -} - -#endif // WEBP_TESTS_FUZZER_FUZZ_UTILS_H_ diff --git a/libwebp/tests/fuzzer/huffman_fuzzer.c b/libwebp/tests/fuzzer/huffman_fuzzer.c deleted file mode 100644 index 03e1fdc4..00000000 --- a/libwebp/tests/fuzzer/huffman_fuzzer.c +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2023 Google Inc. -// -// 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. -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include - -#include "src/dec/vp8li_dec.h" -#include "src/utils/bit_reader_utils.h" -#include "src/utils/huffman_utils.h" -#include "src/utils/utils.h" -#include "src/webp/format_constants.h" - -int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) { - // Number of bits to initialize data. - static const int kColorCacheBitsBits = 4; - // 'num_htree_groups' is contained in the RG channel, hence 16 bits. - static const int kNumHtreeGroupsBits = 16; - if (size * sizeof(*data) < kColorCacheBitsBits + kNumHtreeGroupsBits) { - return 0; - } - - // A non-NULL mapping brings minor changes that are tested by the normal - // fuzzer. - int* const mapping = NULL; - HuffmanTables huffman_tables; - memset(&huffman_tables, 0, sizeof(huffman_tables)); - HTreeGroup* htree_groups = NULL; - - VP8LDecoder* dec = VP8LNew(); - if (dec == NULL) goto Error; - VP8LBitReader* const br = &dec->br_; - VP8LInitBitReader(br, data, size); - - const int color_cache_bits = VP8LReadBits(br, kColorCacheBitsBits); - if (color_cache_bits < 1 || color_cache_bits > MAX_CACHE_BITS) goto Error; - - const int num_htree_groups = VP8LReadBits(br, kNumHtreeGroupsBits); - // 'num_htree_groups' cannot be 0 as it is built from a non-empty image. - if (num_htree_groups == 0) goto Error; - // This variable is only useful when mapping is not NULL. - const int num_htree_groups_max = num_htree_groups; - (void)ReadHuffmanCodesHelper(color_cache_bits, num_htree_groups, - num_htree_groups_max, mapping, dec, - &huffman_tables, &htree_groups); - - Error: - WebPSafeFree(mapping); - VP8LHtreeGroupsFree(htree_groups); - VP8LHuffmanTablesDeallocate(&huffman_tables); - VP8LDelete(dec); - return 0; -} diff --git a/libwebp/tests/fuzzer/img_alpha.h b/libwebp/tests/fuzzer/img_alpha.h deleted file mode 100644 index fac63feb..00000000 --- a/libwebp/tests/fuzzer/img_alpha.h +++ /dev/null @@ -1,381 +0,0 @@ -// Copyright 2018 Google Inc. -// -// 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. -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef WEBP_TESTS_FUZZER_IMG_ALPHA_H_ -#define WEBP_TESTS_FUZZER_IMG_ALPHA_H_ - -#include - -static const int kImgAlphaWidth = 32; -static const int kImgAlphaHeight = 32; - -/*Pixel format: Red: 8 bit, Green: 8 bit, Blue: 8 bit, Fix 0xFF: 8 bit*/ -static const uint8_t kImgAlphaData[] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfd, 0xff, 0xfe, 0xfd, 0xfc, 0xff, - 0xfe, 0xfd, 0xfb, 0xff, 0xfe, 0xfc, 0xfb, 0xff, 0xfe, 0xfc, 0xfa, 0xff, - 0xfe, 0xfc, 0xf9, 0xff, 0xfe, 0xfb, 0xf8, 0xff, 0xfe, 0xfb, 0xf7, 0xff, - 0xfe, 0xfb, 0xf7, 0xff, 0xfe, 0xfa, 0xf6, 0xff, 0xfe, 0xf9, 0xf5, 0xff, - 0xfd, 0xf9, 0xf3, 0xff, 0xfd, 0xf8, 0xf2, 0xff, 0xfd, 0xf7, 0xf1, 0xff, - 0xfc, 0xf7, 0xf0, 0xff, 0xfc, 0xf6, 0xef, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xff, - 0xfe, 0xfe, 0xfd, 0xff, 0xfe, 0xfd, 0xfc, 0xff, 0xfe, 0xfd, 0xfb, 0xff, - 0xfe, 0xfc, 0xfa, 0xff, 0xfe, 0xfc, 0xfa, 0xff, 0xfe, 0xfb, 0xf9, 0xff, - 0xfe, 0xfb, 0xf8, 0xff, 0xfe, 0xfb, 0xf7, 0xff, 0xfe, 0xfa, 0xf7, 0xff, - 0xfe, 0xfa, 0xf5, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xfd, 0xf9, 0xf4, 0xff, - 0xfd, 0xf8, 0xf2, 0xff, 0xfc, 0xf7, 0xf1, 0xff, 0xfc, 0xf7, 0xf0, 0xff, - 0xfc, 0xf7, 0xef, 0xff, 0xfc, 0xf6, 0xee, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfd, 0xff, 0xfe, 0xfd, 0xfd, 0xff, - 0xfe, 0xfd, 0xfc, 0xff, 0xfe, 0xfd, 0xfb, 0xff, 0xfe, 0xfc, 0xfa, 0xff, - 0xfe, 0xfc, 0xfa, 0xff, 0xfe, 0xfc, 0xf9, 0xff, 0xfe, 0xfb, 0xf8, 0xff, - 0xfe, 0xfb, 0xf7, 0xff, 0xfe, 0xfb, 0xf6, 0xff, 0xfe, 0xfa, 0xf5, 0xff, - 0xfe, 0xfa, 0xf5, 0xff, 0xfe, 0xf9, 0xf4, 0xff, 0xfe, 0xf8, 0xf3, 0xff, - 0xfd, 0xf8, 0xf2, 0xff, 0xfc, 0xf7, 0xf1, 0xff, 0xfc, 0xf5, 0xf0, 0xff, - 0xfc, 0xf6, 0xee, 0xff, 0xfc, 0xf5, 0xed, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xfd, 0xfd, 0xff, - 0xfc, 0xfb, 0xfb, 0xff, 0xfd, 0xfc, 0xfc, 0xff, 0xfe, 0xfd, 0xfb, 0xff, - 0xfe, 0xfc, 0xfa, 0xff, 0xfe, 0xfc, 0xfa, 0xff, 0xfe, 0xfc, 0xf9, 0xff, - 0xfe, 0xfb, 0xf8, 0xff, 0xfe, 0xfb, 0xf8, 0xff, 0xfe, 0xfb, 0xf7, 0xff, - 0xfe, 0xfb, 0xf6, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xfe, 0xfa, 0xf5, 0xff, - 0xfe, 0xf9, 0xf4, 0xff, 0xfe, 0xf9, 0xf3, 0xff, 0xfe, 0xf8, 0xf2, 0xff, - 0xfd, 0xf7, 0xf1, 0xff, 0xfc, 0xf6, 0xf0, 0xff, 0xfc, 0xf6, 0xee, 0xff, - 0xfc, 0xf5, 0xec, 0xff, 0xfb, 0xf5, 0xec, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xff, 0xfb, 0xfb, 0xfb, 0xff, - 0xfa, 0xf9, 0xf9, 0xff, 0xf7, 0xf6, 0xf6, 0xff, 0xfd, 0xfc, 0xfa, 0xff, - 0xfe, 0xfc, 0xfa, 0xff, 0xfe, 0xfc, 0xf9, 0xff, 0xfe, 0xfb, 0xf9, 0xff, - 0xfe, 0xfb, 0xf7, 0xff, 0xfe, 0xfb, 0xf7, 0xff, 0xfe, 0xfb, 0xf6, 0xff, - 0xfe, 0xfa, 0xf5, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xfe, 0xfa, 0xf3, 0xff, - 0xfe, 0xfa, 0xf4, 0xfb, 0xfe, 0xf9, 0xf4, 0xeb, 0xfe, 0xfb, 0xf6, 0xdc, - 0xfd, 0xfa, 0xf6, 0xcf, 0xfd, 0xfa, 0xf5, 0xcc, 0xfc, 0xf9, 0xf4, 0xcb, - 0xfd, 0xf8, 0xf3, 0xc7, 0xfc, 0xf8, 0xf2, 0xc7, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xfd, 0xfd, 0xff, - 0xfb, 0xfa, 0xfa, 0xff, 0xf8, 0xf7, 0xf7, 0xff, 0xf6, 0xf4, 0xf4, 0xff, - 0xf7, 0xf5, 0xf5, 0xff, 0xf5, 0xf5, 0xf4, 0xff, 0xf8, 0xf7, 0xf7, 0xff, - 0xfd, 0xfb, 0xf8, 0xff, 0xfe, 0xfb, 0xf8, 0xff, 0xfe, 0xfb, 0xf7, 0xff, - 0xfe, 0xfb, 0xf7, 0xff, 0xfe, 0xfa, 0xf6, 0xff, 0xfe, 0xfa, 0xf5, 0xff, - 0xfe, 0xfa, 0xf4, 0xff, 0xfd, 0xfa, 0xf4, 0xfc, 0xfe, 0xfc, 0xf9, 0xcf, - 0xff, 0xff, 0xff, 0xaf, 0xff, 0xff, 0xff, 0xa8, 0xff, 0xff, 0xff, 0xa4, - 0xff, 0xff, 0xff, 0x9f, 0xff, 0xff, 0xff, 0x9b, 0xff, 0xff, 0xff, 0x94, - 0xff, 0xff, 0xff, 0x90, 0xff, 0xff, 0xff, 0x8b, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xfd, 0xfc, 0xfc, 0xff, 0xfa, 0xf9, 0xf9, 0xff, - 0xf6, 0xf5, 0xf4, 0xff, 0xf5, 0xf3, 0xf3, 0xff, 0xf4, 0xf2, 0xf1, 0xff, - 0xf2, 0xf1, 0xf0, 0xff, 0xf2, 0xf0, 0xf0, 0xff, 0xf0, 0xee, 0xee, 0xff, - 0xf1, 0xf0, 0xef, 0xff, 0xfe, 0xfb, 0xf8, 0xff, 0xfe, 0xfb, 0xf6, 0xff, - 0xfe, 0xfa, 0xf6, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xfe, 0xfb, 0xf4, 0xff, - 0xfe, 0xfb, 0xf5, 0xf3, 0xff, 0xfe, 0xfe, 0xb4, 0xff, 0xff, 0xff, 0xac, - 0xff, 0xff, 0xff, 0xa7, 0xff, 0xff, 0xff, 0xa3, 0xff, 0xff, 0xff, 0x9c, - 0xff, 0xff, 0xff, 0x98, 0xff, 0xff, 0xff, 0x93, 0xff, 0xff, 0xff, 0x8f, - 0xff, 0xff, 0xff, 0x88, 0xff, 0xff, 0xff, 0x84, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xff, - 0xfc, 0xfb, 0xfb, 0xff, 0xf9, 0xf8, 0xf8, 0xff, 0xf6, 0xf5, 0xf4, 0xff, - 0xf3, 0xf1, 0xf1, 0xff, 0xf0, 0xed, 0xed, 0xff, 0xef, 0xec, 0xeb, 0xff, - 0xee, 0xeb, 0xeb, 0xff, 0xf0, 0xee, 0xee, 0xff, 0xea, 0xe7, 0xe7, 0xff, - 0xec, 0xe9, 0xe9, 0xff, 0xf5, 0xf2, 0xf0, 0xff, 0xfe, 0xfb, 0xf6, 0xff, - 0xfe, 0xfb, 0xf5, 0xff, 0xfe, 0xfa, 0xf4, 0xff, 0xfe, 0xfb, 0xf6, 0xeb, - 0xff, 0xff, 0xff, 0xaf, 0xff, 0xff, 0xff, 0xab, 0xff, 0xff, 0xff, 0xa4, - 0xff, 0xff, 0xff, 0xa0, 0xff, 0xff, 0xff, 0x9b, 0xff, 0xff, 0xff, 0x97, - 0xff, 0xff, 0xff, 0x90, 0xff, 0xff, 0xff, 0x8c, 0xff, 0xff, 0xff, 0x87, - 0xff, 0xff, 0xff, 0x83, 0xff, 0xff, 0xff, 0x7c, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xfd, 0xfc, 0xfc, 0xff, 0xfb, 0xfb, 0xfa, 0xff, - 0xf8, 0xf6, 0xf6, 0xff, 0xf4, 0xf3, 0xf2, 0xff, 0xf2, 0xf0, 0xf0, 0xff, - 0xef, 0xec, 0xeb, 0xff, 0xef, 0xec, 0xeb, 0xff, 0xeb, 0xe7, 0xe6, 0xff, - 0xea, 0xe6, 0xe5, 0xff, 0xeb, 0xe8, 0xe8, 0xff, 0xe9, 0xe6, 0xe7, 0xff, - 0xe5, 0xe2, 0xe2, 0xff, 0xed, 0xeb, 0xeb, 0xff, 0xf7, 0xf5, 0xf2, 0xff, - 0xfe, 0xfa, 0xf5, 0xff, 0xfe, 0xfb, 0xf5, 0xf8, 0xff, 0xff, 0xff, 0xac, - 0xff, 0xff, 0xff, 0xa8, 0xff, 0xff, 0xff, 0xa3, 0xff, 0xff, 0xff, 0x9f, - 0xff, 0xff, 0xff, 0x98, 0xff, 0xff, 0xff, 0x94, 0xff, 0xff, 0xff, 0x8f, - 0xff, 0xff, 0xff, 0x8b, 0xff, 0xff, 0xff, 0x84, 0xff, 0xff, 0xff, 0x80, - 0xff, 0xff, 0xff, 0x7c, 0xff, 0xff, 0xff, 0x77, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfc, 0xfc, 0xfc, 0xff, 0xf8, 0xf7, 0xf7, 0xff, 0xf6, 0xf5, 0xf4, 0xff, - 0xf3, 0xf1, 0xf0, 0xff, 0xf1, 0xef, 0xef, 0xff, 0xef, 0xed, 0xec, 0xff, - 0xec, 0xe8, 0xe7, 0xff, 0xe9, 0xe6, 0xe6, 0xff, 0xec, 0xe9, 0xe9, 0xff, - 0xe4, 0xe0, 0xdf, 0xff, 0xec, 0xe9, 0xe9, 0xff, 0xea, 0xe6, 0xe6, 0xff, - 0xe6, 0xe2, 0xe2, 0xff, 0xea, 0xe8, 0xe8, 0xff, 0xec, 0xe8, 0xe7, 0xff, - 0xfc, 0xf9, 0xf4, 0xff, 0xfe, 0xfd, 0xfa, 0xc3, 0xff, 0xff, 0xff, 0xa7, - 0xff, 0xff, 0xff, 0xa0, 0xff, 0xff, 0xff, 0x9c, 0xff, 0xff, 0xff, 0x97, - 0xff, 0xff, 0xff, 0x93, 0xff, 0xff, 0xff, 0x8c, 0xfe, 0xfc, 0xf9, 0xa3, - 0xfc, 0xfb, 0xf5, 0xb0, 0xfc, 0xf9, 0xf1, 0xbb, 0xfb, 0xf8, 0xf1, 0xb8, - 0xfb, 0xf8, 0xef, 0xb4, 0xfb, 0xf9, 0xf2, 0xa4, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfc, 0xfc, 0xfc, 0xff, - 0xf8, 0xf7, 0xf7, 0xff, 0xf5, 0xf3, 0xf3, 0xff, 0xf1, 0xef, 0xef, 0xff, - 0xef, 0xec, 0xeb, 0xff, 0xeb, 0xe7, 0xe7, 0xff, 0xea, 0xe7, 0xe6, 0xff, - 0xe7, 0xe3, 0xe2, 0xff, 0xe4, 0xdf, 0xde, 0xff, 0xe6, 0xe2, 0xe2, 0xff, - 0xe4, 0xe1, 0xe0, 0xff, 0xe6, 0xe3, 0xe2, 0xff, 0xe0, 0xdc, 0xdc, 0xff, - 0xe3, 0xdf, 0xdf, 0xff, 0xe8, 0xe5, 0xe5, 0xff, 0xe4, 0xe1, 0xe2, 0xff, - 0xec, 0xe8, 0xe5, 0xf8, 0xff, 0xff, 0xff, 0xa4, 0xff, 0xff, 0xff, 0xa0, - 0xff, 0xff, 0xff, 0x9b, 0xff, 0xff, 0xff, 0x97, 0xff, 0xff, 0xff, 0x90, - 0xfe, 0xfe, 0xfb, 0x9c, 0xfc, 0xf9, 0xef, 0xf7, 0xfc, 0xf8, 0xed, 0xff, - 0xfc, 0xf7, 0xeb, 0xff, 0xfb, 0xf7, 0xeb, 0xff, 0xfa, 0xf6, 0xe9, 0xff, - 0xfa, 0xf5, 0xe7, 0xff, 0xf8, 0xf4, 0xe5, 0xff, - 0xfd, 0xfd, 0xfd, 0xff, 0xfa, 0xfa, 0xfa, 0xff, 0xfc, 0xfc, 0xfc, 0xff, - 0xf8, 0xf7, 0xf7, 0xff, 0xf1, 0xef, 0xee, 0xff, 0xed, 0xea, 0xe9, 0xff, - 0xea, 0xe6, 0xe5, 0xff, 0xe7, 0xe3, 0xe2, 0xff, 0xe4, 0xe0, 0xdf, 0xff, - 0xe3, 0xde, 0xdd, 0xff, 0xe2, 0xde, 0xdd, 0xff, 0xe5, 0xe1, 0xe1, 0xff, - 0xde, 0xda, 0xda, 0xff, 0xe0, 0xdd, 0xdc, 0xff, 0xe1, 0xdd, 0xdd, 0xff, - 0xe3, 0xe0, 0xdf, 0xff, 0xe4, 0xe1, 0xe1, 0xff, 0xe3, 0xe0, 0xe0, 0xff, - 0xec, 0xea, 0xea, 0xe8, 0xff, 0xff, 0xff, 0x9f, 0xff, 0xff, 0xff, 0x98, - 0xff, 0xff, 0xff, 0x93, 0xff, 0xff, 0xff, 0x8f, 0xfe, 0xfe, 0xfe, 0x8c, - 0xfd, 0xfb, 0xef, 0xff, 0xfd, 0xfb, 0xed, 0xff, 0xfd, 0xf8, 0xec, 0xff, - 0xfc, 0xf8, 0xeb, 0xff, 0xfc, 0xf7, 0xea, 0xff, 0xfb, 0xf6, 0xe9, 0xff, - 0xfa, 0xf6, 0xe7, 0xff, 0xfa, 0xf5, 0xe5, 0xff, - 0xfa, 0xfa, 0xfa, 0xff, 0xf8, 0xf7, 0xf8, 0xff, 0xf6, 0xf6, 0xf6, 0xff, - 0xf1, 0xf0, 0xf0, 0xff, 0xed, 0xec, 0xec, 0xff, 0xe9, 0xe6, 0xe5, 0xff, - 0xe6, 0xe1, 0xe0, 0xff, 0xe2, 0xde, 0xdc, 0xff, 0xe0, 0xda, 0xd8, 0xff, - 0xdd, 0xd7, 0xd5, 0xff, 0xde, 0xda, 0xd9, 0xff, 0xde, 0xda, 0xda, 0xff, - 0xdc, 0xd7, 0xd8, 0xff, 0xdf, 0xdc, 0xdc, 0xff, 0xe5, 0xe3, 0xe4, 0xff, - 0xe1, 0xde, 0xde, 0xff, 0xde, 0xdc, 0xdc, 0xff, 0xe9, 0xe7, 0xe8, 0xff, - 0xe8, 0xe7, 0xe6, 0xe7, 0xff, 0xff, 0xff, 0x97, 0xff, 0xff, 0xff, 0x93, - 0xff, 0xff, 0xff, 0x8c, 0xff, 0xff, 0xff, 0x88, 0xfe, 0xfe, 0xfa, 0x9b, - 0xfc, 0xfb, 0xee, 0xff, 0xfc, 0xfa, 0xed, 0xff, 0xfb, 0xfa, 0xeb, 0xff, - 0xfb, 0xf8, 0xeb, 0xff, 0xfb, 0xf7, 0xea, 0xff, 0xfa, 0xf6, 0xe8, 0xff, - 0xf8, 0xf6, 0xe6, 0xff, 0xf7, 0xf5, 0xe3, 0xff, - 0xf9, 0xf9, 0xf9, 0xff, 0xf7, 0xf6, 0xf7, 0xff, 0xf5, 0xf4, 0xf4, 0xff, - 0xf0, 0xee, 0xef, 0xff, 0xe8, 0xe7, 0xe7, 0xff, 0xe7, 0xe4, 0xe3, 0xff, - 0xe2, 0xdd, 0xdb, 0xff, 0xdf, 0xd9, 0xd7, 0xff, 0xdc, 0xd6, 0xd4, 0xff, - 0xd8, 0xd2, 0xcf, 0xff, 0xd8, 0xd2, 0xd1, 0xff, 0xe0, 0xdc, 0xdc, 0xff, - 0xdb, 0xd7, 0xd7, 0xff, 0xdb, 0xd7, 0xd7, 0xff, 0xe7, 0xe5, 0xe5, 0xff, - 0xde, 0xda, 0xdb, 0xff, 0xdb, 0xd8, 0xd9, 0xff, 0xe0, 0xde, 0xde, 0xff, - 0xed, 0xeb, 0xec, 0xe4, 0xff, 0xff, 0xff, 0x8f, 0xff, 0xff, 0xff, 0x8b, - 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0x80, 0xfe, 0xfe, 0xfa, 0x94, - 0xfd, 0xfb, 0xee, 0xff, 0xfd, 0xfb, 0xed, 0xff, 0xfc, 0xfb, 0xec, 0xff, - 0xfc, 0xfa, 0xea, 0xff, 0xf8, 0xf7, 0xe9, 0xff, 0xf8, 0xf6, 0xe7, 0xff, - 0xf7, 0xf7, 0xe5, 0xff, 0xf7, 0xf5, 0xe3, 0xff, - 0xf9, 0xf9, 0xf9, 0xff, 0xf5, 0xf4, 0xf4, 0xff, 0xf2, 0xf2, 0xf2, 0xff, - 0xe9, 0xe6, 0xe6, 0xff, 0xe9, 0xe7, 0xe6, 0xff, 0xe9, 0xe7, 0xe7, 0xff, - 0xe0, 0xdb, 0xda, 0xff, 0xda, 0xd3, 0xd2, 0xff, 0xd6, 0xd0, 0xce, 0xff, - 0xd4, 0xcd, 0xcb, 0xff, 0xd0, 0xc8, 0xc7, 0xff, 0xd7, 0xd2, 0xd1, 0xff, - 0xd8, 0xd3, 0xd3, 0xff, 0xd4, 0xd1, 0xd1, 0xff, 0xe6, 0xe3, 0xe2, 0xff, - 0xdd, 0xda, 0xda, 0xff, 0xe3, 0xe1, 0xe1, 0xff, 0xe0, 0xde, 0xde, 0xff, - 0xe7, 0xe5, 0xe5, 0xe3, 0xff, 0xff, 0xff, 0x88, 0xff, 0xff, 0xff, 0x84, - 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7b, 0xfe, 0xfe, 0xfb, 0x88, - 0xfc, 0xfc, 0xef, 0xff, 0xfb, 0xfc, 0xee, 0xff, 0xfb, 0xfa, 0xeb, 0xff, - 0xfa, 0xfa, 0xea, 0xff, 0xf9, 0xf9, 0xe7, 0xff, 0xf7, 0xf7, 0xe6, 0xff, - 0xf6, 0xf5, 0xe5, 0xff, 0xf7, 0xf5, 0xe3, 0xff, - 0xf8, 0xf7, 0xf7, 0xff, 0xf4, 0xf4, 0xf4, 0xff, 0xf2, 0xf2, 0xf1, 0xff, - 0xe8, 0xe6, 0xe6, 0xff, 0xe4, 0xe1, 0xe1, 0xff, 0xdd, 0xda, 0xda, 0xff, - 0xe7, 0xe3, 0xe3, 0xff, 0xd6, 0xcf, 0xcd, 0xff, 0xd4, 0xcc, 0xca, 0xff, - 0xcf, 0xc7, 0xc5, 0xff, 0xcc, 0xc3, 0xc1, 0xff, 0xd3, 0xce, 0xcc, 0xff, - 0xd9, 0xd4, 0xd4, 0xff, 0xda, 0xd6, 0xd6, 0xff, 0xe3, 0xe1, 0xe0, 0xff, - 0xdb, 0xd8, 0xd7, 0xff, 0xe4, 0xe2, 0xe2, 0xff, 0xe1, 0xde, 0xdf, 0xff, - 0xe3, 0xe1, 0xe1, 0xf0, 0xff, 0xff, 0xff, 0x83, 0xff, 0xff, 0xff, 0x7c, - 0xff, 0xff, 0xff, 0x78, 0xff, 0xff, 0xff, 0x73, 0xff, 0xff, 0xff, 0x6f, - 0xfb, 0xfc, 0xed, 0xff, 0xfa, 0xfb, 0xed, 0xff, 0xfb, 0xfa, 0xeb, 0xff, - 0xfa, 0xf9, 0xe9, 0xff, 0xfa, 0xf9, 0xe7, 0xff, 0xf8, 0xf9, 0xe7, 0xff, - 0xf7, 0xf5, 0xe3, 0xff, 0xf7, 0xf4, 0xe1, 0xff, - 0xf2, 0xf2, 0xf2, 0xff, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0xf0, 0xef, 0xff, - 0xe5, 0xe3, 0xe3, 0xff, 0xdd, 0xd9, 0xd9, 0xff, 0xdf, 0xdc, 0xdc, 0xff, - 0xe6, 0xe3, 0xe3, 0xff, 0xe1, 0xda, 0xdb, 0xff, 0xd2, 0xca, 0xc7, 0xff, - 0xca, 0xc2, 0xc0, 0xff, 0xc7, 0xbe, 0xbc, 0xff, 0xc8, 0xc2, 0xc0, 0xff, - 0xd2, 0xcf, 0xce, 0xff, 0xd5, 0xcf, 0xd0, 0xff, 0xd5, 0xd1, 0xd1, 0xff, - 0xda, 0xd6, 0xd7, 0xff, 0xde, 0xdc, 0xdd, 0xff, 0xde, 0xdd, 0xdc, 0xff, - 0xe2, 0xe0, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x7c, 0xff, 0xff, 0xff, 0x77, - 0xff, 0xff, 0xff, 0x70, 0xff, 0xff, 0xff, 0x6c, 0xff, 0xff, 0xff, 0x67, - 0xfa, 0xfd, 0xed, 0xf8, 0xf9, 0xfc, 0xeb, 0xff, 0xf9, 0xfb, 0xea, 0xff, - 0xf8, 0xf9, 0xe8, 0xff, 0xf7, 0xf9, 0xe6, 0xff, 0xf7, 0xf8, 0xe6, 0xff, - 0xf6, 0xf5, 0xe4, 0xff, 0xf6, 0xf4, 0xe1, 0xff, - 0xe7, 0xe7, 0xe7, 0xff, 0xe3, 0xe4, 0xe3, 0xff, 0xe1, 0xe2, 0xe2, 0xff, - 0xe4, 0xe4, 0xe4, 0xff, 0xd7, 0xd6, 0xd5, 0xff, 0xd5, 0xd4, 0xd4, 0xff, - 0xdd, 0xdc, 0xdc, 0xff, 0xdc, 0xda, 0xda, 0xff, 0xd0, 0xc9, 0xc9, 0xff, - 0xc9, 0xbf, 0xbe, 0xff, 0xc2, 0xba, 0xb8, 0xff, 0xc0, 0xb8, 0xb6, 0xff, - 0xcc, 0xc7, 0xc7, 0xff, 0xd2, 0xcd, 0xcd, 0xff, 0xd2, 0xce, 0xcf, 0xff, - 0xd1, 0xcc, 0xcd, 0xff, 0xdf, 0xde, 0xde, 0xff, 0xe7, 0xe6, 0xe6, 0xff, - 0xe4, 0xe3, 0xe3, 0xff, 0xfd, 0xfd, 0xfd, 0x78, 0xff, 0xff, 0xff, 0x70, - 0xff, 0xff, 0xff, 0x6b, 0xff, 0xff, 0xff, 0x67, 0xff, 0xff, 0xff, 0x60, - 0xfc, 0xfe, 0xef, 0xcf, 0xf9, 0xfc, 0xec, 0xff, 0xfa, 0xfa, 0xe9, 0xff, - 0xf8, 0xfa, 0xe8, 0xff, 0xf7, 0xf7, 0xe5, 0xff, 0xf6, 0xf7, 0xe5, 0xff, - 0xf5, 0xf5, 0xe3, 0xff, 0xf6, 0xf4, 0xe0, 0xff, - 0xdc, 0xdd, 0xdd, 0xff, 0xdb, 0xdc, 0xdc, 0xff, 0xd3, 0xd4, 0xd4, 0xff, - 0xd8, 0xd8, 0xd8, 0xff, 0xd1, 0xd1, 0xd1, 0xff, 0xd0, 0xd0, 0xd0, 0xff, - 0xca, 0xcb, 0xcb, 0xff, 0xcc, 0xcc, 0xcd, 0xff, 0xcb, 0xcb, 0xcb, 0xff, - 0xc6, 0xc1, 0xc1, 0xff, 0xc0, 0xbc, 0xba, 0xff, 0xba, 0xb1, 0xaf, 0xff, - 0xc5, 0xbf, 0xc0, 0xff, 0xd6, 0xd2, 0xd2, 0xff, 0xc4, 0xbf, 0xbf, 0xff, - 0xd3, 0xce, 0xcd, 0xff, 0xd3, 0xd1, 0xd2, 0xff, 0xe3, 0xe2, 0xe2, 0xff, - 0xe6, 0xe4, 0xe4, 0xff, 0xee, 0xee, 0xed, 0x9b, 0xff, 0xff, 0xff, 0x68, - 0xff, 0xff, 0xff, 0x63, 0xff, 0xff, 0xff, 0x5f, 0xff, 0xff, 0xff, 0x5b, - 0xfd, 0xfe, 0xf6, 0x80, 0xf9, 0xfc, 0xeb, 0xff, 0xf7, 0xfa, 0xeb, 0xff, - 0xf7, 0xf9, 0xe9, 0xff, 0xf6, 0xf8, 0xe8, 0xff, 0xf6, 0xf7, 0xe5, 0xff, - 0xf5, 0xf4, 0xe4, 0xff, 0xf5, 0xf4, 0xe3, 0xff, - 0xd7, 0xd8, 0xd8, 0xff, 0xd4, 0xd5, 0xd4, 0xff, 0xd2, 0xd3, 0xd3, 0xff, - 0xcf, 0xd0, 0xd0, 0xff, 0xcc, 0xce, 0xcd, 0xff, 0xc9, 0xca, 0xca, 0xff, - 0xc5, 0xc6, 0xc6, 0xff, 0xc3, 0xc4, 0xc4, 0xff, 0xbf, 0xbf, 0xbd, 0xff, - 0xbe, 0xbf, 0xbf, 0xff, 0xba, 0xba, 0xba, 0xff, 0xb4, 0xb1, 0xb1, 0xff, - 0xbb, 0xba, 0xb9, 0xff, 0xc9, 0xc8, 0xc7, 0xff, 0xe2, 0xde, 0xde, 0xff, - 0xc1, 0xbd, 0xbd, 0xff, 0xd6, 0xd5, 0xd5, 0xff, 0xde, 0xdd, 0xdc, 0xff, - 0xdc, 0xda, 0xda, 0xff, 0xe6, 0xe5, 0xe5, 0xcf, 0xff, 0xff, 0xff, 0x63, - 0xff, 0xff, 0xff, 0x5c, 0xff, 0xff, 0xff, 0x58, 0xff, 0xff, 0xff, 0x53, - 0xff, 0xff, 0xff, 0x4f, 0xf9, 0xfc, 0xeb, 0xfb, 0xf6, 0xf9, 0xeb, 0xff, - 0xf6, 0xf9, 0xea, 0xff, 0xf6, 0xf9, 0xe8, 0xff, 0xf5, 0xf5, 0xe4, 0xff, - 0xf6, 0xf6, 0xe4, 0xff, 0xf5, 0xf4, 0xe2, 0xff, - 0xd3, 0xd4, 0xd4, 0xff, 0xcc, 0xcd, 0xcd, 0xff, 0xce, 0xcf, 0xcf, 0xff, - 0xc9, 0xcb, 0xcb, 0xff, 0xc6, 0xc7, 0xc7, 0xff, 0xc3, 0xc5, 0xc4, 0xff, - 0xc0, 0xc1, 0xc1, 0xff, 0xbb, 0xbd, 0xbc, 0xff, 0xb7, 0xb9, 0xb8, 0xff, - 0xb6, 0xb7, 0xb7, 0xff, 0xb4, 0xb7, 0xb6, 0xff, 0xaf, 0xaf, 0xaf, 0xff, - 0xb0, 0xb2, 0xb2, 0xff, 0xb5, 0xb5, 0xb5, 0xff, 0xc1, 0xc0, 0xc0, 0xff, - 0xc9, 0xc6, 0xc7, 0xff, 0xb3, 0xad, 0xae, 0xff, 0xcf, 0xcd, 0xce, 0xff, - 0xe3, 0xe2, 0xe2, 0xff, 0xe4, 0xe2, 0xe2, 0xff, 0xfd, 0xfd, 0xfd, 0x60, - 0xff, 0xff, 0xff, 0x57, 0xff, 0xff, 0xff, 0x50, 0xff, 0xff, 0xff, 0x4c, - 0xff, 0xff, 0xff, 0x47, 0xfa, 0xfb, 0xef, 0xa8, 0xf8, 0xfc, 0xed, 0xff, - 0xf7, 0xf9, 0xea, 0xff, 0xf6, 0xf7, 0xe7, 0xff, 0xf6, 0xf4, 0xe7, 0xff, - 0xf5, 0xf4, 0xe5, 0xff, 0xf4, 0xf3, 0xe3, 0xff, - 0xce, 0xcf, 0xcf, 0xff, 0xc8, 0xc9, 0xc9, 0xff, 0xc6, 0xc8, 0xc8, 0xff, - 0xc4, 0xc6, 0xc6, 0xff, 0xc2, 0xc3, 0xc3, 0xff, 0xba, 0xbd, 0xbc, 0xff, - 0xbc, 0xbe, 0xbe, 0xff, 0xb5, 0xb8, 0xb7, 0xff, 0xb4, 0xb6, 0xb5, 0xff, - 0xb0, 0xb2, 0xb2, 0xff, 0xaf, 0xb1, 0xb0, 0xff, 0xaa, 0xad, 0xac, 0xff, - 0xaa, 0xad, 0xac, 0xff, 0xa7, 0xa9, 0xa8, 0xff, 0xa4, 0xa5, 0xa5, 0xff, - 0xa7, 0xa8, 0xa8, 0xff, 0xc4, 0xc3, 0xc3, 0xff, 0xb8, 0xb7, 0xb7, 0xff, - 0xc0, 0xbf, 0xbe, 0xff, 0xd0, 0xce, 0xce, 0xff, 0xe3, 0xe2, 0xe2, 0x94, - 0xff, 0xff, 0xff, 0x4f, 0xff, 0xff, 0xff, 0x4b, 0xff, 0xff, 0xff, 0x44, - 0xff, 0xff, 0xff, 0x40, 0xed, 0xe7, 0xe6, 0x48, 0xba, 0xad, 0xa1, 0xff, - 0xd6, 0xcf, 0xc1, 0xff, 0xf4, 0xf3, 0xe4, 0xff, 0xf5, 0xf4, 0xe5, 0xff, - 0xf5, 0xf3, 0xe5, 0xff, 0xf5, 0xf5, 0xe5, 0xff, - 0xc7, 0xc9, 0xc8, 0xff, 0xc5, 0xc6, 0xc6, 0xff, 0xc1, 0xc2, 0xc2, 0xff, - 0xbd, 0xbe, 0xbe, 0xff, 0xba, 0xbc, 0xbb, 0xff, 0xb3, 0xb4, 0xb4, 0xff, - 0xb2, 0xb5, 0xb4, 0xff, 0xb1, 0xb4, 0xb3, 0xff, 0xac, 0xaf, 0xae, 0xff, - 0xa8, 0xaa, 0xa9, 0xff, 0xa8, 0xab, 0xaa, 0xff, 0xa1, 0xa4, 0xa3, 0xff, - 0xa1, 0xa4, 0xa3, 0xff, 0xa3, 0xa5, 0xa4, 0xff, 0x9f, 0xa1, 0xa0, 0xff, - 0x99, 0x9b, 0x9a, 0xff, 0x98, 0x9a, 0x9a, 0xff, 0x97, 0x9a, 0x99, 0xff, - 0xa0, 0xa0, 0xa0, 0xff, 0x9b, 0x9b, 0x9b, 0xff, 0x9f, 0xa0, 0x9f, 0xe8, - 0xff, 0xff, 0xff, 0x48, 0xff, 0xff, 0xff, 0x44, 0xff, 0xff, 0xff, 0x3f, - 0xff, 0xff, 0xff, 0x3b, 0xff, 0xff, 0xff, 0x34, 0xbb, 0xa7, 0xa5, 0xd8, - 0xb9, 0xa9, 0xa6, 0xff, 0xb9, 0xac, 0xa0, 0xff, 0xf8, 0xfa, 0xe7, 0xff, - 0xf5, 0xf4, 0xe6, 0xff, 0xf4, 0xf3, 0xe4, 0xff, - 0xc0, 0xc0, 0xbf, 0xff, 0xbb, 0xbb, 0xbb, 0xff, 0xbb, 0xbc, 0xbb, 0xff, - 0xb6, 0xb6, 0xb6, 0xff, 0xb0, 0xb1, 0xb1, 0xff, 0xad, 0xad, 0xad, 0xff, - 0xa8, 0xa7, 0xa7, 0xff, 0xa8, 0xa9, 0xa9, 0xff, 0xa5, 0xa6, 0xa6, 0xff, - 0xa4, 0xa6, 0xa5, 0xff, 0xa3, 0xa6, 0xa6, 0xff, 0x9b, 0x9d, 0x9c, 0xff, - 0x96, 0x99, 0x99, 0xff, 0x9b, 0x9d, 0x9d, 0xff, 0x97, 0x99, 0x98, 0xff, - 0x8e, 0x91, 0x91, 0xff, 0x98, 0x9b, 0x9b, 0xff, 0x89, 0x8c, 0x8b, 0xff, - 0x87, 0x8b, 0x89, 0xff, 0x84, 0x7f, 0x81, 0xff, 0x82, 0x82, 0x83, 0xff, - 0xc0, 0xbe, 0xbf, 0x67, 0xff, 0xff, 0xff, 0x3c, 0xff, 0xff, 0xff, 0x37, - 0xff, 0xff, 0xff, 0x33, 0xff, 0xff, 0xff, 0x2f, 0xc6, 0xbb, 0xb9, 0x50, - 0xac, 0x9c, 0x99, 0xff, 0xa8, 0x98, 0x91, 0xff, 0xbd, 0xb0, 0xa5, 0xff, - 0xf6, 0xf5, 0xe6, 0xff, 0xf4, 0xf3, 0xe4, 0xff, - 0xbb, 0xbb, 0xba, 0xff, 0xb3, 0xb3, 0xb3, 0xff, 0xb3, 0xb4, 0xb4, 0xff, - 0xae, 0xaf, 0xae, 0xff, 0xad, 0xae, 0xae, 0xff, 0xb2, 0xb4, 0xb4, 0xfc, - 0xa8, 0xa8, 0xa9, 0xf3, 0xa7, 0xa7, 0xa7, 0xf3, 0x9e, 0x9f, 0x9d, 0xfc, - 0x9b, 0x9c, 0x9a, 0xff, 0x9c, 0x9e, 0x9e, 0xff, 0x94, 0x96, 0x94, 0xff, - 0x90, 0x90, 0x90, 0xff, 0x96, 0x98, 0x99, 0xff, 0x8d, 0x8f, 0x8e, 0xff, - 0x83, 0x83, 0x84, 0xff, 0x8f, 0x92, 0x91, 0xff, 0x83, 0x85, 0x85, 0xff, - 0x87, 0x87, 0x87, 0xff, 0x7c, 0x7d, 0x7d, 0xff, 0x78, 0x74, 0x72, 0xff, - 0x95, 0x93, 0x92, 0x97, 0xff, 0xff, 0xff, 0x34, 0xff, 0xff, 0xff, 0x30, - 0xff, 0xff, 0xff, 0x2c, 0xff, 0xff, 0xff, 0x27, 0xff, 0xff, 0xff, 0x23, - 0xa2, 0x93, 0x94, 0xe7, 0x96, 0x83, 0x81, 0xff, 0xa8, 0x91, 0x8b, 0xff, - 0xc4, 0xbc, 0xb2, 0xff, 0xf5, 0xf5, 0xe4, 0xff, - 0xb7, 0xb9, 0xb8, 0xff, 0xaf, 0xaf, 0xae, 0xff, 0xaf, 0xaf, 0xaf, 0xff, - 0xac, 0xad, 0xae, 0xff, 0xa8, 0xaa, 0xa9, 0xff, 0xae, 0xaf, 0xaf, 0xec, - 0xc6, 0xc7, 0xc7, 0xb4, 0xc5, 0xc6, 0xc6, 0xb3, 0x9a, 0x99, 0x99, 0xeb, - 0x91, 0x91, 0x90, 0xff, 0x94, 0x95, 0x95, 0xff, 0x95, 0x96, 0x96, 0xff, - 0x8c, 0x8e, 0x8e, 0xff, 0x86, 0x88, 0x87, 0xff, 0x83, 0x82, 0x82, 0xff, - 0x80, 0x81, 0x81, 0xff, 0x82, 0x84, 0x84, 0xff, 0x7b, 0x79, 0x7a, 0xff, - 0x73, 0x74, 0x73, 0xff, 0x79, 0x7a, 0x7b, 0xff, 0x75, 0x73, 0x72, 0xff, - 0x6f, 0x70, 0x6e, 0xfc, 0xe8, 0xe7, 0xe7, 0x37, 0xff, 0xff, 0xff, 0x2b, - 0xff, 0xff, 0xff, 0x24, 0xff, 0xff, 0xff, 0x20, 0xff, 0xff, 0xff, 0x1c, - 0x70, 0x6e, 0x6d, 0xeb, 0x6c, 0x69, 0x66, 0xff, 0x83, 0x78, 0x7b, 0xff, - 0x83, 0x7f, 0x78, 0xff, 0xdc, 0xd5, 0xcd, 0xff, - 0xb3, 0xb5, 0xb4, 0xff, 0xa9, 0xa9, 0xaa, 0xff, 0xa7, 0xa8, 0xa7, 0xff, - 0xa7, 0xa8, 0xa7, 0xff, 0xa6, 0xa8, 0xa8, 0xff, 0xab, 0xac, 0xab, 0xe3, - 0xdb, 0xdc, 0xdc, 0x97, 0xd9, 0xda, 0xda, 0x93, 0x99, 0x99, 0x98, 0xe0, - 0x94, 0x95, 0x95, 0xff, 0x8e, 0x8f, 0x8e, 0xff, 0x8f, 0x93, 0x92, 0xff, - 0x88, 0x8a, 0x89, 0xff, 0x79, 0x78, 0x78, 0xff, 0x80, 0x82, 0x82, 0xff, - 0x7f, 0x81, 0x81, 0xff, 0x7f, 0x7d, 0x7e, 0xff, 0x76, 0x72, 0x72, 0xff, - 0x70, 0x70, 0x70, 0xff, 0x73, 0x73, 0x73, 0xff, 0x67, 0x66, 0x64, 0xff, - 0x6b, 0x6b, 0x6a, 0xff, 0x70, 0x73, 0x72, 0xd4, 0xff, 0xff, 0xff, 0x23, - 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xff, 0x1b, 0x79, 0x74, 0x72, 0x67, - 0x63, 0x61, 0x61, 0xff, 0x63, 0x62, 0x60, 0xff, 0x5e, 0x5c, 0x5a, 0xff, - 0x61, 0x5f, 0x5c, 0xff, 0x6b, 0x63, 0x5e, 0xff, - 0xae, 0xaf, 0xaf, 0xff, 0xa9, 0xa9, 0xa9, 0xff, 0x9c, 0x9b, 0x99, 0xff, - 0x9d, 0x9c, 0x9b, 0xff, 0x9c, 0x9c, 0x9c, 0xff, 0x9c, 0x9c, 0x9d, 0xf7, - 0xaa, 0xac, 0xac, 0xd4, 0xa5, 0xa7, 0xa6, 0xd3, 0x98, 0x9a, 0x9a, 0xf4, - 0x8d, 0x8e, 0x8e, 0xff, 0x85, 0x85, 0x85, 0xff, 0x85, 0x86, 0x86, 0xff, - 0x82, 0x84, 0x84, 0xff, 0x7b, 0x7b, 0x7b, 0xff, 0x7e, 0x82, 0x81, 0xff, - 0x79, 0x7b, 0x7b, 0xff, 0x79, 0x7b, 0x7b, 0xff, 0x72, 0x73, 0x73, 0xff, - 0x70, 0x6e, 0x6e, 0xff, 0x6d, 0x6d, 0x6d, 0xff, 0x61, 0x5f, 0x5d, 0xff, - 0x5d, 0x5d, 0x5b, 0xff, 0x64, 0x60, 0x61, 0xff, 0x5e, 0x5d, 0x5d, 0xec, - 0x6a, 0x69, 0x67, 0xa0, 0x67, 0x66, 0x64, 0xbc, 0x59, 0x56, 0x55, 0xff, - 0x54, 0x51, 0x4e, 0xff, 0x56, 0x52, 0x51, 0xff, 0x55, 0x52, 0x4f, 0xff, - 0x52, 0x4e, 0x49, 0xff, 0x54, 0x54, 0x52, 0xff, - 0xa9, 0xac, 0xab, 0xff, 0xa1, 0xa0, 0xa0, 0xff, 0x9a, 0x99, 0x98, 0xff, - 0x97, 0x97, 0x96, 0xff, 0x95, 0x94, 0x94, 0xff, 0x8e, 0x8c, 0x8c, 0xff, - 0x95, 0x98, 0x97, 0xfc, 0x90, 0x91, 0x91, 0xfc, 0x95, 0x96, 0x96, 0xff, - 0x86, 0x86, 0x86, 0xff, 0x81, 0x82, 0x80, 0xff, 0x7d, 0x7e, 0x7b, 0xff, - 0x78, 0x79, 0x78, 0xff, 0x71, 0x70, 0x6e, 0xff, 0x72, 0x71, 0x70, 0xff, - 0x72, 0x73, 0x72, 0xff, 0x70, 0x70, 0x6e, 0xff, 0x6d, 0x6a, 0x6a, 0xff, - 0x64, 0x64, 0x63, 0xff, 0x69, 0x68, 0x67, 0xff, 0x61, 0x5f, 0x5e, 0xff, - 0x59, 0x57, 0x57, 0xff, 0x5f, 0x5f, 0x5e, 0xff, 0x55, 0x55, 0x53, 0xff, - 0x57, 0x58, 0x57, 0xff, 0x51, 0x53, 0x50, 0xff, 0x54, 0x51, 0x51, 0xff, - 0x4c, 0x4b, 0x4a, 0xff, 0x49, 0x4a, 0x47, 0xff, 0x4f, 0x51, 0x4e, 0xff, - 0x4f, 0x4d, 0x49, 0xff, 0x4c, 0x4b, 0x46, 0xff, - 0xa7, 0xaa, 0xaa, 0xff, 0x99, 0x98, 0x98, 0xff, 0x95, 0x92, 0x92, 0xff, - 0x94, 0x93, 0x92, 0xff, 0x8a, 0x87, 0x84, 0xff, 0x85, 0x80, 0x7f, 0xff, - 0x8d, 0x90, 0x8f, 0xff, 0x85, 0x85, 0x85, 0xff, 0x8e, 0x8e, 0x8e, 0xff, - 0x80, 0x80, 0x81, 0xff, 0x7c, 0x7d, 0x7b, 0xff, 0x79, 0x79, 0x78, 0xff, - 0x78, 0x79, 0x78, 0xff, 0x6e, 0x6c, 0x6b, 0xff, 0x68, 0x66, 0x66, 0xff, - 0x69, 0x6a, 0x67, 0xff, 0x60, 0x5e, 0x5d, 0xff, 0x5b, 0x58, 0x57, 0xff, - 0x58, 0x56, 0x55, 0xff, 0x61, 0x5e, 0x5d, 0xff, 0x54, 0x53, 0x52, 0xff, - 0x60, 0x5d, 0x5c, 0xff, 0x5b, 0x5b, 0x5a, 0xff, 0x59, 0x5a, 0x58, 0xff, - 0x48, 0x43, 0x42, 0xff, 0x44, 0x40, 0x40, 0xff, 0x48, 0x46, 0x44, 0xff, - 0x4a, 0x46, 0x46, 0xff, 0x4c, 0x4f, 0x4c, 0xff, 0x49, 0x4a, 0x48, 0xff, - 0x47, 0x46, 0x41, 0xff, 0x44, 0x43, 0x3f, 0xff, - 0xa2, 0xa4, 0xa4, 0xff, 0x96, 0x95, 0x96, 0xff, 0x8e, 0x8c, 0x8a, 0xff, - 0x89, 0x86, 0x86, 0xff, 0x82, 0x7c, 0x7c, 0xff, 0x83, 0x80, 0x7f, 0xff, - 0x82, 0x82, 0x80, 0xff, 0x82, 0x83, 0x81, 0xff, 0x82, 0x85, 0x85, 0xff, - 0x7c, 0x7c, 0x7c, 0xff, 0x77, 0x78, 0x75, 0xff, 0x75, 0x77, 0x76, 0xff, - 0x71, 0x72, 0x70, 0xff, 0x68, 0x66, 0x65, 0xff, 0x62, 0x60, 0x5f, 0xff, - 0x5f, 0x5e, 0x5c, 0xff, 0x5a, 0x52, 0x4f, 0xff, 0x5b, 0x53, 0x4f, 0xff, - 0x50, 0x49, 0x49, 0xff, 0x5c, 0x58, 0x57, 0xff, 0x50, 0x4b, 0x49, 0xff, - 0x57, 0x54, 0x53, 0xff, 0x4f, 0x4f, 0x4e, 0xff, 0x53, 0x57, 0x55, 0xff, - 0x48, 0x45, 0x44, 0xff, 0x3c, 0x33, 0x33, 0xff, 0x49, 0x45, 0x43, 0xff, - 0x41, 0x3f, 0x3d, 0xff, 0x49, 0x46, 0x44, 0xff, 0x4a, 0x48, 0x47, 0xff, - 0x3f, 0x3c, 0x3a, 0xff, 0x43, 0x41, 0x3e, 0xff, - 0x99, 0x9c, 0x9a, 0xff, 0x90, 0x8e, 0x8f, 0xff, 0x8c, 0x8b, 0x89, 0xff, - 0x81, 0x7c, 0x7c, 0xff, 0x7d, 0x78, 0x78, 0xff, 0x82, 0x82, 0x80, 0xff, - 0x77, 0x74, 0x73, 0xff, 0x75, 0x73, 0x73, 0xff, 0x78, 0x76, 0x76, 0xff, - 0x70, 0x6f, 0x6f, 0xff, 0x6d, 0x6c, 0x6b, 0xff, 0x6e, 0x6f, 0x6d, 0xff, - 0x68, 0x68, 0x66, 0xff, 0x5f, 0x5b, 0x5b, 0xff, 0x5b, 0x56, 0x56, 0xff, - 0x5a, 0x58, 0x57, 0xff, 0x53, 0x49, 0x47, 0xff, 0x4e, 0x45, 0x43, 0xff, - 0x49, 0x43, 0x41, 0xff, 0x5f, 0x5b, 0x5a, 0xff, 0x46, 0x3f, 0x3e, 0xff, - 0x4b, 0x48, 0x47, 0xff, 0x42, 0x3f, 0x3f, 0xff, 0x4d, 0x50, 0x50, 0xff, - 0x52, 0x52, 0x51, 0xff, 0x37, 0x31, 0x30, 0xff, 0x3d, 0x38, 0x37, 0xff, - 0x3f, 0x39, 0x38, 0xff, 0x40, 0x3c, 0x3b, 0xff, 0x4a, 0x48, 0x47, 0xff, - 0x3f, 0x3d, 0x3b, 0xff, 0x46, 0x45, 0x43, 0xff, -}; - -#endif // WEBP_TESTS_FUZZER_IMG_ALPHA_H_ diff --git a/libwebp/tests/fuzzer/img_grid.h b/libwebp/tests/fuzzer/img_grid.h deleted file mode 100644 index f269bbd6..00000000 --- a/libwebp/tests/fuzzer/img_grid.h +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright 2018 Google Inc. -// -// 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. -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef WEBP_TESTS_FUZZER_IMG_GRID_H_ -#define WEBP_TESTS_FUZZER_IMG_GRID_H_ - -#include - -static const int kImgGridWidth = 16; -static const int kImgGridHeight = 16; - -/*Pixel format: Red: 8 bit, Green: 8 bit, Blue: 8 bit, Fix 0xFF: 8 bit*/ -static const uint8_t kImgGridData[] = { - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, - 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, -}; - -#endif // WEBP_TESTS_FUZZER_IMG_GRID_H_ diff --git a/libwebp/tests/fuzzer/img_peak.h b/libwebp/tests/fuzzer/img_peak.h deleted file mode 100644 index d17ba1ed..00000000 --- a/libwebp/tests/fuzzer/img_peak.h +++ /dev/null @@ -1,5533 +0,0 @@ -// Copyright 2018 Google Inc. -// -// 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. -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef WEBP_TESTS_FUZZER_IMG_PEAK_H_ -#define WEBP_TESTS_FUZZER_IMG_PEAK_H_ - -#include - -static const int kImgPeakWidth = 128; -static const int kImgPeakHeight = 128; - -/*Pixel format: Red: 8 bit, Green: 8 bit, Blue: 8 bit, Fix 0xFF: 8 bit*/ -static const uint8_t kImgPeakData[] = { - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf7, 0xdd, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xf7, 0xdd, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf7, 0xdd, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf7, 0xdd, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xf7, 0xdd, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf7, 0xdd, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf7, 0xdd, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xf7, 0xdd, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf7, 0xdd, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xe4, 0xe2, 0xd8, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xe4, 0xe2, 0xd8, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf7, 0xdd, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf7, 0xdd, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xec, 0xdb, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf7, 0xdd, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xf7, 0xdd, 0xcc, 0xff, 0xec, 0xd6, 0xc4, 0xff, 0xd9, 0xc6, 0xb4, 0xff, - 0xa7, 0x94, 0x84, 0xff, 0xa9, 0x9b, 0x8c, 0xff, 0xa9, 0x9b, 0x8c, 0xff, - 0xc5, 0xb7, 0xb4, 0xff, 0xc0, 0xaa, 0x9c, 0xff, 0xc4, 0xb2, 0xac, 0xff, - 0xe6, 0xd6, 0xcc, 0xff, 0xee, 0xdd, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xde, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xf7, 0xdd, 0xcc, 0xff, 0xf7, 0xdd, 0xcc, 0xff, 0xc0, 0xaa, 0x9c, 0xff, - 0x9c, 0x7e, 0x6c, 0xff, 0x8c, 0x6e, 0x64, 0xff, 0x94, 0x79, 0x6c, 0xff, - 0x94, 0x79, 0x6c, 0xff, 0x8e, 0x79, 0x74, 0xff, 0x9e, 0x8b, 0x84, 0xff, - 0x9c, 0x80, 0x7c, 0xff, 0x9e, 0x8b, 0x84, 0xff, 0xa6, 0x95, 0x94, 0xff, - 0xbf, 0xaa, 0xa4, 0xff, 0xc5, 0xb7, 0xb4, 0xff, 0xd6, 0xc5, 0xbc, 0xff, - 0xec, 0xdb, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xde, 0xd4, 0xff, - 0xd4, 0xb8, 0xac, 0xff, 0x94, 0x79, 0x6c, 0xff, 0x84, 0x6e, 0x5c, 0xff, - 0x94, 0x79, 0x6c, 0xff, 0x8d, 0x72, 0x6b, 0xff, 0x8a, 0x76, 0x6c, 0xff, - 0x9e, 0x8b, 0x84, 0xff, 0x9e, 0x8b, 0x84, 0xff, 0xa8, 0x93, 0x8c, 0xff, - 0x9c, 0x80, 0x7c, 0xff, 0x94, 0x8c, 0x8c, 0xff, 0x8f, 0x86, 0x7c, 0xff, - 0xc4, 0xb2, 0xac, 0xff, 0xcc, 0xbd, 0xbc, 0xff, 0xa8, 0x9b, 0x94, 0xff, - 0xd9, 0xcc, 0xbc, 0xff, 0xe4, 0xe2, 0xd8, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xdc, 0xbe, 0xb4, 0xff, 0xac, 0x8e, 0x7c, 0xff, 0x9c, 0x81, 0x74, 0xff, - 0x7c, 0x62, 0x54, 0xff, 0x80, 0x67, 0x5c, 0xff, 0xa4, 0x89, 0x7c, 0xff, - 0xbc, 0xa4, 0x9c, 0xff, 0x8d, 0x72, 0x6b, 0xff, 0xac, 0x8d, 0x84, 0xff, - 0x9c, 0x80, 0x7c, 0xff, 0x96, 0x85, 0x84, 0xff, 0xad, 0x9a, 0x9c, 0xff, - 0x96, 0x85, 0x84, 0xff, 0x96, 0x85, 0x84, 0xff, 0x96, 0x85, 0x84, 0xff, - 0xa8, 0x9b, 0x94, 0xff, 0xbc, 0xb1, 0xb4, 0xff, 0xc7, 0xb8, 0xac, 0xff, - 0xa8, 0x9b, 0x94, 0xff, 0xc9, 0xc0, 0xb4, 0xff, 0xe4, 0xd2, 0xc4, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xf2, 0xe9, 0xdc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf2, 0xe9, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xe4, 0xe2, 0xd8, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf7, 0xdd, 0xcc, 0xff, 0xfc, 0xea, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xec, 0xd6, 0xc4, 0xff, 0xa4, 0x89, 0x7c, 0xff, - 0x7c, 0x5c, 0x4c, 0xff, 0x7e, 0x67, 0x54, 0xff, 0x7c, 0x62, 0x54, 0xff, - 0x80, 0x67, 0x5c, 0xff, 0x8c, 0x6e, 0x64, 0xff, 0x8c, 0x6d, 0x6c, 0xff, - 0xac, 0x8d, 0x84, 0xff, 0x8c, 0x6e, 0x64, 0xff, 0xac, 0x8d, 0x8c, 0xff, - 0x8e, 0x79, 0x74, 0xff, 0x9c, 0x80, 0x7c, 0xff, 0x9c, 0x7a, 0x7c, 0xff, - 0x8e, 0x72, 0x74, 0xff, 0x9d, 0x8d, 0x8c, 0xff, 0xad, 0x9a, 0x9c, 0xff, - 0x96, 0x86, 0x8c, 0xff, 0xa8, 0x9b, 0x94, 0xff, 0xad, 0x9e, 0x9e, 0xff, - 0xd7, 0xcc, 0xc4, 0xff, 0xd6, 0xc5, 0xbc, 0xff, 0xb0, 0xa3, 0x9c, 0xff, - 0xc7, 0xb8, 0xac, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xf2, 0xe9, 0xdc, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xec, 0xd6, 0xc4, 0xff, 0x94, 0x76, 0x64, 0xff, 0x7c, 0x5c, 0x4c, 0xff, - 0x74, 0x5b, 0x4c, 0xff, 0x74, 0x5b, 0x4c, 0xff, 0x75, 0x56, 0x54, 0xff, - 0x80, 0x67, 0x5c, 0xff, 0x8d, 0x72, 0x6b, 0xff, 0x9c, 0x80, 0x7c, 0xff, - 0x8e, 0x79, 0x74, 0xff, 0x8e, 0x72, 0x74, 0xff, 0xa4, 0x85, 0x84, 0xff, - 0xa4, 0x85, 0x84, 0xff, 0x8e, 0x72, 0x74, 0xff, 0x8e, 0x72, 0x74, 0xff, - 0x9c, 0x80, 0x7c, 0xff, 0xad, 0x9e, 0x9e, 0xff, 0xad, 0x9a, 0x9c, 0xff, - 0x9c, 0x80, 0x7c, 0xff, 0xa1, 0x99, 0x9c, 0xff, 0xb1, 0xaa, 0xa4, 0xff, - 0xc4, 0xba, 0xbc, 0xff, 0x9c, 0x93, 0x8c, 0xff, 0xa8, 0x93, 0x8c, 0xff, - 0xa8, 0x93, 0x8c, 0xff, 0xc4, 0xb2, 0xac, 0xff, 0xee, 0xdd, 0xd4, 0xff, - 0xef, 0xe2, 0xdc, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xe7, 0xce, 0xbc, 0xff, - 0x84, 0x6e, 0x5c, 0xff, 0x74, 0x5b, 0x4c, 0xff, 0x74, 0x5b, 0x4c, 0xff, - 0x7c, 0x5d, 0x54, 0xff, 0x74, 0x5b, 0x4c, 0xff, 0x7f, 0x6a, 0x64, 0xff, - 0x8e, 0x79, 0x74, 0xff, 0xa8, 0x93, 0x8c, 0xff, 0xa4, 0x85, 0x84, 0xff, - 0x9c, 0x80, 0x7c, 0xff, 0xa4, 0x85, 0x84, 0xff, 0xcc, 0xaa, 0xac, 0xff, - 0x9c, 0x80, 0x7c, 0xff, 0x9c, 0x80, 0x7c, 0xff, 0x8e, 0x72, 0x74, 0xff, - 0x8c, 0x81, 0x84, 0xff, 0xad, 0x9a, 0x9c, 0xff, 0xad, 0x9e, 0x9e, 0xff, - 0x96, 0x85, 0x84, 0xff, 0xbc, 0xb6, 0xac, 0xff, 0xae, 0xa4, 0xa4, 0xff, - 0x8f, 0x86, 0x7c, 0xff, 0xbc, 0xb0, 0xac, 0xff, 0x8f, 0x7f, 0x7c, 0xff, - 0x9d, 0x8d, 0x8c, 0xff, 0xa8, 0x9b, 0x94, 0xff, 0xdc, 0xbe, 0xb4, 0xff, - 0xee, 0xdd, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf7, 0xdd, 0xcc, 0xff, 0x84, 0x6e, 0x5c, 0xff, - 0x6f, 0x56, 0x44, 0xff, 0x74, 0x5b, 0x4c, 0xff, 0x74, 0x5b, 0x4c, 0xff, - 0x69, 0x4e, 0x44, 0xff, 0x94, 0x79, 0x6c, 0xff, 0xad, 0x9e, 0x9e, 0xff, - 0xbd, 0xa6, 0xa4, 0xff, 0xb4, 0x96, 0x94, 0xff, 0x8e, 0x79, 0x74, 0xff, - 0x8e, 0x72, 0x74, 0xff, 0xbd, 0xa6, 0xa4, 0xff, 0xdc, 0xba, 0xbc, 0xff, - 0xc6, 0xb1, 0xb4, 0xff, 0xac, 0x8d, 0x8c, 0xff, 0x7e, 0x6d, 0x6c, 0xff, - 0x9c, 0x7a, 0x7c, 0xff, 0x84, 0x77, 0x74, 0xff, 0xad, 0x9e, 0x9e, 0xff, - 0xbc, 0xb0, 0xac, 0xff, 0xd5, 0xcd, 0xcc, 0xff, 0x9c, 0x93, 0x8c, 0xff, - 0x9d, 0x8d, 0x8c, 0xff, 0xad, 0x9e, 0x9e, 0xff, 0xad, 0x9a, 0x9c, 0xff, - 0x8f, 0x86, 0x7c, 0xff, 0xa8, 0x93, 0x8c, 0xff, 0xbc, 0xb0, 0xac, 0xff, - 0xee, 0xdd, 0xd4, 0xff, 0xee, 0xdd, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xe7, 0xce, 0xbc, 0xff, 0x9c, 0x7e, 0x6c, 0xff, 0x74, 0x55, 0x4c, 0xff, - 0x74, 0x55, 0x4c, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x69, 0x4e, 0x44, 0xff, - 0x75, 0x56, 0x54, 0xff, 0x8d, 0x72, 0x6b, 0xff, 0xd4, 0xc6, 0xc4, 0xff, - 0xae, 0xa4, 0xa4, 0xff, 0xef, 0xe2, 0xdc, 0xff, 0xc4, 0xba, 0xbc, 0xff, - 0x96, 0x85, 0x84, 0xff, 0xad, 0x9e, 0x9e, 0xff, 0xe4, 0xce, 0xcc, 0xff, - 0xec, 0xde, 0xdc, 0xff, 0xf8, 0xea, 0xec, 0xff, 0xc5, 0xb7, 0xb4, 0xff, - 0xae, 0xa4, 0xa4, 0xff, 0x84, 0x77, 0x74, 0xff, 0xa6, 0x95, 0x94, 0xff, - 0xbc, 0xb1, 0xb4, 0xff, 0xc4, 0xba, 0xbc, 0xff, 0x94, 0x8c, 0x8c, 0xff, - 0x9a, 0x94, 0x94, 0xff, 0xa1, 0x9e, 0x9c, 0xff, 0xb3, 0xae, 0xac, 0xff, - 0xa8, 0x9b, 0x94, 0xff, 0x89, 0x86, 0x84, 0xff, 0xae, 0xa4, 0xa4, 0xff, - 0xbc, 0xb0, 0xac, 0xff, 0xee, 0xdd, 0xd4, 0xff, 0xf2, 0xe9, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xea, 0xdc, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xd4, 0xc2, 0xac, 0xff, - 0x7e, 0x67, 0x54, 0xff, 0x7c, 0x5c, 0x4c, 0xff, 0x7c, 0x5c, 0x4c, 0xff, - 0x74, 0x4e, 0x44, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x74, 0x4e, 0x44, 0xff, - 0x7f, 0x6a, 0x64, 0xff, 0xac, 0x8d, 0x8c, 0xff, 0xa6, 0x95, 0x94, 0xff, - 0xc6, 0xb1, 0xb4, 0xff, 0xdc, 0xdc, 0xdc, 0xff, 0xd6, 0xd2, 0xd4, 0xff, - 0x9c, 0x80, 0x7c, 0xff, 0xa6, 0x95, 0x94, 0xff, 0xdc, 0xba, 0xbc, 0xff, - 0xcf, 0xc6, 0xcc, 0xff, 0xbc, 0xb0, 0xac, 0xff, 0xa1, 0x99, 0x9c, 0xff, - 0x9d, 0x8d, 0x8c, 0xff, 0x8e, 0x7a, 0x7c, 0xff, 0xba, 0xb6, 0xb4, 0xff, - 0xae, 0xa4, 0xa4, 0xff, 0xad, 0x9e, 0x9e, 0xff, 0x8f, 0x7f, 0x7c, 0xff, - 0xa1, 0x99, 0x9c, 0xff, 0xb3, 0xae, 0xac, 0xff, 0xb4, 0xaa, 0xac, 0xff, - 0xc4, 0xba, 0xbc, 0xff, 0xba, 0xb0, 0xa4, 0xff, 0xad, 0x9e, 0x9e, 0xff, - 0xad, 0x9e, 0x9e, 0xff, 0xbd, 0xa6, 0xa4, 0xff, 0xec, 0xdb, 0xcc, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xe7, 0xce, 0xbc, 0xff, 0x7c, 0x62, 0x54, 0xff, - 0x6f, 0x56, 0x44, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x7c, 0x5d, 0x54, 0xff, - 0x74, 0x55, 0x4c, 0xff, 0x6a, 0x53, 0x4c, 0xff, 0x69, 0x4e, 0x4c, 0xff, - 0x8d, 0x72, 0x6b, 0xff, 0xa6, 0x95, 0x94, 0xff, 0x9e, 0x8b, 0x84, 0xff, - 0xb0, 0xa3, 0x9c, 0xff, 0x94, 0x8c, 0x8c, 0xff, 0x9d, 0x8d, 0x8c, 0xff, - 0x7e, 0x6d, 0x6c, 0xff, 0x8c, 0x81, 0x84, 0xff, 0x8e, 0x7a, 0x7c, 0xff, - 0xa6, 0x95, 0x94, 0xff, 0x7e, 0x6d, 0x6c, 0xff, 0x77, 0x66, 0x6c, 0xff, - 0x84, 0x77, 0x74, 0xff, 0x9e, 0x8b, 0x84, 0xff, 0xd5, 0xcd, 0xcc, 0xff, - 0x94, 0x8b, 0x84, 0xff, 0x84, 0x77, 0x74, 0xff, 0x9e, 0x8e, 0x94, 0xff, - 0xae, 0xa4, 0xa4, 0xff, 0xb4, 0xaa, 0xac, 0xff, 0xa1, 0x99, 0x9c, 0xff, - 0xb4, 0xaa, 0xac, 0xff, 0xc5, 0xb7, 0xb4, 0xff, 0xa6, 0x95, 0x94, 0xff, - 0xba, 0xb0, 0xa4, 0xff, 0x94, 0x8b, 0x84, 0xff, 0xba, 0xb0, 0xa4, 0xff, - 0xec, 0xd6, 0xc4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xea, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xea, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xea, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xc7, 0xb2, 0xa4, 0xff, 0x7e, 0x67, 0x54, 0xff, 0x6f, 0x56, 0x44, 0xff, - 0x74, 0x55, 0x4c, 0xff, 0x7c, 0x5c, 0x4c, 0xff, 0x7c, 0x5d, 0x54, 0xff, - 0x74, 0x55, 0x4c, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x74, 0x4e, 0x44, 0xff, - 0x78, 0x66, 0x64, 0xff, 0x9c, 0x80, 0x7c, 0xff, 0x7e, 0x6d, 0x6c, 0xff, - 0x84, 0x77, 0x74, 0xff, 0x81, 0x7e, 0x7c, 0xff, 0x81, 0x7e, 0x7c, 0xff, - 0x70, 0x5e, 0x5c, 0xff, 0x9c, 0x80, 0x7c, 0xff, 0xae, 0xa4, 0xa4, 0xff, - 0x6f, 0x6c, 0x6c, 0xff, 0x7f, 0x6a, 0x64, 0xff, 0x78, 0x66, 0x64, 0xff, - 0x72, 0x62, 0x5c, 0xff, 0x84, 0x77, 0x74, 0xff, 0x9d, 0x8d, 0x8c, 0xff, - 0x8c, 0x81, 0x84, 0xff, 0x9e, 0x8b, 0x84, 0xff, 0x84, 0x77, 0x74, 0xff, - 0x71, 0x6a, 0x64, 0xff, 0xae, 0xa4, 0xa4, 0xff, 0xc4, 0xc3, 0xc4, 0xff, - 0x9a, 0x94, 0x94, 0xff, 0x94, 0x8c, 0x8c, 0xff, 0x8f, 0x7f, 0x7c, 0xff, - 0x9a, 0x94, 0x94, 0xff, 0x94, 0x8b, 0x84, 0xff, 0xa1, 0x9e, 0x9c, 0xff, - 0xe6, 0xd6, 0xcc, 0xff, 0xef, 0xe2, 0xdc, 0xff, 0xfc, 0xea, 0xdc, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xec, 0xdb, 0xcc, 0xff, 0x9c, 0x7e, 0x6c, 0xff, - 0x74, 0x5b, 0x4c, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x74, 0x5b, 0x4c, 0xff, - 0x7c, 0x5c, 0x4c, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x74, 0x5b, 0x4c, 0xff, - 0x7c, 0x5d, 0x54, 0xff, 0x69, 0x4e, 0x44, 0xff, 0x7c, 0x5d, 0x54, 0xff, - 0x9c, 0x7a, 0x74, 0xff, 0x8d, 0x72, 0x6b, 0xff, 0x70, 0x5e, 0x5c, 0xff, - 0x8a, 0x76, 0x6c, 0xff, 0x71, 0x6a, 0x64, 0xff, 0x96, 0x85, 0x84, 0xff, - 0x7f, 0x6a, 0x64, 0xff, 0x94, 0x8c, 0x8c, 0xff, 0x94, 0x8b, 0x84, 0xff, - 0x84, 0x77, 0x74, 0xff, 0x9e, 0x8b, 0x84, 0xff, 0x8f, 0x7f, 0x7c, 0xff, - 0x7e, 0x6d, 0x6c, 0xff, 0x78, 0x66, 0x64, 0xff, 0x70, 0x5e, 0x5c, 0xff, - 0x84, 0x77, 0x74, 0xff, 0x9e, 0x8b, 0x84, 0xff, 0x78, 0x66, 0x64, 0xff, - 0x6c, 0x61, 0x64, 0xff, 0x8c, 0x81, 0x84, 0xff, 0xc4, 0xb2, 0xac, 0xff, - 0xcc, 0xbd, 0xbc, 0xff, 0xbc, 0xb6, 0xac, 0xff, 0xd7, 0xcc, 0xc4, 0xff, - 0xc9, 0xc0, 0xb4, 0xff, 0xae, 0xa4, 0xa4, 0xff, 0xc5, 0xb7, 0xb4, 0xff, - 0xc5, 0xb7, 0xb4, 0xff, 0xd9, 0xcc, 0xbc, 0xff, 0xef, 0xe2, 0xdc, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xea, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xec, 0xd6, 0xc4, 0xff, 0x84, 0x6e, 0x5c, 0xff, 0x74, 0x5b, 0x4c, 0xff, - 0x74, 0x5b, 0x4c, 0xff, 0x69, 0x4e, 0x44, 0xff, 0x7c, 0x5d, 0x54, 0xff, - 0x74, 0x5b, 0x4c, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x74, 0x55, 0x4c, 0xff, - 0x74, 0x55, 0x4c, 0xff, 0x69, 0x4e, 0x4c, 0xff, 0x80, 0x67, 0x5c, 0xff, - 0x8d, 0x72, 0x6b, 0xff, 0x72, 0x5b, 0x54, 0xff, 0x72, 0x5b, 0x54, 0xff, - 0x6b, 0x56, 0x5c, 0xff, 0x7f, 0x6a, 0x64, 0xff, 0x84, 0x77, 0x74, 0xff, - 0x8e, 0x79, 0x74, 0xff, 0x7e, 0x6d, 0x6c, 0xff, 0x72, 0x62, 0x5c, 0xff, - 0x70, 0x5e, 0x5c, 0xff, 0x7f, 0x72, 0x6c, 0xff, 0x72, 0x62, 0x5c, 0xff, - 0x70, 0x5e, 0x5c, 0xff, 0x7f, 0x6a, 0x64, 0xff, 0x7f, 0x6a, 0x64, 0xff, - 0x78, 0x66, 0x64, 0xff, 0x7e, 0x6d, 0x6c, 0xff, 0x78, 0x66, 0x64, 0xff, - 0x8f, 0x7f, 0x7c, 0xff, 0xa6, 0x95, 0x94, 0xff, 0xae, 0xa4, 0xa4, 0xff, - 0xb4, 0xaa, 0xac, 0xff, 0xae, 0xa4, 0xa4, 0xff, 0xc2, 0xbe, 0xbc, 0xff, - 0xbc, 0xb0, 0xac, 0xff, 0xbc, 0xb6, 0xac, 0xff, 0xcc, 0xc5, 0xc4, 0xff, - 0xd9, 0xd4, 0xcc, 0xff, 0xc4, 0xba, 0xbc, 0xff, 0xd6, 0xc5, 0xbc, 0xff, - 0xef, 0xe2, 0xdc, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xea, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xd9, 0xc6, 0xb4, 0xff, - 0x7e, 0x67, 0x54, 0xff, 0x6f, 0x56, 0x44, 0xff, 0x74, 0x5b, 0x4c, 0xff, - 0x69, 0x4e, 0x44, 0xff, 0x7e, 0x67, 0x54, 0xff, 0x74, 0x55, 0x4c, 0xff, - 0x74, 0x55, 0x4c, 0xff, 0x7c, 0x5d, 0x54, 0xff, 0x74, 0x4e, 0x4c, 0xff, - 0x74, 0x55, 0x4c, 0xff, 0x7d, 0x62, 0x5c, 0xff, 0x80, 0x67, 0x5c, 0xff, - 0x75, 0x56, 0x54, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x6a, 0x53, 0x4c, 0xff, - 0x69, 0x4e, 0x4c, 0xff, 0x7c, 0x5d, 0x54, 0xff, 0x7e, 0x6d, 0x6c, 0xff, - 0x7c, 0x5d, 0x54, 0xff, 0x78, 0x66, 0x64, 0xff, 0x72, 0x5b, 0x54, 0xff, - 0x72, 0x5b, 0x54, 0xff, 0x72, 0x5b, 0x54, 0xff, 0x72, 0x62, 0x5c, 0xff, - 0x72, 0x5b, 0x54, 0xff, 0x7d, 0x62, 0x5c, 0xff, 0x7f, 0x72, 0x6c, 0xff, - 0x7c, 0x72, 0x64, 0xff, 0x72, 0x5b, 0x54, 0xff, 0x69, 0x55, 0x54, 0xff, - 0x81, 0x72, 0x74, 0xff, 0x9a, 0x94, 0x94, 0xff, 0xb4, 0xaa, 0xac, 0xff, - 0xa6, 0x95, 0x94, 0xff, 0x94, 0x8c, 0x8c, 0xff, 0x94, 0x8c, 0x8c, 0xff, - 0x94, 0x8b, 0x84, 0xff, 0xba, 0xb6, 0xb4, 0xff, 0xba, 0xb6, 0xb4, 0xff, - 0xcc, 0xcc, 0xcc, 0xff, 0xe4, 0xde, 0xdc, 0xff, 0xcc, 0xc2, 0xbc, 0xff, - 0xcc, 0xc2, 0xbc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf2, 0xe9, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xd9, 0xc6, 0xb4, 0xff, 0x74, 0x5b, 0x4c, 0xff, - 0x74, 0x5b, 0x4c, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x6f, 0x56, 0x44, 0xff, - 0x7c, 0x62, 0x54, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x74, 0x55, 0x4c, 0xff, - 0x7c, 0x5c, 0x4c, 0xff, 0x69, 0x4e, 0x44, 0xff, 0x74, 0x55, 0x4c, 0xff, - 0x7c, 0x5d, 0x54, 0xff, 0x7c, 0x5d, 0x54, 0xff, 0x7c, 0x5d, 0x54, 0xff, - 0x7c, 0x5d, 0x54, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x75, 0x56, 0x54, 0xff, - 0x75, 0x56, 0x54, 0xff, 0x8f, 0x7f, 0x7c, 0xff, 0x7d, 0x62, 0x5c, 0xff, - 0x69, 0x55, 0x54, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x69, 0x55, 0x54, 0xff, - 0x74, 0x55, 0x4c, 0xff, 0x6b, 0x56, 0x5c, 0xff, 0x8d, 0x72, 0x6b, 0xff, - 0x75, 0x56, 0x54, 0xff, 0x69, 0x55, 0x54, 0xff, 0x8d, 0x72, 0x6b, 0xff, - 0x8e, 0x79, 0x74, 0xff, 0x75, 0x62, 0x64, 0xff, 0x72, 0x5b, 0x54, 0xff, - 0x8f, 0x7f, 0x7c, 0xff, 0xad, 0x9a, 0x9c, 0xff, 0x9e, 0x8e, 0x94, 0xff, - 0x9a, 0x94, 0x94, 0xff, 0x8f, 0x7f, 0x7c, 0xff, 0x94, 0x8b, 0x84, 0xff, - 0x81, 0x7e, 0x7c, 0xff, 0x7b, 0x7a, 0x7c, 0xff, 0x94, 0x8c, 0x8c, 0xff, - 0xc4, 0xc3, 0xc4, 0xff, 0xd5, 0xcd, 0xcc, 0xff, 0xb1, 0xaa, 0xa4, 0xff, - 0xc7, 0xb8, 0xac, 0xff, 0xda, 0xd4, 0xc4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xea, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xd4, 0xb8, 0xac, 0xff, 0x80, 0x67, 0x5c, 0xff, 0x74, 0x5b, 0x4c, 0xff, - 0x74, 0x5b, 0x4c, 0xff, 0x7c, 0x5c, 0x4c, 0xff, 0x7c, 0x5d, 0x54, 0xff, - 0x7c, 0x5c, 0x4c, 0xff, 0x74, 0x5b, 0x4c, 0xff, 0x7c, 0x5c, 0x4c, 0xff, - 0x74, 0x5b, 0x4c, 0xff, 0x74, 0x4e, 0x44, 0xff, 0x7c, 0x5c, 0x4c, 0xff, - 0x7c, 0x5d, 0x54, 0xff, 0x7c, 0x5d, 0x54, 0xff, 0x7c, 0x5e, 0x5c, 0xff, - 0x7c, 0x5d, 0x54, 0xff, 0x75, 0x56, 0x54, 0xff, 0x75, 0x56, 0x54, 0xff, - 0x7c, 0x5e, 0x5c, 0xff, 0x8c, 0x6e, 0x64, 0xff, 0x75, 0x56, 0x54, 0xff, - 0x6a, 0x53, 0x4c, 0xff, 0x69, 0x4e, 0x4c, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x61, 0x48, 0x44, 0xff, 0x61, 0x48, 0x44, 0xff, 0x94, 0x8b, 0x84, 0xff, - 0x8d, 0x72, 0x6b, 0xff, 0x75, 0x56, 0x54, 0xff, 0x9c, 0x80, 0x7c, 0xff, - 0x96, 0x85, 0x84, 0xff, 0x75, 0x56, 0x54, 0xff, 0x78, 0x66, 0x64, 0xff, - 0x84, 0x77, 0x74, 0xff, 0xb1, 0xaa, 0xa4, 0xff, 0x94, 0x8b, 0x84, 0xff, - 0x8f, 0x7f, 0x7c, 0xff, 0x81, 0x72, 0x74, 0xff, 0x96, 0x85, 0x84, 0xff, - 0x9d, 0x8d, 0x8c, 0xff, 0x8c, 0x81, 0x84, 0xff, 0x96, 0x85, 0x84, 0xff, - 0xa4, 0x9e, 0xa4, 0xff, 0xd4, 0xc6, 0xc4, 0xff, 0xc5, 0xb7, 0xb4, 0xff, - 0xae, 0xa4, 0xa4, 0xff, 0xae, 0xa4, 0xa4, 0xff, 0xd7, 0xcc, 0xc4, 0xff, - 0xef, 0xe2, 0xdc, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xac, 0x8e, 0x7c, 0xff, - 0x7c, 0x5c, 0x4c, 0xff, 0x74, 0x5b, 0x4c, 0xff, 0x74, 0x55, 0x4c, 0xff, - 0x74, 0x55, 0x4c, 0xff, 0x7c, 0x5d, 0x54, 0xff, 0x74, 0x5b, 0x4c, 0xff, - 0x74, 0x5b, 0x4c, 0xff, 0x74, 0x5b, 0x4c, 0xff, 0x6f, 0x56, 0x44, 0xff, - 0x74, 0x5b, 0x4c, 0xff, 0x6f, 0x56, 0x44, 0xff, 0x7c, 0x62, 0x54, 0xff, - 0x7c, 0x5d, 0x54, 0xff, 0x7d, 0x62, 0x5c, 0xff, 0x7d, 0x62, 0x5c, 0xff, - 0x8c, 0x6e, 0x64, 0xff, 0x6b, 0x56, 0x5c, 0xff, 0x7c, 0x5d, 0x54, 0xff, - 0x7c, 0x5d, 0x54, 0xff, 0x70, 0x5e, 0x5c, 0xff, 0x75, 0x56, 0x54, 0xff, - 0x75, 0x56, 0x54, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x6a, 0x53, 0x4c, 0xff, - 0x61, 0x48, 0x44, 0xff, 0x69, 0x4e, 0x4c, 0xff, 0x8f, 0x7f, 0x7c, 0xff, - 0x7d, 0x62, 0x5c, 0xff, 0x7d, 0x62, 0x5c, 0xff, 0xb4, 0x9b, 0x94, 0xff, - 0x96, 0x85, 0x84, 0xff, 0x7c, 0x5d, 0x54, 0xff, 0x75, 0x56, 0x54, 0xff, - 0x7c, 0x72, 0x64, 0xff, 0x9d, 0x8d, 0x8c, 0xff, 0xae, 0xa4, 0xa4, 0xff, - 0xbc, 0xb0, 0xac, 0xff, 0x84, 0x77, 0x74, 0xff, 0x9d, 0x8d, 0x8c, 0xff, - 0x96, 0x85, 0x84, 0xff, 0xad, 0x9a, 0x9c, 0xff, 0x96, 0x86, 0x8c, 0xff, - 0x81, 0x72, 0x74, 0xff, 0xa1, 0x99, 0x9c, 0xff, 0xcc, 0xbd, 0xbc, 0xff, - 0x88, 0x8a, 0x84, 0xff, 0xae, 0xa4, 0xa4, 0xff, 0xc2, 0xc2, 0xbc, 0xff, - 0xd5, 0xcd, 0xcc, 0xff, 0xf2, 0xe9, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xa4, 0x86, 0x74, 0xff, 0x74, 0x5b, 0x4c, 0xff, - 0x69, 0x4e, 0x44, 0xff, 0x74, 0x5b, 0x4c, 0xff, 0x74, 0x55, 0x4c, 0xff, - 0x72, 0x5b, 0x54, 0xff, 0x7c, 0x5d, 0x54, 0xff, 0x74, 0x5b, 0x4c, 0xff, - 0x7c, 0x5d, 0x54, 0xff, 0x74, 0x5b, 0x4c, 0xff, 0x69, 0x4e, 0x44, 0xff, - 0x74, 0x5b, 0x4c, 0xff, 0x7c, 0x5c, 0x4c, 0xff, 0x7c, 0x62, 0x54, 0xff, - 0x7d, 0x62, 0x5c, 0xff, 0x8d, 0x72, 0x6b, 0xff, 0x7d, 0x62, 0x5c, 0xff, - 0x8e, 0x72, 0x74, 0xff, 0x9c, 0x80, 0x7c, 0xff, 0x7d, 0x62, 0x5c, 0xff, - 0x75, 0x56, 0x54, 0xff, 0x7d, 0x62, 0x5c, 0xff, 0x72, 0x5b, 0x54, 0xff, - 0x6c, 0x4a, 0x44, 0xff, 0x58, 0x49, 0x4c, 0xff, 0x74, 0x4e, 0x4c, 0xff, - 0x61, 0x48, 0x44, 0xff, 0x50, 0x4e, 0x44, 0xff, 0x7c, 0x5e, 0x5c, 0xff, - 0x70, 0x5e, 0x5c, 0xff, 0x8f, 0x7f, 0x7c, 0xff, 0xbc, 0xa4, 0x9c, 0xff, - 0x8e, 0x79, 0x74, 0xff, 0x72, 0x5b, 0x54, 0xff, 0x70, 0x5e, 0x5c, 0xff, - 0x84, 0x77, 0x74, 0xff, 0x84, 0x77, 0x74, 0xff, 0x9e, 0x8b, 0x84, 0xff, - 0x9d, 0x8d, 0x8c, 0xff, 0x8c, 0x81, 0x84, 0xff, 0x96, 0x86, 0x8c, 0xff, - 0xae, 0xa4, 0xa4, 0xff, 0xbc, 0xaa, 0xac, 0xff, 0xc4, 0xba, 0xbc, 0xff, - 0x84, 0x77, 0x74, 0xff, 0x8f, 0x7f, 0x7c, 0xff, 0xad, 0x9e, 0x9e, 0xff, - 0xb1, 0xaa, 0xa4, 0xff, 0xb3, 0xae, 0xac, 0xff, 0xb1, 0xaa, 0xa4, 0xff, - 0xc9, 0xc0, 0xb4, 0xff, 0xf2, 0xe9, 0xdc, 0xff, 0xfc, 0xea, 0xdc, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xac, 0x8e, 0x7c, 0xff, 0x6f, 0x56, 0x44, 0xff, 0x74, 0x5b, 0x4c, 0xff, - 0x74, 0x5b, 0x4c, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x74, 0x55, 0x4c, 0xff, - 0x72, 0x5b, 0x54, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x7c, 0x5d, 0x54, 0xff, - 0x72, 0x5b, 0x54, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x74, 0x55, 0x4c, 0xff, - 0x7c, 0x5d, 0x54, 0xff, 0x7c, 0x5d, 0x54, 0xff, 0x7c, 0x5d, 0x54, 0xff, - 0x80, 0x67, 0x5c, 0xff, 0x7c, 0x5d, 0x54, 0xff, 0x75, 0x62, 0x64, 0xff, - 0x9c, 0x7a, 0x74, 0xff, 0xa4, 0x85, 0x84, 0xff, 0x9c, 0x7a, 0x7c, 0xff, - 0x72, 0x5b, 0x54, 0xff, 0x7d, 0x62, 0x5c, 0xff, 0x70, 0x5e, 0x5c, 0xff, - 0x75, 0x56, 0x54, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x6a, 0x53, 0x4c, 0xff, - 0x69, 0x55, 0x54, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x6a, 0x53, 0x4c, 0xff, - 0x69, 0x55, 0x54, 0xff, 0x9c, 0x80, 0x7c, 0xff, 0xbc, 0xa4, 0x9c, 0xff, - 0x7f, 0x72, 0x6c, 0xff, 0x7d, 0x62, 0x5c, 0xff, 0x7c, 0x5e, 0x5c, 0xff, - 0x84, 0x77, 0x74, 0xff, 0x5d, 0x5a, 0x54, 0xff, 0x70, 0x5e, 0x5c, 0xff, - 0x7e, 0x6d, 0x6c, 0xff, 0x8c, 0x81, 0x84, 0xff, 0xa8, 0x9b, 0x94, 0xff, - 0xc6, 0xb1, 0xb4, 0xff, 0xc4, 0xba, 0xbc, 0xff, 0xb4, 0xaa, 0xac, 0xff, - 0x78, 0x66, 0x64, 0xff, 0x84, 0x77, 0x74, 0xff, 0x94, 0x8c, 0x8c, 0xff, - 0x9d, 0x8d, 0x8c, 0xff, 0xa8, 0x9b, 0x94, 0xff, 0xa1, 0x99, 0x9c, 0xff, - 0xb0, 0xa3, 0x9c, 0xff, 0xd7, 0xcc, 0xc4, 0xff, 0xfc, 0xea, 0xdc, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xea, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, - 0xf7, 0xdd, 0xcc, 0xff, 0xf7, 0xdd, 0xcc, 0xff, 0x94, 0x79, 0x6c, 0xff, - 0x74, 0x55, 0x4c, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x6f, 0x56, 0x44, 0xff, - 0x69, 0x4e, 0x44, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x74, 0x55, 0x4c, 0xff, - 0x7c, 0x5d, 0x54, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x6a, 0x53, 0x4c, 0xff, - 0x74, 0x55, 0x4c, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x7c, 0x5d, 0x54, 0xff, - 0x64, 0x5a, 0x4c, 0xff, 0x7c, 0x5d, 0x54, 0xff, 0x7c, 0x5d, 0x54, 0xff, - 0x75, 0x62, 0x64, 0xff, 0x8d, 0x72, 0x6b, 0xff, 0x8c, 0x6d, 0x6c, 0xff, - 0x8c, 0x6d, 0x6c, 0xff, 0x9c, 0x80, 0x7c, 0xff, 0x8c, 0x6d, 0x6c, 0xff, - 0x7c, 0x5e, 0x5c, 0xff, 0x69, 0x4e, 0x4c, 0xff, 0x6a, 0x53, 0x4c, 0xff, - 0x75, 0x56, 0x54, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x70, 0x5e, 0x5c, 0xff, - 0x69, 0x4e, 0x4c, 0xff, 0x6a, 0x53, 0x4c, 0xff, 0x69, 0x55, 0x54, 0xff, - 0x7c, 0x5d, 0x54, 0xff, 0x78, 0x66, 0x64, 0xff, 0x72, 0x5b, 0x54, 0xff, - 0x72, 0x5b, 0x54, 0xff, 0x7e, 0x6d, 0x6c, 0xff, 0x7c, 0x5d, 0x54, 0xff, - 0x72, 0x62, 0x5c, 0xff, 0x7d, 0x62, 0x5c, 0xff, 0x78, 0x66, 0x64, 0xff, - 0x78, 0x66, 0x64, 0xff, 0x78, 0x66, 0x64, 0xff, 0xa4, 0x9e, 0xa4, 0xff, - 0xae, 0xa4, 0xa4, 0xff, 0xad, 0x9e, 0x9e, 0xff, 0x9d, 0x8d, 0x8c, 0xff, - 0x7e, 0x6d, 0x6c, 0xff, 0x78, 0x66, 0x64, 0xff, 0x84, 0x77, 0x74, 0xff, - 0x8f, 0x7f, 0x7c, 0xff, 0x94, 0x8c, 0x8c, 0xff, 0x9d, 0x8d, 0x8c, 0xff, - 0xae, 0xa4, 0xa4, 0xff, 0xae, 0xa4, 0xa4, 0xff, 0xec, 0xdb, 0xcc, 0xff, - 0xf2, 0xe9, 0xdc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xfc, 0xe2, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xf7, 0xdd, 0xcc, 0xff, 0x94, 0x76, 0x64, 0xff, 0x69, 0x4e, 0x44, 0xff, - 0x74, 0x5b, 0x4c, 0xff, 0x69, 0x4e, 0x44, 0xff, 0x6f, 0x56, 0x44, 0xff, - 0x74, 0x5b, 0x4c, 0xff, 0x7c, 0x5d, 0x54, 0xff, 0x7c, 0x5d, 0x54, 0xff, - 0x69, 0x4e, 0x4c, 0xff, 0x6a, 0x53, 0x4c, 0xff, 0x74, 0x4e, 0x4c, 0xff, - 0x7c, 0x5d, 0x54, 0xff, 0x7d, 0x62, 0x5c, 0xff, 0x8e, 0x79, 0x74, 0xff, - 0x7c, 0x5e, 0x5c, 0xff, 0x72, 0x62, 0x5c, 0xff, 0x7d, 0x62, 0x5c, 0xff, - 0x8c, 0x6e, 0x64, 0xff, 0x78, 0x66, 0x64, 0xff, 0x7f, 0x6a, 0x64, 0xff, - 0x78, 0x66, 0x64, 0xff, 0x7d, 0x62, 0x5c, 0xff, 0x69, 0x55, 0x54, 0xff, - 0x6a, 0x53, 0x4c, 0xff, 0x72, 0x5b, 0x54, 0xff, 0x7d, 0x62, 0x5c, 0xff, - 0x7c, 0x5e, 0x5c, 0xff, 0x6a, 0x53, 0x4c, 0xff, 0x69, 0x55, 0x54, 0xff, - 0x80, 0x67, 0x5c, 0xff, 0x75, 0x56, 0x54, 0xff, 0x50, 0x4e, 0x44, 0xff, - 0x69, 0x4e, 0x4c, 0xff, 0x69, 0x4e, 0x4c, 0xff, 0x6a, 0x53, 0x4c, 0xff, - 0x7f, 0x6a, 0x64, 0xff, 0x8f, 0x7f, 0x7c, 0xff, 0x7e, 0x6d, 0x6c, 0xff, - 0x72, 0x5b, 0x54, 0xff, 0x7e, 0x6d, 0x6c, 0xff, 0x8c, 0x81, 0x84, 0xff, - 0x9d, 0x8d, 0x8c, 0xff, 0x8c, 0x81, 0x84, 0xff, 0x96, 0x85, 0x84, 0xff, - 0xb4, 0xaa, 0xac, 0xff, 0xad, 0x9e, 0x9e, 0xff, 0x8e, 0x7a, 0x7c, 0xff, - 0x96, 0x85, 0x84, 0xff, 0x8c, 0x81, 0x84, 0xff, 0x8f, 0x7f, 0x7c, 0xff, - 0x8e, 0x7a, 0x7c, 0xff, 0x9e, 0x8e, 0x94, 0xff, 0x9a, 0x94, 0x94, 0xff, - 0xbf, 0xaa, 0xa4, 0xff, 0xa8, 0x9b, 0x94, 0xff, 0xd9, 0xcc, 0xbc, 0xff, - 0xef, 0xe2, 0xdc, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xf2, 0xe9, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0x9c, 0x80, 0x7c, 0xff, 0x6f, 0x56, 0x44, 0xff, 0x74, 0x5b, 0x4c, 0xff, - 0x7c, 0x5c, 0x4c, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x74, 0x5b, 0x4c, 0xff, - 0x7c, 0x5d, 0x54, 0xff, 0x7c, 0x5d, 0x54, 0xff, 0x74, 0x55, 0x4c, 0xff, - 0x69, 0x4e, 0x44, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x74, 0x55, 0x4c, 0xff, - 0x7c, 0x5e, 0x5c, 0xff, 0x8c, 0x6d, 0x6c, 0xff, 0x9c, 0x80, 0x7c, 0xff, - 0x8d, 0x72, 0x6b, 0xff, 0x69, 0x55, 0x54, 0xff, 0x78, 0x66, 0x64, 0xff, - 0x96, 0x85, 0x84, 0xff, 0x7c, 0x5d, 0x54, 0xff, 0x70, 0x5e, 0x5c, 0xff, - 0x72, 0x5b, 0x54, 0xff, 0x6a, 0x53, 0x4c, 0xff, 0x70, 0x5e, 0x5c, 0xff, - 0x80, 0x67, 0x5c, 0xff, 0x78, 0x66, 0x64, 0xff, 0x90, 0x7f, 0x74, 0xff, - 0x8e, 0x79, 0x74, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x75, 0x56, 0x54, 0xff, - 0x7f, 0x6a, 0x64, 0xff, 0x61, 0x48, 0x44, 0xff, 0x69, 0x4e, 0x44, 0xff, - 0x74, 0x55, 0x4c, 0xff, 0x69, 0x4e, 0x44, 0xff, 0x70, 0x5e, 0x5c, 0xff, - 0x90, 0x7f, 0x74, 0xff, 0x9c, 0x88, 0x7c, 0xff, 0x72, 0x5b, 0x54, 0xff, - 0x69, 0x55, 0x54, 0xff, 0x8e, 0x79, 0x74, 0xff, 0xac, 0x8d, 0x8c, 0xff, - 0xa6, 0x95, 0x94, 0xff, 0xad, 0x9e, 0x9e, 0xff, 0xa1, 0x99, 0x9c, 0xff, - 0xb3, 0xae, 0xac, 0xff, 0x94, 0x8c, 0x8c, 0xff, 0x84, 0x77, 0x74, 0xff, - 0x9c, 0x80, 0x7c, 0xff, 0x96, 0x85, 0x84, 0xff, 0x9d, 0x8d, 0x8c, 0xff, - 0x8e, 0x7a, 0x7c, 0xff, 0xa6, 0x95, 0x94, 0xff, 0xa1, 0x99, 0x9c, 0xff, - 0xc6, 0xb1, 0xb4, 0xff, 0xa6, 0x95, 0x94, 0xff, 0xba, 0xb0, 0xa4, 0xff, - 0xe6, 0xd6, 0xcc, 0xff, 0xf2, 0xe9, 0xdc, 0xff, 0xfc, 0xea, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xea, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe2, 0xcc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xac, 0x8e, 0x7c, 0xff, - 0x69, 0x4e, 0x44, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x74, 0x55, 0x4c, 0xff, - 0x74, 0x55, 0x4c, 0xff, 0x74, 0x5b, 0x4c, 0xff, 0x7c, 0x5d, 0x54, 0xff, - 0x7c, 0x5d, 0x54, 0xff, 0x74, 0x5b, 0x4c, 0xff, 0x74, 0x4e, 0x44, 0xff, - 0x69, 0x4e, 0x4c, 0xff, 0x6c, 0x4a, 0x44, 0xff, 0x74, 0x55, 0x4c, 0xff, - 0x78, 0x66, 0x64, 0xff, 0xac, 0x8d, 0x8c, 0xff, 0xbf, 0xaa, 0xa4, 0xff, - 0xad, 0x9e, 0x9e, 0xff, 0x70, 0x5e, 0x5c, 0xff, 0x9c, 0x80, 0x7c, 0xff, - 0x7e, 0x6d, 0x6c, 0xff, 0x69, 0x55, 0x54, 0xff, 0x69, 0x55, 0x54, 0xff, - 0x6a, 0x53, 0x4c, 0xff, 0x61, 0x48, 0x44, 0xff, 0x6a, 0x53, 0x4c, 0xff, - 0x80, 0x67, 0x5c, 0xff, 0x8a, 0x76, 0x6c, 0xff, 0x7c, 0x5d, 0x54, 0xff, - 0x72, 0x5b, 0x54, 0xff, 0x80, 0x67, 0x5c, 0xff, 0x6a, 0x53, 0x4c, 0xff, - 0x69, 0x4e, 0x44, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x74, 0x55, 0x4c, 0xff, - 0x69, 0x4e, 0x44, 0xff, 0x69, 0x4e, 0x4c, 0xff, 0x69, 0x4e, 0x44, 0xff, - 0x8e, 0x79, 0x74, 0xff, 0x7c, 0x5d, 0x54, 0xff, 0x69, 0x4e, 0x4c, 0xff, - 0x64, 0x4e, 0x54, 0xff, 0x9c, 0x7a, 0x74, 0xff, 0xad, 0x9a, 0x9c, 0xff, - 0x96, 0x85, 0x84, 0xff, 0x96, 0x85, 0x84, 0xff, 0x9d, 0x8d, 0x8c, 0xff, - 0xc4, 0xba, 0xbc, 0xff, 0x9a, 0x94, 0x94, 0xff, 0x8c, 0x81, 0x84, 0xff, - 0x94, 0x8b, 0x84, 0xff, 0x96, 0x85, 0x84, 0xff, 0x84, 0x79, 0x7c, 0xff, - 0x81, 0x72, 0x74, 0xff, 0x9d, 0x8d, 0x8c, 0xff, 0xad, 0x9e, 0x9e, 0xff, - 0xbc, 0xb1, 0xb4, 0xff, 0xbc, 0xb0, 0xac, 0xff, 0xa8, 0x9b, 0x94, 0xff, - 0xbc, 0xb0, 0xac, 0xff, 0xe2, 0xdc, 0xcc, 0xff, 0xf2, 0xe9, 0xdc, 0xff, - 0xf2, 0xe9, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe6, 0xcc, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0x94, 0x79, 0x6c, 0xff, 0x74, 0x55, 0x4c, 0xff, - 0x74, 0x55, 0x4c, 0xff, 0x6a, 0x53, 0x4c, 0xff, 0x74, 0x55, 0x4c, 0xff, - 0x7c, 0x5d, 0x54, 0xff, 0x7d, 0x62, 0x5c, 0xff, 0x7c, 0x62, 0x54, 0xff, - 0x74, 0x55, 0x4c, 0xff, 0x69, 0x4e, 0x4c, 0xff, 0x74, 0x4e, 0x44, 0xff, - 0x69, 0x4e, 0x44, 0xff, 0x6a, 0x53, 0x4c, 0xff, 0x75, 0x56, 0x54, 0xff, - 0x7f, 0x6a, 0x64, 0xff, 0xbc, 0xa4, 0x9c, 0xff, 0xc5, 0xb7, 0xb4, 0xff, - 0xac, 0x8d, 0x8c, 0xff, 0x7f, 0x6a, 0x64, 0xff, 0x7e, 0x6d, 0x6c, 0xff, - 0x7d, 0x62, 0x5c, 0xff, 0x6a, 0x53, 0x4c, 0xff, 0x69, 0x4e, 0x4c, 0xff, - 0x69, 0x55, 0x54, 0xff, 0x6a, 0x53, 0x4c, 0xff, 0x72, 0x5b, 0x54, 0xff, - 0x75, 0x62, 0x64, 0xff, 0x78, 0x66, 0x64, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x74, 0x55, 0x4c, 0xff, 0x69, 0x4e, 0x4c, 0xff, 0x69, 0x4e, 0x44, 0xff, - 0x74, 0x55, 0x4c, 0xff, 0x7d, 0x62, 0x5c, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x75, 0x56, 0x54, 0xff, 0x69, 0x4e, 0x4c, 0xff, 0x75, 0x56, 0x54, 0xff, - 0x7f, 0x6a, 0x64, 0xff, 0x6a, 0x53, 0x4c, 0xff, 0x6a, 0x53, 0x4c, 0xff, - 0x7c, 0x5d, 0x54, 0xff, 0x9c, 0x80, 0x7c, 0xff, 0x8e, 0x7a, 0x7c, 0xff, - 0x70, 0x5e, 0x5c, 0xff, 0x75, 0x62, 0x64, 0xff, 0x78, 0x66, 0x64, 0xff, - 0xa6, 0x95, 0x94, 0xff, 0x9e, 0x8e, 0x94, 0xff, 0x94, 0x8c, 0x8c, 0xff, - 0x9d, 0x8d, 0x8c, 0xff, 0xad, 0x9a, 0x9c, 0xff, 0x70, 0x5e, 0x5c, 0xff, - 0x75, 0x62, 0x64, 0xff, 0x96, 0x86, 0x8c, 0xff, 0xad, 0x9e, 0x9e, 0xff, - 0xd4, 0xc6, 0xc4, 0xff, 0xc4, 0xba, 0xbc, 0xff, 0xae, 0xa4, 0xa4, 0xff, - 0xae, 0xa4, 0xa4, 0xff, 0xba, 0xb0, 0xa4, 0xff, 0xd9, 0xd4, 0xcc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0x9c, 0x7e, 0x6c, 0xff, 0x7c, 0x62, 0x54, 0xff, 0x74, 0x55, 0x4c, 0xff, - 0x74, 0x55, 0x4c, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x75, 0x56, 0x54, 0xff, - 0x7c, 0x5d, 0x54, 0xff, 0x7c, 0x5d, 0x54, 0xff, 0x75, 0x56, 0x54, 0xff, - 0x69, 0x4e, 0x44, 0xff, 0x6c, 0x4a, 0x44, 0xff, 0x74, 0x55, 0x4c, 0xff, - 0x74, 0x55, 0x4c, 0xff, 0x69, 0x4e, 0x44, 0xff, 0x72, 0x62, 0x5c, 0xff, - 0x94, 0x79, 0x6c, 0xff, 0xbc, 0xa4, 0x9c, 0xff, 0xc7, 0xb8, 0xac, 0xff, - 0x70, 0x66, 0x5c, 0xff, 0x7d, 0x62, 0x5c, 0xff, 0x7d, 0x62, 0x5c, 0xff, - 0x72, 0x5b, 0x54, 0xff, 0x72, 0x5b, 0x54, 0xff, 0x6a, 0x53, 0x4c, 0xff, - 0x6a, 0x53, 0x4c, 0xff, 0x70, 0x5e, 0x5c, 0xff, 0x7c, 0x72, 0x64, 0xff, - 0x70, 0x5e, 0x5c, 0xff, 0x8c, 0x6e, 0x64, 0xff, 0x58, 0x49, 0x4c, 0xff, - 0x69, 0x4e, 0x44, 0xff, 0x74, 0x4e, 0x4c, 0xff, 0x69, 0x4e, 0x44, 0xff, - 0x72, 0x5b, 0x54, 0xff, 0x7e, 0x6d, 0x6c, 0xff, 0x7d, 0x62, 0x5c, 0xff, - 0x9c, 0x80, 0x7c, 0xff, 0x7c, 0x5e, 0x5c, 0xff, 0x75, 0x56, 0x54, 0xff, - 0x7f, 0x6a, 0x64, 0xff, 0x75, 0x56, 0x54, 0xff, 0x6a, 0x53, 0x4c, 0xff, - 0x75, 0x62, 0x64, 0xff, 0xac, 0x8d, 0x8c, 0xff, 0x7c, 0x5e, 0x5c, 0xff, - 0x70, 0x5e, 0x5c, 0xff, 0x8e, 0x7a, 0x7c, 0xff, 0x8e, 0x7a, 0x7c, 0xff, - 0xa1, 0x99, 0x9c, 0xff, 0x9d, 0x8d, 0x8c, 0xff, 0x9e, 0x8e, 0x94, 0xff, - 0xa6, 0x95, 0x94, 0xff, 0xad, 0x9e, 0x9e, 0xff, 0x6b, 0x56, 0x5c, 0xff, - 0x6b, 0x56, 0x5c, 0xff, 0x7e, 0x6d, 0x6c, 0xff, 0xad, 0x9e, 0x9e, 0xff, - 0xbc, 0xb1, 0xb4, 0xff, 0xc4, 0xba, 0xbc, 0xff, 0xc2, 0xbe, 0xbc, 0xff, - 0xb4, 0xaa, 0xac, 0xff, 0xba, 0xb0, 0xa4, 0xff, 0xc5, 0xb7, 0xb4, 0xff, - 0xe2, 0xdc, 0xcc, 0xff, 0xfc, 0xf2, 0xe4, 0xff, 0xf2, 0xe9, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf9, 0xe2, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xac, 0x8d, 0x84, 0xff, - 0x74, 0x55, 0x4c, 0xff, 0x7c, 0x5d, 0x54, 0xff, 0x72, 0x5b, 0x54, 0xff, - 0x74, 0x55, 0x4c, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x7c, 0x5c, 0x4c, 0xff, - 0x7c, 0x5d, 0x54, 0xff, 0x75, 0x56, 0x54, 0xff, 0x74, 0x4e, 0x44, 0xff, - 0x74, 0x4e, 0x44, 0xff, 0x75, 0x56, 0x54, 0xff, 0x74, 0x4e, 0x4c, 0xff, - 0x61, 0x48, 0x44, 0xff, 0x69, 0x4e, 0x4c, 0xff, 0x74, 0x55, 0x4c, 0xff, - 0x8a, 0x76, 0x6c, 0xff, 0xc5, 0xb7, 0xb4, 0xff, 0x8a, 0x76, 0x6c, 0xff, - 0x70, 0x5e, 0x5c, 0xff, 0x78, 0x66, 0x64, 0xff, 0x7c, 0x5e, 0x5c, 0xff, - 0x6a, 0x53, 0x4c, 0xff, 0x69, 0x55, 0x54, 0xff, 0x69, 0x55, 0x54, 0xff, - 0x74, 0x55, 0x4c, 0xff, 0x78, 0x66, 0x64, 0xff, 0x72, 0x62, 0x5c, 0xff, - 0x7e, 0x6d, 0x6c, 0xff, 0x7d, 0x62, 0x5c, 0xff, 0x6c, 0x4a, 0x44, 0xff, - 0x74, 0x55, 0x4c, 0xff, 0x6a, 0x53, 0x4c, 0xff, 0x69, 0x4e, 0x44, 0xff, - 0x74, 0x55, 0x4c, 0xff, 0x72, 0x5b, 0x54, 0xff, 0x84, 0x77, 0x74, 0xff, - 0xbd, 0xa6, 0xa4, 0xff, 0x84, 0x77, 0x74, 0xff, 0x7c, 0x5d, 0x54, 0xff, - 0x7e, 0x6d, 0x6c, 0xff, 0x69, 0x4e, 0x4c, 0xff, 0x75, 0x56, 0x54, 0xff, - 0x8d, 0x72, 0x6b, 0xff, 0x96, 0x85, 0x84, 0xff, 0x69, 0x4e, 0x4c, 0xff, - 0x70, 0x5e, 0x5c, 0xff, 0x84, 0x77, 0x74, 0xff, 0x96, 0x86, 0x8c, 0xff, - 0xae, 0xa4, 0xa4, 0xff, 0x9d, 0x8d, 0x8c, 0xff, 0xad, 0x9a, 0x9c, 0xff, - 0x96, 0x86, 0x8c, 0xff, 0x81, 0x72, 0x74, 0xff, 0x81, 0x72, 0x74, 0xff, - 0x70, 0x5e, 0x5c, 0xff, 0x70, 0x5e, 0x5c, 0xff, 0x9e, 0x8b, 0x84, 0xff, - 0xbc, 0xb0, 0xac, 0xff, 0xbc, 0xb1, 0xb4, 0xff, 0xba, 0xb6, 0xb4, 0xff, - 0xcc, 0xbe, 0xc4, 0xff, 0xa1, 0xa2, 0x9c, 0xff, 0xc7, 0xb8, 0xac, 0xff, - 0xd7, 0xcc, 0xc4, 0xff, 0xf2, 0xe9, 0xdc, 0xff, 0xf2, 0xe9, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf2, 0xe9, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf9, 0xe2, 0xd4, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xb4, 0x9a, 0x8c, 0xff, 0x72, 0x5b, 0x54, 0xff, - 0x72, 0x5b, 0x54, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x7c, 0x5d, 0x54, 0xff, - 0x74, 0x55, 0x4c, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x7c, 0x5d, 0x54, 0xff, - 0x74, 0x55, 0x4c, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x69, 0x4e, 0x44, 0xff, - 0x74, 0x4e, 0x44, 0xff, 0x75, 0x56, 0x54, 0xff, 0x7c, 0x5d, 0x54, 0xff, - 0x6a, 0x53, 0x4c, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x69, 0x4e, 0x44, 0xff, - 0x72, 0x5b, 0x54, 0xff, 0x9c, 0x80, 0x7c, 0xff, 0x7d, 0x62, 0x5c, 0xff, - 0x7c, 0x5d, 0x54, 0xff, 0x72, 0x5b, 0x54, 0xff, 0x69, 0x4e, 0x4c, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x69, 0x4e, 0x4c, 0xff, 0x78, 0x66, 0x64, 0xff, - 0x74, 0x55, 0x4c, 0xff, 0x84, 0x77, 0x74, 0xff, 0x7e, 0x6d, 0x6c, 0xff, - 0x7f, 0x6a, 0x64, 0xff, 0x69, 0x55, 0x54, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x74, 0x55, 0x4c, 0xff, 0x69, 0x4e, 0x4c, 0xff, 0x74, 0x55, 0x4c, 0xff, - 0x69, 0x4e, 0x44, 0xff, 0x58, 0x49, 0x4c, 0xff, 0x7c, 0x5d, 0x54, 0xff, - 0x7e, 0x6d, 0x6c, 0xff, 0x7f, 0x6a, 0x64, 0xff, 0x9c, 0x80, 0x7c, 0xff, - 0x9c, 0x80, 0x7c, 0xff, 0x74, 0x4e, 0x4c, 0xff, 0x7e, 0x6d, 0x6c, 0xff, - 0x8e, 0x79, 0x74, 0xff, 0x8c, 0x6d, 0x6c, 0xff, 0x69, 0x55, 0x54, 0xff, - 0x7d, 0x62, 0x5c, 0xff, 0x8e, 0x7a, 0x7c, 0xff, 0x9d, 0x8d, 0x8c, 0xff, - 0xad, 0x9a, 0x9c, 0xff, 0x9e, 0x8e, 0x94, 0xff, 0xa4, 0x9e, 0xa4, 0xff, - 0x9e, 0x8e, 0x94, 0xff, 0x9d, 0x8d, 0x8c, 0xff, 0x9e, 0x8e, 0x94, 0xff, - 0x81, 0x72, 0x74, 0xff, 0x6b, 0x56, 0x5c, 0xff, 0x7e, 0x6d, 0x6c, 0xff, - 0xae, 0xa4, 0xa4, 0xff, 0x9a, 0x94, 0x94, 0xff, 0xc4, 0xba, 0xbc, 0xff, - 0xd5, 0xcd, 0xcc, 0xff, 0xa1, 0x9e, 0x9c, 0xff, 0xb0, 0xa3, 0x9c, 0xff, - 0xbc, 0xb6, 0xac, 0xff, 0xd9, 0xd4, 0xcc, 0xff, 0xf2, 0xe9, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xf2, 0xe9, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xb1, 0xa3, 0x94, 0xff, 0xc9, 0xc0, 0xb4, 0xff, 0xd9, 0xcc, 0xbc, 0xff, - 0x9c, 0x80, 0x7c, 0xff, 0x72, 0x5b, 0x54, 0xff, 0x7c, 0x5d, 0x54, 0xff, - 0x74, 0x5b, 0x4c, 0xff, 0x7c, 0x5d, 0x54, 0xff, 0x7c, 0x5d, 0x54, 0xff, - 0x7c, 0x5d, 0x54, 0xff, 0x75, 0x56, 0x54, 0xff, 0x74, 0x55, 0x4c, 0xff, - 0x6c, 0x4a, 0x44, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x74, 0x55, 0x4c, 0xff, - 0x7c, 0x5d, 0x54, 0xff, 0x7c, 0x5d, 0x54, 0xff, 0x75, 0x56, 0x54, 0xff, - 0x6a, 0x53, 0x4c, 0xff, 0x61, 0x48, 0x44, 0xff, 0x69, 0x4e, 0x44, 0xff, - 0x74, 0x55, 0x4c, 0xff, 0x72, 0x5b, 0x54, 0xff, 0x69, 0x4e, 0x44, 0xff, - 0x69, 0x4e, 0x4c, 0xff, 0x6a, 0x53, 0x4c, 0xff, 0x6a, 0x53, 0x4c, 0xff, - 0x72, 0x5b, 0x54, 0xff, 0x69, 0x4e, 0x4c, 0xff, 0x84, 0x77, 0x74, 0xff, - 0x70, 0x5e, 0x5c, 0xff, 0x8f, 0x7f, 0x7c, 0xff, 0x7c, 0x72, 0x64, 0xff, - 0x8f, 0x86, 0x7c, 0xff, 0x7c, 0x5d, 0x54, 0xff, 0x69, 0x4e, 0x4c, 0xff, - 0x72, 0x5b, 0x54, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x74, 0x55, 0x4c, 0xff, - 0x7c, 0x5d, 0x54, 0xff, 0x75, 0x56, 0x54, 0xff, 0x58, 0x49, 0x4c, 0xff, - 0x75, 0x56, 0x54, 0xff, 0x8e, 0x72, 0x74, 0xff, 0x8c, 0x81, 0x84, 0xff, - 0x8e, 0x79, 0x74, 0xff, 0x7e, 0x6d, 0x6c, 0xff, 0x8e, 0x72, 0x74, 0xff, - 0x69, 0x55, 0x54, 0xff, 0x6a, 0x53, 0x4c, 0xff, 0x69, 0x55, 0x54, 0xff, - 0x84, 0x77, 0x74, 0xff, 0x9d, 0x8d, 0x8c, 0xff, 0xad, 0x9a, 0x9c, 0xff, - 0xbc, 0xaa, 0xac, 0xff, 0x9a, 0x94, 0x94, 0xff, 0xad, 0x9a, 0x9c, 0xff, - 0xbd, 0xa6, 0xa4, 0xff, 0xbd, 0xa6, 0xa4, 0xff, 0xad, 0x9a, 0x9c, 0xff, - 0xad, 0x9e, 0x9e, 0xff, 0x8e, 0x72, 0x74, 0xff, 0x7f, 0x72, 0x6c, 0xff, - 0xa1, 0x99, 0x9c, 0xff, 0xa4, 0x9e, 0xa4, 0xff, 0xb4, 0xaa, 0xac, 0xff, - 0xbc, 0xb1, 0xb4, 0xff, 0xc5, 0xb7, 0xb4, 0xff, 0xb0, 0xa3, 0x9c, 0xff, - 0xbc, 0xb0, 0xac, 0xff, 0xbc, 0xb0, 0xac, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf4, 0xea, 0xe4, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xf2, 0xe4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf2, 0xe9, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xf2, 0xe9, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0x7c, 0x72, 0x64, 0xff, 0x7f, 0x72, 0x6c, 0xff, 0x64, 0x5a, 0x4c, 0xff, - 0x6a, 0x53, 0x4c, 0xff, 0x72, 0x5b, 0x54, 0xff, 0x72, 0x5b, 0x54, 0xff, - 0x70, 0x5e, 0x5c, 0xff, 0x7c, 0x5e, 0x5c, 0xff, 0x75, 0x56, 0x54, 0xff, - 0x75, 0x56, 0x54, 0xff, 0x7c, 0x5d, 0x54, 0xff, 0x7c, 0x5c, 0x4c, 0xff, - 0x74, 0x55, 0x4c, 0xff, 0x75, 0x56, 0x54, 0xff, 0x7c, 0x5d, 0x54, 0xff, - 0x72, 0x5b, 0x54, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x74, 0x55, 0x4c, 0xff, - 0x61, 0x48, 0x44, 0xff, 0x61, 0x48, 0x44, 0xff, 0x6a, 0x53, 0x4c, 0xff, - 0x50, 0x4e, 0x44, 0xff, 0x61, 0x48, 0x44, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x69, 0x4e, 0x4c, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x69, 0x55, 0x54, 0xff, - 0x8c, 0x6d, 0x6c, 0xff, 0x84, 0x77, 0x74, 0xff, 0x7f, 0x6a, 0x64, 0xff, - 0x7f, 0x6a, 0x64, 0xff, 0x6a, 0x53, 0x4c, 0xff, 0x69, 0x55, 0x54, 0xff, - 0x71, 0x6a, 0x64, 0xff, 0x55, 0x52, 0x4c, 0xff, 0x72, 0x5b, 0x54, 0xff, - 0x72, 0x5b, 0x54, 0xff, 0x72, 0x5b, 0x54, 0xff, 0x75, 0x56, 0x54, 0xff, - 0x7c, 0x5d, 0x54, 0xff, 0x72, 0x5b, 0x54, 0xff, 0x69, 0x55, 0x54, 0xff, - 0x7f, 0x6a, 0x64, 0xff, 0x81, 0x72, 0x74, 0xff, 0x7d, 0x62, 0x5c, 0xff, - 0x81, 0x72, 0x74, 0xff, 0x9d, 0x8d, 0x8c, 0xff, 0x8e, 0x79, 0x74, 0xff, - 0x69, 0x55, 0x54, 0xff, 0x69, 0x55, 0x54, 0xff, 0x72, 0x5b, 0x54, 0xff, - 0x7e, 0x6d, 0x6c, 0xff, 0x9e, 0x8e, 0x94, 0xff, 0xae, 0xa4, 0xa4, 0xff, - 0xad, 0x9a, 0x9c, 0xff, 0xa4, 0x9e, 0xa4, 0xff, 0xc6, 0xb1, 0xb4, 0xff, - 0xa4, 0x9e, 0xa4, 0xff, 0x9e, 0x8e, 0x94, 0xff, 0x96, 0x86, 0x8c, 0xff, - 0x9e, 0x8e, 0x94, 0xff, 0xad, 0x9a, 0x9c, 0xff, 0xa6, 0x95, 0x94, 0xff, - 0x9d, 0x8d, 0x8c, 0xff, 0xa1, 0x99, 0x9c, 0xff, 0x94, 0x8c, 0x8c, 0xff, - 0xc5, 0xb7, 0xb4, 0xff, 0xcc, 0xc5, 0xc4, 0xff, 0xb4, 0xaa, 0xac, 0xff, - 0xbc, 0xb6, 0xac, 0xff, 0xbf, 0xaa, 0xa4, 0xff, 0xc9, 0xc0, 0xb4, 0xff, - 0xfc, 0xf2, 0xe4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf2, 0xe4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf2, 0xe9, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0x94, 0x8b, 0x84, 0xff, 0x90, 0x7f, 0x74, 0xff, 0x71, 0x6a, 0x64, 0xff, - 0x6a, 0x53, 0x4c, 0xff, 0x72, 0x5b, 0x54, 0xff, 0x70, 0x5e, 0x5c, 0xff, - 0x72, 0x5b, 0x54, 0xff, 0x7c, 0x5e, 0x5c, 0xff, 0x72, 0x5b, 0x54, 0xff, - 0x7c, 0x5d, 0x54, 0xff, 0x7c, 0x5d, 0x54, 0xff, 0x72, 0x5b, 0x54, 0xff, - 0x7c, 0x5d, 0x54, 0xff, 0x7c, 0x5d, 0x54, 0xff, 0x7c, 0x5d, 0x54, 0xff, - 0x74, 0x55, 0x4c, 0xff, 0x69, 0x4e, 0x4c, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x50, 0x4e, 0x44, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x69, 0x4e, 0x44, 0xff, - 0x74, 0x4e, 0x4c, 0xff, 0x5c, 0x3e, 0x34, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x7c, 0x5d, 0x54, 0xff, 0x69, 0x4e, 0x4c, 0xff, 0x7f, 0x6a, 0x64, 0xff, - 0x9d, 0x8d, 0x8c, 0xff, 0x50, 0x4e, 0x44, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x6a, 0x53, 0x4c, 0xff, 0x78, 0x66, 0x64, 0xff, 0x80, 0x67, 0x5c, 0xff, - 0x6a, 0x53, 0x4c, 0xff, 0x6a, 0x53, 0x4c, 0xff, 0x7c, 0x5d, 0x54, 0xff, - 0x7f, 0x6a, 0x64, 0xff, 0x70, 0x5e, 0x5c, 0xff, 0x77, 0x66, 0x6c, 0xff, - 0x81, 0x72, 0x74, 0xff, 0x78, 0x66, 0x64, 0xff, 0x77, 0x66, 0x6c, 0xff, - 0x7e, 0x6d, 0x6c, 0xff, 0xad, 0x9a, 0x9c, 0xff, 0xad, 0x9e, 0x9e, 0xff, - 0x84, 0x77, 0x74, 0xff, 0x7d, 0x62, 0x5c, 0xff, 0x78, 0x66, 0x64, 0xff, - 0x70, 0x5e, 0x5c, 0xff, 0x8f, 0x7f, 0x7c, 0xff, 0xae, 0xa4, 0xa4, 0xff, - 0xad, 0x9a, 0x9c, 0xff, 0xad, 0x9a, 0x9c, 0xff, 0xbc, 0xaa, 0xac, 0xff, - 0x9e, 0x8e, 0x94, 0xff, 0x9c, 0x7a, 0x7c, 0xff, 0x84, 0x79, 0x7c, 0xff, - 0x8e, 0x7a, 0x7c, 0xff, 0x96, 0x85, 0x84, 0xff, 0xa6, 0x95, 0x94, 0xff, - 0x9a, 0x94, 0x94, 0xff, 0x9d, 0x8d, 0x8c, 0xff, 0x8b, 0x8b, 0x8c, 0xff, - 0xb4, 0xaa, 0xac, 0xff, 0xcc, 0xc2, 0xbc, 0xff, 0xba, 0xb6, 0xb4, 0xff, - 0xc5, 0xb7, 0xb4, 0xff, 0xc5, 0xb7, 0xb4, 0xff, 0xb0, 0xa3, 0x9c, 0xff, - 0xd7, 0xcc, 0xc4, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xf2, 0xe4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xfc, 0xe8, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0x94, 0x8b, 0x84, 0xff, 0x90, 0x7f, 0x74, 0xff, 0x78, 0x77, 0x74, 0xff, - 0x7f, 0x72, 0x6c, 0xff, 0x6f, 0x6c, 0x6c, 0xff, 0x7f, 0x6a, 0x64, 0xff, - 0x69, 0x55, 0x54, 0xff, 0x72, 0x62, 0x5c, 0xff, 0x70, 0x5e, 0x5c, 0xff, - 0x72, 0x62, 0x5c, 0xff, 0x7c, 0x5d, 0x54, 0xff, 0x74, 0x55, 0x4c, 0xff, - 0x75, 0x56, 0x54, 0xff, 0x72, 0x5b, 0x54, 0xff, 0x74, 0x55, 0x4c, 0xff, - 0x69, 0x4e, 0x44, 0xff, 0x61, 0x48, 0x44, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x61, 0x48, 0x44, 0xff, 0x69, 0x4e, 0x44, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x5c, 0x42, 0x44, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x69, 0x4e, 0x4c, 0xff, - 0x69, 0x4e, 0x44, 0xff, 0x61, 0x48, 0x44, 0xff, 0x6a, 0x53, 0x4c, 0xff, - 0x74, 0x55, 0x4c, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x70, 0x5e, 0x5c, 0xff, - 0x84, 0x77, 0x74, 0xff, 0x7f, 0x6a, 0x64, 0xff, 0x69, 0x55, 0x54, 0xff, - 0x72, 0x5b, 0x54, 0xff, 0x69, 0x4e, 0x44, 0xff, 0x6a, 0x53, 0x4c, 0xff, - 0x72, 0x5b, 0x54, 0xff, 0x72, 0x5b, 0x54, 0xff, 0x70, 0x5e, 0x5c, 0xff, - 0x72, 0x62, 0x5c, 0xff, 0x77, 0x66, 0x6c, 0xff, 0x75, 0x62, 0x64, 0xff, - 0x7e, 0x6d, 0x6c, 0xff, 0x96, 0x86, 0x8c, 0xff, 0xae, 0xa4, 0xa4, 0xff, - 0x8e, 0x72, 0x74, 0xff, 0x8f, 0x7f, 0x7c, 0xff, 0x9c, 0x80, 0x7c, 0xff, - 0x84, 0x77, 0x74, 0xff, 0x8e, 0x7a, 0x7c, 0xff, 0x8c, 0x81, 0x84, 0xff, - 0xa1, 0x99, 0x9c, 0xff, 0x96, 0x86, 0x8c, 0xff, 0x8e, 0x7a, 0x7c, 0xff, - 0x96, 0x86, 0x8c, 0xff, 0x96, 0x86, 0x8c, 0xff, 0x96, 0x86, 0x8c, 0xff, - 0x96, 0x85, 0x84, 0xff, 0x9d, 0x8d, 0x8c, 0xff, 0xa6, 0x95, 0x94, 0xff, - 0x94, 0x8c, 0x8c, 0xff, 0xa1, 0x99, 0x9c, 0xff, 0xbc, 0xb9, 0xbc, 0xff, - 0xc4, 0xba, 0xbc, 0xff, 0xc2, 0xbe, 0xbc, 0xff, 0xcc, 0xc2, 0xbc, 0xff, - 0xc4, 0xbe, 0xc4, 0xff, 0xc5, 0xb7, 0xb4, 0xff, 0xbc, 0xb0, 0xac, 0xff, - 0xa9, 0x9b, 0x8c, 0xff, 0xf9, 0xe2, 0xd4, 0xff, 0xfc, 0xf2, 0xe4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xfc, 0xea, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0x9c, 0x93, 0x8c, 0xff, 0xa6, 0x95, 0x94, 0xff, 0x94, 0x8b, 0x84, 0xff, - 0x9d, 0x8d, 0x8c, 0xff, 0xd7, 0xcc, 0xc4, 0xff, 0xbc, 0xb1, 0xb4, 0xff, - 0xa1, 0x99, 0x9c, 0xff, 0xad, 0x9a, 0x9c, 0xff, 0x84, 0x77, 0x74, 0xff, - 0x71, 0x6a, 0x64, 0xff, 0x81, 0x72, 0x74, 0xff, 0x72, 0x5b, 0x54, 0xff, - 0x72, 0x5b, 0x54, 0xff, 0x69, 0x55, 0x54, 0xff, 0x69, 0x4e, 0x4c, 0xff, - 0x61, 0x48, 0x44, 0xff, 0x61, 0x48, 0x44, 0xff, 0x69, 0x4e, 0x4c, 0xff, - 0x5c, 0x42, 0x44, 0xff, 0x6c, 0x4a, 0x44, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x5c, 0x42, 0x44, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x6c, 0x4a, 0x44, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x69, 0x4e, 0x4c, 0xff, - 0x6c, 0x4a, 0x44, 0xff, 0x61, 0x48, 0x44, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x61, 0x48, 0x44, 0xff, 0x6a, 0x53, 0x4c, 0xff, 0x72, 0x62, 0x5c, 0xff, - 0x72, 0x5b, 0x54, 0xff, 0x70, 0x66, 0x5c, 0xff, 0x7f, 0x6a, 0x64, 0xff, - 0x7c, 0x5d, 0x54, 0xff, 0x6a, 0x53, 0x4c, 0xff, 0x6a, 0x53, 0x4c, 0xff, - 0x74, 0x55, 0x4c, 0xff, 0x69, 0x55, 0x54, 0xff, 0x69, 0x4e, 0x4c, 0xff, - 0x69, 0x4e, 0x4c, 0xff, 0x70, 0x5e, 0x5c, 0xff, 0x75, 0x62, 0x64, 0xff, - 0x8e, 0x79, 0x74, 0xff, 0xbc, 0xb1, 0xb4, 0xff, 0x96, 0x85, 0x84, 0xff, - 0x7f, 0x72, 0x6c, 0xff, 0x8f, 0x7f, 0x7c, 0xff, 0xa6, 0x95, 0x94, 0xff, - 0xb0, 0xa3, 0x9c, 0xff, 0xa6, 0x95, 0x94, 0xff, 0x96, 0x85, 0x84, 0xff, - 0x8f, 0x7f, 0x7c, 0xff, 0x78, 0x77, 0x74, 0xff, 0x8c, 0x81, 0x84, 0xff, - 0x81, 0x72, 0x74, 0xff, 0x9d, 0x8d, 0x8c, 0xff, 0x9d, 0x8d, 0x8c, 0xff, - 0x8c, 0x81, 0x84, 0xff, 0x8c, 0x81, 0x84, 0xff, 0xa6, 0x95, 0x94, 0xff, - 0xad, 0x9a, 0x9c, 0xff, 0xa1, 0x99, 0x9c, 0xff, 0xbc, 0xaa, 0xac, 0xff, - 0xc4, 0xba, 0xbc, 0xff, 0xc2, 0xbe, 0xbc, 0xff, 0xae, 0xa4, 0xa4, 0xff, - 0xc4, 0xba, 0xbc, 0xff, 0xc4, 0xba, 0xbc, 0xff, 0xba, 0xb6, 0xb4, 0xff, - 0xa8, 0x9b, 0x94, 0xff, 0xb0, 0xaa, 0x9c, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf2, 0xe4, 0xff, 0xfc, 0xea, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf2, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0x92, 0x92, 0x8c, 0xff, 0x8b, 0x8b, 0x8c, 0xff, 0xa1, 0x9e, 0x9c, 0xff, - 0xa3, 0xa3, 0xa4, 0xff, 0xbc, 0xb1, 0xb4, 0xff, 0xdc, 0xdc, 0xdc, 0xff, - 0xc8, 0xca, 0xc4, 0xff, 0xb3, 0xae, 0xac, 0xff, 0xc2, 0xbe, 0xbc, 0xff, - 0xc5, 0xb7, 0xb4, 0xff, 0xb1, 0xaa, 0xa4, 0xff, 0x70, 0x5e, 0x5c, 0xff, - 0x75, 0x62, 0x64, 0xff, 0x78, 0x66, 0x64, 0xff, 0x69, 0x4e, 0x4c, 0xff, - 0x69, 0x4e, 0x4c, 0xff, 0x69, 0x4e, 0x4c, 0xff, 0x74, 0x4e, 0x4c, 0xff, - 0x6c, 0x4a, 0x44, 0xff, 0x6c, 0x4a, 0x44, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x6c, 0x4a, 0x44, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x6c, 0x4a, 0x44, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x69, 0x4e, 0x44, 0xff, - 0x61, 0x48, 0x44, 0xff, 0x61, 0x48, 0x44, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x69, 0x4e, 0x44, 0xff, 0x50, 0x4e, 0x44, 0xff, - 0x61, 0x48, 0x44, 0xff, 0x69, 0x4e, 0x44, 0xff, 0x7f, 0x6a, 0x64, 0xff, - 0x72, 0x5b, 0x54, 0xff, 0x6a, 0x53, 0x4c, 0xff, 0x69, 0x4e, 0x44, 0xff, - 0x74, 0x55, 0x4c, 0xff, 0x74, 0x4e, 0x4c, 0xff, 0x69, 0x4e, 0x4c, 0xff, - 0x75, 0x56, 0x54, 0xff, 0x7c, 0x5e, 0x5c, 0xff, 0x70, 0x5e, 0x5c, 0xff, - 0x7f, 0x72, 0x6c, 0xff, 0x96, 0x85, 0x84, 0xff, 0x8e, 0x7a, 0x7c, 0xff, - 0x96, 0x85, 0x84, 0xff, 0x8f, 0x7f, 0x7c, 0xff, 0x84, 0x77, 0x74, 0xff, - 0x94, 0x8b, 0x84, 0xff, 0xae, 0xa4, 0xa4, 0xff, 0xae, 0xa4, 0xa4, 0xff, - 0x81, 0x72, 0x74, 0xff, 0x84, 0x77, 0x74, 0xff, 0x9c, 0x80, 0x7c, 0xff, - 0x8c, 0x81, 0x84, 0xff, 0x81, 0x72, 0x74, 0xff, 0x9e, 0x8e, 0x94, 0xff, - 0x9d, 0x8d, 0x8c, 0xff, 0x8f, 0x7f, 0x7c, 0xff, 0x94, 0x8c, 0x8c, 0xff, - 0xad, 0x9e, 0x9e, 0xff, 0xa1, 0x99, 0x9c, 0xff, 0xa1, 0x99, 0x9c, 0xff, - 0xae, 0xa4, 0xa4, 0xff, 0xd6, 0xd2, 0xd4, 0xff, 0xae, 0xa4, 0xa4, 0xff, - 0xb4, 0xaa, 0xac, 0xff, 0xbc, 0xb1, 0xb4, 0xff, 0xbc, 0xb0, 0xac, 0xff, - 0xc5, 0xb7, 0xb4, 0xff, 0x94, 0x8b, 0x84, 0xff, 0xe4, 0xde, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf2, 0xe4, 0xff, 0xfc, 0xf2, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xc4, 0xc3, 0xc4, 0xff, 0xae, 0xa4, 0xa4, 0xff, 0x94, 0x8c, 0x8c, 0xff, - 0x9a, 0x94, 0x94, 0xff, 0x9c, 0x9a, 0x94, 0xff, 0xe4, 0xde, 0xdc, 0xff, - 0xd5, 0xcd, 0xcc, 0xff, 0xcc, 0xc5, 0xc4, 0xff, 0xc4, 0xc3, 0xc4, 0xff, - 0xba, 0xb6, 0xb4, 0xff, 0xc4, 0xba, 0xbc, 0xff, 0x8e, 0x7a, 0x7c, 0xff, - 0x75, 0x62, 0x64, 0xff, 0x8c, 0x6e, 0x64, 0xff, 0x75, 0x56, 0x54, 0xff, - 0x74, 0x4e, 0x4c, 0xff, 0x69, 0x4e, 0x4c, 0xff, 0x69, 0x4e, 0x4c, 0xff, - 0x6c, 0x4a, 0x44, 0xff, 0x5c, 0x42, 0x44, 0xff, 0x5c, 0x42, 0x44, 0xff, - 0x5c, 0x42, 0x44, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x6c, 0x4a, 0x44, 0xff, 0x6c, 0x4a, 0x44, 0xff, - 0x61, 0x48, 0x44, 0xff, 0x6c, 0x4a, 0x44, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x61, 0x48, 0x44, 0xff, 0x69, 0x4e, 0x44, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x69, 0x4e, 0x44, 0xff, 0x70, 0x66, 0x5c, 0xff, - 0x6a, 0x53, 0x4c, 0xff, 0x50, 0x4e, 0x44, 0xff, 0x74, 0x55, 0x4c, 0xff, - 0x70, 0x5e, 0x5c, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x6a, 0x53, 0x4c, 0xff, - 0x69, 0x4e, 0x4c, 0xff, 0x70, 0x5e, 0x5c, 0xff, 0x69, 0x55, 0x54, 0xff, - 0x75, 0x62, 0x64, 0xff, 0x7e, 0x6d, 0x6c, 0xff, 0x8e, 0x7a, 0x7c, 0xff, - 0x8e, 0x7a, 0x7c, 0xff, 0x7e, 0x6d, 0x6c, 0xff, 0x69, 0x55, 0x54, 0xff, - 0x70, 0x5e, 0x5c, 0xff, 0x96, 0x85, 0x84, 0xff, 0x9d, 0x8d, 0x8c, 0xff, - 0x94, 0x8b, 0x84, 0xff, 0x9d, 0x8d, 0x8c, 0xff, 0x96, 0x86, 0x8c, 0xff, - 0x63, 0x66, 0x64, 0xff, 0x75, 0x62, 0x64, 0xff, 0x8e, 0x79, 0x74, 0xff, - 0x94, 0x8c, 0x8c, 0xff, 0x9d, 0x8d, 0x8c, 0xff, 0x9d, 0x8d, 0x8c, 0xff, - 0x9a, 0x94, 0x94, 0xff, 0xad, 0x9a, 0x9c, 0xff, 0xa1, 0x99, 0x9c, 0xff, - 0xad, 0x9e, 0x9e, 0xff, 0xbc, 0xb1, 0xb4, 0xff, 0xa1, 0x99, 0x9c, 0xff, - 0xae, 0xa4, 0xa4, 0xff, 0xae, 0xa4, 0xa4, 0xff, 0x94, 0x8e, 0x94, 0xff, - 0xc5, 0xb7, 0xb4, 0xff, 0xa8, 0x9b, 0x94, 0xff, 0xc7, 0xb8, 0xac, 0xff, - 0xf4, 0xea, 0xe4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf2, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf2, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xe8, 0xd4, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xcc, 0xcc, 0xcc, 0xff, 0xba, 0xb6, 0xb4, 0xff, 0xb1, 0xaa, 0xa4, 0xff, - 0x9c, 0x93, 0x8c, 0xff, 0x8b, 0x8b, 0x8c, 0xff, 0xbc, 0xb9, 0xbc, 0xff, - 0xe4, 0xde, 0xdc, 0xff, 0xdc, 0xdc, 0xdc, 0xff, 0xba, 0xb6, 0xb4, 0xff, - 0xbc, 0xb1, 0xb4, 0xff, 0xcc, 0xc5, 0xc4, 0xff, 0xbd, 0xa6, 0xa4, 0xff, - 0x9c, 0x7a, 0x7c, 0xff, 0x75, 0x62, 0x64, 0xff, 0x7c, 0x5e, 0x5c, 0xff, - 0x74, 0x4e, 0x4c, 0xff, 0x61, 0x48, 0x44, 0xff, 0x5c, 0x42, 0x44, 0xff, - 0x5c, 0x42, 0x44, 0xff, 0x5c, 0x42, 0x44, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x5c, 0x42, 0x44, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x6c, 0x4a, 0x44, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x61, 0x48, 0x44, 0xff, 0x69, 0x4e, 0x44, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x6a, 0x53, 0x4c, 0xff, 0x72, 0x62, 0x5c, 0xff, - 0x74, 0x55, 0x4c, 0xff, 0x6a, 0x53, 0x4c, 0xff, 0x72, 0x62, 0x5c, 0xff, - 0x6a, 0x53, 0x4c, 0xff, 0x69, 0x4e, 0x4c, 0xff, 0x69, 0x55, 0x54, 0xff, - 0x70, 0x5e, 0x5c, 0xff, 0x6a, 0x53, 0x4c, 0xff, 0x69, 0x55, 0x54, 0xff, - 0x70, 0x5e, 0x5c, 0xff, 0x8e, 0x72, 0x74, 0xff, 0x84, 0x77, 0x74, 0xff, - 0x9c, 0x80, 0x7c, 0xff, 0x7e, 0x6d, 0x6c, 0xff, 0x69, 0x55, 0x54, 0xff, - 0x71, 0x6a, 0x64, 0xff, 0x84, 0x79, 0x7c, 0xff, 0x94, 0x8b, 0x84, 0xff, - 0x96, 0x85, 0x84, 0xff, 0xa6, 0x95, 0x94, 0xff, 0x9c, 0x93, 0x8c, 0xff, - 0x70, 0x5e, 0x5c, 0xff, 0x84, 0x77, 0x74, 0xff, 0x8c, 0x81, 0x84, 0xff, - 0x96, 0x86, 0x8c, 0xff, 0x96, 0x85, 0x84, 0xff, 0x9e, 0x8e, 0x94, 0xff, - 0xa6, 0x95, 0x94, 0xff, 0x9a, 0x94, 0x94, 0xff, 0xae, 0xa4, 0xa4, 0xff, - 0xad, 0x9e, 0x9e, 0xff, 0xb4, 0xb2, 0xb4, 0xff, 0x96, 0x85, 0x84, 0xff, - 0xae, 0xa4, 0xa4, 0xff, 0xa4, 0x9e, 0xa4, 0xff, 0xa1, 0xa2, 0x9c, 0xff, - 0xc5, 0xb7, 0xb4, 0xff, 0xbc, 0xb0, 0xac, 0xff, 0x9c, 0x93, 0x8c, 0xff, - 0xef, 0xe2, 0xdc, 0xff, 0xfc, 0xf2, 0xe4, 0xff, 0xfc, 0xf2, 0xe4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf2, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf2, 0xe4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xe8, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xac, 0xa9, 0xac, 0xff, 0xc2, 0xc2, 0xbc, 0xff, 0x94, 0x8e, 0x94, 0xff, - 0x8b, 0x8b, 0x8c, 0xff, 0x71, 0x72, 0x6c, 0xff, 0x81, 0x7e, 0x7c, 0xff, - 0xcc, 0xcc, 0xcc, 0xff, 0xe4, 0xe2, 0xd8, 0xff, 0xdc, 0xd6, 0xdc, 0xff, - 0xd6, 0xd2, 0xd4, 0xff, 0xc4, 0xc3, 0xc4, 0xff, 0xcc, 0xbe, 0xc4, 0xff, - 0xc6, 0xb1, 0xb4, 0xff, 0xb4, 0x96, 0x94, 0xff, 0x75, 0x62, 0x64, 0xff, - 0x64, 0x4e, 0x54, 0xff, 0x6c, 0x4a, 0x44, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x69, 0x4e, 0x4c, 0xff, 0x6c, 0x4a, 0x44, 0xff, 0x5c, 0x42, 0x44, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x6c, 0x4a, 0x44, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x6c, 0x4a, 0x44, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x74, 0x55, 0x4c, 0xff, - 0x72, 0x5b, 0x54, 0xff, 0x69, 0x4e, 0x4c, 0xff, 0x69, 0x4e, 0x44, 0xff, - 0x72, 0x5b, 0x54, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x72, 0x5b, 0x54, 0xff, - 0x6a, 0x53, 0x4c, 0xff, 0x6a, 0x53, 0x4c, 0xff, 0x7d, 0x62, 0x5c, 0xff, - 0x69, 0x4e, 0x4c, 0xff, 0x78, 0x66, 0x64, 0xff, 0x70, 0x5e, 0x5c, 0xff, - 0x7e, 0x6d, 0x6c, 0xff, 0x6f, 0x6c, 0x6c, 0xff, 0x8c, 0x81, 0x84, 0xff, - 0x8e, 0x7a, 0x7c, 0xff, 0x72, 0x5b, 0x54, 0xff, 0x5d, 0x5a, 0x54, 0xff, - 0x84, 0x77, 0x74, 0xff, 0x7f, 0x72, 0x6c, 0xff, 0x8f, 0x7f, 0x7c, 0xff, - 0xa6, 0x95, 0x94, 0xff, 0xae, 0xa4, 0xa4, 0xff, 0xa6, 0x95, 0x94, 0xff, - 0x84, 0x79, 0x7c, 0xff, 0x8f, 0x7f, 0x7c, 0xff, 0x94, 0x8c, 0x8c, 0xff, - 0x96, 0x85, 0x84, 0xff, 0x9a, 0x94, 0x94, 0xff, 0xb0, 0xa3, 0x9c, 0xff, - 0x9a, 0x94, 0x94, 0xff, 0xa1, 0x99, 0x9c, 0xff, 0x9a, 0x94, 0x94, 0xff, - 0xa1, 0x99, 0x9c, 0xff, 0xcc, 0xc5, 0xc4, 0xff, 0xae, 0xa4, 0xa4, 0xff, - 0xa1, 0x99, 0x9c, 0xff, 0xb4, 0xaa, 0xac, 0xff, 0xbc, 0xb0, 0xac, 0xff, - 0xec, 0xde, 0xdc, 0xff, 0xc2, 0xbe, 0xbc, 0xff, 0xa6, 0x95, 0x94, 0xff, - 0xd6, 0xc5, 0xbc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xf2, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf2, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0x81, 0x7e, 0x7c, 0xff, 0xbc, 0xb6, 0xac, 0xff, 0x8b, 0x8b, 0x8c, 0xff, - 0x81, 0x7e, 0x7c, 0xff, 0x63, 0x66, 0x64, 0xff, 0x92, 0x92, 0x8c, 0xff, - 0xb3, 0xae, 0xac, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xbc, 0xb9, 0xbc, 0xff, - 0xd5, 0xcd, 0xcc, 0xff, 0xdc, 0xdc, 0xdc, 0xff, 0xd6, 0xd2, 0xd4, 0xff, - 0xbc, 0xaa, 0xac, 0xff, 0xbc, 0xaa, 0xac, 0xff, 0x8e, 0x7a, 0x7c, 0xff, - 0x69, 0x55, 0x54, 0xff, 0x69, 0x55, 0x54, 0xff, 0x6a, 0x53, 0x4c, 0xff, - 0x69, 0x4e, 0x4c, 0xff, 0x69, 0x4e, 0x4c, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x6c, 0x4a, 0x44, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x6c, 0x4a, 0x44, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x61, 0x48, 0x44, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x69, 0x4e, 0x44, 0xff, 0x50, 0x4e, 0x44, 0xff, 0x6a, 0x53, 0x4c, 0xff, - 0x7c, 0x5d, 0x54, 0xff, 0x5d, 0x5a, 0x54, 0xff, 0x72, 0x5b, 0x54, 0xff, - 0x7c, 0x5d, 0x54, 0xff, 0x72, 0x5b, 0x54, 0xff, 0x7f, 0x6a, 0x64, 0xff, - 0x69, 0x55, 0x54, 0xff, 0x72, 0x5b, 0x54, 0xff, 0x78, 0x66, 0x64, 0xff, - 0x6f, 0x6c, 0x6c, 0xff, 0x8e, 0x7a, 0x7c, 0xff, 0x9d, 0x8d, 0x8c, 0xff, - 0x8e, 0x7a, 0x7c, 0xff, 0x70, 0x5e, 0x5c, 0xff, 0x7e, 0x6d, 0x6c, 0xff, - 0x8e, 0x7a, 0x7c, 0xff, 0x94, 0x8c, 0x8c, 0xff, 0xa6, 0x95, 0x94, 0xff, - 0x84, 0x79, 0x7c, 0xff, 0x8f, 0x7f, 0x7c, 0xff, 0xa6, 0x95, 0x94, 0xff, - 0x9d, 0x8d, 0x8c, 0xff, 0x8c, 0x81, 0x84, 0xff, 0x9a, 0x94, 0x94, 0xff, - 0xa6, 0x95, 0x94, 0xff, 0x94, 0x8b, 0x84, 0xff, 0xa1, 0x99, 0x9c, 0xff, - 0xa6, 0x95, 0x94, 0xff, 0xad, 0x9a, 0x9c, 0xff, 0xa4, 0x9e, 0xa4, 0xff, - 0xae, 0xa4, 0xa4, 0xff, 0xad, 0x9e, 0x9e, 0xff, 0xb4, 0xb2, 0xb4, 0xff, - 0xae, 0xa4, 0xa4, 0xff, 0xb4, 0xaa, 0xac, 0xff, 0xb4, 0xaa, 0xac, 0xff, - 0xbc, 0xb1, 0xb4, 0xff, 0xbc, 0xb1, 0xb4, 0xff, 0xb3, 0xae, 0xac, 0xff, - 0x9c, 0x93, 0x8c, 0xff, 0xf2, 0xe9, 0xdc, 0xff, 0xf2, 0xe9, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf2, 0xe4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf2, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf2, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xa3, 0xa3, 0xa4, 0xff, 0x9a, 0x94, 0x94, 0xff, 0x89, 0x86, 0x84, 0xff, - 0x81, 0x7e, 0x7c, 0xff, 0x63, 0x66, 0x64, 0xff, 0x89, 0x86, 0x84, 0xff, - 0xa1, 0x99, 0x9c, 0xff, 0xa1, 0x99, 0x9c, 0xff, 0xa1, 0x99, 0x9c, 0xff, - 0xc4, 0xc3, 0xc4, 0xff, 0xdc, 0xd6, 0xdc, 0xff, 0xd6, 0xd2, 0xd4, 0xff, - 0xcc, 0xcc, 0xcc, 0xff, 0xc4, 0xc3, 0xc4, 0xff, 0xbc, 0xb0, 0xac, 0xff, - 0x71, 0x6a, 0x64, 0xff, 0x5d, 0x5a, 0x54, 0xff, 0x69, 0x55, 0x54, 0xff, - 0x69, 0x55, 0x54, 0xff, 0x6a, 0x53, 0x4c, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x5c, 0x42, 0x44, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x69, 0x4e, 0x44, 0xff, 0x61, 0x48, 0x44, 0xff, 0x74, 0x55, 0x4c, 0xff, - 0x69, 0x4e, 0x44, 0xff, 0x6a, 0x53, 0x4c, 0xff, 0x74, 0x55, 0x4c, 0xff, - 0x72, 0x5b, 0x54, 0xff, 0x7f, 0x6a, 0x64, 0xff, 0x9c, 0x80, 0x7c, 0xff, - 0x72, 0x5b, 0x54, 0xff, 0x71, 0x6a, 0x64, 0xff, 0x84, 0x77, 0x74, 0xff, - 0x8e, 0x79, 0x74, 0xff, 0xae, 0xa4, 0xa4, 0xff, 0x7e, 0x6d, 0x6c, 0xff, - 0x72, 0x5b, 0x54, 0xff, 0x8e, 0x7a, 0x7c, 0xff, 0x84, 0x77, 0x74, 0xff, - 0x84, 0x77, 0x74, 0xff, 0x8f, 0x86, 0x7c, 0xff, 0xa6, 0x95, 0x94, 0xff, - 0x71, 0x6a, 0x64, 0xff, 0x78, 0x66, 0x64, 0xff, 0x9d, 0x8d, 0x8c, 0xff, - 0x9a, 0x94, 0x94, 0xff, 0x84, 0x77, 0x74, 0xff, 0x96, 0x85, 0x84, 0xff, - 0xae, 0xa4, 0xa4, 0xff, 0xcc, 0xbe, 0xc4, 0xff, 0xa6, 0x95, 0x94, 0xff, - 0xad, 0x9a, 0x9c, 0xff, 0xa1, 0x99, 0x9c, 0xff, 0xa1, 0x99, 0x9c, 0xff, - 0xbc, 0xb0, 0xac, 0xff, 0xc4, 0xbe, 0xc4, 0xff, 0xae, 0xa4, 0xa4, 0xff, - 0xbc, 0xb1, 0xb4, 0xff, 0xb4, 0xaa, 0xac, 0xff, 0xb3, 0xae, 0xac, 0xff, - 0xae, 0xa4, 0xa4, 0xff, 0xd5, 0xcd, 0xcc, 0xff, 0xc2, 0xbe, 0xbc, 0xff, - 0xb0, 0xa3, 0x9c, 0xff, 0xbc, 0xb6, 0xac, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xfc, 0xee, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xee, 0xd4, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xbc, 0xb0, 0xac, 0xff, 0xb4, 0xb2, 0xb4, 0xff, 0xa3, 0xa3, 0xa4, 0xff, - 0x94, 0x8c, 0x8c, 0xff, 0x81, 0x7e, 0x7c, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x71, 0x72, 0x6c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0xb3, 0xae, 0xac, 0xff, - 0xd6, 0xd2, 0xd4, 0xff, 0x9a, 0x94, 0x94, 0xff, 0xa3, 0xa3, 0xa4, 0xff, - 0x94, 0x8e, 0x94, 0xff, 0x94, 0x8c, 0x8c, 0xff, 0x9a, 0x94, 0x94, 0xff, - 0x94, 0x8c, 0x8c, 0xff, 0x75, 0x62, 0x64, 0xff, 0x5d, 0x5a, 0x54, 0xff, - 0x5d, 0x5a, 0x54, 0xff, 0x6a, 0x53, 0x4c, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x44, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x69, 0x4e, 0x44, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x53, 0x41, 0x3c, 0xff, 0x6a, 0x53, 0x4c, 0xff, - 0x69, 0x4e, 0x44, 0xff, 0x61, 0x48, 0x44, 0xff, 0x53, 0x41, 0x3c, 0xff, - 0x61, 0x48, 0x44, 0xff, 0x72, 0x5b, 0x54, 0xff, 0x78, 0x66, 0x64, 0xff, - 0x72, 0x62, 0x5c, 0xff, 0x7f, 0x6a, 0x64, 0xff, 0x8f, 0x7f, 0x7c, 0xff, - 0x9c, 0x80, 0x7c, 0xff, 0xad, 0x9a, 0x9c, 0xff, 0x7e, 0x6d, 0x6c, 0xff, - 0x84, 0x79, 0x7c, 0xff, 0x72, 0x62, 0x5c, 0xff, 0x7e, 0x6d, 0x6c, 0xff, - 0x8f, 0x7f, 0x7c, 0xff, 0x6f, 0x6c, 0x6c, 0xff, 0x8f, 0x7f, 0x7c, 0xff, - 0x7f, 0x72, 0x6c, 0xff, 0x84, 0x79, 0x7c, 0xff, 0xa1, 0x99, 0x9c, 0xff, - 0x9d, 0x8d, 0x8c, 0xff, 0x9c, 0x93, 0x8c, 0xff, 0x96, 0x86, 0x8c, 0xff, - 0x81, 0x7e, 0x7c, 0xff, 0xa6, 0x95, 0x94, 0xff, 0xb4, 0xaa, 0xac, 0xff, - 0x9a, 0x94, 0x94, 0xff, 0xad, 0x9e, 0x9e, 0xff, 0xa4, 0x9e, 0xa4, 0xff, - 0xa6, 0x95, 0x94, 0xff, 0xae, 0xa4, 0xa4, 0xff, 0xa1, 0x99, 0x9c, 0xff, - 0xb1, 0xaa, 0xa4, 0xff, 0xa4, 0x9e, 0xa4, 0xff, 0xba, 0xb6, 0xb4, 0xff, - 0xa4, 0x9e, 0xa4, 0xff, 0xd6, 0xd2, 0xd4, 0xff, 0xc4, 0xc3, 0xc4, 0xff, - 0xbc, 0xb0, 0xac, 0xff, 0xba, 0xb0, 0xa4, 0xff, 0xf2, 0xe9, 0xdc, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xfc, 0xf2, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf2, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xee, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xba, 0xb6, 0xb4, 0xff, 0xac, 0xa9, 0xac, 0xff, 0xa1, 0x9e, 0x9c, 0xff, - 0xa1, 0x99, 0x9c, 0xff, 0x81, 0x7e, 0x7c, 0xff, 0x7b, 0x7a, 0x7c, 0xff, - 0x8b, 0x8b, 0x8c, 0xff, 0x71, 0x72, 0x74, 0xff, 0x71, 0x72, 0x74, 0xff, - 0xac, 0xa9, 0xac, 0xff, 0xc4, 0xc3, 0xc4, 0xff, 0x94, 0x8c, 0x8c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x69, 0x55, 0x54, 0xff, 0x6f, 0x6c, 0x6c, 0xff, - 0x84, 0x79, 0x7c, 0xff, 0x7e, 0x6d, 0x6c, 0xff, 0x5d, 0x5a, 0x54, 0xff, - 0x69, 0x55, 0x54, 0xff, 0x69, 0x55, 0x54, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x58, 0x49, 0x4c, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x6c, 0x4a, 0x44, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x61, 0x48, 0x44, 0xff, 0x6a, 0x53, 0x4c, 0xff, 0x6a, 0x53, 0x4c, 0xff, - 0x6c, 0x61, 0x64, 0xff, 0x84, 0x77, 0x74, 0xff, 0x94, 0x8b, 0x84, 0xff, - 0x8c, 0x81, 0x84, 0xff, 0x84, 0x77, 0x74, 0xff, 0x81, 0x72, 0x74, 0xff, - 0x84, 0x77, 0x74, 0xff, 0x7e, 0x6d, 0x6c, 0xff, 0x81, 0x72, 0x74, 0xff, - 0x8f, 0x7f, 0x7c, 0xff, 0x84, 0x79, 0x7c, 0xff, 0xa6, 0x95, 0x94, 0xff, - 0x9a, 0x94, 0x94, 0xff, 0xa6, 0x95, 0x94, 0xff, 0xbc, 0xb1, 0xb4, 0xff, - 0xac, 0xa9, 0xac, 0xff, 0xa1, 0x99, 0x9c, 0xff, 0x9a, 0x94, 0x94, 0xff, - 0x8c, 0x81, 0x84, 0xff, 0x9a, 0x94, 0x94, 0xff, 0x9d, 0x8d, 0x8c, 0xff, - 0xa4, 0x9e, 0xa4, 0xff, 0xb0, 0xa3, 0x9c, 0xff, 0x9a, 0x94, 0x94, 0xff, - 0x94, 0x8c, 0x8c, 0xff, 0xa3, 0xa3, 0xa4, 0xff, 0xd6, 0xd2, 0xd4, 0xff, - 0xb4, 0xaa, 0xac, 0xff, 0xae, 0xa4, 0xa4, 0xff, 0xb4, 0xb2, 0xb4, 0xff, - 0xbc, 0xb1, 0xb4, 0xff, 0xb4, 0xaa, 0xac, 0xff, 0xba, 0xb6, 0xb4, 0xff, - 0xba, 0xb6, 0xb4, 0xff, 0xbc, 0xb6, 0xac, 0xff, 0xc5, 0xb7, 0xb4, 0xff, - 0xe4, 0xe2, 0xd8, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xf2, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0x71, 0x72, 0x74, 0xff, 0xa3, 0xa3, 0xa4, 0xff, 0xa1, 0x99, 0x9c, 0xff, - 0xa1, 0x99, 0x9c, 0xff, 0x7b, 0x7a, 0x7c, 0xff, 0x94, 0x8e, 0x94, 0xff, - 0x8c, 0x81, 0x84, 0xff, 0x7b, 0x7a, 0x7c, 0xff, 0x81, 0x7e, 0x7c, 0xff, - 0xae, 0xa4, 0xa4, 0xff, 0xc4, 0xba, 0xbc, 0xff, 0xa1, 0x99, 0x9c, 0xff, - 0x6c, 0x61, 0x64, 0xff, 0x70, 0x5e, 0x5c, 0xff, 0x6c, 0x61, 0x64, 0xff, - 0x75, 0x62, 0x64, 0xff, 0x81, 0x72, 0x74, 0xff, 0x70, 0x5e, 0x5c, 0xff, - 0x55, 0x52, 0x4c, 0xff, 0x64, 0x5d, 0x5c, 0xff, 0x69, 0x55, 0x54, 0xff, - 0x6c, 0x4a, 0x44, 0xff, 0x6c, 0x4a, 0x44, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x5c, 0x42, 0x44, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x69, 0x4e, 0x44, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x61, 0x48, 0x44, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x69, 0x4e, 0x44, 0xff, 0x72, 0x5b, 0x54, 0xff, 0x69, 0x55, 0x54, 0xff, - 0x72, 0x62, 0x5c, 0xff, 0x8f, 0x86, 0x7c, 0xff, 0x8c, 0x81, 0x84, 0xff, - 0x84, 0x77, 0x74, 0xff, 0x84, 0x79, 0x7c, 0xff, 0x77, 0x66, 0x6c, 0xff, - 0x81, 0x72, 0x74, 0xff, 0x75, 0x62, 0x64, 0xff, 0x8f, 0x7f, 0x7c, 0xff, - 0x96, 0x86, 0x8c, 0xff, 0x8f, 0x7f, 0x7c, 0xff, 0x8f, 0x7f, 0x7c, 0xff, - 0xa1, 0x99, 0x9c, 0xff, 0x9a, 0x94, 0x94, 0xff, 0xb3, 0xae, 0xac, 0xff, - 0xac, 0xa9, 0xac, 0xff, 0xb4, 0xaa, 0xac, 0xff, 0xa1, 0x99, 0x9c, 0xff, - 0x9a, 0x94, 0x94, 0xff, 0xb4, 0xaa, 0xac, 0xff, 0x9e, 0x8e, 0x94, 0xff, - 0xa6, 0x95, 0x94, 0xff, 0xae, 0xa4, 0xa4, 0xff, 0x9a, 0x94, 0x94, 0xff, - 0x9a, 0x94, 0x94, 0xff, 0xa4, 0x9e, 0xa4, 0xff, 0xbc, 0xb1, 0xb4, 0xff, - 0xc4, 0xc3, 0xc4, 0xff, 0xd6, 0xd2, 0xd4, 0xff, 0xbc, 0xb9, 0xbc, 0xff, - 0xb3, 0xae, 0xac, 0xff, 0xb1, 0xaa, 0xa4, 0xff, 0xbc, 0xb9, 0xbc, 0xff, - 0xc2, 0xc2, 0xbc, 0xff, 0xb1, 0xaa, 0xa4, 0xff, 0xd6, 0xc5, 0xbc, 0xff, - 0xb0, 0xa3, 0x9c, 0xff, 0xf4, 0xf2, 0xe4, 0xff, 0xfc, 0xf2, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0x84, 0x79, 0x7c, 0xff, 0x78, 0x77, 0x74, 0xff, 0x71, 0x72, 0x74, 0xff, - 0x78, 0x77, 0x74, 0xff, 0x83, 0x82, 0x84, 0xff, 0xb3, 0xae, 0xac, 0xff, - 0xa4, 0x9e, 0xa4, 0xff, 0x94, 0x8c, 0x8c, 0xff, 0x94, 0x8c, 0x8c, 0xff, - 0x8c, 0x86, 0x8c, 0xff, 0x96, 0x85, 0x84, 0xff, 0xa1, 0x99, 0x9c, 0xff, - 0x8c, 0x81, 0x84, 0xff, 0x96, 0x86, 0x8c, 0xff, 0x6c, 0x61, 0x64, 0xff, - 0x69, 0x55, 0x54, 0xff, 0x64, 0x5d, 0x5c, 0xff, 0x70, 0x5e, 0x5c, 0xff, - 0x64, 0x5d, 0x5c, 0xff, 0x70, 0x5e, 0x5c, 0xff, 0x6a, 0x53, 0x4c, 0xff, - 0x55, 0x4e, 0x4c, 0xff, 0x69, 0x4e, 0x4c, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x6c, 0x4a, 0x44, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x6c, 0x4a, 0x44, 0xff, - 0x61, 0x48, 0x44, 0xff, 0x7d, 0x62, 0x5c, 0xff, 0x6a, 0x53, 0x4c, 0xff, - 0x78, 0x66, 0x64, 0xff, 0x96, 0x85, 0x84, 0xff, 0x7c, 0x72, 0x64, 0xff, - 0x6b, 0x56, 0x5c, 0xff, 0x8e, 0x7a, 0x7c, 0xff, 0x70, 0x5e, 0x5c, 0xff, - 0x69, 0x55, 0x54, 0xff, 0x6c, 0x61, 0x64, 0xff, 0x81, 0x72, 0x74, 0xff, - 0x8f, 0x7f, 0x7c, 0xff, 0x84, 0x79, 0x7c, 0xff, 0x81, 0x72, 0x74, 0xff, - 0x9d, 0x8d, 0x8c, 0xff, 0x94, 0x8c, 0x8c, 0xff, 0xb4, 0xaa, 0xac, 0xff, - 0xac, 0xa9, 0xac, 0xff, 0xb3, 0xae, 0xac, 0xff, 0xa1, 0x99, 0x9c, 0xff, - 0xae, 0xa4, 0xa4, 0xff, 0xc4, 0xc3, 0xc4, 0xff, 0xb4, 0xaa, 0xac, 0xff, - 0x9e, 0x8e, 0x94, 0xff, 0xb4, 0xaa, 0xac, 0xff, 0x9e, 0x8e, 0x94, 0xff, - 0xa1, 0x9e, 0x9c, 0xff, 0xae, 0xa4, 0xa4, 0xff, 0xa1, 0x9e, 0x9c, 0xff, - 0xc4, 0xc3, 0xc4, 0xff, 0xf8, 0xea, 0xec, 0xff, 0xcc, 0xcc, 0xcc, 0xff, - 0xcc, 0xc5, 0xc4, 0xff, 0xb4, 0xb2, 0xb4, 0xff, 0xcc, 0xc5, 0xc4, 0xff, - 0xc2, 0xbe, 0xbc, 0xff, 0xbc, 0xb1, 0xb4, 0xff, 0xc2, 0xc2, 0xbc, 0xff, - 0x9a, 0x94, 0x94, 0xff, 0xd7, 0xcc, 0xc4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf2, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xc2, 0xbe, 0xbc, 0xff, 0x94, 0x8c, 0x8c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x6c, 0x61, 0x64, 0xff, 0x8c, 0x81, 0x84, 0xff, 0xb4, 0xb2, 0xb4, 0xff, - 0xba, 0xb6, 0xb4, 0xff, 0x9a, 0x94, 0x94, 0xff, 0x9a, 0x94, 0x94, 0xff, - 0x8b, 0x8b, 0x8c, 0xff, 0x8c, 0x81, 0x84, 0xff, 0x64, 0x5d, 0x5c, 0xff, - 0x8c, 0x81, 0x84, 0xff, 0xcc, 0xbd, 0xbc, 0xff, 0x9e, 0x8e, 0x94, 0xff, - 0x6c, 0x61, 0x64, 0xff, 0x70, 0x5e, 0x5c, 0xff, 0x5d, 0x5a, 0x54, 0xff, - 0x6f, 0x6c, 0x6c, 0xff, 0x6c, 0x61, 0x64, 0xff, 0x6a, 0x53, 0x4c, 0xff, - 0x69, 0x4e, 0x4c, 0xff, 0x69, 0x4e, 0x4c, 0xff, 0x6c, 0x4a, 0x44, 0xff, - 0x6c, 0x4a, 0x44, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x69, 0x4e, 0x44, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x6c, 0x4a, 0x44, 0xff, 0x58, 0x49, 0x4c, 0xff, 0x7c, 0x5d, 0x54, 0xff, - 0x78, 0x66, 0x64, 0xff, 0x71, 0x6a, 0x64, 0xff, 0x70, 0x5e, 0x5c, 0xff, - 0x71, 0x6a, 0x64, 0xff, 0x8f, 0x7f, 0x7c, 0xff, 0x6c, 0x61, 0x64, 0xff, - 0x6b, 0x56, 0x5c, 0xff, 0x81, 0x72, 0x74, 0xff, 0x84, 0x77, 0x74, 0xff, - 0x8e, 0x7a, 0x7c, 0xff, 0x8c, 0x81, 0x84, 0xff, 0x84, 0x79, 0x7c, 0xff, - 0x94, 0x8c, 0x8c, 0xff, 0x9a, 0x94, 0x94, 0xff, 0xae, 0xa4, 0xa4, 0xff, - 0xac, 0xa9, 0xac, 0xff, 0xbc, 0xb1, 0xb4, 0xff, 0xa1, 0x99, 0x9c, 0xff, - 0x9a, 0x94, 0x94, 0xff, 0xb4, 0xaa, 0xac, 0xff, 0xad, 0x9a, 0x9c, 0xff, - 0xae, 0xa4, 0xa4, 0xff, 0xba, 0xb6, 0xb4, 0xff, 0x94, 0x8c, 0x8c, 0xff, - 0xae, 0xa4, 0xa4, 0xff, 0xb4, 0xaa, 0xac, 0xff, 0xae, 0xa4, 0xa4, 0xff, - 0xac, 0xa9, 0xac, 0xff, 0xcc, 0xc5, 0xc4, 0xff, 0xc4, 0xbe, 0xc4, 0xff, - 0xc2, 0xbe, 0xbc, 0xff, 0xc2, 0xbe, 0xbc, 0xff, 0xbc, 0xb9, 0xbc, 0xff, - 0xc8, 0xca, 0xc4, 0xff, 0xbc, 0xb9, 0xbc, 0xff, 0xcc, 0xc2, 0xbc, 0xff, - 0xcc, 0xc2, 0xbc, 0xff, 0x9c, 0x93, 0x8c, 0xff, 0xee, 0xdd, 0xd4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xac, 0xa9, 0xac, 0xff, 0xb4, 0xb2, 0xb4, 0xff, 0x6c, 0x61, 0x64, 0xff, - 0x81, 0x7e, 0x7c, 0xff, 0xa4, 0x9e, 0xa4, 0xff, 0x9a, 0x94, 0x94, 0xff, - 0xb4, 0xaa, 0xac, 0xff, 0xac, 0xa9, 0xac, 0xff, 0xa1, 0x99, 0x9c, 0xff, - 0x9a, 0x94, 0x94, 0xff, 0xa1, 0x9e, 0x9c, 0xff, 0x8e, 0x7a, 0x7c, 0xff, - 0x6b, 0x56, 0x5c, 0xff, 0xb4, 0xaa, 0xac, 0xff, 0xd5, 0xcd, 0xcc, 0xff, - 0x77, 0x66, 0x6c, 0xff, 0x6c, 0x61, 0x64, 0xff, 0x7f, 0x72, 0x6c, 0xff, - 0x70, 0x5e, 0x5c, 0xff, 0x63, 0x66, 0x64, 0xff, 0x72, 0x62, 0x5c, 0xff, - 0x69, 0x4e, 0x4c, 0xff, 0x69, 0x4e, 0x4c, 0xff, 0x69, 0x4e, 0x4c, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x3e, 0x34, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x69, 0x4e, 0x44, 0xff, 0x6a, 0x53, 0x4c, 0xff, 0x72, 0x5b, 0x54, 0xff, - 0x70, 0x5e, 0x5c, 0xff, 0x7e, 0x6d, 0x6c, 0xff, 0x72, 0x62, 0x5c, 0xff, - 0x81, 0x7e, 0x7c, 0xff, 0x8c, 0x81, 0x84, 0xff, 0x7e, 0x6d, 0x6c, 0xff, - 0x7e, 0x6d, 0x6c, 0xff, 0x81, 0x72, 0x74, 0xff, 0x8e, 0x7a, 0x7c, 0xff, - 0x84, 0x77, 0x74, 0xff, 0x81, 0x72, 0x74, 0xff, 0x84, 0x77, 0x74, 0xff, - 0x9a, 0x94, 0x94, 0xff, 0xad, 0x9a, 0x9c, 0xff, 0xb4, 0xaa, 0xac, 0xff, - 0xac, 0xa9, 0xac, 0xff, 0xb4, 0xaa, 0xac, 0xff, 0xa1, 0x99, 0x9c, 0xff, - 0x9a, 0x94, 0x94, 0xff, 0xad, 0x9a, 0x9c, 0xff, 0xae, 0xa4, 0xa4, 0xff, - 0xc4, 0xba, 0xbc, 0xff, 0xae, 0xa4, 0xa4, 0xff, 0xa1, 0x99, 0x9c, 0xff, - 0x94, 0x8c, 0x8c, 0xff, 0xa1, 0x99, 0x9c, 0xff, 0xa1, 0x99, 0x9c, 0xff, - 0xa3, 0xa3, 0xa4, 0xff, 0xc2, 0xbe, 0xbc, 0xff, 0xcc, 0xc5, 0xc4, 0xff, - 0xc4, 0xbe, 0xc4, 0xff, 0xc4, 0xc3, 0xc4, 0xff, 0xc2, 0xbe, 0xbc, 0xff, - 0xd6, 0xd2, 0xd4, 0xff, 0xbc, 0xb1, 0xb4, 0xff, 0xc2, 0xbe, 0xbc, 0xff, - 0xcc, 0xc2, 0xbc, 0xff, 0xae, 0xa4, 0xa4, 0xff, 0x9c, 0x92, 0x84, 0xff, - 0xe2, 0xdc, 0xcc, 0xff, 0xfc, 0xf2, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xc4, 0xba, 0xbc, 0xff, 0xc4, 0xc3, 0xc4, 0xff, 0xa3, 0xa3, 0xa4, 0xff, - 0x94, 0x8c, 0x8c, 0xff, 0xac, 0xa9, 0xac, 0xff, 0xa3, 0xa3, 0xa4, 0xff, - 0x9a, 0x94, 0x94, 0xff, 0x9a, 0x94, 0x94, 0xff, 0xb4, 0xaa, 0xac, 0xff, - 0xa1, 0x99, 0x9c, 0xff, 0xa4, 0x9e, 0xa4, 0xff, 0xb3, 0xae, 0xac, 0xff, - 0x83, 0x82, 0x84, 0xff, 0x64, 0x5d, 0x5c, 0xff, 0x6b, 0x56, 0x5c, 0xff, - 0xc5, 0xb7, 0xb4, 0xff, 0x64, 0x5d, 0x5c, 0xff, 0x64, 0x5d, 0x5c, 0xff, - 0x72, 0x62, 0x5c, 0xff, 0x72, 0x62, 0x5c, 0xff, 0x7f, 0x72, 0x6c, 0xff, - 0x7f, 0x6a, 0x64, 0xff, 0x61, 0x48, 0x44, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x6c, 0x4a, 0x44, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x69, 0x4e, 0x4c, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x69, 0x55, 0x54, 0xff, - 0x69, 0x55, 0x54, 0xff, 0x7f, 0x72, 0x6c, 0xff, 0x84, 0x77, 0x74, 0xff, - 0x8e, 0x7a, 0x7c, 0xff, 0x75, 0x62, 0x64, 0xff, 0x75, 0x62, 0x64, 0xff, - 0x84, 0x77, 0x74, 0xff, 0x84, 0x77, 0x74, 0xff, 0x81, 0x72, 0x74, 0xff, - 0x8c, 0x81, 0x84, 0xff, 0x94, 0x8c, 0x8c, 0xff, 0x81, 0x72, 0x74, 0xff, - 0x96, 0x85, 0x84, 0xff, 0xac, 0xa9, 0xac, 0xff, 0xcc, 0xc5, 0xc4, 0xff, - 0xc2, 0xbe, 0xbc, 0xff, 0xbc, 0xb0, 0xac, 0xff, 0xc4, 0xba, 0xbc, 0xff, - 0xad, 0x9e, 0x9e, 0xff, 0x94, 0x8c, 0x8c, 0xff, 0x9e, 0x8e, 0x94, 0xff, - 0x84, 0x79, 0x7c, 0xff, 0x83, 0x82, 0x84, 0xff, 0x9d, 0x8d, 0x8c, 0xff, - 0xa4, 0x9e, 0xa4, 0xff, 0x9a, 0x94, 0x94, 0xff, 0x94, 0x8e, 0x94, 0xff, - 0xae, 0xa4, 0xa4, 0xff, 0xbc, 0xb9, 0xbc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, - 0xcc, 0xc5, 0xc4, 0xff, 0xcf, 0xc6, 0xcc, 0xff, 0xc4, 0xc3, 0xc4, 0xff, - 0xcc, 0xbe, 0xc4, 0xff, 0xc4, 0xba, 0xbc, 0xff, 0xcc, 0xbd, 0xbc, 0xff, - 0xc4, 0xc3, 0xc4, 0xff, 0xbc, 0xb0, 0xac, 0xff, 0x8f, 0x86, 0x7c, 0xff, - 0xa8, 0x9b, 0x94, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf2, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf1, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xd5, 0xcd, 0xcc, 0xff, 0xb3, 0xae, 0xac, 0xff, 0xae, 0xa4, 0xa4, 0xff, - 0xa3, 0xa3, 0xa4, 0xff, 0x9a, 0x94, 0x94, 0xff, 0xa1, 0x99, 0x9c, 0xff, - 0xa1, 0x9e, 0x9c, 0xff, 0x94, 0x8e, 0x94, 0xff, 0x94, 0x8c, 0x8c, 0xff, - 0x96, 0x86, 0x8c, 0xff, 0x9a, 0x94, 0x94, 0xff, 0xc4, 0xba, 0xbc, 0xff, - 0xd4, 0xc6, 0xc4, 0xff, 0x6b, 0x56, 0x5c, 0xff, 0x6c, 0x61, 0x64, 0xff, - 0x81, 0x72, 0x74, 0xff, 0x55, 0x55, 0x54, 0xff, 0x6b, 0x56, 0x5c, 0xff, - 0x5d, 0x62, 0x5c, 0xff, 0x6c, 0x61, 0x64, 0xff, 0x71, 0x6a, 0x64, 0xff, - 0x8f, 0x7f, 0x7c, 0xff, 0x55, 0x4e, 0x4c, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x69, 0x4e, 0x44, 0xff, 0x6c, 0x4a, 0x44, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x6c, 0x4a, 0x44, 0xff, 0x61, 0x48, 0x44, 0xff, 0x6a, 0x53, 0x4c, 0xff, - 0x6a, 0x53, 0x4c, 0xff, 0x72, 0x62, 0x5c, 0xff, 0x89, 0x86, 0x84, 0xff, - 0x9c, 0x93, 0x8c, 0xff, 0x8c, 0x81, 0x84, 0xff, 0x96, 0x86, 0x8c, 0xff, - 0x84, 0x79, 0x7c, 0xff, 0x8c, 0x81, 0x84, 0xff, 0x84, 0x77, 0x74, 0xff, - 0x8c, 0x81, 0x84, 0xff, 0x9d, 0x8d, 0x8c, 0xff, 0x8f, 0x7f, 0x7c, 0xff, - 0x81, 0x72, 0x74, 0xff, 0x94, 0x8c, 0x8c, 0xff, 0xbc, 0xb1, 0xb4, 0xff, - 0xbc, 0xb9, 0xbc, 0xff, 0xae, 0xa4, 0xa4, 0xff, 0xbc, 0xb9, 0xbc, 0xff, - 0xb4, 0xaa, 0xac, 0xff, 0x9a, 0x94, 0x94, 0xff, 0xae, 0xa4, 0xa4, 0xff, - 0x9e, 0x8e, 0x94, 0xff, 0xa6, 0x95, 0x94, 0xff, 0xa1, 0x99, 0x9c, 0xff, - 0x9a, 0x94, 0x94, 0xff, 0xa1, 0x99, 0x9c, 0xff, 0x8b, 0x8b, 0x8c, 0xff, - 0xac, 0xa9, 0xac, 0xff, 0xbc, 0xb9, 0xbc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, - 0xe4, 0xe1, 0xe4, 0xff, 0xd6, 0xd2, 0xd4, 0xff, 0xc4, 0xbe, 0xc4, 0xff, - 0xcc, 0xcc, 0xcc, 0xff, 0xd5, 0xcd, 0xcc, 0xff, 0xd5, 0xcd, 0xcc, 0xff, - 0xc4, 0xba, 0xbc, 0xff, 0xb1, 0xaa, 0xa4, 0xff, 0xb1, 0xaa, 0xa4, 0xff, - 0x8f, 0x7f, 0x7c, 0xff, 0xbc, 0xb6, 0xac, 0xff, 0xfb, 0xf9, 0xec, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xfc, 0xf1, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xcf, 0xc6, 0xcc, 0xff, 0xac, 0xa9, 0xac, 0xff, 0x9a, 0x94, 0x94, 0xff, - 0xb3, 0xae, 0xac, 0xff, 0xac, 0xa9, 0xac, 0xff, 0xa3, 0xa3, 0xa4, 0xff, - 0xb4, 0xb2, 0xb4, 0xff, 0xb3, 0xae, 0xac, 0xff, 0xa3, 0xa3, 0xa4, 0xff, - 0x7b, 0x7a, 0x7c, 0xff, 0x96, 0x85, 0x84, 0xff, 0xa1, 0x99, 0x9c, 0xff, - 0xa4, 0x9e, 0xa4, 0xff, 0x7e, 0x6d, 0x6c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x69, 0x55, 0x54, 0xff, 0x55, 0x52, 0x4c, 0xff, 0x70, 0x5e, 0x5c, 0xff, - 0x71, 0x6a, 0x64, 0xff, 0x78, 0x66, 0x64, 0xff, 0x71, 0x6a, 0x64, 0xff, - 0x7e, 0x6d, 0x6c, 0xff, 0x84, 0x77, 0x74, 0xff, 0x50, 0x4e, 0x44, 0xff, - 0x61, 0x48, 0x44, 0xff, 0x6c, 0x4a, 0x44, 0xff, 0x6c, 0x4a, 0x44, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x5c, 0x3e, 0x34, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x5c, 0x3e, 0x34, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x61, 0x48, 0x44, 0xff, 0x81, 0x72, 0x74, 0xff, 0x9d, 0x8d, 0x8c, 0xff, - 0xad, 0x9e, 0x9e, 0xff, 0xa6, 0x95, 0x94, 0xff, 0x8c, 0x81, 0x84, 0xff, - 0x9c, 0x80, 0x7c, 0xff, 0x84, 0x79, 0x7c, 0xff, 0x8f, 0x7f, 0x7c, 0xff, - 0x8c, 0x81, 0x84, 0xff, 0x96, 0x85, 0x84, 0xff, 0x96, 0x85, 0x84, 0xff, - 0x78, 0x77, 0x74, 0xff, 0x96, 0x85, 0x84, 0xff, 0xc2, 0xbe, 0xbc, 0xff, - 0xb4, 0xb2, 0xb4, 0xff, 0xac, 0xa9, 0xac, 0xff, 0x9a, 0x94, 0x94, 0xff, - 0x94, 0x8c, 0x8c, 0xff, 0xa4, 0x9e, 0xa4, 0xff, 0xc5, 0xb7, 0xb4, 0xff, - 0xb4, 0xaa, 0xac, 0xff, 0xc4, 0xba, 0xbc, 0xff, 0xb4, 0xaa, 0xac, 0xff, - 0xba, 0xb6, 0xb4, 0xff, 0xa3, 0xa3, 0xa4, 0xff, 0x9a, 0x94, 0x94, 0xff, - 0xb4, 0xaa, 0xac, 0xff, 0xc2, 0xbe, 0xbc, 0xff, 0xc4, 0xc3, 0xc4, 0xff, - 0xcf, 0xc6, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xba, 0xb6, 0xb4, 0xff, - 0xbc, 0xb9, 0xbc, 0xff, 0xbc, 0xb1, 0xb4, 0xff, 0xbc, 0xb1, 0xb4, 0xff, - 0xd4, 0xc6, 0xc4, 0xff, 0xc4, 0xc3, 0xc4, 0xff, 0xcc, 0xc2, 0xbc, 0xff, - 0xae, 0xa4, 0xa4, 0xff, 0x9c, 0x88, 0x7c, 0xff, 0xe6, 0xd6, 0xcc, 0xff, - 0xfc, 0xf2, 0xe4, 0xff, 0xfb, 0xf9, 0xec, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xcc, 0xc5, 0xc4, 0xff, 0xd6, 0xd2, 0xd4, 0xff, 0xc2, 0xbe, 0xbc, 0xff, - 0xa3, 0xa3, 0xa4, 0xff, 0x9a, 0x94, 0x94, 0xff, 0xb1, 0xaa, 0xa4, 0xff, - 0xbc, 0xb9, 0xbc, 0xff, 0xb3, 0xae, 0xac, 0xff, 0xa1, 0x99, 0x9c, 0xff, - 0xa1, 0x9e, 0x9c, 0xff, 0x83, 0x82, 0x84, 0xff, 0x78, 0x77, 0x74, 0xff, - 0xa6, 0x95, 0x94, 0xff, 0x6f, 0x6c, 0x6c, 0xff, 0x58, 0x49, 0x4c, 0xff, - 0x64, 0x4e, 0x54, 0xff, 0x69, 0x55, 0x54, 0xff, 0x72, 0x62, 0x5c, 0xff, - 0x6f, 0x6c, 0x6c, 0xff, 0x78, 0x66, 0x64, 0xff, 0x6f, 0x6c, 0x6c, 0xff, - 0x81, 0x72, 0x74, 0xff, 0x8f, 0x7f, 0x7c, 0xff, 0x7f, 0x6a, 0x64, 0xff, - 0x61, 0x48, 0x44, 0xff, 0x61, 0x48, 0x44, 0xff, 0x69, 0x4e, 0x4c, 0xff, - 0x6c, 0x4a, 0x44, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x61, 0x48, 0x44, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x69, 0x4e, 0x4c, 0xff, - 0x7f, 0x72, 0x6c, 0xff, 0x9d, 0x8d, 0x8c, 0xff, 0xad, 0x9a, 0x9c, 0xff, - 0x94, 0x8c, 0x8c, 0xff, 0x84, 0x79, 0x7c, 0xff, 0x8f, 0x7f, 0x7c, 0xff, - 0x81, 0x72, 0x74, 0xff, 0x84, 0x77, 0x74, 0xff, 0x78, 0x77, 0x74, 0xff, - 0x8c, 0x81, 0x84, 0xff, 0x8c, 0x81, 0x84, 0xff, 0xba, 0xb6, 0xb4, 0xff, - 0xc4, 0xba, 0xbc, 0xff, 0xbc, 0xb0, 0xac, 0xff, 0xae, 0xa4, 0xa4, 0xff, - 0x9a, 0x94, 0x94, 0xff, 0xb3, 0xae, 0xac, 0xff, 0xbc, 0xb1, 0xb4, 0xff, - 0xb4, 0xb2, 0xb4, 0xff, 0xb3, 0xae, 0xac, 0xff, 0xb4, 0xb2, 0xb4, 0xff, - 0xba, 0xb6, 0xb4, 0xff, 0xc4, 0xba, 0xbc, 0xff, 0xa1, 0x9e, 0x9c, 0xff, - 0xa3, 0xa3, 0xa4, 0xff, 0xc4, 0xba, 0xbc, 0xff, 0xcc, 0xc5, 0xc4, 0xff, - 0xc4, 0xc3, 0xc4, 0xff, 0xb4, 0xb2, 0xb4, 0xff, 0xbc, 0xb1, 0xb4, 0xff, - 0xbc, 0xb9, 0xbc, 0xff, 0xb4, 0xb2, 0xb4, 0xff, 0xd5, 0xcd, 0xcc, 0xff, - 0xc4, 0xc3, 0xc4, 0xff, 0xc4, 0xc3, 0xc4, 0xff, 0xcc, 0xbd, 0xbc, 0xff, - 0xba, 0xb6, 0xb4, 0xff, 0x9c, 0x93, 0x8c, 0xff, 0xa8, 0x9b, 0x94, 0xff, - 0xf2, 0xe9, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xdc, 0xdc, 0xdc, 0xff, 0xcf, 0xc6, 0xcc, 0xff, 0xc2, 0xbe, 0xbc, 0xff, - 0xba, 0xb6, 0xb4, 0xff, 0x9a, 0x94, 0x94, 0xff, 0x94, 0x8e, 0x94, 0xff, - 0xc4, 0xbe, 0xc4, 0xff, 0xcc, 0xc5, 0xc4, 0xff, 0xb3, 0xae, 0xac, 0xff, - 0xb3, 0xae, 0xac, 0xff, 0xba, 0xb6, 0xb4, 0xff, 0x8b, 0x8b, 0x8c, 0xff, - 0x64, 0x5d, 0x5c, 0xff, 0x69, 0x55, 0x54, 0xff, 0x69, 0x55, 0x54, 0xff, - 0x72, 0x5b, 0x54, 0xff, 0x5d, 0x5a, 0x54, 0xff, 0x78, 0x66, 0x64, 0xff, - 0x7e, 0x6d, 0x6c, 0xff, 0xc6, 0xb1, 0xb4, 0xff, 0xa1, 0x99, 0x9c, 0xff, - 0x8f, 0x7f, 0x7c, 0xff, 0x78, 0x66, 0x64, 0xff, 0x7e, 0x6d, 0x6c, 0xff, - 0x70, 0x5e, 0x5c, 0xff, 0x61, 0x48, 0x44, 0xff, 0x58, 0x49, 0x4c, 0xff, - 0x74, 0x4e, 0x4c, 0xff, 0x6c, 0x4a, 0x44, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x61, 0x48, 0x44, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x69, 0x55, 0x54, 0xff, - 0x69, 0x55, 0x54, 0xff, 0x69, 0x55, 0x54, 0xff, 0x8f, 0x86, 0x7c, 0xff, - 0xa6, 0x95, 0x94, 0xff, 0x96, 0x85, 0x84, 0xff, 0x96, 0x86, 0x8c, 0xff, - 0x78, 0x66, 0x64, 0xff, 0x77, 0x66, 0x6c, 0xff, 0x7e, 0x6d, 0x6c, 0xff, - 0x8f, 0x7f, 0x7c, 0xff, 0x94, 0x8c, 0x8c, 0xff, 0xbc, 0xb0, 0xac, 0xff, - 0xba, 0xb6, 0xb4, 0xff, 0xba, 0xb6, 0xb4, 0xff, 0xae, 0xa4, 0xa4, 0xff, - 0x89, 0x86, 0x84, 0xff, 0xbc, 0xb0, 0xac, 0xff, 0xb1, 0xaa, 0xa4, 0xff, - 0xbc, 0xb1, 0xb4, 0xff, 0xbc, 0xb9, 0xbc, 0xff, 0xbc, 0xb1, 0xb4, 0xff, - 0xba, 0xb6, 0xb4, 0xff, 0xc4, 0xbe, 0xc4, 0xff, 0xbc, 0xb9, 0xbc, 0xff, - 0xa1, 0x99, 0x9c, 0xff, 0xa3, 0xa3, 0xa4, 0xff, 0xbc, 0xb9, 0xbc, 0xff, - 0xcc, 0xc5, 0xc4, 0xff, 0xbc, 0xb9, 0xbc, 0xff, 0xac, 0xa9, 0xac, 0xff, - 0xba, 0xb6, 0xb4, 0xff, 0xbc, 0xb1, 0xb4, 0xff, 0xdc, 0xd6, 0xdc, 0xff, - 0xc4, 0xc3, 0xc4, 0xff, 0xd4, 0xc6, 0xc4, 0xff, 0xcc, 0xbe, 0xc4, 0xff, - 0xae, 0xa4, 0xa4, 0xff, 0xbc, 0xb1, 0xb4, 0xff, 0x94, 0x8b, 0x84, 0xff, - 0xba, 0xb0, 0xa4, 0xff, 0xf4, 0xea, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xdc, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xe4, 0xe2, 0xd8, 0xff, 0xd6, 0xd2, 0xd4, 0xff, 0xa1, 0x99, 0x9c, 0xff, - 0xa1, 0x9e, 0x9c, 0xff, 0xa3, 0xa3, 0xa4, 0xff, 0x9a, 0x94, 0x94, 0xff, - 0xb3, 0xae, 0xac, 0xff, 0xba, 0xb6, 0xb4, 0xff, 0xb3, 0xae, 0xac, 0xff, - 0xa3, 0xa3, 0xa4, 0xff, 0x9c, 0x9a, 0x94, 0xff, 0xbc, 0xb0, 0xac, 0xff, - 0x81, 0x7e, 0x7c, 0xff, 0x7e, 0x6d, 0x6c, 0xff, 0x55, 0x4e, 0x4c, 0xff, - 0x69, 0x55, 0x54, 0xff, 0x8e, 0x79, 0x74, 0xff, 0x7e, 0x6d, 0x6c, 0xff, - 0x84, 0x79, 0x7c, 0xff, 0x9a, 0x94, 0x94, 0xff, 0xd7, 0xcc, 0xc4, 0xff, - 0x64, 0x5d, 0x5c, 0xff, 0x7e, 0x6d, 0x6c, 0xff, 0x81, 0x72, 0x74, 0xff, - 0x8e, 0x7a, 0x7c, 0xff, 0x69, 0x55, 0x54, 0xff, 0x5c, 0x42, 0x44, 0xff, - 0x69, 0x4e, 0x4c, 0xff, 0x6c, 0x4a, 0x44, 0xff, 0x5c, 0x42, 0x44, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x6c, 0x4a, 0x44, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x3e, 0x34, 0xff, - 0x5c, 0x42, 0x44, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x69, 0x55, 0x54, 0xff, - 0x72, 0x62, 0x5c, 0xff, 0x63, 0x66, 0x64, 0xff, 0x8e, 0x7a, 0x7c, 0xff, - 0x64, 0x5d, 0x5c, 0xff, 0x7e, 0x6d, 0x6c, 0xff, 0x94, 0x8c, 0x8c, 0xff, - 0x84, 0x79, 0x7c, 0xff, 0x6f, 0x6c, 0x6c, 0xff, 0x84, 0x79, 0x7c, 0xff, - 0x96, 0x85, 0x84, 0xff, 0x9a, 0x94, 0x94, 0xff, 0xae, 0xa4, 0xa4, 0xff, - 0xb4, 0xb2, 0xb4, 0xff, 0xba, 0xb6, 0xb4, 0xff, 0xba, 0xb6, 0xb4, 0xff, - 0x9a, 0x94, 0x94, 0xff, 0x9a, 0x94, 0x94, 0xff, 0xba, 0xb6, 0xb4, 0xff, - 0xb1, 0xaa, 0xa4, 0xff, 0xbc, 0xb9, 0xbc, 0xff, 0xb4, 0xb2, 0xb4, 0xff, - 0xb4, 0xaa, 0xac, 0xff, 0xb3, 0xae, 0xac, 0xff, 0xc2, 0xbe, 0xbc, 0xff, - 0xbc, 0xb9, 0xbc, 0xff, 0xb3, 0xae, 0xac, 0xff, 0xae, 0xa4, 0xa4, 0xff, - 0xc4, 0xbe, 0xc4, 0xff, 0xcc, 0xc5, 0xc4, 0xff, 0xbc, 0xb9, 0xbc, 0xff, - 0x9a, 0x94, 0x94, 0xff, 0xc4, 0xba, 0xbc, 0xff, 0xba, 0xb6, 0xb4, 0xff, - 0xc4, 0xbe, 0xc4, 0xff, 0xd5, 0xcd, 0xcc, 0xff, 0xcf, 0xc6, 0xcc, 0xff, - 0xb3, 0xae, 0xac, 0xff, 0xc2, 0xbe, 0xbc, 0xff, 0xad, 0x9e, 0x9e, 0xff, - 0x81, 0x7e, 0x7c, 0xff, 0xcc, 0xbe, 0xac, 0xff, 0xfb, 0xf9, 0xec, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfa, 0xfe, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfa, 0xfe, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xcc, 0xcc, 0xcc, 0xff, 0xd7, 0xd6, 0xd4, 0xff, 0xba, 0xb6, 0xb4, 0xff, - 0xac, 0xa9, 0xac, 0xff, 0xb3, 0xae, 0xac, 0xff, 0xb3, 0xae, 0xac, 0xff, - 0xa1, 0x9e, 0x9c, 0xff, 0x94, 0x8e, 0x94, 0xff, 0xa3, 0xa3, 0xa4, 0xff, - 0xa3, 0xa3, 0xa4, 0xff, 0xa3, 0xa3, 0xa4, 0xff, 0xa3, 0xa3, 0xa4, 0xff, - 0xa8, 0x9b, 0x94, 0xff, 0x89, 0x86, 0x84, 0xff, 0x72, 0x5b, 0x54, 0xff, - 0x69, 0x55, 0x54, 0xff, 0x81, 0x72, 0x74, 0xff, 0x70, 0x5e, 0x5c, 0xff, - 0x8f, 0x7f, 0x7c, 0xff, 0x78, 0x66, 0x64, 0xff, 0x9a, 0x94, 0x94, 0xff, - 0x6b, 0x56, 0x5c, 0xff, 0x9d, 0x8d, 0x8c, 0xff, 0xa4, 0x9e, 0xa4, 0xff, - 0xbd, 0xa6, 0xa4, 0xff, 0x84, 0x77, 0x74, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x61, 0x48, 0x44, 0xff, 0x69, 0x4e, 0x4c, 0xff, 0x74, 0x4e, 0x4c, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x6c, 0x4a, 0x44, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x61, 0x48, 0x44, 0xff, 0x6a, 0x53, 0x4c, 0xff, - 0x78, 0x66, 0x64, 0xff, 0x96, 0x85, 0x84, 0xff, 0xae, 0xa4, 0xa4, 0xff, - 0x94, 0x8c, 0x8c, 0xff, 0x8f, 0x7f, 0x7c, 0xff, 0x78, 0x77, 0x74, 0xff, - 0x96, 0x85, 0x84, 0xff, 0x84, 0x79, 0x7c, 0xff, 0x8f, 0x7f, 0x7c, 0xff, - 0x9a, 0x94, 0x94, 0xff, 0x9d, 0x8d, 0x8c, 0xff, 0xa6, 0x95, 0x94, 0xff, - 0xba, 0xb6, 0xb4, 0xff, 0xba, 0xb6, 0xb4, 0xff, 0xba, 0xb6, 0xb4, 0xff, - 0xae, 0xa4, 0xa4, 0xff, 0x83, 0x82, 0x84, 0xff, 0xae, 0xa4, 0xa4, 0xff, - 0xa3, 0xa3, 0xa4, 0xff, 0xb4, 0xb2, 0xb4, 0xff, 0xb4, 0xb2, 0xb4, 0xff, - 0xb3, 0xae, 0xac, 0xff, 0xbc, 0xb9, 0xbc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, - 0xbc, 0xb9, 0xbc, 0xff, 0xc2, 0xbe, 0xbc, 0xff, 0xbc, 0xb9, 0xbc, 0xff, - 0xc2, 0xbe, 0xbc, 0xff, 0xbc, 0xb9, 0xbc, 0xff, 0xcc, 0xc5, 0xc4, 0xff, - 0x9a, 0x94, 0x94, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xc4, 0xc3, 0xc4, 0xff, - 0xf8, 0xea, 0xec, 0xff, 0xec, 0xe2, 0xe4, 0xff, 0xc4, 0xc3, 0xc4, 0xff, - 0xcf, 0xc6, 0xcc, 0xff, 0xc5, 0xb7, 0xb4, 0xff, 0xbc, 0xb1, 0xb4, 0xff, - 0x90, 0x7f, 0x74, 0xff, 0x9c, 0x93, 0x8c, 0xff, 0xfb, 0xf9, 0xec, 0xff, - 0xfc, 0xf2, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfa, 0xfe, 0xdc, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xcc, 0xc5, 0xc4, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xd6, 0xd2, 0xd4, 0xff, - 0xba, 0xb6, 0xb4, 0xff, 0xbc, 0xb9, 0xbc, 0xff, 0xba, 0xb6, 0xb4, 0xff, - 0xc2, 0xc2, 0xbc, 0xff, 0xb3, 0xae, 0xac, 0xff, 0x9c, 0x9a, 0x94, 0xff, - 0x94, 0x8e, 0x94, 0xff, 0x9a, 0x94, 0x94, 0xff, 0x9c, 0x9a, 0x94, 0xff, - 0xa1, 0x9e, 0x9c, 0xff, 0x94, 0x8b, 0x84, 0xff, 0x55, 0x4e, 0x4c, 0xff, - 0x58, 0x49, 0x4c, 0xff, 0x7f, 0x72, 0x6c, 0xff, 0x7e, 0x6d, 0x6c, 0xff, - 0x6f, 0x6c, 0x6c, 0xff, 0x64, 0x4e, 0x54, 0xff, 0x4e, 0x42, 0x44, 0xff, - 0x55, 0x4e, 0x4c, 0xff, 0x78, 0x66, 0x64, 0xff, 0x8f, 0x7f, 0x7c, 0xff, - 0x84, 0x79, 0x7c, 0xff, 0x96, 0x85, 0x84, 0xff, 0x7d, 0x62, 0x5c, 0xff, - 0x53, 0x41, 0x3c, 0xff, 0x75, 0x56, 0x54, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x6c, 0x4a, 0x44, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x6c, 0x4a, 0x44, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x61, 0x48, 0x44, 0xff, 0x58, 0x49, 0x4c, 0xff, - 0x70, 0x5e, 0x5c, 0xff, 0x8f, 0x86, 0x7c, 0xff, 0xbc, 0xb0, 0xac, 0xff, - 0xbc, 0xb1, 0xb4, 0xff, 0x9a, 0x94, 0x94, 0xff, 0x96, 0x85, 0x84, 0xff, - 0x94, 0x8c, 0x8c, 0xff, 0x9d, 0x8d, 0x8c, 0xff, 0x96, 0x85, 0x84, 0xff, - 0xa1, 0x99, 0x9c, 0xff, 0x96, 0x85, 0x84, 0xff, 0xa4, 0x9e, 0xa4, 0xff, - 0xae, 0xa4, 0xa4, 0xff, 0xbc, 0xb0, 0xac, 0xff, 0xb4, 0xb2, 0xb4, 0xff, - 0xba, 0xb6, 0xb4, 0xff, 0xa1, 0x9e, 0x9c, 0xff, 0x94, 0x8c, 0x8c, 0xff, - 0xbc, 0xb0, 0xac, 0xff, 0xb4, 0xb2, 0xb4, 0xff, 0xbc, 0xb9, 0xbc, 0xff, - 0xb4, 0xb2, 0xb4, 0xff, 0xbc, 0xb9, 0xbc, 0xff, 0xc4, 0xc3, 0xc4, 0xff, - 0xcc, 0xc5, 0xc4, 0xff, 0xc4, 0xba, 0xbc, 0xff, 0xbc, 0xb9, 0xbc, 0xff, - 0xc4, 0xc3, 0xc4, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xc4, 0xc3, 0xc4, 0xff, - 0xae, 0xa4, 0xa4, 0xff, 0xac, 0xa9, 0xac, 0xff, 0xd6, 0xd2, 0xd4, 0xff, - 0xe4, 0xe1, 0xe4, 0xff, 0xdc, 0xdc, 0xdc, 0xff, 0xe4, 0xd2, 0xd4, 0xff, - 0xd5, 0xcd, 0xcc, 0xff, 0xc2, 0xbe, 0xbc, 0xff, 0xd9, 0xd4, 0xcc, 0xff, - 0xa8, 0x9b, 0x94, 0xff, 0xa6, 0x95, 0x94, 0xff, 0xd7, 0xcc, 0xc4, 0xff, - 0xfb, 0xf9, 0xec, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfa, 0xfe, 0xdc, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xc4, 0xbe, 0xc4, 0xff, 0xba, 0xb6, 0xb4, 0xff, 0xcc, 0xcc, 0xcc, 0xff, - 0xc2, 0xbe, 0xbc, 0xff, 0xac, 0xa9, 0xac, 0xff, 0xb4, 0xb2, 0xb4, 0xff, - 0xcc, 0xcc, 0xcc, 0xff, 0xc4, 0xc3, 0xc4, 0xff, 0xb4, 0xb2, 0xb4, 0xff, - 0xac, 0xa9, 0xac, 0xff, 0xb3, 0xae, 0xac, 0xff, 0xa1, 0xa2, 0x9c, 0xff, - 0xa1, 0x99, 0x9c, 0xff, 0xad, 0x9e, 0x9e, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x55, 0x4e, 0x4c, 0xff, 0x69, 0x55, 0x54, 0xff, 0x78, 0x66, 0x64, 0xff, - 0x8c, 0x81, 0x84, 0xff, 0x6b, 0x56, 0x5c, 0xff, 0x55, 0x4e, 0x4c, 0xff, - 0x70, 0x5e, 0x5c, 0xff, 0x64, 0x5d, 0x5c, 0xff, 0x81, 0x72, 0x74, 0xff, - 0x9c, 0x93, 0x8c, 0xff, 0xc4, 0xb2, 0xac, 0xff, 0xa6, 0x95, 0x94, 0xff, - 0x58, 0x49, 0x4c, 0xff, 0x6c, 0x4a, 0x44, 0xff, 0x69, 0x4e, 0x4c, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x6c, 0x4a, 0x44, 0xff, 0x6c, 0x4a, 0x44, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x6c, 0x4a, 0x44, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x61, 0x48, 0x44, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x72, 0x62, 0x5c, 0xff, 0x84, 0x77, 0x74, 0xff, 0x81, 0x7e, 0x7c, 0xff, - 0x8f, 0x7f, 0x7c, 0xff, 0x96, 0x85, 0x84, 0xff, 0x8c, 0x81, 0x84, 0xff, - 0x89, 0x86, 0x84, 0xff, 0x9d, 0x8d, 0x8c, 0xff, 0xa1, 0x99, 0x9c, 0xff, - 0xae, 0xa4, 0xa4, 0xff, 0xb0, 0xa3, 0x9c, 0xff, 0xae, 0xa4, 0xa4, 0xff, - 0xb3, 0xae, 0xac, 0xff, 0xbc, 0xb9, 0xbc, 0xff, 0xba, 0xb6, 0xb4, 0xff, - 0xbc, 0xb0, 0xac, 0xff, 0xbc, 0xb1, 0xb4, 0xff, 0x89, 0x86, 0x84, 0xff, - 0xb3, 0xae, 0xac, 0xff, 0xbc, 0xb9, 0xbc, 0xff, 0xd5, 0xcd, 0xcc, 0xff, - 0xc2, 0xbe, 0xbc, 0xff, 0xb4, 0xaa, 0xac, 0xff, 0xbc, 0xb9, 0xbc, 0xff, - 0xd5, 0xcd, 0xcc, 0xff, 0xc4, 0xc3, 0xc4, 0xff, 0xbc, 0xb9, 0xbc, 0xff, - 0xba, 0xb6, 0xb4, 0xff, 0xc4, 0xba, 0xbc, 0xff, 0xc4, 0xba, 0xbc, 0xff, - 0xb4, 0xb2, 0xb4, 0xff, 0xc2, 0xbe, 0xbc, 0xff, 0xe4, 0xde, 0xdc, 0xff, - 0xc4, 0xc3, 0xc4, 0xff, 0xdc, 0xdc, 0xdc, 0xff, 0xf2, 0xf0, 0xec, 0xff, - 0xcc, 0xbe, 0xc4, 0xff, 0xd4, 0xc6, 0xc4, 0xff, 0xd6, 0xd2, 0xd4, 0xff, - 0xd4, 0xc6, 0xc4, 0xff, 0xa8, 0x93, 0x8c, 0xff, 0xbc, 0xb0, 0xac, 0xff, - 0xfb, 0xf9, 0xec, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfa, 0xfe, 0xdc, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xc4, 0xc3, 0xc4, 0xff, 0xbc, 0xb9, 0xbc, 0xff, 0xc4, 0xc3, 0xc4, 0xff, - 0xc2, 0xbe, 0xbc, 0xff, 0x92, 0x92, 0x8c, 0xff, 0xa3, 0xa3, 0xa4, 0xff, - 0xbc, 0xb9, 0xbc, 0xff, 0xc4, 0xc3, 0xc4, 0xff, 0xc4, 0xc3, 0xc4, 0xff, - 0xc2, 0xbe, 0xbc, 0xff, 0xba, 0xb6, 0xb4, 0xff, 0xb4, 0xb2, 0xb4, 0xff, - 0xbc, 0xb0, 0xac, 0xff, 0xa6, 0x95, 0x94, 0xff, 0x55, 0x4e, 0x4c, 0xff, - 0x6a, 0x53, 0x4c, 0xff, 0x70, 0x5e, 0x5c, 0xff, 0x75, 0x62, 0x64, 0xff, - 0x96, 0x85, 0x84, 0xff, 0x7e, 0x6d, 0x6c, 0xff, 0x69, 0x55, 0x54, 0xff, - 0x6c, 0x61, 0x64, 0xff, 0x64, 0x5d, 0x5c, 0xff, 0x78, 0x66, 0x64, 0xff, - 0xb4, 0xb2, 0xb4, 0xff, 0xc4, 0xba, 0xbc, 0xff, 0x80, 0x67, 0x5c, 0xff, - 0x72, 0x5b, 0x54, 0xff, 0x61, 0x48, 0x44, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x6c, 0x4a, 0x44, 0xff, 0x6c, 0x4a, 0x44, 0xff, 0x6c, 0x4a, 0x44, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x6c, 0x4a, 0x44, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x5c, 0x42, 0x44, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x58, 0x49, 0x4c, 0xff, - 0x70, 0x5e, 0x5c, 0xff, 0x8f, 0x7f, 0x7c, 0xff, 0x8f, 0x7f, 0x7c, 0xff, - 0x81, 0x72, 0x74, 0xff, 0x89, 0x86, 0x84, 0xff, 0x96, 0x85, 0x84, 0xff, - 0x8f, 0x7f, 0x7c, 0xff, 0x94, 0x8c, 0x8c, 0xff, 0xa6, 0x95, 0x94, 0xff, - 0x9a, 0x94, 0x94, 0xff, 0x9e, 0x8e, 0x94, 0xff, 0xae, 0xa4, 0xa4, 0xff, - 0xd5, 0xcd, 0xcc, 0xff, 0xc2, 0xbe, 0xbc, 0xff, 0xba, 0xb6, 0xb4, 0xff, - 0xa3, 0xa3, 0xa4, 0xff, 0xa1, 0xa2, 0x9c, 0xff, 0xbc, 0xb0, 0xac, 0xff, - 0xa1, 0x9e, 0x9c, 0xff, 0xb4, 0xb2, 0xb4, 0xff, 0xc2, 0xbe, 0xbc, 0xff, - 0xd6, 0xd2, 0xd4, 0xff, 0xb4, 0xaa, 0xac, 0xff, 0xb3, 0xae, 0xac, 0xff, - 0xa4, 0x9e, 0xa4, 0xff, 0xb4, 0xaa, 0xac, 0xff, 0xc4, 0xc3, 0xc4, 0xff, - 0xc2, 0xbe, 0xbc, 0xff, 0xb4, 0xb2, 0xb4, 0xff, 0xbc, 0xb9, 0xbc, 0xff, - 0xac, 0xa9, 0xac, 0xff, 0xc4, 0xba, 0xbc, 0xff, 0xc2, 0xbe, 0xbc, 0xff, - 0xd5, 0xcd, 0xcc, 0xff, 0xfc, 0xf6, 0xf4, 0xff, 0xdc, 0xd6, 0xdc, 0xff, - 0xd4, 0xc6, 0xc4, 0xff, 0xc4, 0xba, 0xbc, 0xff, 0xd4, 0xc6, 0xc4, 0xff, - 0xdc, 0xd6, 0xdc, 0xff, 0xad, 0x9e, 0x9e, 0xff, 0xa8, 0x93, 0x8c, 0xff, - 0xd5, 0xcd, 0xcc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xdc, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfa, 0xfe, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xfa, 0xfe, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xe9, 0xd4, 0xff, - 0xcc, 0xc5, 0xc4, 0xff, 0xc4, 0xc3, 0xc4, 0xff, 0xc2, 0xbe, 0xbc, 0xff, - 0xc2, 0xbe, 0xbc, 0xff, 0xa3, 0xa3, 0xa4, 0xff, 0xbc, 0xb9, 0xbc, 0xff, - 0xb3, 0xae, 0xac, 0xff, 0xb4, 0xb2, 0xb4, 0xff, 0xc4, 0xc3, 0xc4, 0xff, - 0xc4, 0xc3, 0xc4, 0xff, 0xb4, 0xb2, 0xb4, 0xff, 0xbc, 0xb0, 0xac, 0xff, - 0xac, 0xa9, 0xac, 0xff, 0xae, 0xa4, 0xa4, 0xff, 0x69, 0x4e, 0x4c, 0xff, - 0x58, 0x49, 0x4c, 0xff, 0x69, 0x55, 0x54, 0xff, 0x7e, 0x6d, 0x6c, 0xff, - 0x69, 0x4e, 0x4c, 0xff, 0x81, 0x72, 0x74, 0xff, 0x6c, 0x61, 0x64, 0xff, - 0x70, 0x5e, 0x5c, 0xff, 0x70, 0x5e, 0x5c, 0xff, 0x6f, 0x6c, 0x6c, 0xff, - 0xb3, 0xae, 0xac, 0xff, 0xbc, 0xaa, 0xac, 0xff, 0x8f, 0x7f, 0x7c, 0xff, - 0x8e, 0x7a, 0x7c, 0xff, 0x69, 0x55, 0x54, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x69, 0x4e, 0x4c, 0xff, 0x61, 0x48, 0x44, 0xff, 0x6c, 0x4a, 0x44, 0xff, - 0x6c, 0x4a, 0x44, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x5c, 0x3e, 0x34, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x61, 0x48, 0x44, 0xff, 0x5c, 0x3e, 0x34, 0xff, - 0x6c, 0x4a, 0x44, 0xff, 0x61, 0x48, 0x44, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x6a, 0x53, 0x4c, 0xff, 0x8f, 0x7f, 0x7c, 0xff, 0x84, 0x77, 0x74, 0xff, - 0x7e, 0x6d, 0x6c, 0xff, 0x8c, 0x81, 0x84, 0xff, 0xa6, 0x95, 0x94, 0xff, - 0x8c, 0x81, 0x84, 0xff, 0x8c, 0x81, 0x84, 0xff, 0x94, 0x8c, 0x8c, 0xff, - 0xa6, 0x95, 0x94, 0xff, 0x89, 0x86, 0x84, 0xff, 0x9c, 0x9a, 0x94, 0xff, - 0x9a, 0x94, 0x94, 0xff, 0xbc, 0xb1, 0xb4, 0xff, 0xc2, 0xc2, 0xbc, 0xff, - 0x94, 0x8c, 0x8c, 0xff, 0xae, 0xa4, 0xa4, 0xff, 0xc2, 0xbe, 0xbc, 0xff, - 0xae, 0xa4, 0xa4, 0xff, 0xae, 0xa4, 0xa4, 0xff, 0xc4, 0xc3, 0xc4, 0xff, - 0xcc, 0xcc, 0xcc, 0xff, 0xbc, 0xb1, 0xb4, 0xff, 0xac, 0xa9, 0xac, 0xff, - 0xba, 0xb6, 0xb4, 0xff, 0xc4, 0xbe, 0xc4, 0xff, 0xbc, 0xb1, 0xb4, 0xff, - 0xbc, 0xb9, 0xbc, 0xff, 0xcc, 0xc5, 0xc4, 0xff, 0xcc, 0xc5, 0xc4, 0xff, - 0xbc, 0xb1, 0xb4, 0xff, 0xc4, 0xbe, 0xc4, 0xff, 0xd5, 0xcd, 0xcc, 0xff, - 0xdc, 0xdc, 0xdc, 0xff, 0xd6, 0xd2, 0xd4, 0xff, 0xd6, 0xd2, 0xd4, 0xff, - 0xec, 0xe2, 0xe4, 0xff, 0xc4, 0xc3, 0xc4, 0xff, 0xb4, 0xaa, 0xac, 0xff, - 0xcc, 0xc2, 0xbc, 0xff, 0xbc, 0xb1, 0xb4, 0xff, 0x8f, 0x7f, 0x7c, 0xff, - 0xb0, 0xa3, 0x9c, 0xff, 0xfc, 0xf2, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xfa, 0xfe, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0x94, 0x8e, 0x94, 0xff, 0xc4, 0xc3, 0xc4, 0xff, 0xac, 0xa9, 0xac, 0xff, - 0xcc, 0xcc, 0xcc, 0xff, 0xc2, 0xbe, 0xbc, 0xff, 0xc4, 0xc3, 0xc4, 0xff, - 0xbc, 0xb9, 0xbc, 0xff, 0xbc, 0xb9, 0xbc, 0xff, 0xc8, 0xca, 0xc4, 0xff, - 0xc2, 0xc2, 0xbc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xb3, 0xae, 0xac, 0xff, - 0xb4, 0xaa, 0xac, 0xff, 0xad, 0x9e, 0x9e, 0xff, 0x64, 0x4e, 0x54, 0xff, - 0x55, 0x4e, 0x4c, 0xff, 0x61, 0x48, 0x44, 0xff, 0x81, 0x72, 0x74, 0xff, - 0x6b, 0x56, 0x5c, 0xff, 0x8e, 0x7a, 0x7c, 0xff, 0x8f, 0x7f, 0x7c, 0xff, - 0x64, 0x5d, 0x5c, 0xff, 0x8c, 0x81, 0x84, 0xff, 0x6f, 0x6c, 0x6c, 0xff, - 0x8f, 0x7f, 0x7c, 0xff, 0x8c, 0x81, 0x84, 0xff, 0xa8, 0x9b, 0x94, 0xff, - 0xbc, 0xaa, 0xac, 0xff, 0xad, 0x9a, 0x9c, 0xff, 0x69, 0x4e, 0x4c, 0xff, - 0x69, 0x4e, 0x4c, 0xff, 0x69, 0x4e, 0x4c, 0xff, 0x6a, 0x53, 0x4c, 0xff, - 0x69, 0x4e, 0x44, 0xff, 0x69, 0x4e, 0x44, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x44, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x53, 0x41, 0x3c, 0xff, 0x6f, 0x6c, 0x6c, 0xff, 0x8f, 0x86, 0x7c, 0xff, - 0x78, 0x77, 0x74, 0xff, 0x78, 0x77, 0x74, 0xff, 0x9e, 0x8e, 0x94, 0xff, - 0x81, 0x7e, 0x7c, 0xff, 0x9d, 0x8d, 0x8c, 0xff, 0x84, 0x77, 0x74, 0xff, - 0xad, 0x9e, 0x9e, 0xff, 0x96, 0x86, 0x8c, 0xff, 0x94, 0x8c, 0x8c, 0xff, - 0xae, 0xa4, 0xa4, 0xff, 0x94, 0x8c, 0x8c, 0xff, 0xae, 0xa4, 0xa4, 0xff, - 0x9a, 0x94, 0x94, 0xff, 0xa1, 0x99, 0x9c, 0xff, 0xbc, 0xb1, 0xb4, 0xff, - 0xa4, 0x9e, 0xa4, 0xff, 0xa3, 0xa3, 0xa4, 0xff, 0xb4, 0xb2, 0xb4, 0xff, - 0xd5, 0xcd, 0xcc, 0xff, 0xc4, 0xc3, 0xc4, 0xff, 0xcc, 0xc5, 0xc4, 0xff, - 0xb4, 0xb2, 0xb4, 0xff, 0xa3, 0xa3, 0xa4, 0xff, 0xbc, 0xb0, 0xac, 0xff, - 0xc2, 0xbe, 0xbc, 0xff, 0xcf, 0xc6, 0xcc, 0xff, 0xc8, 0xca, 0xc4, 0xff, - 0xc4, 0xc3, 0xc4, 0xff, 0xcc, 0xc5, 0xc4, 0xff, 0xcc, 0xc5, 0xc4, 0xff, - 0xcc, 0xcc, 0xcc, 0xff, 0xd5, 0xcd, 0xcc, 0xff, 0xf4, 0xf2, 0xf4, 0xff, - 0xf4, 0xf2, 0xf4, 0xff, 0xd4, 0xc6, 0xc4, 0xff, 0xb3, 0xae, 0xac, 0xff, - 0xc4, 0xbe, 0xc4, 0xff, 0xc4, 0xc3, 0xc4, 0xff, 0x9e, 0x8e, 0x94, 0xff, - 0xa8, 0x9b, 0x94, 0xff, 0xc9, 0xc0, 0xb4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfb, 0xfe, 0xec, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xdc, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0x78, 0x77, 0x74, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xd7, 0xd6, 0xd4, 0xff, - 0xb4, 0xb2, 0xb4, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xa1, 0x9e, 0x9c, 0xff, - 0x88, 0x8a, 0x84, 0xff, 0xb4, 0xb2, 0xb4, 0xff, 0xa3, 0xa3, 0xa4, 0xff, - 0xa3, 0xa3, 0xa4, 0xff, 0xbc, 0xb9, 0xbc, 0xff, 0xb4, 0xb2, 0xb4, 0xff, - 0xbc, 0xb1, 0xb4, 0xff, 0xa4, 0x9e, 0xa4, 0xff, 0x58, 0x49, 0x4c, 0xff, - 0x58, 0x49, 0x4c, 0xff, 0x69, 0x55, 0x54, 0xff, 0x75, 0x56, 0x54, 0xff, - 0x58, 0x49, 0x4c, 0xff, 0x78, 0x66, 0x64, 0xff, 0xa1, 0x99, 0x9c, 0xff, - 0x75, 0x62, 0x64, 0xff, 0xa1, 0x9e, 0x9c, 0xff, 0x81, 0x72, 0x74, 0xff, - 0x6c, 0x66, 0x6c, 0xff, 0x83, 0x82, 0x84, 0xff, 0xae, 0xa4, 0xa4, 0xff, - 0xc6, 0xb1, 0xb4, 0xff, 0xcf, 0xc6, 0xcc, 0xff, 0x96, 0x86, 0x8c, 0xff, - 0x64, 0x4e, 0x54, 0xff, 0x75, 0x56, 0x54, 0xff, 0x69, 0x4e, 0x44, 0xff, - 0x74, 0x5b, 0x4c, 0xff, 0x74, 0x4e, 0x44, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x61, 0x48, 0x44, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x5c, 0x42, 0x44, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x72, 0x62, 0x5c, 0xff, 0x81, 0x7e, 0x7c, 0xff, - 0x84, 0x77, 0x74, 0xff, 0x81, 0x72, 0x74, 0xff, 0x96, 0x85, 0x84, 0xff, - 0x94, 0x8c, 0x8c, 0xff, 0xa6, 0x95, 0x94, 0xff, 0x94, 0x8c, 0x8c, 0xff, - 0x8e, 0x7a, 0x7c, 0xff, 0x9a, 0x94, 0x94, 0xff, 0x92, 0x92, 0x8c, 0xff, - 0xa4, 0x9e, 0xa4, 0xff, 0x9a, 0x94, 0x94, 0xff, 0x94, 0x8c, 0x8c, 0xff, - 0x9a, 0x94, 0x94, 0xff, 0x94, 0x8c, 0x8c, 0xff, 0xc6, 0xb1, 0xb4, 0xff, - 0xc4, 0xba, 0xbc, 0xff, 0x9a, 0x94, 0x94, 0xff, 0xb4, 0xb2, 0xb4, 0xff, - 0xc4, 0xc3, 0xc4, 0xff, 0xbc, 0xb9, 0xbc, 0xff, 0xc2, 0xc2, 0xbc, 0xff, - 0xcc, 0xc5, 0xc4, 0xff, 0xb3, 0xae, 0xac, 0xff, 0xa3, 0xa3, 0xa4, 0xff, - 0xbc, 0xb9, 0xbc, 0xff, 0xcc, 0xc5, 0xc4, 0xff, 0xc2, 0xbe, 0xbc, 0xff, - 0xc4, 0xc3, 0xc4, 0xff, 0xc2, 0xc2, 0xbc, 0xff, 0xcf, 0xc6, 0xcc, 0xff, - 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xc5, 0xc4, 0xff, 0xec, 0xe2, 0xe4, 0xff, - 0xc4, 0xc3, 0xc4, 0xff, 0xd6, 0xd2, 0xd4, 0xff, 0xba, 0xb6, 0xb4, 0xff, - 0xc4, 0xbe, 0xc4, 0xff, 0xcc, 0xbd, 0xbc, 0xff, 0xb4, 0xaa, 0xac, 0xff, - 0x94, 0x8c, 0x8c, 0xff, 0xae, 0xa4, 0xa4, 0xff, 0xf4, 0xea, 0xe4, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xdc, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xfa, 0xfe, 0xdc, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0x64, 0x6a, 0x6c, 0xff, 0x9a, 0x94, 0x94, 0xff, 0xcc, 0xcc, 0xcc, 0xff, - 0xc4, 0xc3, 0xc4, 0xff, 0xba, 0xb6, 0xb4, 0xff, 0x7b, 0x7a, 0x7c, 0xff, - 0x83, 0x82, 0x84, 0xff, 0xc2, 0xc2, 0xbc, 0xff, 0xa3, 0xa3, 0xa4, 0xff, - 0xa1, 0x9e, 0x9c, 0xff, 0xa3, 0xa3, 0xa4, 0xff, 0xb3, 0xae, 0xac, 0xff, - 0xb4, 0xaa, 0xac, 0xff, 0xbc, 0xaa, 0xac, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x64, 0x4e, 0x54, 0xff, 0x6b, 0x56, 0x5c, 0xff, 0x69, 0x55, 0x54, 0xff, - 0x69, 0x55, 0x54, 0xff, 0x6b, 0x56, 0x5c, 0xff, 0x84, 0x77, 0x74, 0xff, - 0x84, 0x77, 0x74, 0xff, 0x84, 0x79, 0x7c, 0xff, 0x71, 0x6a, 0x64, 0xff, - 0x6f, 0x6c, 0x6c, 0xff, 0xa6, 0x95, 0x94, 0xff, 0xb4, 0xb2, 0xb4, 0xff, - 0xc4, 0xba, 0xbc, 0xff, 0xdc, 0xba, 0xbc, 0xff, 0xc6, 0xb1, 0xb4, 0xff, - 0x6b, 0x56, 0x5c, 0xff, 0x75, 0x56, 0x54, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x72, 0x5b, 0x54, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x44, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x61, 0x48, 0x44, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x44, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x6a, 0x53, 0x4c, 0xff, 0x84, 0x77, 0x74, 0xff, - 0x84, 0x77, 0x74, 0xff, 0x81, 0x7e, 0x7c, 0xff, 0x8f, 0x7f, 0x7c, 0xff, - 0x9a, 0x94, 0x94, 0xff, 0x84, 0x79, 0x7c, 0xff, 0xa1, 0x99, 0x9c, 0xff, - 0x89, 0x86, 0x84, 0xff, 0x8c, 0x81, 0x84, 0xff, 0x84, 0x79, 0x7c, 0xff, - 0xa6, 0x95, 0x94, 0xff, 0xa1, 0x9e, 0x9c, 0xff, 0xa1, 0x99, 0x9c, 0xff, - 0xa6, 0x95, 0x94, 0xff, 0xa1, 0x99, 0x9c, 0xff, 0xac, 0xa9, 0xac, 0xff, - 0xcc, 0xc5, 0xc4, 0xff, 0xb4, 0xb2, 0xb4, 0xff, 0xbc, 0xb1, 0xb4, 0xff, - 0xac, 0xa9, 0xac, 0xff, 0xb3, 0xae, 0xac, 0xff, 0xb4, 0xb2, 0xb4, 0xff, - 0xac, 0xa9, 0xac, 0xff, 0xc2, 0xbe, 0xbc, 0xff, 0xcc, 0xc5, 0xc4, 0xff, - 0xba, 0xb6, 0xb4, 0xff, 0xc4, 0xc3, 0xc4, 0xff, 0xcc, 0xc5, 0xc4, 0xff, - 0xc4, 0xc3, 0xc4, 0xff, 0xbc, 0xb9, 0xbc, 0xff, 0xc2, 0xbe, 0xbc, 0xff, - 0xcc, 0xcc, 0xcc, 0xff, 0xcf, 0xc6, 0xcc, 0xff, 0xc2, 0xbe, 0xbc, 0xff, - 0xcc, 0xc5, 0xc4, 0xff, 0xbc, 0xb9, 0xbc, 0xff, 0xc2, 0xbe, 0xbc, 0xff, - 0xc4, 0xba, 0xbc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xc5, 0xb7, 0xb4, 0xff, - 0x94, 0x8c, 0x8c, 0xff, 0x9c, 0x93, 0x8c, 0xff, 0xd7, 0xcc, 0xc4, 0xff, - 0xfb, 0xf9, 0xec, 0xff, 0xfb, 0xf9, 0xec, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xdc, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xfa, 0xfe, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0x5d, 0x62, 0x5c, 0xff, 0x7b, 0x7a, 0x7c, 0xff, 0xdc, 0xdc, 0xdc, 0xff, - 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0x8b, 0x8b, 0x8c, 0xff, - 0x71, 0x72, 0x74, 0xff, 0xa3, 0xa3, 0xa4, 0xff, 0xa1, 0xa2, 0x9c, 0xff, - 0xb4, 0xb2, 0xb4, 0xff, 0xa1, 0x9e, 0x9c, 0xff, 0xa4, 0x9e, 0xa4, 0xff, - 0xae, 0xa4, 0xa4, 0xff, 0xa1, 0x99, 0x9c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x58, 0x49, 0x4c, 0xff, 0x55, 0x4e, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x64, 0x4e, 0x54, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x6c, 0x61, 0x64, 0xff, - 0x55, 0x4e, 0x4c, 0xff, 0x55, 0x4e, 0x4c, 0xff, 0x6f, 0x6c, 0x6c, 0xff, - 0x6f, 0x6c, 0x6c, 0xff, 0xa1, 0x99, 0x9c, 0xff, 0xc4, 0xba, 0xbc, 0xff, - 0xae, 0xa4, 0xa4, 0xff, 0xcc, 0xbe, 0xc4, 0xff, 0xc4, 0xba, 0xbc, 0xff, - 0x8e, 0x72, 0x74, 0xff, 0x69, 0x55, 0x54, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x74, 0x55, 0x4c, 0xff, 0x74, 0x55, 0x4c, 0xff, 0x6c, 0x4a, 0x44, 0xff, - 0x6c, 0x4a, 0x44, 0xff, 0x5c, 0x42, 0x44, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x44, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x61, 0x48, 0x44, 0xff, 0x61, 0x48, 0x44, 0xff, 0x78, 0x77, 0x74, 0xff, - 0x84, 0x77, 0x74, 0xff, 0x81, 0x72, 0x74, 0xff, 0x84, 0x79, 0x7c, 0xff, - 0xa8, 0x9b, 0x94, 0xff, 0x89, 0x86, 0x84, 0xff, 0x94, 0x8c, 0x8c, 0xff, - 0x9d, 0x8d, 0x8c, 0xff, 0xa6, 0x95, 0x94, 0xff, 0x81, 0x72, 0x74, 0xff, - 0x9d, 0x8d, 0x8c, 0xff, 0xae, 0xa4, 0xa4, 0xff, 0xae, 0xa4, 0xa4, 0xff, - 0xa1, 0x99, 0x9c, 0xff, 0xa1, 0x99, 0x9c, 0xff, 0x92, 0x92, 0x8c, 0xff, - 0xbc, 0xb9, 0xbc, 0xff, 0xba, 0xb6, 0xb4, 0xff, 0xba, 0xb6, 0xb4, 0xff, - 0xc2, 0xbe, 0xbc, 0xff, 0xcc, 0xc5, 0xc4, 0xff, 0xbc, 0xb9, 0xbc, 0xff, - 0xba, 0xb6, 0xb4, 0xff, 0xba, 0xb6, 0xb4, 0xff, 0xec, 0xea, 0xec, 0xff, - 0xbc, 0xb9, 0xbc, 0xff, 0xc4, 0xc3, 0xc4, 0xff, 0xc4, 0xc3, 0xc4, 0xff, - 0xc4, 0xc3, 0xc4, 0xff, 0xc2, 0xbe, 0xbc, 0xff, 0xb4, 0xb2, 0xb4, 0xff, - 0xba, 0xb6, 0xb4, 0xff, 0xbc, 0xb9, 0xbc, 0xff, 0xa3, 0xa3, 0xa4, 0xff, - 0xcc, 0xcc, 0xcc, 0xff, 0xc4, 0xc3, 0xc4, 0xff, 0xbc, 0xb9, 0xbc, 0xff, - 0xbc, 0xb1, 0xb4, 0xff, 0xba, 0xb6, 0xb4, 0xff, 0xcf, 0xc6, 0xcc, 0xff, - 0xad, 0x9e, 0x9e, 0xff, 0x89, 0x86, 0x84, 0xff, 0xa8, 0x9b, 0x94, 0xff, - 0xf2, 0xe9, 0xdc, 0xff, 0xfc, 0xf2, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xdc, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xfa, 0xfe, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x71, 0x72, 0x6c, 0xff, 0xbc, 0xb9, 0xbc, 0xff, - 0xbc, 0xb9, 0xbc, 0xff, 0x92, 0x92, 0x8c, 0xff, 0x71, 0x72, 0x74, 0xff, - 0x83, 0x82, 0x84, 0xff, 0x92, 0x92, 0x8c, 0xff, 0x83, 0x82, 0x84, 0xff, - 0xb4, 0xb2, 0xb4, 0xff, 0xb4, 0xb2, 0xb4, 0xff, 0x83, 0x82, 0x84, 0xff, - 0xa1, 0xa2, 0x9c, 0xff, 0x8b, 0x8b, 0x8c, 0xff, 0xa6, 0x95, 0x94, 0xff, - 0x6f, 0x6c, 0x6c, 0xff, 0x75, 0x62, 0x64, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x69, 0x55, 0x54, 0xff, 0x55, 0x4e, 0x4c, 0xff, 0x64, 0x5d, 0x5c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x55, 0x4e, 0x4c, 0xff, 0x6c, 0x61, 0x64, 0xff, - 0x6f, 0x6c, 0x6c, 0xff, 0x8b, 0x8b, 0x8c, 0xff, 0xae, 0xa4, 0xa4, 0xff, - 0xa4, 0x9e, 0xa4, 0xff, 0xc4, 0xc3, 0xc4, 0xff, 0xae, 0xa4, 0xa4, 0xff, - 0x81, 0x72, 0x74, 0xff, 0x75, 0x62, 0x64, 0xff, 0x69, 0x55, 0x54, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x69, 0x55, 0x54, 0xff, 0x74, 0x55, 0x4c, 0xff, - 0x69, 0x4e, 0x4c, 0xff, 0x6c, 0x4a, 0x44, 0xff, 0x5c, 0x3e, 0x34, 0xff, - 0x5c, 0x42, 0x44, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x44, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x54, 0x46, 0x3c, 0xff, 0x8f, 0x7f, 0x7c, 0xff, - 0x84, 0x77, 0x74, 0xff, 0x7e, 0x6d, 0x6c, 0xff, 0x7e, 0x6d, 0x6c, 0xff, - 0x9d, 0x8d, 0x8c, 0xff, 0x9a, 0x94, 0x94, 0xff, 0x89, 0x86, 0x84, 0xff, - 0xa1, 0x9e, 0x9c, 0xff, 0x9a, 0x94, 0x94, 0xff, 0x9d, 0x8d, 0x8c, 0xff, - 0x81, 0x72, 0x74, 0xff, 0x94, 0x8e, 0x94, 0xff, 0xbc, 0xb1, 0xb4, 0xff, - 0xbc, 0xb0, 0xac, 0xff, 0xad, 0x9a, 0x9c, 0xff, 0x94, 0x8c, 0x8c, 0xff, - 0x94, 0x8e, 0x94, 0xff, 0xb4, 0xb2, 0xb4, 0xff, 0xc4, 0xc3, 0xc4, 0xff, - 0xc4, 0xc3, 0xc4, 0xff, 0xbc, 0xb9, 0xbc, 0xff, 0xc8, 0xca, 0xc4, 0xff, - 0xc4, 0xc3, 0xc4, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, - 0xba, 0xb6, 0xb4, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xc5, 0xc4, 0xff, - 0xc4, 0xc3, 0xc4, 0xff, 0xc4, 0xc3, 0xc4, 0xff, 0xc2, 0xbe, 0xbc, 0xff, - 0xbc, 0xb9, 0xbc, 0xff, 0xb4, 0xb2, 0xb4, 0xff, 0xbc, 0xb9, 0xbc, 0xff, - 0xf4, 0xea, 0xe4, 0xff, 0xdc, 0xdc, 0xdc, 0xff, 0xc2, 0xbe, 0xbc, 0xff, - 0xc4, 0xba, 0xbc, 0xff, 0xbc, 0xb9, 0xbc, 0xff, 0xd5, 0xcd, 0xcc, 0xff, - 0xd4, 0xc6, 0xc4, 0xff, 0x94, 0x8c, 0x8c, 0xff, 0x90, 0x7f, 0x74, 0xff, - 0xbc, 0xb0, 0xac, 0xff, 0xfb, 0xf9, 0xec, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xfa, 0xfe, 0xdc, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0x53, 0x5a, 0x54, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x81, 0x7e, 0x7c, 0xff, - 0xac, 0xa9, 0xac, 0xff, 0xa3, 0xa3, 0xa4, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x88, 0x8a, 0x84, 0xff, 0x71, 0x72, 0x74, 0xff, 0x64, 0x6a, 0x6c, 0xff, - 0x8b, 0x8b, 0x8c, 0xff, 0x8b, 0x8b, 0x8c, 0xff, 0x81, 0x7e, 0x7c, 0xff, - 0x83, 0x82, 0x84, 0xff, 0x89, 0x86, 0x84, 0xff, 0xb4, 0xb2, 0xb4, 0xff, - 0xb4, 0xb2, 0xb4, 0xff, 0x6f, 0x6c, 0x6c, 0xff, 0x64, 0x5d, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x6c, 0x61, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x64, 0x5d, 0x5c, 0xff, 0x55, 0x55, 0x54, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x71, 0x72, 0x74, 0xff, 0x78, 0x77, 0x74, 0xff, 0xbc, 0xb9, 0xbc, 0xff, - 0xa1, 0x99, 0x9c, 0xff, 0xc5, 0xb7, 0xb4, 0xff, 0x96, 0x86, 0x8c, 0xff, - 0xb4, 0xb2, 0xb4, 0xff, 0x96, 0x85, 0x84, 0xff, 0x78, 0x66, 0x64, 0xff, - 0x69, 0x4e, 0x4c, 0xff, 0x6a, 0x53, 0x4c, 0xff, 0x69, 0x55, 0x54, 0xff, - 0x69, 0x4e, 0x4c, 0xff, 0x6c, 0x4a, 0x44, 0xff, 0x5c, 0x42, 0x44, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x4e, 0x42, 0x44, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x60, 0x46, 0x3c, 0xff, 0x5c, 0x42, 0x44, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x61, 0x48, 0x44, 0xff, 0x7f, 0x72, 0x6c, 0xff, - 0x8f, 0x7f, 0x7c, 0xff, 0x84, 0x79, 0x7c, 0xff, 0x6c, 0x61, 0x64, 0xff, - 0x84, 0x79, 0x7c, 0xff, 0xad, 0x9e, 0x9e, 0xff, 0x8c, 0x81, 0x84, 0xff, - 0x9a, 0x94, 0x94, 0xff, 0xa6, 0x95, 0x94, 0xff, 0xa4, 0x9e, 0xa4, 0xff, - 0x9e, 0x8e, 0x94, 0xff, 0x81, 0x72, 0x74, 0xff, 0x9d, 0x8d, 0x8c, 0xff, - 0xb4, 0xb2, 0xb4, 0xff, 0xb4, 0xb2, 0xb4, 0xff, 0xa1, 0x99, 0x9c, 0xff, - 0x89, 0x86, 0x84, 0xff, 0xb1, 0xaa, 0xa4, 0xff, 0xbc, 0xb9, 0xbc, 0xff, - 0xc4, 0xc3, 0xc4, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xc2, 0xbe, 0xbc, 0xff, - 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xc5, 0xc4, 0xff, 0xe4, 0xe1, 0xe4, 0xff, - 0xcc, 0xcc, 0xcc, 0xff, 0xbc, 0xb9, 0xbc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, - 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xc5, 0xc4, 0xff, 0xc4, 0xc3, 0xc4, 0xff, - 0xc4, 0xc3, 0xc4, 0xff, 0xc2, 0xc2, 0xbc, 0xff, 0xbc, 0xb9, 0xbc, 0xff, - 0xc2, 0xbe, 0xbc, 0xff, 0xc4, 0xc3, 0xc4, 0xff, 0xcf, 0xc6, 0xcc, 0xff, - 0xcc, 0xc5, 0xc4, 0xff, 0xae, 0xa4, 0xa4, 0xff, 0xd6, 0xd2, 0xd4, 0xff, - 0xcc, 0xc5, 0xc4, 0xff, 0xb0, 0xa3, 0x9c, 0xff, 0x81, 0x7e, 0x7c, 0xff, - 0x94, 0x8b, 0x84, 0xff, 0xe4, 0xe2, 0xd8, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xfc, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf7, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf4, 0xf0, 0xd4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x63, 0x6a, 0x64, 0xff, 0x64, 0x6a, 0x6c, 0xff, - 0xac, 0xa9, 0xac, 0xff, 0x88, 0x8a, 0x84, 0xff, 0x53, 0x5a, 0x54, 0xff, - 0x83, 0x82, 0x84, 0xff, 0x64, 0x6a, 0x6c, 0xff, 0x63, 0x6a, 0x64, 0xff, - 0x71, 0x72, 0x74, 0xff, 0x64, 0x6a, 0x6c, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x5f, 0x62, 0x64, 0xff, 0xa1, 0x9e, 0x9c, 0xff, - 0x8b, 0x8b, 0x8c, 0xff, 0x6f, 0x6c, 0x6c, 0xff, 0x6f, 0x6c, 0x6c, 0xff, - 0x64, 0x5d, 0x5c, 0xff, 0x64, 0x5d, 0x5c, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x89, 0x86, 0x84, 0xff, 0x55, 0x4e, 0x4c, 0xff, 0x6f, 0x6c, 0x6c, 0xff, - 0x71, 0x72, 0x74, 0xff, 0x6f, 0x6c, 0x6c, 0xff, 0xa1, 0x9e, 0x9c, 0xff, - 0x8b, 0x8b, 0x8c, 0xff, 0x9c, 0x9a, 0x94, 0xff, 0x6f, 0x6c, 0x6c, 0xff, - 0x6c, 0x61, 0x64, 0xff, 0x8c, 0x81, 0x84, 0xff, 0x81, 0x7e, 0x7c, 0xff, - 0x71, 0x6a, 0x64, 0xff, 0x69, 0x55, 0x54, 0xff, 0x69, 0x55, 0x54, 0xff, - 0x6a, 0x53, 0x4c, 0xff, 0x75, 0x56, 0x54, 0xff, 0x6c, 0x4a, 0x44, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x4e, 0x42, 0x44, 0xff, 0x60, 0x46, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, - 0x61, 0x48, 0x44, 0xff, 0x61, 0x48, 0x44, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x90, 0x7f, 0x74, 0xff, 0x84, 0x79, 0x7c, 0xff, 0x6f, 0x6c, 0x6c, 0xff, - 0x84, 0x77, 0x74, 0xff, 0x96, 0x85, 0x84, 0xff, 0x8c, 0x81, 0x84, 0xff, - 0x96, 0x85, 0x84, 0xff, 0xa1, 0x99, 0x9c, 0xff, 0x94, 0x8c, 0x8c, 0xff, - 0xa1, 0x9e, 0x9c, 0xff, 0xa4, 0x9e, 0xa4, 0xff, 0x8c, 0x81, 0x84, 0xff, - 0x9a, 0x94, 0x94, 0xff, 0xbc, 0xb1, 0xb4, 0xff, 0xa6, 0x95, 0x94, 0xff, - 0x94, 0x8c, 0x8c, 0xff, 0xa3, 0xa3, 0xa4, 0xff, 0xc2, 0xbe, 0xbc, 0xff, - 0xcc, 0xc5, 0xc4, 0xff, 0xd7, 0xd6, 0xd4, 0xff, 0xcc, 0xcc, 0xcc, 0xff, - 0xcf, 0xc6, 0xcc, 0xff, 0xd7, 0xd6, 0xd4, 0xff, 0xc8, 0xca, 0xc4, 0xff, - 0xe4, 0xe1, 0xe4, 0xff, 0xbc, 0xb9, 0xbc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, - 0xcc, 0xc5, 0xc4, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, - 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xc5, 0xc4, 0xff, 0xc4, 0xc3, 0xc4, 0xff, - 0xcc, 0xcc, 0xcc, 0xff, 0xcf, 0xc6, 0xcc, 0xff, 0xac, 0xa9, 0xac, 0xff, - 0xba, 0xb6, 0xb4, 0xff, 0xb4, 0xaa, 0xac, 0xff, 0xc4, 0xba, 0xbc, 0xff, - 0xd5, 0xcd, 0xcc, 0xff, 0xc4, 0xc3, 0xc4, 0xff, 0x8f, 0x7f, 0x7c, 0xff, - 0x94, 0x8b, 0x84, 0xff, 0xb4, 0xae, 0x9c, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x63, 0x6a, 0x64, 0xff, - 0x64, 0x6a, 0x6c, 0xff, 0x63, 0x6a, 0x64, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x63, 0x6a, 0x64, 0xff, 0x63, 0x6a, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x5d, 0x62, 0x5c, 0xff, 0x5d, 0x62, 0x5c, 0xff, 0x53, 0x5a, 0x54, 0xff, - 0x64, 0x6a, 0x6c, 0xff, 0x63, 0x66, 0x64, 0xff, 0x8b, 0x8b, 0x8c, 0xff, - 0x71, 0x72, 0x74, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x5d, 0x62, 0x5c, 0xff, 0x55, 0x55, 0x54, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x81, 0x7e, 0x7c, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x6f, 0x6c, 0x6c, 0xff, - 0x71, 0x72, 0x74, 0xff, 0x71, 0x6a, 0x64, 0xff, 0x64, 0x6a, 0x6c, 0xff, - 0x9a, 0x94, 0x94, 0xff, 0x7b, 0x7a, 0x7c, 0xff, 0x78, 0x77, 0x74, 0xff, - 0x78, 0x77, 0x74, 0xff, 0x7b, 0x7a, 0x7c, 0xff, 0x96, 0x86, 0x8c, 0xff, - 0x83, 0x82, 0x84, 0xff, 0x75, 0x62, 0x64, 0xff, 0x69, 0x55, 0x54, 0xff, - 0x69, 0x55, 0x54, 0xff, 0x69, 0x55, 0x54, 0xff, 0x69, 0x4e, 0x4c, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x61, 0x48, 0x44, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x44, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x7e, 0x6d, 0x6c, 0xff, 0x81, 0x7e, 0x7c, 0xff, 0x7e, 0x6d, 0x6c, 0xff, - 0x84, 0x79, 0x7c, 0xff, 0x96, 0x85, 0x84, 0xff, 0x7e, 0x6d, 0x6c, 0xff, - 0x81, 0x72, 0x74, 0xff, 0x8c, 0x81, 0x84, 0xff, 0x94, 0x8c, 0x8c, 0xff, - 0x9a, 0x94, 0x94, 0xff, 0xad, 0x9e, 0x9e, 0xff, 0xae, 0xa4, 0xa4, 0xff, - 0x84, 0x79, 0x7c, 0xff, 0x96, 0x85, 0x84, 0xff, 0x9e, 0x8e, 0x94, 0xff, - 0x8c, 0x81, 0x84, 0xff, 0x9a, 0x94, 0x94, 0xff, 0xa3, 0xa3, 0xa4, 0xff, - 0xba, 0xb6, 0xb4, 0xff, 0xcc, 0xc5, 0xc4, 0xff, 0xcc, 0xcc, 0xcc, 0xff, - 0xcc, 0xcc, 0xcc, 0xff, 0xd6, 0xd2, 0xd4, 0xff, 0xd7, 0xd6, 0xd4, 0xff, - 0xd6, 0xd2, 0xd4, 0xff, 0xdc, 0xdc, 0xdc, 0xff, 0xd9, 0xd4, 0xcc, 0xff, - 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, - 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xc5, 0xc4, 0xff, - 0xc8, 0xca, 0xc4, 0xff, 0xc4, 0xc3, 0xc4, 0xff, 0xc2, 0xbe, 0xbc, 0xff, - 0xbc, 0xb1, 0xb4, 0xff, 0xba, 0xb6, 0xb4, 0xff, 0xbc, 0xb1, 0xb4, 0xff, - 0xd6, 0xd2, 0xd4, 0xff, 0xd9, 0xd4, 0xcc, 0xff, 0x9c, 0x93, 0x8c, 0xff, - 0x88, 0x8a, 0x84, 0xff, 0x8f, 0x86, 0x7c, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xfb, 0xfe, 0xec, 0xff, 0xfb, 0xfe, 0xec, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xfc, 0xf9, 0xe4, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xfc, 0xf9, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xfc, 0xf9, 0xe4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf0, 0xd4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x64, 0x6a, 0x6c, 0xff, - 0x88, 0x8a, 0x84, 0xff, 0x64, 0x6a, 0x6c, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x6f, 0x6c, 0x6c, 0xff, 0x71, 0x72, 0x74, 0xff, 0x53, 0x5a, 0x54, 0xff, - 0x63, 0x66, 0x64, 0xff, 0x6f, 0x6c, 0x6c, 0xff, 0x5d, 0x62, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x55, 0x55, 0x54, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x6f, 0x6c, 0x6c, 0xff, 0x71, 0x6a, 0x64, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x6c, 0x66, 0x6c, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x64, 0x6a, 0x6c, 0xff, 0x83, 0x82, 0x84, 0xff, - 0x7b, 0x7a, 0x7c, 0xff, 0x71, 0x72, 0x6c, 0xff, 0x78, 0x77, 0x74, 0xff, - 0x6f, 0x6c, 0x6c, 0xff, 0x6f, 0x6c, 0x6c, 0xff, 0x6c, 0x61, 0x64, 0xff, - 0x55, 0x4e, 0x4c, 0xff, 0x69, 0x4e, 0x4c, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x5c, 0x42, 0x44, 0xff, 0x61, 0x48, 0x44, 0xff, 0x55, 0x4e, 0x4c, 0xff, - 0x69, 0x4e, 0x4c, 0xff, 0x5c, 0x42, 0x3c, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x4e, 0x42, 0x44, 0xff, 0x60, 0x46, 0x3c, 0xff, - 0x75, 0x62, 0x64, 0xff, 0x96, 0x85, 0x84, 0xff, 0x81, 0x7e, 0x7c, 0xff, - 0x7e, 0x6d, 0x6c, 0xff, 0x94, 0x8b, 0x84, 0xff, 0x96, 0x86, 0x8c, 0xff, - 0x63, 0x66, 0x64, 0xff, 0x8f, 0x7f, 0x7c, 0xff, 0x9d, 0x8d, 0x8c, 0xff, - 0x89, 0x86, 0x84, 0xff, 0x9e, 0x8e, 0x94, 0xff, 0x9c, 0x9a, 0x94, 0xff, - 0xb4, 0xaa, 0xac, 0xff, 0x94, 0x8c, 0x8c, 0xff, 0xa6, 0x95, 0x94, 0xff, - 0x94, 0x8c, 0x8c, 0xff, 0x8b, 0x8b, 0x8c, 0xff, 0xa4, 0x9e, 0xa4, 0xff, - 0xb3, 0xae, 0xac, 0xff, 0xc4, 0xc3, 0xc4, 0xff, 0xcc, 0xcc, 0xcc, 0xff, - 0xc2, 0xc2, 0xbc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xd7, 0xd6, 0xd4, 0xff, - 0xcf, 0xc6, 0xcc, 0xff, 0xdc, 0xdc, 0xdc, 0xff, 0xc4, 0xc3, 0xc4, 0xff, - 0xd6, 0xd2, 0xd4, 0xff, 0xc8, 0xca, 0xc4, 0xff, 0xcc, 0xc5, 0xc4, 0xff, - 0xcc, 0xc5, 0xc4, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcf, 0xc6, 0xcc, 0xff, - 0xcc, 0xcc, 0xcc, 0xff, 0xcf, 0xc6, 0xcc, 0xff, 0xc2, 0xbe, 0xbc, 0xff, - 0xb3, 0xae, 0xac, 0xff, 0xae, 0xa4, 0xa4, 0xff, 0xbc, 0xb1, 0xb4, 0xff, - 0xd4, 0xc6, 0xc4, 0xff, 0xd6, 0xd2, 0xd4, 0xff, 0xc6, 0xb1, 0xb4, 0xff, - 0x94, 0x8c, 0x8c, 0xff, 0x9c, 0x9a, 0x94, 0xff, 0xfb, 0xf9, 0xec, 0xff, - 0xfb, 0xf9, 0xec, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x64, 0x6a, 0x6c, 0xff, - 0x71, 0x72, 0x74, 0xff, 0x71, 0x72, 0x74, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x64, 0x6a, 0x6c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x63, 0x66, 0x64, 0xff, 0x8b, 0x8b, 0x8c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x6c, 0x66, 0x6c, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x63, 0x66, 0x64, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x63, 0x66, 0x64, 0xff, 0x55, 0x55, 0x54, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x63, 0x66, 0x64, 0xff, 0x64, 0x6a, 0x6c, 0xff, 0x71, 0x72, 0x74, 0xff, - 0x64, 0x6a, 0x6c, 0xff, 0x64, 0x6a, 0x6c, 0xff, 0x8c, 0x81, 0x84, 0xff, - 0x6c, 0x61, 0x64, 0xff, 0x69, 0x55, 0x54, 0xff, 0x69, 0x55, 0x54, 0xff, - 0x69, 0x55, 0x54, 0xff, 0x55, 0x4e, 0x4c, 0xff, 0x72, 0x5b, 0x54, 0xff, - 0x5d, 0x5a, 0x54, 0xff, 0x61, 0x48, 0x44, 0xff, 0x5c, 0x42, 0x44, 0xff, - 0x5c, 0x42, 0x3c, 0xff, 0x53, 0x41, 0x3c, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x58, 0x49, 0x4c, 0xff, 0x6f, 0x6c, 0x6c, 0xff, 0x96, 0x85, 0x84, 0xff, - 0x8e, 0x7a, 0x7c, 0xff, 0x8c, 0x81, 0x84, 0xff, 0xb1, 0xaa, 0xa4, 0xff, - 0xae, 0xa4, 0xa4, 0xff, 0x8c, 0x81, 0x84, 0xff, 0x70, 0x5e, 0x5c, 0xff, - 0x71, 0x72, 0x74, 0xff, 0x8f, 0x7f, 0x7c, 0xff, 0x9a, 0x94, 0x94, 0xff, - 0xa6, 0x95, 0x94, 0xff, 0xa6, 0x95, 0x94, 0xff, 0xae, 0xa4, 0xa4, 0xff, - 0xb4, 0xaa, 0xac, 0xff, 0x94, 0x8e, 0x94, 0xff, 0xa1, 0x9e, 0x9c, 0xff, - 0xba, 0xb6, 0xb4, 0xff, 0xba, 0xb6, 0xb4, 0xff, 0xcc, 0xcc, 0xcc, 0xff, - 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xc5, 0xc4, 0xff, 0xcc, 0xcc, 0xcc, 0xff, - 0xcc, 0xc5, 0xc4, 0xff, 0xdc, 0xdc, 0xdc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, - 0xd6, 0xd2, 0xd4, 0xff, 0xc4, 0xc3, 0xc4, 0xff, 0xcc, 0xcc, 0xcc, 0xff, - 0xd7, 0xd6, 0xd4, 0xff, 0xdc, 0xdc, 0xdc, 0xff, 0xdc, 0xdc, 0xdc, 0xff, - 0xcc, 0xc5, 0xc4, 0xff, 0xcc, 0xc5, 0xc4, 0xff, 0xc4, 0xc3, 0xc4, 0xff, - 0xcc, 0xcc, 0xcc, 0xff, 0xa1, 0x99, 0x9c, 0xff, 0xb4, 0xaa, 0xac, 0xff, - 0xcc, 0xbe, 0xc4, 0xff, 0xcf, 0xc6, 0xcc, 0xff, 0xd7, 0xd6, 0xd4, 0xff, - 0xa1, 0x9e, 0x9c, 0xff, 0x92, 0x92, 0x8c, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xfb, 0xfe, 0xec, 0xff, 0xfb, 0xfe, 0xec, 0xff, 0xfb, 0xfe, 0xec, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xfa, 0xfe, 0xdc, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x63, 0x6a, 0x64, 0xff, 0x63, 0x6a, 0x64, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x5d, 0x62, 0x5c, 0xff, 0x63, 0x6a, 0x64, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x83, 0x82, 0x84, 0xff, 0x81, 0x7e, 0x7c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x63, 0x66, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x64, 0x6a, 0x6c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x63, 0x66, 0x64, 0xff, 0x64, 0x6a, 0x6c, 0xff, 0x6f, 0x6c, 0x6c, 0xff, - 0x6f, 0x6c, 0x6c, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x71, 0x72, 0x6c, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x94, 0x8c, 0x8c, 0xff, - 0x81, 0x7e, 0x7c, 0xff, 0x64, 0x5d, 0x5c, 0xff, 0x64, 0x5d, 0x5c, 0xff, - 0x5d, 0x5a, 0x54, 0xff, 0x5d, 0x5a, 0x54, 0xff, 0x72, 0x62, 0x5c, 0xff, - 0x70, 0x5e, 0x5c, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x53, 0x41, 0x3c, 0xff, 0x61, 0x48, 0x44, 0xff, 0x61, 0x48, 0x44, 0xff, - 0x69, 0x55, 0x54, 0xff, 0x6f, 0x6c, 0x6c, 0xff, 0x8e, 0x7a, 0x7c, 0xff, - 0x78, 0x77, 0x74, 0xff, 0x9d, 0x8d, 0x8c, 0xff, 0xae, 0xa4, 0xa4, 0xff, - 0xbc, 0xb1, 0xb4, 0xff, 0xcc, 0xc5, 0xc4, 0xff, 0x94, 0x8c, 0x8c, 0xff, - 0x75, 0x62, 0x64, 0xff, 0x64, 0x5d, 0x5c, 0xff, 0x8c, 0x81, 0x84, 0xff, - 0x9a, 0x94, 0x94, 0xff, 0x94, 0x8c, 0x8c, 0xff, 0x9a, 0x94, 0x94, 0xff, - 0xba, 0xb6, 0xb4, 0xff, 0xba, 0xb6, 0xb4, 0xff, 0xa1, 0x99, 0x9c, 0xff, - 0xbc, 0xb9, 0xbc, 0xff, 0xba, 0xb6, 0xb4, 0xff, 0xc4, 0xc3, 0xc4, 0xff, - 0xd6, 0xd2, 0xd4, 0xff, 0xc4, 0xc3, 0xc4, 0xff, 0xd6, 0xd2, 0xd4, 0xff, - 0xd7, 0xd6, 0xd4, 0xff, 0xd7, 0xd6, 0xd4, 0xff, 0xd6, 0xd2, 0xd4, 0xff, - 0xd6, 0xd2, 0xd4, 0xff, 0xcc, 0xc5, 0xc4, 0xff, 0xcc, 0xc5, 0xc4, 0xff, - 0xcf, 0xc6, 0xcc, 0xff, 0xa3, 0xa3, 0xa4, 0xff, 0xba, 0xb6, 0xb4, 0xff, - 0xc2, 0xbe, 0xbc, 0xff, 0xc4, 0xc3, 0xc4, 0xff, 0xcf, 0xc6, 0xcc, 0xff, - 0xc2, 0xbe, 0xbc, 0xff, 0xcf, 0xc6, 0xcc, 0xff, 0xa1, 0x99, 0x9c, 0xff, - 0xbc, 0xb1, 0xb4, 0xff, 0xcf, 0xc6, 0xcc, 0xff, 0xcc, 0xbd, 0xbc, 0xff, - 0xc4, 0xc3, 0xc4, 0xff, 0x9c, 0x93, 0x8c, 0xff, 0xf2, 0xe9, 0xdc, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x5d, 0x62, 0x5c, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x63, 0x6a, 0x64, 0xff, 0x94, 0x8e, 0x94, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x53, 0x5a, 0x54, 0xff, - 0x53, 0x5a, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x5d, 0x62, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x63, 0x66, 0x64, 0xff, 0x63, 0x66, 0x64, 0xff, 0x6f, 0x6c, 0x6c, 0xff, - 0x64, 0x6a, 0x6c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x78, 0x77, 0x74, 0xff, - 0x88, 0x8a, 0x84, 0xff, 0x6f, 0x6c, 0x6c, 0xff, 0x64, 0x5d, 0x5c, 0xff, - 0x64, 0x5d, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x5d, 0x62, 0x5c, 0xff, - 0x64, 0x5d, 0x5c, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x4e, 0x42, 0x44, 0xff, - 0x61, 0x48, 0x44, 0xff, 0x58, 0x49, 0x4c, 0xff, 0x69, 0x55, 0x54, 0xff, - 0x58, 0x49, 0x4c, 0xff, 0x6c, 0x61, 0x64, 0xff, 0x8f, 0x7f, 0x7c, 0xff, - 0x8c, 0x81, 0x84, 0xff, 0x89, 0x86, 0x84, 0xff, 0xa3, 0xa3, 0xa4, 0xff, - 0xba, 0xb6, 0xb4, 0xff, 0xcc, 0xc5, 0xc4, 0xff, 0xd4, 0xc6, 0xc4, 0xff, - 0x8c, 0x81, 0x84, 0xff, 0x69, 0x55, 0x54, 0xff, 0x75, 0x62, 0x64, 0xff, - 0x94, 0x8c, 0x8c, 0xff, 0x89, 0x86, 0x84, 0xff, 0xa6, 0x95, 0x94, 0xff, - 0xae, 0xa4, 0xa4, 0xff, 0xa1, 0x9e, 0x9c, 0xff, 0xa3, 0xa3, 0xa4, 0xff, - 0xb1, 0xaa, 0xa4, 0xff, 0xc4, 0xbe, 0xc4, 0xff, 0xba, 0xb6, 0xb4, 0xff, - 0xbc, 0xb9, 0xbc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, - 0xc2, 0xbe, 0xbc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xc5, 0xc4, 0xff, - 0xcc, 0xc5, 0xc4, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, - 0x8b, 0x8b, 0x8c, 0xff, 0x7b, 0x7a, 0x7c, 0xff, 0x8b, 0x8b, 0x8c, 0xff, - 0xa3, 0xa3, 0xa4, 0xff, 0xc4, 0xc3, 0xc4, 0xff, 0xc4, 0xbe, 0xc4, 0xff, - 0xc2, 0xbe, 0xbc, 0xff, 0xd6, 0xd2, 0xd4, 0xff, 0xb4, 0xaa, 0xac, 0xff, - 0x9a, 0x94, 0x94, 0xff, 0xc5, 0xb7, 0xb4, 0xff, 0xd6, 0xd2, 0xd4, 0xff, - 0xd7, 0xd6, 0xd4, 0xff, 0x9c, 0x9a, 0x94, 0xff, 0xe2, 0xdc, 0xcc, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xfb, 0xfe, 0xec, 0xff, 0xfb, 0xfe, 0xec, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf2, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x63, 0x66, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x5d, 0x62, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x81, 0x7e, 0x7c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x5d, 0x62, 0x5c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x5d, 0x62, 0x5c, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x63, 0x66, 0x64, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x55, 0x55, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x5d, 0x5a, 0x54, 0xff, 0x5d, 0x62, 0x5c, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x6f, 0x6c, 0x6c, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x64, 0x5d, 0x5c, 0xff, 0x69, 0x55, 0x54, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x4e, 0x42, 0x44, 0xff, 0x69, 0x4e, 0x4c, 0xff, 0x70, 0x5e, 0x5c, 0xff, - 0x64, 0x5d, 0x5c, 0xff, 0x6c, 0x61, 0x64, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x8c, 0x81, 0x84, 0xff, 0x81, 0x7e, 0x7c, 0xff, 0x8b, 0x8b, 0x8c, 0xff, - 0xbc, 0xb0, 0xac, 0xff, 0xc4, 0xc3, 0xc4, 0xff, 0xcc, 0xcc, 0xcc, 0xff, - 0xd5, 0xcd, 0xcc, 0xff, 0x96, 0x86, 0x8c, 0xff, 0x55, 0x4e, 0x4c, 0xff, - 0x81, 0x72, 0x74, 0xff, 0x9c, 0x9a, 0x94, 0xff, 0xa1, 0x99, 0x9c, 0xff, - 0x94, 0x8e, 0x94, 0xff, 0x81, 0x7e, 0x7c, 0xff, 0xcc, 0xc5, 0xc4, 0xff, - 0xb3, 0xae, 0xac, 0xff, 0xc2, 0xbe, 0xbc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, - 0xc2, 0xbe, 0xbc, 0xff, 0xc4, 0xc3, 0xc4, 0xff, 0xc2, 0xbe, 0xbc, 0xff, - 0xcc, 0xcc, 0xcc, 0xff, 0xcf, 0xc6, 0xcc, 0xff, 0xba, 0xb6, 0xb4, 0xff, - 0xc2, 0xbe, 0xbc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, - 0xd7, 0xd6, 0xd4, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, - 0xb4, 0xb2, 0xb4, 0xff, 0xc2, 0xbe, 0xbc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, - 0xc5, 0xb7, 0xb4, 0xff, 0xc4, 0xba, 0xbc, 0xff, 0xd6, 0xd2, 0xd4, 0xff, - 0x9e, 0x8e, 0x94, 0xff, 0xbc, 0xb9, 0xbc, 0xff, 0xd5, 0xcd, 0xcc, 0xff, - 0xdc, 0xdc, 0xdc, 0xff, 0xd9, 0xd4, 0xcc, 0xff, 0xe4, 0xe2, 0xd8, 0xff, - 0xfb, 0xfe, 0xec, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xfa, 0xfe, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf2, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x53, 0x5a, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x64, 0x6a, 0x6c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x5d, 0x62, 0x5c, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x53, 0x5a, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x63, 0x66, 0x64, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x63, 0x66, 0x64, 0xff, 0x55, 0x55, 0x54, 0xff, 0x5d, 0x5a, 0x54, 0xff, - 0x5d, 0x5a, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x6c, 0x61, 0x64, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x6f, 0x6c, 0x6c, 0xff, - 0x53, 0x5a, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x55, 0x55, 0x54, 0xff, 0x58, 0x49, 0x4c, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x6b, 0x56, 0x5c, 0xff, - 0x70, 0x5e, 0x5c, 0xff, 0x6f, 0x6c, 0x6c, 0xff, 0x64, 0x5d, 0x5c, 0xff, - 0x81, 0x7e, 0x7c, 0xff, 0x81, 0x7e, 0x7c, 0xff, 0x81, 0x7e, 0x7c, 0xff, - 0xb1, 0xaa, 0xa4, 0xff, 0xbc, 0xb0, 0xac, 0xff, 0xc4, 0xc3, 0xc4, 0xff, - 0xe4, 0xce, 0xcc, 0xff, 0xd5, 0xcd, 0xcc, 0xff, 0x81, 0x72, 0x74, 0xff, - 0x70, 0x5e, 0x5c, 0xff, 0xa1, 0x99, 0x9c, 0xff, 0xa1, 0x99, 0x9c, 0xff, - 0xa3, 0xa3, 0xa4, 0xff, 0xa1, 0x99, 0x9c, 0xff, 0xc4, 0xbe, 0xc4, 0xff, - 0xb4, 0xb2, 0xb4, 0xff, 0xc4, 0xc3, 0xc4, 0xff, 0xba, 0xb6, 0xb4, 0xff, - 0xcc, 0xc5, 0xc4, 0xff, 0xc4, 0xc3, 0xc4, 0xff, 0xcc, 0xcc, 0xcc, 0xff, - 0xd6, 0xd2, 0xd4, 0xff, 0xd6, 0xd2, 0xd4, 0xff, 0xac, 0xa9, 0xac, 0xff, - 0xa3, 0xa3, 0xa4, 0xff, 0xbc, 0xb9, 0xbc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, - 0xd6, 0xd2, 0xd4, 0xff, 0xd7, 0xd6, 0xd4, 0xff, 0xe4, 0xe1, 0xe4, 0xff, - 0xec, 0xea, 0xec, 0xff, 0xba, 0xb6, 0xb4, 0xff, 0xc4, 0xbe, 0xc4, 0xff, - 0xcc, 0xcc, 0xcc, 0xff, 0xbc, 0xb1, 0xb4, 0xff, 0xc4, 0xc3, 0xc4, 0xff, - 0xb4, 0xaa, 0xac, 0xff, 0xbc, 0xaa, 0xac, 0xff, 0xcc, 0xbe, 0xc4, 0xff, - 0xd5, 0xcd, 0xcc, 0xff, 0xd8, 0xdc, 0xd4, 0xff, 0xe8, 0xe7, 0xe4, 0xff, - 0xfb, 0xf9, 0xec, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xfb, 0xfe, 0xec, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x55, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x5d, 0x62, 0x5c, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x63, 0x66, 0x64, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x5d, 0x62, 0x5c, 0xff, 0x63, 0x66, 0x64, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x6c, 0x61, 0x64, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x5d, 0x5a, 0x54, 0xff, 0x5d, 0x5a, 0x54, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x55, 0x52, 0x4c, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x71, 0x6a, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x55, 0x55, 0x54, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x64, 0x5d, 0x5c, 0xff, 0x69, 0x55, 0x54, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x64, 0x4e, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x64, 0x5d, 0x5c, 0xff, 0x78, 0x77, 0x74, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x71, 0x72, 0x74, 0xff, 0x78, 0x77, 0x74, 0xff, 0x78, 0x77, 0x74, 0xff, - 0xa1, 0x9e, 0x9c, 0xff, 0xa1, 0x99, 0x9c, 0xff, 0xb1, 0xaa, 0xa4, 0xff, - 0xd5, 0xcd, 0xcc, 0xff, 0xe6, 0xd6, 0xd6, 0xff, 0xcc, 0xbd, 0xbc, 0xff, - 0x64, 0x5d, 0x5c, 0xff, 0x84, 0x77, 0x74, 0xff, 0x9e, 0x8b, 0x84, 0xff, - 0x9a, 0x94, 0x94, 0xff, 0x89, 0x86, 0x84, 0xff, 0xc2, 0xbe, 0xbc, 0xff, - 0xdc, 0xdc, 0xdc, 0xff, 0xa3, 0xa3, 0xa4, 0xff, 0xb4, 0xb2, 0xb4, 0xff, - 0xc2, 0xbe, 0xbc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xc4, 0xc3, 0xc4, 0xff, - 0xcc, 0xcc, 0xcc, 0xff, 0xd9, 0xd4, 0xcc, 0xff, 0xa3, 0xa3, 0xa4, 0xff, - 0x9a, 0x94, 0x94, 0xff, 0xc2, 0xbe, 0xbc, 0xff, 0xcc, 0xc5, 0xc4, 0xff, - 0xd7, 0xd6, 0xd4, 0xff, 0xdc, 0xdc, 0xdc, 0xff, 0xe8, 0xe7, 0xe4, 0xff, - 0xe8, 0xe7, 0xe4, 0xff, 0xdc, 0xdc, 0xdc, 0xff, 0xc2, 0xbe, 0xbc, 0xff, - 0xd5, 0xcd, 0xcc, 0xff, 0xc2, 0xbe, 0xbc, 0xff, 0xd5, 0xcd, 0xcc, 0xff, - 0xcf, 0xc6, 0xcc, 0xff, 0xa4, 0x9e, 0xa4, 0xff, 0xc5, 0xb7, 0xb4, 0xff, - 0xc4, 0xc3, 0xc4, 0xff, 0xf2, 0xe9, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xfb, 0xfe, 0xec, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x63, 0x66, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x53, 0x5a, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x53, 0x5a, 0x54, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x63, 0x66, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x53, 0x5a, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x55, 0x55, 0x54, 0xff, 0x55, 0x52, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x5d, 0x62, 0x5c, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x6c, 0x61, 0x64, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x55, 0x55, 0x54, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x64, 0x5d, 0x5c, 0xff, 0x55, 0x55, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x71, 0x6a, 0x64, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x5d, 0x62, 0x5c, 0xff, 0x63, 0x6a, 0x64, 0xff, 0x78, 0x77, 0x74, 0xff, - 0x8b, 0x8b, 0x8c, 0xff, 0x83, 0x82, 0x84, 0xff, 0x8b, 0x8b, 0x8c, 0xff, - 0xcc, 0xc5, 0xc4, 0xff, 0xd7, 0xd6, 0xd4, 0xff, 0xd6, 0xd2, 0xd4, 0xff, - 0xae, 0xa4, 0xa4, 0xff, 0x84, 0x79, 0x7c, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x96, 0x85, 0x84, 0xff, 0x8b, 0x8b, 0x8c, 0xff, 0x8b, 0x8b, 0x8c, 0xff, - 0xe4, 0xe1, 0xe4, 0xff, 0xa1, 0x99, 0x9c, 0xff, 0xba, 0xb6, 0xb4, 0xff, - 0xc4, 0xc3, 0xc4, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, - 0xcc, 0xc5, 0xc4, 0xff, 0xd6, 0xd2, 0xd4, 0xff, 0xcc, 0xcc, 0xcc, 0xff, - 0xe8, 0xe7, 0xe4, 0xff, 0xd7, 0xd6, 0xd4, 0xff, 0xcc, 0xcc, 0xcc, 0xff, - 0xcc, 0xcc, 0xcc, 0xff, 0xe4, 0xde, 0xdc, 0xff, 0xe4, 0xe1, 0xe4, 0xff, - 0xf4, 0xf2, 0xf4, 0xff, 0xe8, 0xe7, 0xe4, 0xff, 0xcf, 0xc6, 0xcc, 0xff, - 0xc4, 0xc3, 0xc4, 0xff, 0xd6, 0xd2, 0xd4, 0xff, 0xcf, 0xc6, 0xcc, 0xff, - 0xc4, 0xc3, 0xc4, 0xff, 0xc4, 0xba, 0xbc, 0xff, 0xac, 0xa9, 0xac, 0xff, - 0xcc, 0xc5, 0xc4, 0xff, 0xd9, 0xd4, 0xcc, 0xff, 0xe8, 0xe7, 0xe4, 0xff, - 0xfb, 0xf9, 0xec, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xfb, 0xfe, 0xec, 0xff, - 0xfb, 0xfe, 0xec, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf2, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf2, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4c, 0x52, 0x4c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x5d, 0x62, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x53, 0x5a, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x5d, 0x62, 0x5c, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x5d, 0x62, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x5d, 0x62, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x6c, 0x61, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x55, 0x55, 0x54, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x6c, 0x61, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x55, 0x4e, 0x4c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x6c, 0x66, 0x6c, 0xff, 0x53, 0x5a, 0x54, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x6f, 0x6c, 0x6c, 0xff, 0x7b, 0x7a, 0x7c, 0xff, - 0x89, 0x86, 0x84, 0xff, 0x83, 0x82, 0x84, 0xff, 0x8b, 0x8b, 0x8c, 0xff, - 0xc2, 0xbe, 0xbc, 0xff, 0xd6, 0xd2, 0xd4, 0xff, 0xcc, 0xcc, 0xcc, 0xff, - 0xbc, 0xb1, 0xb4, 0xff, 0xae, 0xa4, 0xa4, 0xff, 0x84, 0x79, 0x7c, 0xff, - 0x6c, 0x61, 0x64, 0xff, 0x81, 0x72, 0x74, 0xff, 0x96, 0x86, 0x8c, 0xff, - 0xa1, 0x9e, 0x9c, 0xff, 0x9a, 0x94, 0x94, 0xff, 0xa1, 0x9e, 0x9c, 0xff, - 0xdc, 0xdc, 0xdc, 0xff, 0xd6, 0xd2, 0xd4, 0xff, 0xcc, 0xcc, 0xcc, 0xff, - 0xc4, 0xc3, 0xc4, 0xff, 0xc8, 0xca, 0xc4, 0xff, 0xe4, 0xe1, 0xe4, 0xff, - 0xcc, 0xcc, 0xcc, 0xff, 0xd7, 0xd6, 0xd4, 0xff, 0xd6, 0xd2, 0xd4, 0xff, - 0xd6, 0xd2, 0xd4, 0xff, 0xdc, 0xdc, 0xdc, 0xff, 0xdc, 0xdc, 0xdc, 0xff, - 0xec, 0xea, 0xec, 0xff, 0xec, 0xea, 0xec, 0xff, 0xd7, 0xd6, 0xd4, 0xff, - 0xcc, 0xc5, 0xc4, 0xff, 0xcc, 0xc5, 0xc4, 0xff, 0xd7, 0xd6, 0xd4, 0xff, - 0xc4, 0xc3, 0xc4, 0xff, 0xc2, 0xbe, 0xbc, 0xff, 0xbc, 0xb9, 0xbc, 0xff, - 0xc2, 0xbe, 0xbc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xd9, 0xd4, 0xcc, 0xff, - 0xd8, 0xdc, 0xd4, 0xff, 0xfb, 0xf9, 0xec, 0xff, 0xfb, 0xf9, 0xec, 0xff, - 0xfb, 0xfe, 0xec, 0xff, 0xfb, 0xfe, 0xec, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xfb, 0xfe, 0xec, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x5d, 0x62, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x53, 0x5a, 0x54, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x53, 0x5a, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x55, 0x4e, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x6f, 0x6c, 0x6c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x5d, 0x62, 0x5c, 0xff, - 0x63, 0x66, 0x64, 0xff, 0x71, 0x72, 0x74, 0xff, 0x78, 0x77, 0x74, 0xff, - 0x71, 0x72, 0x74, 0xff, 0x71, 0x72, 0x6c, 0xff, 0x7b, 0x7a, 0x7c, 0xff, - 0xa1, 0x99, 0x9c, 0xff, 0xa3, 0xa3, 0xa4, 0xff, 0x81, 0x7e, 0x7c, 0xff, - 0xa4, 0x9e, 0xa4, 0xff, 0xba, 0xb6, 0xb4, 0xff, 0xa1, 0x99, 0x9c, 0xff, - 0x8f, 0x7f, 0x7c, 0xff, 0x6c, 0x61, 0x64, 0xff, 0x84, 0x79, 0x7c, 0xff, - 0x96, 0x85, 0x84, 0xff, 0x8b, 0x8b, 0x8c, 0xff, 0x9a, 0x94, 0x94, 0xff, - 0xac, 0xa9, 0xac, 0xff, 0xc4, 0xc3, 0xc4, 0xff, 0xc4, 0xc3, 0xc4, 0xff, - 0xcc, 0xc5, 0xc4, 0xff, 0xd6, 0xd2, 0xd4, 0xff, 0xd7, 0xd6, 0xd4, 0xff, - 0xbc, 0xb9, 0xbc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xdc, 0xdc, 0xdc, 0xff, - 0xcc, 0xc5, 0xc4, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xdc, 0xdc, 0xdc, 0xff, - 0xd8, 0xdc, 0xd4, 0xff, 0xdc, 0xdc, 0xdc, 0xff, 0xd7, 0xd6, 0xd4, 0xff, - 0xcc, 0xc5, 0xc4, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, - 0xcc, 0xc5, 0xc4, 0xff, 0xc2, 0xc2, 0xbc, 0xff, 0xcf, 0xc6, 0xcc, 0xff, - 0xbc, 0xb6, 0xac, 0xff, 0xc4, 0xc3, 0xc4, 0xff, 0xc8, 0xca, 0xc4, 0xff, - 0xc8, 0xca, 0xc4, 0xff, 0xf2, 0xf0, 0xec, 0xff, 0xf2, 0xf0, 0xec, 0xff, - 0xfb, 0xfe, 0xec, 0xff, 0xfb, 0xfe, 0xec, 0xff, 0xfb, 0xfe, 0xec, 0xff, - 0xfb, 0xfe, 0xec, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xfa, 0xfe, 0xe4, 0xff, - 0xfa, 0xfe, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf2, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x52, 0x4c, 0xff, 0x5d, 0x62, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x53, 0x5a, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x5d, 0x62, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x53, 0x5a, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x53, 0x5a, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x53, 0x5a, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x5d, 0x62, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x53, 0x5a, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x64, 0x6a, 0x6c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x63, 0x66, 0x64, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x63, 0x66, 0x64, 0xff, 0x63, 0x66, 0x64, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x71, 0x72, 0x74, 0xff, 0x64, 0x6a, 0x6c, 0xff, 0x6f, 0x6c, 0x6c, 0xff, - 0x7b, 0x7a, 0x7c, 0xff, 0x81, 0x7e, 0x7c, 0xff, 0x78, 0x77, 0x74, 0xff, - 0x83, 0x82, 0x84, 0xff, 0xa3, 0xa3, 0xa4, 0xff, 0x8b, 0x8b, 0x8c, 0xff, - 0xa3, 0xa3, 0xa4, 0xff, 0x6c, 0x61, 0x64, 0xff, 0x6c, 0x61, 0x64, 0xff, - 0x6f, 0x6c, 0x6c, 0xff, 0xc6, 0xb1, 0xb4, 0xff, 0xb4, 0xb2, 0xb4, 0xff, - 0xa1, 0x9e, 0x9c, 0xff, 0xb3, 0xae, 0xac, 0xff, 0x9a, 0x94, 0x94, 0xff, - 0xba, 0xb6, 0xb4, 0xff, 0xd7, 0xd6, 0xd4, 0xff, 0xdc, 0xdc, 0xdc, 0xff, - 0xdc, 0xdc, 0xdc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xd7, 0xd6, 0xd4, 0xff, - 0xcf, 0xc6, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xd6, 0xd2, 0xd4, 0xff, - 0xd6, 0xd2, 0xd4, 0xff, 0xdc, 0xdc, 0xdc, 0xff, 0xd6, 0xd2, 0xd4, 0xff, - 0xcc, 0xcc, 0xcc, 0xff, 0xd7, 0xd6, 0xd4, 0xff, 0xcf, 0xc6, 0xcc, 0xff, - 0xc4, 0xc3, 0xc4, 0xff, 0xcf, 0xc6, 0xcc, 0xff, 0xbc, 0xb9, 0xbc, 0xff, - 0x8b, 0x8b, 0x8c, 0xff, 0xbc, 0xb9, 0xbc, 0xff, 0xd9, 0xd4, 0xcc, 0xff, - 0xc4, 0xc3, 0xc4, 0xff, 0xd8, 0xdc, 0xd4, 0xff, 0xfc, 0xfe, 0xf4, 0xff, - 0xfb, 0xfe, 0xec, 0xff, 0xfa, 0xfe, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xfb, 0xfe, 0xec, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf2, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x4c, 0x52, 0x4c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x5d, 0x62, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x5d, 0x62, 0x5c, 0xff, 0x55, 0x55, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x5d, 0x62, 0x5c, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x5d, 0x62, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x53, 0x5a, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x52, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x64, 0x6a, 0x6c, 0xff, 0x53, 0x5a, 0x54, 0xff, 0x53, 0x5a, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x63, 0x66, 0x64, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x63, 0x6a, 0x64, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x63, 0x66, 0x64, 0xff, 0x64, 0x5d, 0x5c, 0xff, 0x5d, 0x62, 0x5c, 0xff, - 0x71, 0x72, 0x74, 0xff, 0x6f, 0x6c, 0x6c, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x71, 0x72, 0x74, 0xff, 0x81, 0x7e, 0x7c, 0xff, 0x7b, 0x7a, 0x7c, 0xff, - 0xc4, 0xc3, 0xc4, 0xff, 0x84, 0x79, 0x7c, 0xff, 0x64, 0x5d, 0x5c, 0xff, - 0x6b, 0x56, 0x5c, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x6f, 0x6c, 0x6c, 0xff, - 0x8c, 0x86, 0x8c, 0xff, 0xac, 0xa9, 0xac, 0xff, 0x9a, 0x94, 0x94, 0xff, - 0xac, 0xa9, 0xac, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xc5, 0xc4, 0xff, - 0xe4, 0xe1, 0xe4, 0xff, 0xd7, 0xd6, 0xd4, 0xff, 0xd7, 0xd6, 0xd4, 0xff, - 0xd7, 0xd6, 0xd4, 0xff, 0xd6, 0xd2, 0xd4, 0xff, 0xdc, 0xdc, 0xdc, 0xff, - 0xdc, 0xdc, 0xdc, 0xff, 0xdc, 0xdc, 0xdc, 0xff, 0xe4, 0xe1, 0xe4, 0xff, - 0xd7, 0xd6, 0xd4, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xd7, 0xd6, 0xd4, 0xff, - 0xcc, 0xcc, 0xcc, 0xff, 0xba, 0xb6, 0xb4, 0xff, 0xcc, 0xcc, 0xcc, 0xff, - 0xa1, 0xa2, 0x9c, 0xff, 0xbc, 0xb6, 0xac, 0xff, 0xba, 0xb6, 0xb4, 0xff, - 0xd8, 0xdc, 0xd4, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xf2, 0xf0, 0xec, 0xff, - 0xfb, 0xf9, 0xec, 0xff, 0xfb, 0xf9, 0xec, 0xff, 0xfb, 0xfe, 0xec, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xfb, 0xf9, 0xec, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xfb, 0xf9, 0xec, 0xff, 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x53, 0x5a, 0x54, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x53, 0x5a, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x53, 0x5a, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x5d, 0x62, 0x5c, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x4c, 0x52, 0x4c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x63, 0x66, 0x64, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x53, 0x5a, 0x54, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x63, 0x6a, 0x64, 0xff, - 0x63, 0x66, 0x64, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x5d, 0x62, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x6f, 0x6c, 0x6c, 0xff, 0x64, 0x6a, 0x6c, 0xff, 0x5d, 0x62, 0x5c, 0xff, - 0x64, 0x6a, 0x6c, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x71, 0x6a, 0x64, 0xff, - 0xae, 0xa4, 0xa4, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0x94, 0x8c, 0x8c, 0xff, - 0x9a, 0x94, 0x94, 0xff, 0x84, 0x79, 0x7c, 0xff, 0x81, 0x7e, 0x7c, 0xff, - 0xac, 0xa9, 0xac, 0xff, 0xa3, 0xa3, 0xa4, 0xff, 0x63, 0x66, 0x64, 0xff, - 0xb3, 0xae, 0xac, 0xff, 0xc2, 0xbe, 0xbc, 0xff, 0xa3, 0xa3, 0xa4, 0xff, - 0xc2, 0xbe, 0xbc, 0xff, 0xc4, 0xbe, 0xc4, 0xff, 0xcc, 0xcc, 0xcc, 0xff, - 0xd6, 0xd2, 0xd4, 0xff, 0xd6, 0xd2, 0xd4, 0xff, 0xdc, 0xdc, 0xdc, 0xff, - 0xe4, 0xe1, 0xe4, 0xff, 0xe4, 0xe2, 0xd8, 0xff, 0xe4, 0xe1, 0xe4, 0xff, - 0xdc, 0xdc, 0xdc, 0xff, 0xd7, 0xd6, 0xd4, 0xff, 0xcc, 0xcc, 0xcc, 0xff, - 0xc4, 0xc3, 0xc4, 0xff, 0xc4, 0xc3, 0xc4, 0xff, 0xc4, 0xc3, 0xc4, 0xff, - 0xa1, 0x9e, 0x9c, 0xff, 0xb4, 0xb2, 0xb4, 0xff, 0xb3, 0xae, 0xac, 0xff, - 0xc8, 0xca, 0xc4, 0xff, 0xe4, 0xe2, 0xd8, 0xff, 0xe8, 0xe7, 0xe4, 0xff, - 0xfb, 0xf9, 0xec, 0xff, 0xfb, 0xf9, 0xec, 0xff, 0xe4, 0xe2, 0xd8, 0xff, - 0xc9, 0xc0, 0xb4, 0xff, 0xb0, 0xa3, 0x9c, 0xff, 0xb1, 0xa3, 0x94, 0xff, - 0xbc, 0xa4, 0x9c, 0xff, 0xc0, 0xaa, 0x9c, 0xff, 0xd6, 0xc5, 0xbc, 0xff, - 0xcc, 0xbe, 0xac, 0xff, 0xd9, 0xcc, 0xbc, 0xff, 0xe2, 0xdc, 0xcc, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf7, 0xdc, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x52, 0x4c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x53, 0x5a, 0x54, 0xff, 0x5d, 0x62, 0x5c, 0xff, 0x5d, 0x62, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x53, 0x5a, 0x54, 0xff, 0x63, 0x66, 0x64, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x5d, 0x62, 0x5c, 0xff, 0x53, 0x5a, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x63, 0x66, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x63, 0x66, 0x64, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x5d, 0x62, 0x5c, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x8b, 0x8b, 0x8c, 0xff, 0xa1, 0x9e, 0x9c, 0xff, 0xbc, 0xb1, 0xb4, 0xff, - 0xb4, 0xb2, 0xb4, 0xff, 0x8b, 0x8b, 0x8c, 0xff, 0x81, 0x7e, 0x7c, 0xff, - 0xa1, 0x9e, 0x9c, 0xff, 0xba, 0xb6, 0xb4, 0xff, 0x64, 0x6a, 0x6c, 0xff, - 0x83, 0x82, 0x84, 0xff, 0x8b, 0x8b, 0x8c, 0xff, 0xa1, 0x99, 0x9c, 0xff, - 0xac, 0xa9, 0xac, 0xff, 0xba, 0xb6, 0xb4, 0xff, 0xb4, 0xb2, 0xb4, 0xff, - 0xc2, 0xbe, 0xbc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, - 0xdc, 0xdc, 0xdc, 0xff, 0xdc, 0xdc, 0xdc, 0xff, 0xec, 0xea, 0xec, 0xff, - 0xe8, 0xe7, 0xe4, 0xff, 0xdc, 0xdc, 0xdc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, - 0xbc, 0xb9, 0xbc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xc2, 0xc2, 0xbc, 0xff, - 0xa3, 0xa3, 0xa4, 0xff, 0xb1, 0xaa, 0xa4, 0xff, 0xb3, 0xae, 0xac, 0xff, - 0xba, 0xb6, 0xb4, 0xff, 0xd9, 0xd4, 0xcc, 0xff, 0xe8, 0xe7, 0xe4, 0xff, - 0xd9, 0xd4, 0xcc, 0xff, 0xd7, 0xcc, 0xc4, 0xff, 0xbc, 0xb6, 0xac, 0xff, - 0xb0, 0xa3, 0x9c, 0xff, 0xc4, 0xb2, 0xac, 0xff, 0xbc, 0xa4, 0x9c, 0xff, - 0xa4, 0x85, 0x84, 0xff, 0x9e, 0x8b, 0x84, 0xff, 0xa7, 0x94, 0x84, 0xff, - 0x9c, 0x8e, 0x7c, 0xff, 0xa9, 0x9b, 0x8c, 0xff, 0xb4, 0xaa, 0x94, 0xff, - 0xbc, 0xb6, 0xac, 0xff, 0xda, 0xd4, 0xc4, 0xff, 0xf2, 0xe9, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x53, 0x5a, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x53, 0x5a, 0x54, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x53, 0x5a, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x53, 0x5a, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x53, 0x5a, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x53, 0x5a, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x52, 0x4c, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x53, 0x5a, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x53, 0x5a, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x53, 0x5a, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x53, 0x5a, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x5d, 0x62, 0x5c, 0xff, 0x5d, 0x62, 0x5c, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x53, 0x5a, 0x54, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x53, 0x5a, 0x54, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x64, 0x6a, 0x6c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x6f, 0x6c, 0x6c, 0xff, 0x6f, 0x6c, 0x6c, 0xff, 0x81, 0x7e, 0x7c, 0xff, - 0xba, 0xb6, 0xb4, 0xff, 0xa4, 0x9e, 0xa4, 0xff, 0x89, 0x86, 0x84, 0xff, - 0xa1, 0x9e, 0x9c, 0xff, 0xa3, 0xa3, 0xa4, 0xff, 0x6f, 0x6c, 0x6c, 0xff, - 0x88, 0x8a, 0x84, 0xff, 0xcc, 0xc5, 0xc4, 0xff, 0x9a, 0x94, 0x94, 0xff, - 0x89, 0x86, 0x84, 0xff, 0x9a, 0x94, 0x94, 0xff, 0xbc, 0xb9, 0xbc, 0xff, - 0xbc, 0xb9, 0xbc, 0xff, 0x83, 0x82, 0x84, 0xff, 0x94, 0x8e, 0x94, 0xff, - 0xd7, 0xd6, 0xd4, 0xff, 0xf4, 0xf2, 0xf4, 0xff, 0xd6, 0xd2, 0xd4, 0xff, - 0xdc, 0xdc, 0xdc, 0xff, 0xe4, 0xe1, 0xe4, 0xff, 0xd8, 0xdc, 0xd4, 0xff, - 0xc4, 0xc3, 0xc4, 0xff, 0xc4, 0xc3, 0xc4, 0xff, 0xd6, 0xd2, 0xd4, 0xff, - 0xa1, 0x99, 0x9c, 0xff, 0xb3, 0xae, 0xac, 0xff, 0xbc, 0xb6, 0xac, 0xff, - 0xb1, 0xaa, 0xa4, 0xff, 0xc2, 0xbe, 0xbc, 0xff, 0xe4, 0xe2, 0xd8, 0xff, - 0xf2, 0xf0, 0xec, 0xff, 0xd8, 0xdc, 0xd4, 0xff, 0xd5, 0xcd, 0xcc, 0xff, - 0xcc, 0xbd, 0xbc, 0xff, 0xef, 0xe2, 0xdc, 0xff, 0xc6, 0xb1, 0xb4, 0xff, - 0xac, 0x8d, 0x8c, 0xff, 0xac, 0x8d, 0x84, 0xff, 0xa4, 0x89, 0x7c, 0xff, - 0x9c, 0x88, 0x7c, 0xff, 0x9c, 0x8e, 0x7c, 0xff, 0x9c, 0x8e, 0x7c, 0xff, - 0xb1, 0xa3, 0x94, 0xff, 0xb1, 0xa3, 0x94, 0xff, 0xb4, 0xae, 0x9c, 0xff, - 0xd9, 0xcc, 0xbc, 0xff, 0xf2, 0xe9, 0xdc, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0x53, 0x5a, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x52, 0x4c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x52, 0x4c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x53, 0x5a, 0x54, 0xff, 0x5d, 0x62, 0x5c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x52, 0x4c, 0xff, 0x53, 0x5a, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x53, 0x5a, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x52, 0x4c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x5d, 0x62, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x53, 0x5a, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x53, 0x5a, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x5d, 0x62, 0x5c, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x53, 0x5a, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x63, 0x66, 0x64, 0xff, 0x6f, 0x6c, 0x6c, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x9a, 0x94, 0x94, 0xff, 0xa3, 0xa3, 0xa4, 0xff, 0x81, 0x7e, 0x7c, 0xff, - 0xb3, 0xae, 0xac, 0xff, 0xa1, 0x99, 0x9c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x7b, 0x7a, 0x7c, 0xff, 0xbc, 0xb9, 0xbc, 0xff, 0x88, 0x8a, 0x84, 0xff, - 0x64, 0x6a, 0x6c, 0xff, 0x83, 0x82, 0x84, 0xff, 0xc2, 0xbe, 0xbc, 0xff, - 0x9c, 0x9a, 0x94, 0xff, 0x89, 0x86, 0x84, 0xff, 0x71, 0x72, 0x6c, 0xff, - 0xb4, 0xb2, 0xb4, 0xff, 0xe8, 0xe7, 0xe4, 0xff, 0xec, 0xea, 0xec, 0xff, - 0xe8, 0xe7, 0xe4, 0xff, 0xe4, 0xe1, 0xe4, 0xff, 0xdc, 0xdc, 0xdc, 0xff, - 0xcc, 0xcc, 0xcc, 0xff, 0xc4, 0xbe, 0xc4, 0xff, 0xc4, 0xc3, 0xc4, 0xff, - 0xc4, 0xc3, 0xc4, 0xff, 0x8b, 0x8b, 0x8c, 0xff, 0xb4, 0xb2, 0xb4, 0xff, - 0x9c, 0x9a, 0x94, 0xff, 0xac, 0xa9, 0xac, 0xff, 0xd7, 0xd6, 0xd4, 0xff, - 0xf2, 0xf0, 0xec, 0xff, 0xd7, 0xd6, 0xd4, 0xff, 0xc2, 0xbe, 0xbc, 0xff, - 0xcc, 0xc2, 0xbc, 0xff, 0xdc, 0xba, 0xbc, 0xff, 0xad, 0x9e, 0x9e, 0xff, - 0x9c, 0x80, 0x7c, 0xff, 0xa4, 0x85, 0x84, 0xff, 0x9c, 0x88, 0x7c, 0xff, - 0x9c, 0x88, 0x7c, 0xff, 0x9c, 0x88, 0x7c, 0xff, 0x8f, 0x86, 0x7c, 0xff, - 0xa4, 0x86, 0x74, 0xff, 0x9c, 0x88, 0x7c, 0xff, 0xa8, 0x93, 0x8c, 0xff, - 0xb1, 0xa3, 0x94, 0xff, 0xb4, 0xae, 0x9c, 0xff, 0xe2, 0xdc, 0xcc, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x53, 0x5a, 0x54, 0xff, 0x53, 0x5a, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x53, 0x5a, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x52, 0x4c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x52, 0x4c, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x53, 0x5a, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x53, 0x5a, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x53, 0x5a, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x63, 0x66, 0x64, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x64, 0x6a, 0x6c, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x55, 0x55, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x64, 0x6a, 0x6c, 0xff, 0x81, 0x7e, 0x7c, 0xff, 0x64, 0x6a, 0x6c, 0xff, - 0x83, 0x82, 0x84, 0xff, 0x64, 0x6a, 0x6c, 0xff, 0x53, 0x5a, 0x54, 0xff, - 0x6f, 0x6c, 0x6c, 0xff, 0xa3, 0xa3, 0xa4, 0xff, 0x83, 0x82, 0x84, 0xff, - 0x8b, 0x8b, 0x8c, 0xff, 0x9a, 0x94, 0x94, 0xff, 0xa1, 0x9e, 0x9c, 0xff, - 0x7b, 0x7a, 0x7c, 0xff, 0x64, 0x6a, 0x6c, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x94, 0x8e, 0x94, 0xff, 0xba, 0xb6, 0xb4, 0xff, 0xcc, 0xcc, 0xcc, 0xff, - 0xe8, 0xe7, 0xe4, 0xff, 0xd7, 0xd6, 0xd4, 0xff, 0xdc, 0xd6, 0xdc, 0xff, - 0xb3, 0xae, 0xac, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xba, 0xb6, 0xb4, 0xff, - 0xd9, 0xd4, 0xcc, 0xff, 0xb4, 0xb2, 0xb4, 0xff, 0xac, 0xa9, 0xac, 0xff, - 0xa1, 0x9e, 0x9c, 0xff, 0xa1, 0x9e, 0x9c, 0xff, 0xa3, 0xa3, 0xa4, 0xff, - 0xcc, 0xcc, 0xcc, 0xff, 0xf4, 0xea, 0xe4, 0xff, 0xbc, 0xb0, 0xac, 0xff, - 0xbc, 0xaa, 0xac, 0xff, 0xad, 0x9e, 0x9e, 0xff, 0xa8, 0x93, 0x8c, 0xff, - 0xa4, 0x85, 0x84, 0xff, 0xa4, 0x85, 0x84, 0xff, 0x9d, 0x8d, 0x8c, 0xff, - 0xa8, 0x9b, 0x94, 0xff, 0xbc, 0xa4, 0x9c, 0xff, 0xbf, 0xaa, 0xa4, 0xff, - 0xa6, 0x95, 0x94, 0xff, 0xac, 0x8d, 0x84, 0xff, 0x9c, 0x88, 0x7c, 0xff, - 0x90, 0x7f, 0x74, 0xff, 0xac, 0x8d, 0x84, 0xff, 0xba, 0xb0, 0xa4, 0xff, - 0xf4, 0xe9, 0xd4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf7, 0xdc, 0xff, 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x53, 0x5a, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x5d, 0x62, 0x5c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4c, 0x52, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x52, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x52, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x53, 0x5a, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x53, 0x5a, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x52, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x5d, 0x62, 0x5c, 0xff, - 0x5d, 0x62, 0x5c, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x5d, 0x62, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x53, 0x5a, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x53, 0x5a, 0x54, 0xff, - 0x63, 0x66, 0x64, 0xff, 0x64, 0x6a, 0x6c, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x7b, 0x7a, 0x7c, 0xff, 0x63, 0x66, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x81, 0x7e, 0x7c, 0xff, 0x71, 0x72, 0x74, 0xff, - 0x88, 0x8a, 0x84, 0xff, 0x89, 0x86, 0x84, 0xff, 0x7b, 0x7a, 0x7c, 0xff, - 0x64, 0x6a, 0x6c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x78, 0x77, 0x74, 0xff, 0xa3, 0xa3, 0xa4, 0xff, 0x8b, 0x8b, 0x8c, 0xff, - 0xdc, 0xdc, 0xdc, 0xff, 0xac, 0xa9, 0xac, 0xff, 0xc4, 0xc3, 0xc4, 0xff, - 0x8b, 0x8b, 0x8c, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xbc, 0xb9, 0xbc, 0xff, - 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xdc, 0xdc, 0xdc, 0xff, - 0xc2, 0xbe, 0xbc, 0xff, 0xbc, 0xb9, 0xbc, 0xff, 0xac, 0xa9, 0xac, 0xff, - 0xdc, 0xdc, 0xdc, 0xff, 0xd6, 0xd2, 0xd4, 0xff, 0xc2, 0xbe, 0xbc, 0xff, - 0xbc, 0xb0, 0xac, 0xff, 0xa6, 0x95, 0x94, 0xff, 0x96, 0x86, 0x8c, 0xff, - 0x9e, 0x8b, 0x84, 0xff, 0x9d, 0x8d, 0x8c, 0xff, 0xa4, 0x85, 0x84, 0xff, - 0xa4, 0x85, 0x84, 0xff, 0xa8, 0x93, 0x8c, 0xff, 0xad, 0x9e, 0x9e, 0xff, - 0xbd, 0xa6, 0xa4, 0xff, 0xa6, 0x95, 0x94, 0xff, 0xa6, 0x95, 0x94, 0xff, - 0xa4, 0x85, 0x84, 0xff, 0x8f, 0x86, 0x7c, 0xff, 0xa7, 0x94, 0x84, 0xff, - 0xba, 0xb0, 0xa4, 0xff, 0xe4, 0xe2, 0xd8, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf7, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x52, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x53, 0x5a, 0x54, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x52, 0x4c, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x52, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x53, 0x5a, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x53, 0x5a, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x53, 0x5a, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x63, 0x6a, 0x64, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x63, 0x66, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x71, 0x72, 0x74, 0xff, 0x7b, 0x7a, 0x7c, 0xff, 0x63, 0x6a, 0x64, 0xff, - 0x71, 0x72, 0x74, 0xff, 0x55, 0x55, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x63, 0x6a, 0x64, 0xff, 0x64, 0x6a, 0x6c, 0xff, 0x7b, 0x7a, 0x7c, 0xff, - 0xb4, 0xb2, 0xb4, 0xff, 0x7b, 0x7a, 0x7c, 0xff, 0x9c, 0x9a, 0x94, 0xff, - 0x71, 0x72, 0x74, 0xff, 0xb4, 0xb2, 0xb4, 0xff, 0xb4, 0xb2, 0xb4, 0xff, - 0xc8, 0xca, 0xc4, 0xff, 0xc4, 0xc3, 0xc4, 0xff, 0xc4, 0xc3, 0xc4, 0xff, - 0xb3, 0xae, 0xac, 0xff, 0xc2, 0xbe, 0xbc, 0xff, 0xc2, 0xbe, 0xbc, 0xff, - 0xe4, 0xe1, 0xe4, 0xff, 0xd4, 0xc6, 0xc4, 0xff, 0xd5, 0xcd, 0xcc, 0xff, - 0xa6, 0x95, 0x94, 0xff, 0xa8, 0x93, 0x8c, 0xff, 0x9c, 0x80, 0x7c, 0xff, - 0x9c, 0x7a, 0x7c, 0xff, 0xa4, 0x85, 0x84, 0xff, 0xa4, 0x85, 0x84, 0xff, - 0x8e, 0x79, 0x74, 0xff, 0x9c, 0x80, 0x7c, 0xff, 0xb4, 0x96, 0x94, 0xff, - 0xbd, 0xa6, 0xa4, 0xff, 0xc5, 0xb7, 0xb4, 0xff, 0xbc, 0xa4, 0x9c, 0xff, - 0xa6, 0x95, 0x94, 0xff, 0x9c, 0x88, 0x7c, 0xff, 0x9c, 0x88, 0x7c, 0xff, - 0x9c, 0x92, 0x84, 0xff, 0xc7, 0xb8, 0xac, 0xff, 0xf2, 0xe9, 0xdc, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x50, 0x4e, 0x44, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x52, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x52, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x53, 0x5a, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x55, 0x55, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x4c, 0x52, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x53, 0x5a, 0x54, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x53, 0x5a, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x5d, 0x62, 0x5c, 0xff, 0x53, 0x5a, 0x54, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x63, 0x66, 0x64, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x63, 0x66, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x63, 0x66, 0x64, 0xff, 0x63, 0x6a, 0x64, 0xff, - 0x83, 0x82, 0x84, 0xff, 0x63, 0x6a, 0x64, 0xff, 0x64, 0x6a, 0x6c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0xa1, 0xa2, 0x9c, 0xff, 0xb4, 0xb2, 0xb4, 0xff, - 0xbc, 0xb9, 0xbc, 0xff, 0xc2, 0xc2, 0xbc, 0xff, 0x83, 0x82, 0x84, 0xff, - 0x7b, 0x7a, 0x7c, 0xff, 0xa1, 0x9e, 0x9c, 0xff, 0xc4, 0xc3, 0xc4, 0xff, - 0xdc, 0xd6, 0xdc, 0xff, 0xd4, 0xc6, 0xc4, 0xff, 0xd4, 0xc6, 0xc4, 0xff, - 0xc6, 0xb1, 0xb4, 0xff, 0xe6, 0xd6, 0xd6, 0xff, 0xcc, 0xbe, 0xc4, 0xff, - 0xb4, 0x96, 0x94, 0xff, 0xa4, 0x85, 0x84, 0xff, 0x9c, 0x7a, 0x74, 0xff, - 0x9c, 0x7a, 0x7c, 0xff, 0x9c, 0x80, 0x7c, 0xff, 0x9c, 0x80, 0x7c, 0xff, - 0x9d, 0x8d, 0x8c, 0xff, 0xa6, 0x95, 0x94, 0xff, 0xb0, 0xa3, 0x9c, 0xff, - 0xad, 0x9e, 0x9e, 0xff, 0xa8, 0x93, 0x8c, 0xff, 0x90, 0x7f, 0x74, 0xff, - 0x9c, 0x81, 0x74, 0xff, 0xa9, 0x9b, 0x8c, 0xff, 0xd8, 0xdc, 0xd4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x52, 0x4c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x52, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x53, 0x5a, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x5d, 0x62, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x55, 0x55, 0x54, 0xff, 0x53, 0x5a, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x5d, 0x62, 0x5c, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x55, 0x4e, 0x4c, 0xff, - 0x64, 0x4e, 0x54, 0xff, 0x44, 0x47, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x64, 0x6a, 0x6c, 0xff, 0x8b, 0x8b, 0x8c, 0xff, 0xc4, 0xc3, 0xc4, 0xff, - 0x9a, 0x94, 0x94, 0xff, 0xb4, 0xb2, 0xb4, 0xff, 0x71, 0x72, 0x74, 0xff, - 0x83, 0x82, 0x84, 0xff, 0x89, 0x86, 0x84, 0xff, 0xa1, 0x9e, 0x9c, 0xff, - 0xbc, 0xb9, 0xbc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xc2, 0xbe, 0xbc, 0xff, - 0xa6, 0x95, 0x94, 0xff, 0xd4, 0xc6, 0xc4, 0xff, 0xe4, 0xd2, 0xd4, 0xff, - 0xb4, 0x9b, 0x94, 0xff, 0x96, 0x86, 0x8c, 0xff, 0x9c, 0x7a, 0x7c, 0xff, - 0x9c, 0x7a, 0x74, 0xff, 0x8e, 0x7a, 0x7c, 0xff, 0x9c, 0x80, 0x7c, 0xff, - 0x96, 0x85, 0x84, 0xff, 0xb4, 0x9b, 0x94, 0xff, 0xad, 0x9e, 0x9e, 0xff, - 0xba, 0xb0, 0xa4, 0xff, 0xbf, 0xaa, 0xa4, 0xff, 0xa8, 0x93, 0x8c, 0xff, - 0x84, 0x7e, 0x74, 0xff, 0x90, 0x7f, 0x74, 0xff, 0xa9, 0x9b, 0x8c, 0xff, - 0xd9, 0xc6, 0xb4, 0xff, 0xf2, 0xe9, 0xdc, 0xff, 0xf2, 0xe9, 0xdc, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x52, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x5d, 0x62, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x63, 0x6a, 0x64, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x63, 0x66, 0x64, 0xff, 0x53, 0x5a, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x4c, 0x52, 0x4c, 0xff, 0x64, 0x4e, 0x54, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x53, 0x5a, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x5f, 0x62, 0x64, 0xff, 0xa1, 0x9e, 0x9c, 0xff, - 0x81, 0x7e, 0x7c, 0xff, 0x64, 0x6a, 0x6c, 0xff, 0x64, 0x6a, 0x6c, 0xff, - 0x64, 0x6a, 0x6c, 0xff, 0x83, 0x82, 0x84, 0xff, 0x8b, 0x8b, 0x8c, 0xff, - 0xb4, 0xb2, 0xb4, 0xff, 0xcc, 0xc5, 0xc4, 0xff, 0xac, 0xa9, 0xac, 0xff, - 0x7b, 0x7a, 0x7c, 0xff, 0xbf, 0xaa, 0xa4, 0xff, 0x8f, 0x7f, 0x7c, 0xff, - 0x96, 0x85, 0x84, 0xff, 0x9c, 0x7a, 0x74, 0xff, 0x8e, 0x72, 0x74, 0xff, - 0x9c, 0x7a, 0x7c, 0xff, 0x9c, 0x80, 0x7c, 0xff, 0x8e, 0x79, 0x74, 0xff, - 0x96, 0x85, 0x84, 0xff, 0xa8, 0x93, 0x8c, 0xff, 0xa8, 0x9b, 0x94, 0xff, - 0xae, 0xa4, 0xa4, 0xff, 0xbf, 0xaa, 0xa4, 0xff, 0xa8, 0x93, 0x8c, 0xff, - 0x8e, 0x79, 0x74, 0xff, 0x8a, 0x76, 0x6c, 0xff, 0x84, 0x7e, 0x74, 0xff, - 0xa9, 0x9b, 0x8c, 0xff, 0xc9, 0xc0, 0xb4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x34, 0x33, 0x34, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x5d, 0x62, 0x5c, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x53, 0x5a, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x63, 0x66, 0x64, 0xff, 0x64, 0x6a, 0x6c, 0xff, - 0x64, 0x6a, 0x6c, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x53, 0x5a, 0x54, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x55, 0x4e, 0x4c, 0xff, - 0x64, 0x4e, 0x54, 0xff, 0x42, 0x42, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x55, 0x4e, 0x4c, 0xff, 0x64, 0x5d, 0x5c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x5d, 0x62, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x53, 0x5a, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x63, 0x66, 0x64, 0xff, 0x81, 0x7e, 0x7c, 0xff, 0x83, 0x82, 0x84, 0xff, - 0xb3, 0xae, 0xac, 0xff, 0x9c, 0x9a, 0x94, 0xff, 0xa3, 0xa3, 0xa4, 0xff, - 0x6f, 0x6c, 0x6c, 0xff, 0x9c, 0x93, 0x8c, 0xff, 0x8f, 0x7f, 0x7c, 0xff, - 0x7e, 0x6d, 0x6c, 0xff, 0x81, 0x72, 0x74, 0xff, 0x7f, 0x72, 0x6c, 0xff, - 0x8f, 0x7f, 0x7c, 0xff, 0x8f, 0x7f, 0x7c, 0xff, 0x8e, 0x79, 0x74, 0xff, - 0x8e, 0x79, 0x74, 0xff, 0x96, 0x85, 0x84, 0xff, 0xa4, 0x85, 0x84, 0xff, - 0xa8, 0x93, 0x8c, 0xff, 0xb4, 0x9b, 0x94, 0xff, 0xa8, 0x93, 0x8c, 0xff, - 0x7f, 0x72, 0x6c, 0xff, 0x8c, 0x6e, 0x64, 0xff, 0x90, 0x7f, 0x74, 0xff, - 0xa7, 0x94, 0x84, 0xff, 0xb0, 0xa3, 0x9c, 0xff, 0xe4, 0xd2, 0xc4, 0xff, - 0xf2, 0xe9, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x3b, 0x3a, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x55, 0x55, 0x54, 0xff, 0x53, 0x5a, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x5d, 0x62, 0x5c, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x64, 0x4e, 0x54, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x58, 0x49, 0x4c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x64, 0x4e, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x55, 0x4e, 0x4c, 0xff, - 0x64, 0x5d, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x64, 0x5d, 0x5c, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x55, 0x55, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x64, 0x6a, 0x6c, 0xff, 0x92, 0x92, 0x8c, 0xff, 0x64, 0x6a, 0x6c, 0xff, - 0x83, 0x82, 0x84, 0xff, 0x7b, 0x7a, 0x7c, 0xff, 0x8b, 0x8b, 0x8c, 0xff, - 0x71, 0x6a, 0x64, 0xff, 0x81, 0x7e, 0x7c, 0xff, 0x6f, 0x6c, 0x6c, 0xff, - 0x71, 0x6a, 0x64, 0xff, 0x7e, 0x6d, 0x6c, 0xff, 0x7f, 0x72, 0x6c, 0xff, - 0x8e, 0x79, 0x74, 0xff, 0x8e, 0x72, 0x74, 0xff, 0x78, 0x66, 0x64, 0xff, - 0x8e, 0x79, 0x74, 0xff, 0x96, 0x85, 0x84, 0xff, 0x9c, 0x80, 0x7c, 0xff, - 0x96, 0x85, 0x84, 0xff, 0x9d, 0x8d, 0x8c, 0xff, 0x9e, 0x8b, 0x84, 0xff, - 0x8e, 0x79, 0x74, 0xff, 0x9c, 0x92, 0x84, 0xff, 0x8e, 0x79, 0x74, 0xff, - 0x8e, 0x79, 0x74, 0xff, 0xa7, 0x94, 0x84, 0xff, 0xb1, 0xa3, 0x94, 0xff, - 0xda, 0xd4, 0xc4, 0xff, 0xf2, 0xe9, 0xdc, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0xf3, 0xf2, 0xdc, 0xff, 0xf3, 0xf2, 0xdc, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x3b, 0x3a, 0x34, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x44, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x52, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x63, 0x66, 0x64, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x63, 0x6a, 0x64, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4e, 0x42, 0x44, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, 0x64, 0x4e, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x63, 0x66, 0x64, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x63, 0x66, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x71, 0x6a, 0x64, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x63, 0x66, 0x64, 0xff, 0x71, 0x72, 0x6c, 0xff, - 0x6f, 0x6c, 0x6c, 0xff, 0x63, 0x66, 0x64, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x81, 0x72, 0x74, 0xff, 0x81, 0x72, 0x74, 0xff, 0x6f, 0x6c, 0x6c, 0xff, - 0x81, 0x72, 0x74, 0xff, 0x96, 0x86, 0x8c, 0xff, 0xad, 0x9a, 0x9c, 0xff, - 0xa4, 0x85, 0x84, 0xff, 0xa4, 0x85, 0x84, 0xff, 0x8d, 0x72, 0x6b, 0xff, - 0x78, 0x66, 0x64, 0xff, 0x8f, 0x7f, 0x7c, 0xff, 0x8f, 0x7f, 0x7c, 0xff, - 0x8e, 0x79, 0x74, 0xff, 0x9c, 0x7a, 0x74, 0xff, 0xa4, 0x89, 0x7c, 0xff, - 0xa8, 0x9b, 0x94, 0xff, 0xe2, 0xdc, 0xcc, 0xff, 0xf2, 0xe9, 0xdc, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x42, 0x42, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4c, 0x52, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x64, 0x6a, 0x6c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x44, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x53, 0x5a, 0x54, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x5d, 0x62, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x64, 0x4e, 0x54, 0xff, 0x55, 0x4e, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x4e, 0x42, 0x44, 0xff, 0x58, 0x49, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x55, 0x4e, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x69, 0x55, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x58, 0x49, 0x4c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x53, 0x5a, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x6c, 0x61, 0x64, 0xff, 0x5d, 0x5a, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x64, 0x5d, 0x5c, 0xff, 0x64, 0x5d, 0x5c, 0xff, 0x6c, 0x61, 0x64, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x64, 0x5d, 0x5c, 0xff, 0x6c, 0x61, 0x64, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x81, 0x7e, 0x7c, 0xff, 0x78, 0x66, 0x64, 0xff, - 0x84, 0x77, 0x74, 0xff, 0x9d, 0x8d, 0x8c, 0xff, 0xbc, 0xaa, 0xac, 0xff, - 0xac, 0x8d, 0x8c, 0xff, 0x96, 0x86, 0x8c, 0xff, 0x7e, 0x6d, 0x6c, 0xff, - 0x75, 0x62, 0x64, 0xff, 0x84, 0x77, 0x74, 0xff, 0xbd, 0xa6, 0xa4, 0xff, - 0x9c, 0x80, 0x7c, 0xff, 0x8e, 0x79, 0x74, 0xff, 0x9c, 0x7a, 0x74, 0xff, - 0x9c, 0x88, 0x7c, 0xff, 0xa8, 0x9b, 0x94, 0xff, 0xe4, 0xe2, 0xd8, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0xf2, 0xe9, 0xdc, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x34, 0x32, 0x2c, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x44, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x5d, 0x62, 0x5c, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x4c, 0x52, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x52, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x55, 0x4e, 0x4c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x53, 0x5a, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4c, 0x52, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x55, 0x4e, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x6b, 0x56, 0x5c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, 0x64, 0x5d, 0x5c, 0xff, - 0x5d, 0x5a, 0x54, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x64, 0x5d, 0x5c, 0xff, - 0x64, 0x5d, 0x5c, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x70, 0x66, 0x5c, 0xff, - 0x63, 0x66, 0x64, 0xff, 0x6c, 0x61, 0x64, 0xff, 0x64, 0x5d, 0x5c, 0xff, - 0x77, 0x66, 0x6c, 0xff, 0x7e, 0x6d, 0x6c, 0xff, 0x84, 0x79, 0x7c, 0xff, - 0x96, 0x86, 0x8c, 0xff, 0xac, 0x8d, 0x84, 0xff, 0x8e, 0x72, 0x74, 0xff, - 0x7f, 0x6a, 0x64, 0xff, 0xad, 0x9e, 0x9e, 0xff, 0xba, 0xb0, 0xa4, 0xff, - 0xb4, 0x9b, 0x94, 0xff, 0x8e, 0x72, 0x74, 0xff, 0x8e, 0x79, 0x74, 0xff, - 0x8e, 0x79, 0x74, 0xff, 0x84, 0x7e, 0x74, 0xff, 0xda, 0xd4, 0xc4, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0xf4, 0xf8, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0x53, 0x5a, 0x54, 0xff, 0x4c, 0x52, 0x4c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x52, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x53, 0x5a, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x44, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x53, 0x5a, 0x54, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x53, 0x5a, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x64, 0x4e, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x5d, 0x62, 0x5c, 0xff, 0x4c, 0x52, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x44, 0x47, 0x44, 0xff, 0x53, 0x41, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x64, 0x4e, 0x54, 0xff, 0x55, 0x4e, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x5d, 0x5a, 0x54, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x55, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x55, 0x52, 0x4c, 0xff, 0x55, 0x52, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x5d, 0x62, 0x5c, 0xff, - 0x5d, 0x5a, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x64, 0x5d, 0x5c, 0xff, - 0x63, 0x66, 0x64, 0xff, 0x78, 0x66, 0x64, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x63, 0x66, 0x64, 0xff, 0x6c, 0x61, 0x64, 0xff, 0x8e, 0x79, 0x74, 0xff, - 0x8c, 0x81, 0x84, 0xff, 0xa8, 0x93, 0x8c, 0xff, 0x8f, 0x7f, 0x7c, 0xff, - 0x72, 0x62, 0x5c, 0xff, 0x7f, 0x72, 0x6c, 0xff, 0x9d, 0x8d, 0x8c, 0xff, - 0xa8, 0x9b, 0x94, 0xff, 0x9c, 0x80, 0x7c, 0xff, 0x8e, 0x79, 0x74, 0xff, - 0x7f, 0x72, 0x6c, 0xff, 0x8f, 0x86, 0x7c, 0xff, 0xb1, 0xaa, 0xa4, 0xff, - 0xe4, 0xe2, 0xd8, 0xff, 0xf4, 0xf2, 0xe4, 0xff, 0xf3, 0xf2, 0xdc, 0xff, - 0xf4, 0xf2, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x42, 0x42, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x55, 0x4e, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x44, 0x47, 0x44, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x34, 0x32, 0x2c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x4c, 0x52, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x64, 0x4e, 0x54, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x55, 0x4e, 0x4c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x55, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x64, 0x4e, 0x54, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x55, 0x4e, 0x4c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x64, 0x5d, 0x5c, 0xff, - 0x6b, 0x56, 0x5c, 0xff, 0x55, 0x52, 0x4c, 0xff, 0x6b, 0x56, 0x5c, 0xff, - 0x53, 0x5a, 0x54, 0xff, 0x64, 0x5d, 0x5c, 0xff, 0x64, 0x5d, 0x5c, 0xff, - 0x70, 0x5e, 0x5c, 0xff, 0x5d, 0x62, 0x5c, 0xff, 0x77, 0x66, 0x6c, 0xff, - 0x7e, 0x6d, 0x6c, 0xff, 0x8f, 0x7f, 0x7c, 0xff, 0x6c, 0x61, 0x64, 0xff, - 0x64, 0x5d, 0x5c, 0xff, 0x71, 0x6a, 0x64, 0xff, 0x7e, 0x6d, 0x6c, 0xff, - 0x9d, 0x8d, 0x8c, 0xff, 0x84, 0x79, 0x7c, 0xff, 0x7f, 0x72, 0x6c, 0xff, - 0x7f, 0x72, 0x6c, 0xff, 0x7c, 0x72, 0x64, 0xff, 0x94, 0x8b, 0x84, 0xff, - 0xda, 0xd4, 0xc4, 0xff, 0xf4, 0xea, 0xe4, 0xff, 0xf2, 0xe9, 0xdc, 0xff, - 0xf4, 0xea, 0xe4, 0xff, 0xf4, 0xf8, 0xe4, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x52, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x42, 0x42, 0x44, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x33, 0x2c, 0x2c, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x52, 0x4c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x55, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x4e, 0x42, 0x44, 0xff, 0x55, 0x4e, 0x4c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x55, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x55, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x55, 0x55, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x64, 0x5d, 0x5c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x6f, 0x6c, 0x6c, 0xff, 0x78, 0x66, 0x64, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x5d, 0x5a, 0x54, 0xff, 0x63, 0x66, 0x64, 0xff, 0x81, 0x72, 0x74, 0xff, - 0x8c, 0x81, 0x84, 0xff, 0x81, 0x72, 0x74, 0xff, 0x81, 0x72, 0x74, 0xff, - 0x71, 0x6a, 0x64, 0xff, 0x63, 0x6a, 0x64, 0xff, 0x84, 0x7e, 0x74, 0xff, - 0xc2, 0xbe, 0xbc, 0xff, 0xe4, 0xe2, 0xd8, 0xff, 0xc9, 0xc0, 0xb4, 0xff, - 0xf4, 0xea, 0xe4, 0xff, 0xf4, 0xf2, 0xe4, 0xff, - 0x4c, 0x52, 0x4c, 0xff, 0x4c, 0x52, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x42, 0x42, 0x44, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x34, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x42, 0x42, 0x44, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x64, 0x4e, 0x54, 0xff, 0x42, 0x42, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x55, 0x4e, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x55, 0x52, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x55, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x55, 0x4e, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x69, 0x55, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x55, 0x55, 0x54, 0xff, 0x55, 0x4e, 0x4c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x5d, 0x5a, 0x54, 0xff, 0x55, 0x4e, 0x4c, 0xff, - 0x55, 0x4e, 0x4c, 0xff, 0x64, 0x5d, 0x5c, 0xff, 0x5d, 0x62, 0x5c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, 0x70, 0x5e, 0x5c, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x5d, 0x5a, 0x54, 0xff, 0x5d, 0x5a, 0x54, 0xff, - 0x63, 0x66, 0x64, 0xff, 0x63, 0x66, 0x64, 0xff, 0x6c, 0x61, 0x64, 0xff, - 0x81, 0x72, 0x74, 0xff, 0x84, 0x77, 0x74, 0xff, 0x77, 0x66, 0x6c, 0xff, - 0x63, 0x66, 0x64, 0xff, 0x71, 0x6a, 0x64, 0xff, 0x71, 0x72, 0x6c, 0xff, - 0xb1, 0xaa, 0xa4, 0xff, 0xd6, 0xc5, 0xbc, 0xff, 0x9a, 0x94, 0x94, 0xff, - 0xd9, 0xd4, 0xcc, 0xff, 0xe4, 0xe2, 0xd8, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x34, 0x32, 0x2c, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x34, 0x33, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x4c, 0x52, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x4c, 0x52, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x53, 0x5a, 0x54, 0xff, - 0x6b, 0x56, 0x5c, 0xff, 0x55, 0x55, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x55, 0x52, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x55, 0x4e, 0x4c, 0xff, 0x55, 0x4e, 0x4c, 0xff, 0x55, 0x4e, 0x4c, 0xff, - 0x5d, 0x5a, 0x54, 0xff, 0x64, 0x5d, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x64, 0x5d, 0x5c, 0xff, 0x55, 0x55, 0x54, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x5d, 0x62, 0x5c, 0xff, 0x63, 0x66, 0x64, 0xff, 0x55, 0x52, 0x4c, 0xff, - 0x6c, 0x61, 0x64, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x6c, 0x61, 0x64, 0xff, - 0x6c, 0x66, 0x6c, 0xff, 0x6f, 0x6c, 0x6c, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x5d, 0x62, 0x5c, 0xff, 0x71, 0x6a, 0x64, 0xff, 0x6f, 0x6c, 0x6c, 0xff, - 0x84, 0x77, 0x74, 0xff, 0x89, 0x86, 0x84, 0xff, 0x8f, 0x86, 0x7c, 0xff, - 0xcc, 0xc2, 0xbc, 0xff, 0xe4, 0xe2, 0xd8, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x53, 0x5a, 0x54, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x34, 0x2e, 0x34, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x34, 0x33, 0x34, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x53, 0x5a, 0x54, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x53, 0x5a, 0x54, 0xff, 0x44, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x53, 0x5a, 0x54, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x34, 0x33, 0x34, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x5d, 0x62, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x44, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x55, 0x4e, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x55, 0x52, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x64, 0x5d, 0x5c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, 0x69, 0x55, 0x54, 0xff, - 0x5d, 0x62, 0x5c, 0xff, 0x64, 0x5d, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x70, 0x5e, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x5d, 0x62, 0x5c, 0xff, - 0x64, 0x5d, 0x5c, 0xff, 0x5d, 0x62, 0x5c, 0xff, 0x5d, 0x62, 0x5c, 0xff, - 0x70, 0x5e, 0x5c, 0xff, 0x64, 0x5d, 0x5c, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x64, 0x5d, 0x5c, 0xff, 0x6f, 0x6c, 0x6c, 0xff, 0x71, 0x6a, 0x64, 0xff, - 0x71, 0x6a, 0x64, 0xff, 0x70, 0x66, 0x5c, 0xff, 0x72, 0x62, 0x5c, 0xff, - 0x88, 0x8a, 0x84, 0xff, 0xa8, 0x9b, 0x94, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x3b, 0x3a, 0x34, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x4c, 0x52, 0x4c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x34, 0x33, 0x34, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x52, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x34, 0x33, 0x34, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x44, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x6b, 0x56, 0x5c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, 0x4e, 0x42, 0x44, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x44, 0x3a, 0x3c, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x44, 0x3a, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x64, 0x4e, 0x54, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x55, 0x52, 0x4c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x5d, 0x5a, 0x54, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, 0x64, 0x5d, 0x5c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x55, 0x55, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x5d, 0x5a, 0x54, 0xff, 0x64, 0x5d, 0x5c, 0xff, 0x64, 0x5d, 0x5c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x64, 0x5d, 0x5c, 0xff, 0x64, 0x5d, 0x5c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x5d, 0x5a, 0x54, 0xff, 0x64, 0x5d, 0x5c, 0xff, - 0x5f, 0x62, 0x64, 0xff, 0x5f, 0x62, 0x64, 0xff, 0x5d, 0x62, 0x5c, 0xff, - 0x63, 0x66, 0x64, 0xff, 0x64, 0x5d, 0x5c, 0xff, 0x72, 0x5b, 0x54, 0xff, - 0x78, 0x77, 0x74, 0xff, 0x8f, 0x86, 0x7c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x34, 0x32, 0x2c, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x34, 0x32, 0x2c, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x53, 0x5a, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x53, 0x5a, 0x54, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x33, 0x2c, 0x2c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x3b, 0x3a, 0x34, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x55, 0x55, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x53, 0x5a, 0x54, 0xff, 0x5d, 0x5a, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x4c, 0x52, 0x4c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x55, 0x52, 0x4c, 0xff, 0x55, 0x4e, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x64, 0x5d, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x5d, 0x5a, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x64, 0x5d, 0x5c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x55, 0x52, 0x4c, 0xff, 0x64, 0x5d, 0x5c, 0xff, - 0x5d, 0x62, 0x5c, 0xff, 0x64, 0x5d, 0x5c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x70, 0x5e, 0x5c, 0xff, 0x55, 0x55, 0x54, 0xff, 0x55, 0x52, 0x4c, 0xff, - 0x70, 0x66, 0x5c, 0xff, 0x63, 0x66, 0x64, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x34, 0x33, 0x34, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x44, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x33, 0x2c, 0x2c, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x6b, 0x56, 0x5c, 0xff, - 0x55, 0x4e, 0x4c, 0xff, 0x4e, 0x42, 0x44, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4c, 0x52, 0x4c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x55, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x4e, 0x42, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x55, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x55, 0x4e, 0x4c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x55, 0x4e, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x52, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x55, 0x52, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x55, 0x4e, 0x4c, 0xff, 0x55, 0x4e, 0x4c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x58, 0x49, 0x4c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x69, 0x55, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x64, 0x5d, 0x5c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x55, 0x52, 0x4c, 0xff, 0x55, 0x4e, 0x4c, 0xff, - 0x55, 0x52, 0x4c, 0xff, 0x69, 0x55, 0x54, 0xff, 0x55, 0x52, 0x4c, 0xff, - 0x64, 0x5d, 0x5c, 0xff, 0x5d, 0x5a, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x53, 0x5a, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x33, 0x2c, 0x2c, 0xff, 0x30, 0x2a, 0x24, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x52, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x42, 0x42, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x52, 0x4c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x53, 0x5a, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x33, 0x2c, 0x2c, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x34, 0x2e, 0x34, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x55, 0x4e, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x44, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x58, 0x49, 0x4c, 0xff, 0x64, 0x4e, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x55, 0x4e, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x4c, 0x52, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x55, 0x52, 0x4c, 0xff, 0x5d, 0x5a, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x55, 0x52, 0x4c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x55, 0x4e, 0x4c, 0xff, - 0x55, 0x52, 0x4c, 0xff, 0x64, 0x5d, 0x5c, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x55, 0x55, 0x54, 0xff, 0x55, 0x4e, 0x4c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x64, 0x5d, 0x5c, 0xff, 0x55, 0x4e, 0x4c, 0xff, 0x55, 0x52, 0x4c, 0xff, - 0x55, 0x52, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, 0x55, 0x4e, 0x4c, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x55, 0x4e, 0x4c, 0xff, 0x5d, 0x5a, 0x54, 0xff, - 0x5d, 0x5a, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x34, 0x32, 0x2c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x30, 0x2a, 0x24, 0xff, 0x2c, 0x26, 0x2c, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x34, 0x33, 0x34, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x53, 0x5a, 0x54, 0xff, 0x53, 0x5a, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x64, 0x4e, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x55, 0x4e, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x55, 0x4e, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x55, 0x52, 0x4c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x58, 0x49, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, 0x55, 0x4e, 0x4c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, 0x55, 0x52, 0x4c, 0xff, - 0x55, 0x4e, 0x4c, 0xff, 0x55, 0x52, 0x4c, 0xff, 0x55, 0x52, 0x4c, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x55, 0x4e, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x2c, 0x26, 0x2c, 0xff, 0x34, 0x32, 0x2c, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x3b, 0x3a, 0x34, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x55, 0x4e, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x55, 0x55, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x53, 0x41, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x4e, 0x42, 0x44, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, 0x55, 0x4e, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4e, 0x42, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x4e, 0x42, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x55, 0x52, 0x4c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x53, 0x5a, 0x54, 0xff, 0x55, 0x52, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x55, 0x4e, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x55, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x55, 0x4e, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x55, 0x4e, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x69, 0x55, 0x54, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x55, 0x52, 0x4c, 0xff, 0x5d, 0x5a, 0x54, 0xff, - 0x50, 0x4e, 0x44, 0xff, 0x55, 0x52, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x34, 0x33, 0x34, 0xff, 0x34, 0x32, 0x2c, 0xff, - 0x34, 0x32, 0x2c, 0xff, 0x33, 0x2c, 0x2c, 0xff, 0x34, 0x32, 0x2c, 0xff, - 0x33, 0x2c, 0x2c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x55, 0x52, 0x4c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x55, 0x55, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x64, 0x4e, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x55, 0x55, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x34, 0x33, 0x34, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x64, 0x4e, 0x54, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x55, 0x52, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x6b, 0x56, 0x5c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x55, 0x52, 0x4c, 0xff, 0x58, 0x49, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x55, 0x4e, 0x4c, 0xff, 0x55, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x55, 0x4e, 0x4c, 0xff, 0x5d, 0x5a, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x55, 0x52, 0x4c, 0xff, 0x55, 0x52, 0x4c, 0xff, - 0x55, 0x4e, 0x4c, 0xff, 0x55, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x3b, 0x3a, 0x34, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x34, 0x33, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x34, 0x33, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x34, 0x33, 0x34, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x33, 0x2c, 0x2c, 0xff, - 0x44, 0x3a, 0x3c, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x5d, 0x5a, 0x54, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x44, 0x3a, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x55, 0x4e, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x52, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x55, 0x52, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4c, 0x52, 0x4c, 0xff, 0x53, 0x5a, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x55, 0x4e, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, 0x55, 0x4e, 0x4c, 0xff, - 0x55, 0x4e, 0x4c, 0xff, 0x50, 0x4e, 0x44, 0xff, 0x55, 0x52, 0x4c, 0xff, - 0x55, 0x52, 0x4c, 0xff, 0x50, 0x4e, 0x44, 0xff, 0x55, 0x4e, 0x4c, 0xff, - 0x4c, 0x52, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x34, 0x33, 0x34, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x33, 0x2c, 0x2c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x3b, 0x3a, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x34, 0x2e, 0x34, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x33, 0x2c, 0x2c, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x44, 0x46, 0x3c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x34, 0x33, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x55, 0x4e, 0x4c, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x55, 0x52, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x53, 0x41, 0x3c, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x44, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, 0x5d, 0x5a, 0x54, 0xff, - 0x55, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x55, 0x4e, 0x4c, 0xff, - 0x55, 0x52, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x55, 0x52, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x55, 0x4e, 0x4c, 0xff, 0x55, 0x52, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x52, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x34, 0x33, 0x34, 0xff, 0x33, 0x2c, 0x2c, 0xff, - 0x33, 0x2c, 0x2c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x34, 0x32, 0x2c, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x33, 0x2c, 0x2c, 0xff, - 0x33, 0x2c, 0x2c, 0xff, 0x34, 0x33, 0x34, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x42, 0x42, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x55, 0x55, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x64, 0x5d, 0x5c, 0xff, 0x55, 0x55, 0x54, 0xff, 0x64, 0x4e, 0x54, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x34, 0x33, 0x34, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x55, 0x4e, 0x4c, 0xff, 0x58, 0x49, 0x4c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x53, 0x41, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x53, 0x5a, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x4e, 0x42, 0x44, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x64, 0x4e, 0x54, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x55, 0x4e, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x50, 0x4e, 0x44, 0xff, 0x55, 0x52, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x50, 0x4e, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x44, 0x3a, 0x3c, 0xff, 0x34, 0x32, 0x2c, 0xff, - 0x33, 0x2c, 0x2c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x44, 0x46, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x34, 0x32, 0x2c, 0xff, 0x34, 0x33, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x33, 0x2c, 0x2c, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x44, 0x3a, 0x3c, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x55, 0x52, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x55, 0x4e, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x4e, 0x42, 0x44, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x55, 0x4e, 0x4c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x5d, 0x5a, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x50, 0x4e, 0x44, 0xff, 0x44, 0x46, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, 0x53, 0x5a, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x4e, 0x42, 0x44, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x3b, 0x3a, 0x34, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x3b, 0x3a, 0x34, 0xff, 0x30, 0x2a, 0x24, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x3c, 0x32, 0x2c, 0xff, 0x3c, 0x32, 0x2c, 0xff, - 0x33, 0x2c, 0x2c, 0xff, 0x33, 0x2c, 0x2c, 0xff, 0x33, 0x2c, 0x2c, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x55, 0x4e, 0x4c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x34, 0x32, 0x2c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x44, 0x3a, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x55, 0x52, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x64, 0x5d, 0x5c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x34, 0x2e, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x53, 0x5a, 0x54, 0xff, 0x5f, 0x62, 0x64, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x4e, 0x42, 0x44, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x4e, 0x42, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x55, 0x52, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x44, 0x46, 0x3c, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x50, 0x4e, 0x44, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x3b, 0x3a, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x44, 0x3a, 0x3c, 0xff, - 0x33, 0x2c, 0x2c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x44, 0x47, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x30, 0x2a, 0x24, 0xff, - 0x34, 0x32, 0x2c, 0xff, 0x30, 0x2a, 0x24, 0xff, 0x33, 0x2c, 0x2c, 0xff, - 0x33, 0x2c, 0x2c, 0xff, 0x30, 0x2a, 0x24, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x64, 0x4e, 0x54, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x3c, 0x32, 0x2c, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x44, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x55, 0x4e, 0x4c, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x34, 0x33, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x64, 0x4e, 0x54, 0xff, 0x44, 0x46, 0x3c, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x53, 0x5a, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x55, 0x4e, 0x4c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x44, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x4e, 0x42, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x55, 0x4e, 0x4c, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x55, 0x52, 0x4c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x55, 0x52, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x55, 0x52, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x34, 0x33, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x34, 0x2e, 0x34, 0xff, 0x33, 0x2c, 0x2c, 0xff, - 0x33, 0x2c, 0x2c, 0xff, 0x3b, 0x3a, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x34, 0x32, 0x2c, 0xff, 0x30, 0x2a, 0x24, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x3c, 0x32, 0x2c, 0xff, 0x30, 0x2a, 0x24, 0xff, - 0x30, 0x2a, 0x24, 0xff, 0x33, 0x2c, 0x2c, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x4c, 0x52, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4c, 0x52, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x34, 0x33, 0x34, 0xff, 0x33, 0x2c, 0x2c, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x34, 0x32, 0x2c, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x55, 0x52, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x58, 0x49, 0x4c, 0xff, - 0x4c, 0x52, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x53, 0x5a, 0x54, 0xff, 0x55, 0x4e, 0x4c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x44, 0x3a, 0x3c, 0xff, 0x3b, 0x3a, 0x34, 0xff, 0x4e, 0x42, 0x44, 0xff, - 0x44, 0x3a, 0x3c, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x44, 0x3a, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x53, 0x41, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x55, 0x4e, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x55, 0x4e, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x44, 0x46, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x44, 0x46, 0x3c, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x33, 0x2c, 0x2c, 0xff, 0x30, 0x26, 0x24, 0xff, - 0x33, 0x2c, 0x2c, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x34, 0x32, 0x2c, 0xff, 0x33, 0x2c, 0x2c, 0xff, 0x30, 0x26, 0x24, 0xff, - 0x30, 0x2a, 0x24, 0xff, 0x30, 0x26, 0x24, 0xff, 0x30, 0x26, 0x24, 0xff, - 0x30, 0x26, 0x24, 0xff, 0x30, 0x2a, 0x24, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x55, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x44, 0x47, 0x44, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x33, 0x2c, 0x2c, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x34, 0x32, 0x2c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x44, 0x46, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x34, 0x32, 0x2c, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x34, 0x33, 0x34, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x55, 0x4e, 0x4c, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, 0x58, 0x49, 0x4c, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x55, 0x4e, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x52, 0x4c, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x44, 0x3a, 0x3c, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x34, 0x33, 0x34, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x58, 0x49, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x55, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x44, 0x46, 0x3c, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x34, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x34, 0x33, 0x34, 0xff, 0x33, 0x2c, 0x2c, 0xff, - 0x30, 0x2a, 0x24, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x33, 0x2c, 0x2c, 0xff, 0x30, 0x26, 0x24, 0xff, - 0x30, 0x26, 0x24, 0xff, 0x30, 0x26, 0x24, 0xff, 0x30, 0x26, 0x24, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x34, 0x32, 0x2c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x3b, 0x3a, 0x34, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x4c, 0x52, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x33, 0x2c, 0x2c, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x3b, 0x3a, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x34, 0x33, 0x34, 0xff, 0x3c, 0x32, 0x2c, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x3c, 0x32, 0x2c, 0xff, 0x34, 0x32, 0x2c, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x3c, 0x32, 0x2c, 0xff, - 0x3c, 0x32, 0x2c, 0xff, 0x34, 0x2e, 0x34, 0xff, 0x3c, 0x32, 0x2c, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x58, 0x49, 0x4c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x4e, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x55, 0x55, 0x54, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x44, 0x3a, 0x3c, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x53, 0x41, 0x3c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x53, 0x41, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x55, 0x52, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x34, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x4c, 0x52, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x58, 0x5c, 0x5c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x34, 0x2e, 0x34, 0xff, 0x33, 0x2c, 0x2c, 0xff, - 0x33, 0x2c, 0x2c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x33, 0x2c, 0x2c, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x2c, 0x26, 0x2c, 0xff, 0x30, 0x26, 0x24, 0xff, 0x30, 0x26, 0x24, 0xff, - 0x30, 0x26, 0x24, 0xff, 0x30, 0x26, 0x24, 0xff, 0x30, 0x2a, 0x24, 0xff, - 0x33, 0x2c, 0x2c, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4c, 0x52, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x33, 0x2c, 0x2c, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x3b, 0x3a, 0x34, 0xff, 0x3c, 0x2e, 0x2c, 0xff, - 0x3c, 0x2e, 0x2c, 0xff, 0x3c, 0x32, 0x2c, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x3c, 0x2e, 0x2c, 0xff, - 0x3c, 0x2e, 0x2c, 0xff, 0x34, 0x33, 0x34, 0xff, 0x3c, 0x2e, 0x2c, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x4e, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x4e, 0x42, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x58, 0x49, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x53, 0x41, 0x3c, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x3c, 0x2e, 0x2c, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x34, 0x2e, 0x34, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x64, 0x4e, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x44, 0x3a, 0x3c, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x44, 0x47, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x42, 0x42, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x34, 0x33, 0x34, 0xff, 0x33, 0x2c, 0x2c, 0xff, - 0x34, 0x32, 0x2c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x33, 0x2c, 0x2c, 0xff, 0x34, 0x32, 0x2c, 0xff, 0x34, 0x32, 0x2c, 0xff, - 0x30, 0x26, 0x24, 0xff, 0x30, 0x26, 0x24, 0xff, 0x30, 0x26, 0x24, 0xff, - 0x30, 0x26, 0x24, 0xff, 0x2c, 0x26, 0x2c, 0xff, 0x30, 0x26, 0x24, 0xff, - 0x33, 0x2c, 0x2c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x34, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x44, 0x46, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x3b, 0x3a, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4c, 0x52, 0x4c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x33, 0x2c, 0x2c, 0xff, 0x34, 0x32, 0x2c, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x3c, 0x2e, 0x2c, 0xff, - 0x33, 0x2c, 0x2c, 0xff, 0x3c, 0x32, 0x2c, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x3c, 0x32, 0x2c, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x3c, 0x2e, 0x2c, 0xff, 0x33, 0x2c, 0x2c, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x55, 0x52, 0x4c, 0xff, - 0x4e, 0x42, 0x44, 0xff, 0x34, 0x33, 0x34, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x44, 0x3a, 0x3c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x55, 0x4e, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x5d, 0x5a, 0x54, 0xff, 0x6b, 0x56, 0x5c, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x53, 0x41, 0x3c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x44, 0x3a, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x4e, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x4c, 0x52, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x44, 0x3a, 0x3c, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x4e, 0x42, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x4e, 0x42, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x33, 0x2c, 0x2c, 0xff, 0x30, 0x26, 0x24, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x30, 0x2a, 0x24, 0xff, - 0x33, 0x2c, 0x2c, 0xff, 0x34, 0x2e, 0x34, 0xff, 0x33, 0x2c, 0x2c, 0xff, - 0x30, 0x26, 0x24, 0xff, 0x30, 0x26, 0x24, 0xff, 0x30, 0x26, 0x24, 0xff, - 0x30, 0x26, 0x24, 0xff, 0x33, 0x2c, 0x2c, 0xff, 0x30, 0x26, 0x24, 0xff, - 0x30, 0x26, 0x24, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x3b, 0x3a, 0x34, 0xff, 0x34, 0x32, 0x2c, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x3b, 0x3a, 0x34, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x34, 0x33, 0x34, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x3c, 0x2e, 0x2c, 0xff, 0x34, 0x33, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x3c, 0x32, 0x2c, 0xff, 0x34, 0x33, 0x34, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x3b, 0x3a, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x3c, 0x32, 0x2c, 0xff, 0x3c, 0x32, 0x2c, 0xff, - 0x3c, 0x2e, 0x2c, 0xff, 0x3c, 0x2e, 0x2c, 0xff, 0x3c, 0x2e, 0x2c, 0xff, - 0x5c, 0x3e, 0x34, 0xff, 0x3c, 0x32, 0x2c, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x3c, 0x2e, 0x2c, 0xff, 0x34, 0x33, 0x34, 0xff, 0x33, 0x2c, 0x2c, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x58, 0x49, 0x4c, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x3c, 0x2e, 0x2c, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x53, 0x41, 0x3c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x44, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x5d, 0x62, 0x5c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x3c, 0x2e, 0x2c, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x44, 0x3a, 0x3c, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x4e, 0x42, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x44, 0x3a, 0x3c, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x44, 0x47, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x53, 0x5a, 0x54, 0xff, 0x44, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x34, 0x2e, 0x34, 0xff, 0x33, 0x2c, 0x2c, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x33, 0x2c, 0x2c, 0xff, - 0x2c, 0x26, 0x2c, 0xff, 0x30, 0x2a, 0x24, 0xff, 0x30, 0x26, 0x24, 0xff, - 0x30, 0x26, 0x24, 0xff, 0x30, 0x26, 0x24, 0xff, 0x30, 0x26, 0x24, 0xff, - 0x30, 0x26, 0x24, 0xff, 0x30, 0x26, 0x24, 0xff, 0x30, 0x26, 0x24, 0xff, - 0x2c, 0x26, 0x2c, 0xff, 0x44, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x34, 0x33, 0x34, 0xff, 0x2c, 0x26, 0x2c, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x33, 0x2c, 0x2c, 0xff, 0x33, 0x2c, 0x2c, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x34, 0x33, 0x34, 0xff, 0x33, 0x2c, 0x2c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x33, 0x2c, 0x2c, 0xff, 0x33, 0x2c, 0x2c, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x3b, 0x3a, 0x34, 0xff, 0x33, 0x2c, 0x2c, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x34, 0x32, 0x2c, 0xff, 0x33, 0x2c, 0x2c, 0xff, - 0x3c, 0x2e, 0x2c, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x33, 0x2c, 0x2c, 0xff, - 0x33, 0x2c, 0x2c, 0xff, 0x3c, 0x2e, 0x2c, 0xff, 0x3c, 0x2e, 0x2c, 0xff, - 0x3c, 0x2e, 0x2c, 0xff, 0x33, 0x2c, 0x2c, 0xff, 0x3c, 0x2e, 0x2c, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x55, 0x4e, 0x4c, 0xff, 0x55, 0x4e, 0x4c, 0xff, - 0x55, 0x4e, 0x4c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x3c, 0x2e, 0x2c, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x44, 0x3a, 0x3c, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x4e, 0x42, 0x44, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x44, 0x3a, 0x3c, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x58, 0x5c, 0x5c, 0xff, 0x55, 0x55, 0x54, 0xff, 0x55, 0x4e, 0x4c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x34, 0x33, 0x34, 0xff, 0x3c, 0x2e, 0x2c, 0xff, - 0x33, 0x2c, 0x2c, 0xff, 0x44, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x4e, 0x42, 0x44, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x2c, 0x26, 0x2c, 0xff, 0x30, 0x2a, 0x24, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x42, 0x42, 0x44, 0xff, 0x34, 0x32, 0x2c, 0xff, - 0x30, 0x2a, 0x24, 0xff, 0x2c, 0x26, 0x2c, 0xff, 0x30, 0x26, 0x24, 0xff, - 0x30, 0x26, 0x24, 0xff, 0x30, 0x26, 0x24, 0xff, 0x30, 0x26, 0x24, 0xff, - 0x30, 0x26, 0x24, 0xff, 0x2c, 0x26, 0x2c, 0xff, 0x30, 0x2a, 0x24, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x44, 0x47, 0x44, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x34, 0x32, 0x2c, 0xff, 0x33, 0x2c, 0x2c, 0xff, - 0x34, 0x32, 0x2c, 0xff, 0x33, 0x2c, 0x2c, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x34, 0x33, 0x34, 0xff, 0x33, 0x2c, 0x2c, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x33, 0x2c, 0x2c, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x33, 0x2c, 0x2c, 0xff, 0x33, 0x2c, 0x2c, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x33, 0x2c, 0x2c, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x34, 0x32, 0x2c, 0xff, 0x3c, 0x2e, 0x2c, 0xff, 0x30, 0x2a, 0x24, 0xff, - 0x3c, 0x2e, 0x2c, 0xff, 0x3c, 0x2e, 0x2c, 0xff, 0x3c, 0x2e, 0x2c, 0xff, - 0x33, 0x2c, 0x2c, 0xff, 0x3c, 0x2e, 0x2c, 0xff, 0x33, 0x2c, 0x2c, 0xff, - 0x3c, 0x2e, 0x2c, 0xff, 0x33, 0x2c, 0x2c, 0xff, 0x30, 0x26, 0x24, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x55, 0x55, 0x54, 0xff, 0x58, 0x49, 0x4c, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x44, 0x3a, 0x3c, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x42, 0x42, 0x44, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x55, 0x4e, 0x4c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x33, 0x2c, 0x2c, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x44, 0x3a, 0x3c, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x44, 0x3a, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x53, 0x5a, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x30, 0x26, 0x24, 0xff, 0x33, 0x2c, 0x2c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x55, 0x4e, 0x4c, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x33, 0x2c, 0x2c, 0xff, 0x33, 0x2c, 0x2c, 0xff, 0x2c, 0x26, 0x2c, 0xff, - 0x2c, 0x26, 0x2c, 0xff, 0x2c, 0x26, 0x2c, 0xff, 0x30, 0x26, 0x24, 0xff, - 0x2c, 0x26, 0x2c, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x30, 0x26, 0x24, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x42, 0x42, 0x44, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x33, 0x2c, 0x2c, 0xff, 0x33, 0x2c, 0x2c, 0xff, - 0x33, 0x2c, 0x2c, 0xff, 0x34, 0x33, 0x34, 0xff, 0x33, 0x2c, 0x2c, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x30, 0x2a, 0x24, 0xff, 0x34, 0x2e, 0x34, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x34, 0x2e, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x34, 0x32, 0x2c, 0xff, 0x3c, 0x2e, 0x2c, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x34, 0x33, 0x34, 0xff, 0x33, 0x2c, 0x2c, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x4e, 0x42, 0x44, 0xff, 0x33, 0x2c, 0x2c, 0xff, 0x3c, 0x2e, 0x2c, 0xff, - 0x3c, 0x2e, 0x2c, 0xff, 0x30, 0x2a, 0x24, 0xff, 0x3c, 0x2e, 0x2c, 0xff, - 0x30, 0x2a, 0x24, 0xff, 0x3c, 0x2e, 0x2c, 0xff, 0x30, 0x2a, 0x24, 0xff, - 0x33, 0x2c, 0x2c, 0xff, 0x34, 0x2e, 0x34, 0xff, 0x33, 0x2c, 0x2c, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x4e, 0x42, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x34, 0x32, 0x2c, 0xff, 0x34, 0x33, 0x34, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x55, 0x52, 0x4c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x33, 0x2c, 0x2c, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x44, 0x3a, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x44, 0x3a, 0x3c, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x49, 0x4a, 0x4c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x30, 0x26, 0x24, 0xff, 0x33, 0x2c, 0x2c, 0xff, - 0x4c, 0x47, 0x44, 0xff, 0x4c, 0x53, 0x54, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x34, 0x32, 0x2c, 0xff, - 0x3c, 0x2e, 0x2c, 0xff, 0x30, 0x26, 0x24, 0xff, 0x30, 0x26, 0x24, 0xff, - 0x2c, 0x26, 0x2c, 0xff, 0x44, 0x3a, 0x3c, 0xff, 0x2c, 0x26, 0x2c, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x55, 0x55, 0x54, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x33, 0x2c, 0x2c, 0xff, 0x34, 0x32, 0x2c, 0xff, - 0x33, 0x2c, 0x2c, 0xff, 0x33, 0x2c, 0x2c, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x44, 0x3a, 0x3c, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x44, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x42, 0x42, 0x44, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, - 0x30, 0x2a, 0x24, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x3b, 0x3a, 0x34, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x4c, 0x53, 0x54, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x33, 0x2c, 0x2c, 0xff, 0x33, 0x2c, 0x2c, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x34, 0x33, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x33, 0x2c, 0x2c, 0xff, 0x34, 0x33, 0x34, 0xff, - 0x33, 0x2c, 0x2c, 0xff, 0x34, 0x32, 0x2c, 0xff, 0x34, 0x32, 0x2c, 0xff, - 0x34, 0x33, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x3c, 0x2e, 0x2c, 0xff, 0x3c, 0x2e, 0x2c, 0xff, - 0x3c, 0x2e, 0x2c, 0xff, 0x30, 0x26, 0x24, 0xff, 0x30, 0x26, 0x24, 0xff, - 0x3c, 0x2e, 0x2c, 0xff, 0x30, 0x2a, 0x24, 0xff, 0x33, 0x2c, 0x2c, 0xff, - 0x33, 0x2c, 0x2c, 0xff, 0x30, 0x2a, 0x24, 0xff, 0x33, 0x2c, 0x2c, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x55, 0x52, 0x4c, 0xff, 0x55, 0x52, 0x4c, 0xff, 0x4e, 0x42, 0x44, 0xff, - 0x3c, 0x32, 0x2c, 0xff, 0x33, 0x2c, 0x2c, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x3b, 0x3a, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x4c, 0x53, 0x54, 0xff, 0x55, 0x55, 0x54, 0xff, 0x4c, 0x52, 0x4c, 0xff, - 0x4b, 0x4e, 0x4c, 0xff, 0x55, 0x55, 0x54, 0xff, 0x4b, 0x4e, 0x4c, 0xff, - 0x49, 0x4a, 0x4c, 0xff, 0x34, 0x32, 0x2c, 0xff, 0x34, 0x32, 0x2c, 0xff, - 0x33, 0x2c, 0x2c, 0xff, 0x44, 0x3a, 0x3c, 0xff, 0x4e, 0x42, 0x44, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x34, 0x2e, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x3c, 0x35, 0x34, 0xff, 0x3b, 0x3a, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x3b, 0x3a, 0x34, 0xff, 0x44, 0x3a, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, 0x49, 0x4a, 0x4c, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x3c, 0x35, 0x34, 0xff, 0x3c, 0x35, 0x34, 0xff, - 0x3b, 0x3a, 0x3c, 0xff, 0x40, 0x3f, 0x3c, 0xff, 0x44, 0x47, 0x44, 0xff, - 0x44, 0x47, 0x44, 0xff, 0x4c, 0x47, 0x44, 0xff, -}; - -#endif // WEBP_TESTS_FUZZER_IMG_PEAK_H_ diff --git a/libwebp/tests/fuzzer/makefile.unix b/libwebp/tests/fuzzer/makefile.unix deleted file mode 100644 index 3a3aff0a..00000000 --- a/libwebp/tests/fuzzer/makefile.unix +++ /dev/null @@ -1,31 +0,0 @@ -# This Makefile will compile all fuzzing targets. It doesn't check tool -# requirements and paths may need to be updated depending on your environment. -# Note a clang 6+ toolchain is assumed for use of -fsanitize=fuzzer. - -CC = clang -CXX = clang++ -CFLAGS = -fsanitize=fuzzer -I../../src -I../.. -Wall -Wextra -CXXFLAGS = $(CFLAGS) -LDFLAGS = -fsanitize=fuzzer -LDLIBS = ../../src/mux/libwebpmux.a ../../src/demux/libwebpdemux.a -LDLIBS += ../../src/libwebp.a ../../imageio/libimageio_util.a -LDLIBS += ../../sharpyuv/libsharpyuv.a - -FUZZERS = advanced_api_fuzzer animation_api_fuzzer animdecoder_fuzzer -FUZZERS += animencoder_fuzzer enc_dec_fuzzer huffman_fuzzer -FUZZERS += mux_demux_api_fuzzer simple_api_fuzzer - -%.o: fuzz_utils.h img_alpha.h img_grid.h img_peak.h -all: $(FUZZERS) - -define FUZZER_template -$(1): $$(addsuffix .o, $(1)) $(LDLIBS) -OBJS += $$(addsuffix .o, $(1)) -endef - -$(foreach fuzzer, $(FUZZERS), $(eval $(call FUZZER_template, $(fuzzer)))) - -clean: - $(RM) $(FUZZERS) $(OBJS) - -.PHONY: all clean diff --git a/libwebp/tests/fuzzer/mux_demux_api_fuzzer.c b/libwebp/tests/fuzzer/mux_demux_api_fuzzer.c deleted file mode 100644 index f5983e8d..00000000 --- a/libwebp/tests/fuzzer/mux_demux_api_fuzzer.c +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2018 Google Inc. -// -// 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. -// -//////////////////////////////////////////////////////////////////////////////// - -#include "./fuzz_utils.h" -#include "src/webp/demux.h" -#include "src/webp/mux.h" - -int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) { - WebPData webp_data; - WebPDataInit(&webp_data); - webp_data.size = size; - webp_data.bytes = data; - - // Extracted chunks and frames are not processed or decoded, - // which is already covered extensively by the other fuzz targets. - - if (size & 1) { - // Mux API - WebPMux* mux = WebPMuxCreate(&webp_data, size & 2); - if (!mux) return 0; - - WebPData chunk; - (void)WebPMuxGetChunk(mux, "EXIF", &chunk); - (void)WebPMuxGetChunk(mux, "ICCP", &chunk); - (void)WebPMuxGetChunk(mux, "FUZZ", &chunk); // unknown - - uint32_t flags; - (void)WebPMuxGetFeatures(mux, &flags); - - WebPMuxAnimParams params; - (void)WebPMuxGetAnimationParams(mux, ¶ms); - - WebPMuxError status; - WebPMuxFrameInfo info; - for (int i = 0; i < kFuzzFrameLimit; i++) { - status = WebPMuxGetFrame(mux, i + 1, &info); - if (status == WEBP_MUX_NOT_FOUND) { - break; - } else if (status == WEBP_MUX_OK) { - WebPDataClear(&info.bitstream); - } - } - - WebPMuxDelete(mux); - } else { - // Demux API - WebPDemuxer* demux; - if (size & 2) { - WebPDemuxState state; - demux = WebPDemuxPartial(&webp_data, &state); - if (state < WEBP_DEMUX_PARSED_HEADER) { - WebPDemuxDelete(demux); - return 0; - } - } else { - demux = WebPDemux(&webp_data); - if (!demux) return 0; - } - - WebPChunkIterator chunk_iter; - if (WebPDemuxGetChunk(demux, "EXIF", 1, &chunk_iter)) { - (void)WebPDemuxNextChunk(&chunk_iter); - } - WebPDemuxReleaseChunkIterator(&chunk_iter); - if (WebPDemuxGetChunk(demux, "ICCP", 0, &chunk_iter)) { // 0 == last - (void)WebPDemuxPrevChunk(&chunk_iter); - } - WebPDemuxReleaseChunkIterator(&chunk_iter); - // Skips FUZZ because the Demux API has no concept of (un)known chunks. - - WebPIterator iter; - if (WebPDemuxGetFrame(demux, 1, &iter)) { - for (int i = 1; i < kFuzzFrameLimit; i++) { - if (!WebPDemuxNextFrame(&iter)) break; - } - } - - WebPDemuxReleaseIterator(&iter); - WebPDemuxDelete(demux); - } - - return 0; -} diff --git a/libwebp/tests/fuzzer/simple_api_fuzzer.c b/libwebp/tests/fuzzer/simple_api_fuzzer.c deleted file mode 100644 index 3a4288a4..00000000 --- a/libwebp/tests/fuzzer/simple_api_fuzzer.c +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2018 Google Inc. -// -// 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. -// -//////////////////////////////////////////////////////////////////////////////// - -#include "./fuzz_utils.h" -#include "src/webp/decode.h" - -int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) { - int w, h; - if (!WebPGetInfo(data, size, &w, &h)) return 0; - if ((size_t)w * h > kFuzzPxLimit) return 0; - - const uint8_t value = FuzzHash(data, size); - uint8_t* buf = NULL; - - // For *Into functions, which decode into an external buffer, an - // intentionally too small buffer can be given with low probability. - if (value < 0x16) { - buf = WebPDecodeRGBA(data, size, &w, &h); - } else if (value < 0x2b) { - buf = WebPDecodeBGRA(data, size, &w, &h); -#if !defined(WEBP_REDUCE_CSP) - } else if (value < 0x40) { - buf = WebPDecodeARGB(data, size, &w, &h); - } else if (value < 0x55) { - buf = WebPDecodeRGB(data, size, &w, &h); - } else if (value < 0x6a) { - buf = WebPDecodeBGR(data, size, &w, &h); -#endif // !defined(WEBP_REDUCE_CSP) - } else if (value < 0x7f) { - uint8_t *u, *v; - int stride, uv_stride; - buf = WebPDecodeYUV(data, size, &w, &h, &u, &v, &stride, &uv_stride); - } else if (value < 0xe8) { - const int stride = (value < 0xbe ? 4 : 3) * w; - size_t buf_size = stride * h; - if (value % 0x10 == 0) buf_size--; - uint8_t* const ext_buf = (uint8_t*)malloc(buf_size); - if (value < 0x94) { - (void)WebPDecodeRGBAInto(data, size, ext_buf, buf_size, stride); -#if !defined(WEBP_REDUCE_CSP) - } else if (value < 0xa9) { - (void)WebPDecodeARGBInto(data, size, ext_buf, buf_size, stride); - } else if (value < 0xbe) { - (void)WebPDecodeBGRInto(data, size, ext_buf, buf_size, stride); - } else if (value < 0xd3) { - (void)WebPDecodeRGBInto(data, size, ext_buf, buf_size, stride); -#endif // !defined(WEBP_REDUCE_CSP) - } else { - (void)WebPDecodeBGRAInto(data, size, ext_buf, buf_size, stride); - } - free(ext_buf); - } else { - size_t luma_size = w * h; - const int uv_stride = (w + 1) / 2; - size_t u_size = uv_stride * (h + 1) / 2; - size_t v_size = uv_stride * (h + 1) / 2; - if (value % 0x10 == 0) { - if (size & 1) luma_size--; - if (size & 2) u_size--; - if (size & 4) v_size--; - } - uint8_t* const luma_buf = (uint8_t*)malloc(luma_size); - uint8_t* const u_buf = (uint8_t*)malloc(u_size); - uint8_t* const v_buf = (uint8_t*)malloc(v_size); - (void)WebPDecodeYUVInto(data, size, luma_buf, luma_size, - w /* luma_stride */, u_buf, u_size, uv_stride, - v_buf, v_size, uv_stride); - free(luma_buf); - free(u_buf); - free(v_buf); - } - - if (buf) WebPFree(buf); - - return 0; -} diff --git a/libwebp/webp_js/README.md b/libwebp/webp_js/README.md deleted file mode 100644 index ae9ce8f0..00000000 --- a/libwebp/webp_js/README.md +++ /dev/null @@ -1,60 +0,0 @@ -# WebP JavaScript decoder - -``` - __ __ ____ ____ ____ __ ____ -/ \\/ \ _ \ _ \ _ \ (__)/ __\ -\ / __/ _ \ __/ _) \_ \ - \__\__/_____/____/_/ /____/____/ -``` - -This file describes the compilation of libwebp into a JavaScript decoder using -Emscripten and CMake. - -- install the Emscripten SDK following the procedure described at: - https://emscripten.org/docs/getting_started/downloads.html#installation-instructions-using-the-emsdk-recommended - After installation, you should have some global variable positioned to the - location of the SDK. In particular, $EMSDK should point to the top-level - directory containing Emscripten tools. - -- configure the project 'WEBP_JS' with CMake using: - - ```shell - cd webp_js && \ - emcmake cmake -DWEBP_BUILD_WEBP_JS=ON ../ - ``` - -- compile webp.js using 'emmake make'. - -- that's it! Upon completion, you should have the 'webp.js', 'webp.js.mem', - 'webp_wasm.js' and 'webp_wasm.wasm' files generated. - -The callable JavaScript function is WebPToSDL(), which decodes a raw WebP -bitstream into a canvas. See webp_js/index.html for a simple usage sample (see -below for instructions). - -## Demo HTML page - -The HTML page webp_js/index.html requires the built files 'webp.js' and -'webp.js.mem' to be copied to webp_js/. An HTTP server to serve the WebP image -example is also needed. With Python, just run: - -```shell -cd webp_js && python3 -m http.server 8080 -``` - -and then navigate to http://localhost:8080 in your favorite browser. - -## Web-Assembly (WASM) version: - -CMakeLists.txt is configured to build the WASM version when using the option -WEBP_BUILD_WEBP_JS=ON. The compilation step will assemble the files -'webp_wasm.js' and 'webp_wasm.wasm' that you then need to copy to the webp_js/ -directory. - -See webp_js/index_wasm.html for a simple demo page using the WASM version of the -library. - -## Caveats - -- First decoding using the library is usually slower, due to just-in-time - compilation. diff --git a/libwebp/webp_js/index.html b/libwebp/webp_js/index.html deleted file mode 100644 index 33cacb4c..00000000 --- a/libwebp/webp_js/index.html +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - simple Javascript WebP decoding demo - - - - - - -

- WebP in JavaScript demo - -

-

- WebP decoder in JavaScript, using libwebp compiled with - Emscripten. -

-

- -

-

Timing: N/A

- Your browser does not support canvas - - - diff --git a/libwebp/webp_js/index_wasm.html b/libwebp/webp_js/index_wasm.html deleted file mode 100644 index 7a9b362a..00000000 --- a/libwebp/webp_js/index_wasm.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - simple Javascript WebP decoding demo, using Web-Assembly (WASM) - - - - - - -

- WebP demo using Web-Assembly - -

-

- WASM version of the WebP decoder, using libwebp compiled with - Emscripten. -

-

- -

-

Timing: N/A

- Your browser does not support canvas - - diff --git a/libwebp/webp_js/test_webp_js.webp b/libwebp/webp_js/test_webp_js.webp deleted file mode 100644 index f798f556..00000000 Binary files a/libwebp/webp_js/test_webp_js.webp and /dev/null differ diff --git a/libwebp/webp_js/test_webp_wasm.webp b/libwebp/webp_js/test_webp_wasm.webp deleted file mode 100644 index f798f556..00000000 Binary files a/libwebp/webp_js/test_webp_wasm.webp and /dev/null differ diff --git a/libwebp/xcframeworkbuild.sh b/libwebp/xcframeworkbuild.sh deleted file mode 100644 index 14b987d4..00000000 --- a/libwebp/xcframeworkbuild.sh +++ /dev/null @@ -1,276 +0,0 @@ -#!/bin/bash -# -# This script generates 'WebP.xcframework', 'WebPDecoder.xcframework', -# 'WebPDemux.xcframework' and 'WebPMux.xcframework'. -# An iOS, Mac or Mac Catalyst app can decode WebP images by including -# 'WebPDecoder.xcframework' and both encode and decode WebP images by including -# 'WebP.xcframework'. -# -# Run ./xcframeworkbuild.sh to generate the frameworks under the current -# directory (the previous build will be erased if it exists). -# - -set -e - -# Set these variables based on the desired minimum deployment target. -readonly IOS_MIN_VERSION=6.0 -readonly MACOSX_MIN_VERSION=10.15 -readonly MACOSX_CATALYST_MIN_VERSION=14.0 - -# Extract Xcode version. -readonly XCODE=$(xcodebuild -version | grep Xcode | cut -d " " -f2) -if [[ -z "${XCODE}" ]] || [[ "${XCODE%%.*}" -lt 11 ]]; then - echo "Xcode 11.0 or higher is required!" - exit 1 -fi - -# Extract the latest SDK version from the final field of the form: iphoneosX.Y -# / macosxX.Y -readonly SDK=($( - xcodebuild -showsdks \ - | grep iphoneos | sort | tail -n 1 | awk '{print substr($NF, 9)}' - xcodebuild -showsdks \ - | grep macosx | sort | tail -n 1 | awk '{print substr($NF, 7)}' -)) -readonly IOS=0 -readonly MACOS=1 -readonly IOS_SIMULATOR=2 -readonly MACOS_CATALYST=3 -readonly NUM_PLATFORMS=4 - -readonly OLDPATH=${PATH} - -# Names should be of the form '-[-]'. -PLATFORMS[$IOS]="iPhoneOS-armv7 iPhoneOS-armv7s iPhoneOS-arm64" -PLATFORMS[$IOS_SIMULATOR]="iPhoneSimulator-i386 iPhoneSimulator-x86_64" -PLATFORMS[$MACOS]="MacOSX-x86_64" -PLATFORMS[$MACOS_CATALYST]="MacOSX-Catalyst-x86_64" -if [[ "${XCODE%%.*}" -ge 12 ]]; then - PLATFORMS[$MACOS]+=" MacOSX-arm64" - PLATFORMS[$MACOS_CATALYST]+=" MacOSX-Catalyst-arm64" - PLATFORMS[$IOS_SIMULATOR]+=" iPhoneSimulator-arm64" -elif [[ "${XCODE%%.*}" -eq 11 ]]; then - cat << EOF -WARNING: Xcode 12.0 or higher is required to build targets for -WARNING: Apple Silicon (arm64). The XCFrameworks generated with Xcode 11 will -WARNING: contain libraries for MacOS & Catalyst supporting x86_64 only. -WARNING: The build will continue in 5 seconds... -EOF - sleep 5 -else - echo "Xcode 11.0 or higher is required!" - exit 1 -fi -readonly PLATFORMS -readonly SRCDIR=$(dirname $0) -readonly TOPDIR=$(pwd) -readonly BUILDDIR="${TOPDIR}/xcframeworkbuild" -readonly TARGETDIR="${TOPDIR}/WebP.xcframework" -readonly DECTARGETDIR="${TOPDIR}/WebPDecoder.xcframework" -readonly MUXTARGETDIR="${TOPDIR}/WebPMux.xcframework" -readonly DEMUXTARGETDIR="${TOPDIR}/WebPDemux.xcframework" -readonly SHARPYUVTARGETDIR="${TOPDIR}/SharpYuv.xcframework" -readonly DEVELOPER=$(xcode-select --print-path) -readonly DEVROOT="${DEVELOPER}/Toolchains/XcodeDefault.xctoolchain" -readonly PLATFORMSROOT="${DEVELOPER}/Platforms" -readonly LIPO=$(xcrun -sdk iphoneos${SDK[$IOS]} -find lipo) - -if [[ -z "${SDK[$IOS]}" ]] || [[ ${SDK[$IOS]%%.*} -lt 8 ]]; then - echo "iOS SDK version 8.0 or higher is required!" - exit 1 -fi - -####################################### -# Moves Headers/*.h to Headers// -# -# Places framework headers in a subdirectory to avoid Xcode errors when using -# multiple frameworks: -# error: Multiple commands produce -# '.../Build/Products/Debug-iphoneos/include/types.h' -# Arguments: -# $1 - path to framework -####################################### -update_headers_path() { - local framework_name="$(basename ${1%.xcframework})" - local subdir - for d in $(find "$1" -path "*/Headers"); do - subdir="$d/$framework_name" - if [[ -d "$subdir" ]]; then - # SharpYuv will have a sharpyuv subdirectory. macOS is case insensitive, - # but for consistency with the other frameworks, rename the directory to - # match the case of the framework name. - mv "$(echo ${subdir} | tr 'A-Z' 'a-z')" "$subdir" - else - mkdir "$subdir" - mv "$d/"*.h "$subdir" - fi - done -} - -echo "Xcode Version: ${XCODE}" -echo "iOS SDK Version: ${SDK[$IOS]}" -echo "MacOS SDK Version: ${SDK[$MACOS]}" - -if [[ -e "${BUILDDIR}" || -e "${TARGETDIR}" || -e "${DECTARGETDIR}" \ - || -e "${MUXTARGETDIR}" || -e "${DEMUXTARGETDIR}" \ - || -e "${SHARPYUVTARGETDIR}" ]]; then - cat << EOF -WARNING: The following directories will be deleted: -WARNING: ${BUILDDIR} -WARNING: ${TARGETDIR} -WARNING: ${DECTARGETDIR} -WARNING: ${MUXTARGETDIR} -WARNING: ${DEMUXTARGETDIR} -WARNING: ${SHARPYUVTARGETDIR} -WARNING: The build will continue in 5 seconds... -EOF - sleep 5 -fi -rm -rf ${BUILDDIR} ${TARGETDIR} ${DECTARGETDIR} \ - ${MUXTARGETDIR} ${DEMUXTARGETDIR} ${SHARPYUVTARGETDIR} - -if [[ ! -e ${SRCDIR}/configure ]]; then - if ! (cd ${SRCDIR} && sh autogen.sh); then - cat << EOF -Error creating configure script! -This script requires the autoconf/automake and libtool to build. MacPorts or -Homebrew can be used to obtain these: -https://www.macports.org/install.php -https://brew.sh/ -EOF - exit 1 - fi -fi - -for (( i = 0; i < $NUM_PLATFORMS; ++i )); do - LIBLIST=() - DECLIBLIST=() - MUXLIBLIST=() - DEMUXLIBLIST=() - SHARPYUVLIBLIST=() - - for PLATFORM in ${PLATFORMS[$i]}; do - ROOTDIR="${BUILDDIR}/${PLATFORM}" - mkdir -p "${ROOTDIR}" - - ARCH="${PLATFORM##*-}" - case "${PLATFORM}" in - iPhone*) - sdk="${SDK[$IOS]}" - ;; - MacOS*) - sdk="${SDK[$MACOS]}" - ;; - *) - echo "Unrecognized platform: ${PLATFORM}!" - exit 1 - ;; - esac - - SDKROOT="${PLATFORMSROOT}/${PLATFORM%%-*}.platform/" - SDKROOT+="Developer/SDKs/${PLATFORM%%-*}${sdk}.sdk/" - CFLAGS="-pipe -isysroot ${SDKROOT} -O3 -DNDEBUG" - case "${PLATFORM}" in - iPhone*) - CFLAGS+=" -fembed-bitcode" - CFLAGS+=" -target ${ARCH}-apple-ios${IOS_MIN_VERSION}" - [[ "${PLATFORM}" == *Simulator* ]] && CFLAGS+="-simulator" - ;; - MacOSX-Catalyst*) - CFLAGS+=" -target" - CFLAGS+=" ${ARCH}-apple-ios${MACOSX_CATALYST_MIN_VERSION}-macabi" - ;; - MacOSX*) - CFLAGS+=" -mmacosx-version-min=${MACOSX_MIN_VERSION}" - ;; - esac - - set -x - export PATH="${DEVROOT}/usr/bin:${OLDPATH}" - ${SRCDIR}/configure --host=${ARCH/arm64/aarch64}-apple-darwin \ - --build=$(${SRCDIR}/config.guess) \ - --prefix=${ROOTDIR} \ - --disable-shared --enable-static \ - --enable-libwebpdecoder --enable-swap-16bit-csp \ - --enable-libwebpmux \ - CC="clang -arch ${ARCH}" \ - CFLAGS="${CFLAGS}" - set +x - - # Build only the libraries, skip the examples. - make V=0 -C sharpyuv install - make V=0 -C src install - - LIBLIST+=("${ROOTDIR}/lib/libwebp.a") - DECLIBLIST+=("${ROOTDIR}/lib/libwebpdecoder.a") - MUXLIBLIST+=("${ROOTDIR}/lib/libwebpmux.a") - DEMUXLIBLIST+=("${ROOTDIR}/lib/libwebpdemux.a") - SHARPYUVLIBLIST+=("${ROOTDIR}/lib/libsharpyuv.a") - # xcodebuild requires a directory for the -headers option, these will match - # for all builds. - make -C src install-data DESTDIR="${ROOTDIR}/lib-headers" - make -C src install-commonHEADERS DESTDIR="${ROOTDIR}/dec-headers" - make -C src/demux install-data DESTDIR="${ROOTDIR}/demux-headers" - make -C src/mux install-data DESTDIR="${ROOTDIR}/mux-headers" - make -C sharpyuv install-data DESTDIR="${ROOTDIR}/sharpyuv-headers" - LIB_HEADERS="${ROOTDIR}/lib-headers/${ROOTDIR}/include/webp" - DEC_HEADERS="${ROOTDIR}/dec-headers/${ROOTDIR}/include/webp" - DEMUX_HEADERS="${ROOTDIR}/demux-headers/${ROOTDIR}/include/webp" - MUX_HEADERS="${ROOTDIR}/mux-headers/${ROOTDIR}/include/webp" - SHARPYUV_HEADERS="${ROOTDIR}/sharpyuv-headers/${ROOTDIR}/include/webp" - - make distclean - - export PATH=${OLDPATH} - done - - [[ -z "${LIBLIST[@]}" ]] && continue - - # Create a temporary target directory for each [-]. - target_dir="${BUILDDIR}/${PLATFORMS[$i]}" - target_dir="${target_dir%% *}" - target_dir="${target_dir%-*}" - target_lib="${target_dir}/$(basename ${LIBLIST[0]})" - target_declib="${target_dir}/$(basename ${DECLIBLIST[0]})" - target_demuxlib="${target_dir}/$(basename ${DEMUXLIBLIST[0]})" - target_muxlib="${target_dir}/$(basename ${MUXLIBLIST[0]})" - target_sharpyuvlib="${target_dir}/$(basename ${SHARPYUVLIBLIST[0]})" - - mkdir -p "${target_dir}" - ${LIPO} -create ${LIBLIST[@]} -output "${target_lib}" - ${LIPO} -create ${DECLIBLIST[@]} -output "${target_declib}" - ${LIPO} -create ${DEMUXLIBLIST[@]} -output "${target_demuxlib}" - ${LIPO} -create ${MUXLIBLIST[@]} -output "${target_muxlib}" - ${LIPO} -create ${SHARPYUVLIBLIST[@]} -output "${target_sharpyuvlib}" - FAT_LIBLIST+=(-library "${target_lib}" -headers "${LIB_HEADERS}") - FAT_DECLIBLIST+=(-library "${target_declib}" -headers "${DEC_HEADERS}") - FAT_DEMUXLIBLIST+=(-library "${target_demuxlib}" -headers "${DEMUX_HEADERS}") - FAT_MUXLIBLIST+=(-library "${target_muxlib}" -headers "${MUX_HEADERS}") - FAT_SHARPYUVLIBLIST+=(-library "${target_sharpyuvlib}") - FAT_SHARPYUVLIBLIST+=(-headers "${SHARPYUV_HEADERS}") -done - -# lipo will not put archives with the same architecture (e.g., x86_64 -# iPhoneSimulator & MacOS) in the same fat output file. xcodebuild -# -create-xcframework requires universal archives to avoid e.g.: -# Both ios-x86_64-maccatalyst and ios-arm64-maccatalyst represent two -# equivalent library definitions -set -x -xcodebuild -create-xcframework "${FAT_LIBLIST[@]}" \ - -output ${TARGETDIR} -xcodebuild -create-xcframework "${FAT_DECLIBLIST[@]}" \ - -output ${DECTARGETDIR} -xcodebuild -create-xcframework "${FAT_DEMUXLIBLIST[@]}" \ - -output ${DEMUXTARGETDIR} -xcodebuild -create-xcframework "${FAT_MUXLIBLIST[@]}" \ - -output ${MUXTARGETDIR} -xcodebuild -create-xcframework "${FAT_SHARPYUVLIBLIST[@]}" \ - -output ${SHARPYUVTARGETDIR} -update_headers_path "${TARGETDIR}" -update_headers_path "${DECTARGETDIR}" -update_headers_path "${DEMUXTARGETDIR}" -update_headers_path "${MUXTARGETDIR}" -update_headers_path "${SHARPYUVTARGETDIR}" -set +x - -echo "SUCCESS" diff --git a/nsis/InstallOptions2.ini b/nsis/InstallOptions2.ini index ac7f3adb..261528c5 100644 --- a/nsis/InstallOptions2.ini +++ b/nsis/InstallOptions2.ini @@ -1,5 +1,5 @@ [Settings] -NumFields=11 +NumFields=13 [Field 1] Type=CheckBox @@ -99,3 +99,21 @@ Right=64 Top=126 Bottom=139 + +[Field 12] +Type=CheckBox +Text=EMF +State=1 +Left=76 +Right=134 +Top=22 +Bottom=35 + +[Field 13] +Type=CheckBox +Text=WMF +State=1 +Left=76 +Right=134 +Top=35 +Bottom=48 diff --git a/nsis/InstallOptions2_Chinese.ini b/nsis/InstallOptions2_Chinese.ini index ed8bf953..ba2a15b0 100644 Binary files a/nsis/InstallOptions2_Chinese.ini and b/nsis/InstallOptions2_Chinese.ini differ diff --git a/nsis/InstallOptions_Chinese.ini b/nsis/InstallOptions_Chinese.ini index 0d571d3c..9353bfef 100644 Binary files a/nsis/InstallOptions_Chinese.ini and b/nsis/InstallOptions_Chinese.ini differ diff --git a/nsis/build_installer.ps1 b/nsis/build_installer.ps1 index fb82d503..f513a2e7 100644 --- a/nsis/build_installer.ps1 +++ b/nsis/build_installer.ps1 @@ -19,23 +19,25 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. # -# Build NSIS installer for void Image Viewer -# Usage: .\build_installer.ps1 [arch] [vs_version] [build_config] [lang] +# Build the unified bilingual (English + Simplified Chinese) NSIS installer +# for void Image Viewer. The language is selected inside the installer, there +# is no separate per-language build. +# +# Usage: .\build_installer.ps1 [arch] [vs_version] [build_config] # arch: x86 or x64 (default: x86) -# vs_version: vs2005, vs2019, vs2026, etc. (default: auto-detect) +# vs_version: vs2019, vs2026 (default: auto-detect: +# prefers a project dir with a built exe, then vswhere) # build_config: Release, Debug, etc. (default: Release) -# lang: English or Chinese (default: Chinese) # # Examples: -# .\build_installer.ps1 x64 vs2026 Release Chinese -# .\build_installer.ps1 x86 vs2019 Release English -# .\build_installer.ps1 x64 +# .\build_installer.ps1 x64 vs2026 Release +# .\build_installer.ps1 x86 +# .\build_installer.ps1 x64 vs2019 Release param( [string]$Arch = "x86", [string]$VsVersion = "", - [string]$BuildConfig = "Release", - [string]$Lang = "Chinese" + [string]$BuildConfig = "Release" ) # Change to script directory @@ -45,7 +47,14 @@ Set-Location $ScriptDir # Check if NSIS is installed $makensis = Get-Command makensis.exe -ErrorAction SilentlyContinue if (-not $makensis) { - Write-Host "Error: NSIS compiler (makensis.exe) not found in PATH!" -ForegroundColor Red + # also try the default install location + $defaultMakensis = "C:\Program Files (x86)\NSIS\makensis.exe" + if (Test-Path $defaultMakensis) { + $makensis = $defaultMakensis + } +} +if (-not $makensis) { + Write-Host "Error: NSIS compiler (makensis.exe) not found!" -ForegroundColor Red Write-Host "Please install NSIS from https://nsis.sourceforge.io/Download" -ForegroundColor Yellow Write-Host "and add it to your system PATH." -ForegroundColor Yellow exit 1 @@ -58,35 +67,69 @@ if (-not (Test-Path "version.nsh")) { exit 1 } -# Convert files to UTF-8 with BOM if needed (for Chinese support) -if (Test-Path "convert_to_utf8_bom.ps1") { - Write-Host "Converting files to UTF-8 with BOM encoding..." -ForegroundColor Cyan - & powershell -ExecutionPolicy Bypass -File "convert_to_utf8_bom.ps1" | Out-Null +# Validate and fix the encoding of the bilingual installer files +if (Test-Path "ensure_encodings.ps1") { + Write-Host "Validating installer file encodings..." -ForegroundColor Cyan + & powershell -ExecutionPolicy Bypass -File "ensure_encodings.ps1" | Out-Null } -# Auto-detect VS version if not specified +# Auto-detect VS version if not specified. +# NOTE: a plain directory existence check says nothing about which toolchain +# the user actually has installed. Detection therefore prefers, in order: +# 1. a project directory that already contains a built executable for the +# requested arch/config (packaging what was actually built), +# 2. an installed Visual Studio instance reported by vswhere (VS2017+). if ([string]::IsNullOrEmpty($VsVersion)) { Write-Host "Auto-detecting Visual Studio version..." -ForegroundColor Cyan - if (Test-Path "..\vs2026") { - $VsVersion = "vs2026" + + $detected = $null + + # 1) prefer a project directory that already has a built executable + foreach ($vs in @("vs2026", "vs2019")) { + $candidate = "..\$vs\$BuildConfig\voidImageViewer.exe" + if ($Arch -eq "x64") { + $candidate = "..\$vs\x64\$BuildConfig\voidImageViewer.exe" + } + if (Test-Path $candidate) { + $detected = $vs + break + } } - elseif (Test-Path "..\vs2019") { - $VsVersion = "vs2019" + + # 2) fall back to the installed toolchain (vswhere knows VS2017+) + if (-not $detected) { + $vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" + if (Test-Path $vswhere) { + # newest first: vs2026 = VS 18.x, vs2019 = VS 16.x + foreach ($vs in @("vs2026", "vs2019")) { + $major = "16" + if ($vs -eq "vs2026") { $major = "18" } + $versions = & $vswhere -products * -requires Microsoft.Component.MSBuild -property installationVersion 2>$null + if ($versions | Where-Object { $_.StartsWith("$major.") }) { + if (Test-Path "..\$vs") { + $detected = $vs + break + } + } + } + } } - elseif (Test-Path "..\vs2005") { - $VsVersion = "vs2005" + + if ($detected) { + $VsVersion = $detected + Write-Host "Detected: $VsVersion" -ForegroundColor Green } else { - Write-Host "Error: Could not auto-detect VS version!" -ForegroundColor Red - Write-Host "Please specify VS version manually: .\build_installer.ps1 -Arch $Arch -VsVersion vs2026" -ForegroundColor Yellow + Write-Host "Error: Could not auto-detect Visual Studio version!" -ForegroundColor Red + Write-Host "No built executable was found and no matching Visual Studio installation was detected." -ForegroundColor Yellow + Write-Host "Please build the solution first, or specify VS version manually:" -ForegroundColor Yellow + Write-Host " .\build_installer.ps1 -Arch $Arch -VsVersion vs2026" -ForegroundColor Yellow Write-Host "" Write-Host "Available VS directories:" if (Test-Path "..\vs2026") { Write-Host " - vs2026" } if (Test-Path "..\vs2019") { Write-Host " - vs2019" } - if (Test-Path "..\vs2005") { Write-Host " - vs2005" } exit 1 } - Write-Host "Detected: $VsVersion" -ForegroundColor Green } # Determine executable path based on architecture @@ -105,7 +148,7 @@ Write-Host "Building void Image Viewer Installer" -ForegroundColor Cyan Write-Host "Architecture: $Arch" -ForegroundColor White Write-Host "Visual Studio: $VsVersion" -ForegroundColor White Write-Host "Build Config: $BuildConfig" -ForegroundColor White -Write-Host "Language: $Lang" -ForegroundColor White +Write-Host "Languages: English + Simplified Chinese (selected in the installer)" -ForegroundColor White Write-Host "========================================" -ForegroundColor Cyan Write-Host "" @@ -130,8 +173,7 @@ Write-Host "" Write-Host "Compiling NSIS installer script..." -ForegroundColor Cyan $makensisArgs = @( "/DVS_VERSION=$VsVersion", - "/DBUILD_CONFIG=$BuildConfig", - "/DLANG=$Lang" + "/DBUILD_CONFIG=$BuildConfig" ) if ($Arch -eq "x64") { @@ -143,7 +185,7 @@ $makensisArgs += "installer.nsi" Write-Host "Command: makensis.exe $($makensisArgs -join ' ')" -ForegroundColor Gray Write-Host "" -$process = Start-Process -FilePath "makensis.exe" -ArgumentList $makensisArgs -Wait -NoNewWindow -PassThru +$process = Start-Process -FilePath $makensis -ArgumentList $makensisArgs -Wait -NoNewWindow -PassThru if ($process.ExitCode -eq 0) { Write-Host "" @@ -151,7 +193,8 @@ if ($process.ExitCode -eq 0) { Write-Host "Build completed successfully!" -ForegroundColor Green Write-Host "========================================" -ForegroundColor Green Write-Host "" - Write-Host "Installer file should be in the current directory." -ForegroundColor Green + Write-Host "The installer should be in the current directory." -ForegroundColor Green + Write-Host "The user picks the setup language on the first page." -ForegroundColor Green exit 0 } else { diff --git a/nsis/convert_to_utf8_bom.ps1 b/nsis/convert_to_utf8_bom.ps1 deleted file mode 100644 index cee54259..00000000 --- a/nsis/convert_to_utf8_bom.ps1 +++ /dev/null @@ -1,44 +0,0 @@ -# -# Copyright 2026 hesphoros -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# -# Convert NSIS files to UTF-8 with BOM encoding -# This is required for NSIS to properly handle Chinese characters - -$files = @( - "installer.nsi", - "installer_license_Chinese.txt", - "InstallOptions_Chinese.ini", - "InstallOptions2_Chinese.ini" -) - -foreach ($file in $files) { - $filePath = Join-Path $PSScriptRoot $file - if (Test-Path $filePath) { - Write-Host "Converting $file to UTF-8 with BOM..." - $content = Get-Content $filePath -Raw -Encoding UTF8 - [System.IO.File]::WriteAllText($filePath, $content, [System.Text.UTF8Encoding]::new($true)) - Write-Host " Done: $file" -ForegroundColor Green - } else { - Write-Host " Warning: $file not found" -ForegroundColor Yellow - } -} - -Write-Host "`nConversion completed!" -ForegroundColor Green diff --git a/nsis/ensure_encodings.ps1 b/nsis/ensure_encodings.ps1 new file mode 100644 index 00000000..449290f7 --- /dev/null +++ b/nsis/ensure_encodings.ps1 @@ -0,0 +1,63 @@ +# +# Copyright 2026 hesphoros +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +# Validate (and fix) the encodings required by the bilingual installer: +# - installer.nsi and installer_license_Chinese.txt: +# UTF-8 with BOM (read by makensis at compile time). +# - InstallOptions*_Chinese.ini: +# UTF-16LE with BOM (read by the InstallOptions plugin at runtime, +# non-unicode ini files would be converted with the target system's +# ansi codepage and the chinese text would be corrupted). + +$ErrorActionPreference = "Stop" + +function Ensure-Utf8Bom { + param([string]$Path) + $bytes = [System.IO.File]::ReadAllBytes($Path) + if ($bytes.Length -ge 3 -and $bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF) { + Write-Host " OK (UTF-8 BOM): $Path" -ForegroundColor Green + return + } + Write-Host " fixing (adding UTF-8 BOM): $Path" -ForegroundColor Yellow + $content = [System.Text.Encoding]::UTF8.GetString($bytes) + [System.IO.File]::WriteAllText($Path, $content, [System.Text.UTF8Encoding]::new($true)) +} + +function Ensure-Utf16LeBom { + param([string]$Path) + $bytes = [System.IO.File]::ReadAllBytes($Path) + if ($bytes.Length -ge 2 -and $bytes[0] -eq 0xFF -and $bytes[1] -eq 0xFE) { + Write-Host " OK (UTF-16LE BOM): $Path" -ForegroundColor Green + return + } + Write-Host " fixing (converting to UTF-16LE BOM): $Path" -ForegroundColor Yellow + $content = [System.Text.Encoding]::UTF8.GetString($bytes) + [System.IO.File]::WriteAllText($Path, $content, [System.Text.UnicodeEncoding]::new($false, $true)) +} + +Write-Host "Validating installer file encodings..." -ForegroundColor Cyan + +Ensure-Utf8Bom -Path (Join-Path $PSScriptRoot "installer.nsi") +Ensure-Utf8Bom -Path (Join-Path $PSScriptRoot "installer_license_Chinese.txt") +Ensure-Utf16LeBom -Path (Join-Path $PSScriptRoot "InstallOptions_Chinese.ini") +Ensure-Utf16LeBom -Path (Join-Path $PSScriptRoot "InstallOptions2_Chinese.ini") + +Write-Host "Encoding validation completed!" -ForegroundColor Green diff --git a/nsis/installer.nsi b/nsis/installer.nsi index b41df14f..73d8dfab 100644 --- a/nsis/installer.nsi +++ b/nsis/installer.nsi @@ -1,471 +1,531 @@ -; -; Copyright 2025 voidtools / David Carpenter -; -; Multi-language and multi-VS version support added by hesphoros (2026) -; -; Permission is hereby granted, free of charge, to any person obtaining a copy -; of this software and associated documentation files (the "Software"), to deal -; in the Software without restriction, including without limitation the rights -; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -; copies of the Software, and to permit persons to whom the Software is -; furnished to do so, subject to the following conditions: -; -; The above copyright notice and this permission notice shall be included in all -; copies or substantial portions of the Software. -; -; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -; SOFTWARE. -; - -; defines -!verbose 3 - -; Visual Studio version configuration -; Can be overridden via command line: makensis.exe /DVS_VERSION=vs2026 installer.nsi -; Supported versions: vs2005, vs2019, vs2026, etc. -; Added by hesphoros (2026) -!ifndef VS_VERSION - !define VS_VERSION "vs2026" ; Default VS version -!endif - -; Build configuration (Release, Debug, etc.) -; Added by hesphoros (2026) -!ifndef BUILD_CONFIG - !define BUILD_CONFIG "Release" ; Default build configuration -!endif - -; Language configuration -; Can be overridden via command line: makensis.exe /DLANG=Chinese installer.nsi -; Supported languages: English, Chinese -; Added by hesphoros (2026) -!ifndef LANG - !define LANG "Chinese" ; Default language -!endif - -; we need admin access to write to program files and registry (associations). -RequestExecutionLevel user - -CRCCheck On -XPStyle on - -; includes -!include "MUI.nsh" - -!include "version.nsh" - -!include WinMessages.nsh -!include InstallOptions.nsh -!include FileFunc.nsh - -; Language-specific file names -!if "${LANG}" == "Chinese" - !define LICENSE_FILE "installer_license_Chinese.txt" - !define INSTALL_OPTIONS_FILE "InstallOptions_Chinese.ini" - !define INSTALL_OPTIONS2_FILE "InstallOptions2_Chinese.ini" - !define LANG_CODE "zh-CN" - !define LANG_NAME "Chinese" -!else - !define LICENSE_FILE "installer_license_English.txt" - !define INSTALL_OPTIONS_FILE "InstallOptions.ini" - !define INSTALL_OPTIONS2_FILE "InstallOptions2.ini" - !define LANG_CODE "en-US" - !define LANG_NAME "English" -!endif - -!ifdef x64 - - !define TARGETMACHINE "x64" - InstallDir "$PROGRAMFILES64\voidImageViewer" - -!else - - !define TARGETMACHINE "x86" - InstallDir "$PROGRAMFILES\voidImageViewer" - -!endif - -; vars - -Var existing_ini_filename -Var admin_install_options -Var user_install_options - -BrandingText "void Image Viewer ${VERSION}${BETAVERSION} (${TARGETMACHINE}) Setup" - -; settings /SOLID will save a few KBs -SetCompressor /SOLID lzma -Name "void Image Viewer" - -; Output file name with language code -OutFile "voidImageViewer-${VERSION}${BETAVERSION}.${TARGETMACHINE}.${LANG_CODE}-Setup.exe" - -; MUI settings -!define MUI_ICON "..\res\voidImageViewer.ico" - -!insertmacro MUI_PAGE_LICENSE "${LICENSE_FILE}" - -!insertmacro MUI_PAGE_DIRECTORY - -; options page -Page custom InstallOptions -Page custom InstallOptions2 - -!insertmacro MUI_PAGE_INSTFILES - -!insertmacro MUI_PAGE_FINISH - -;!insertmacro MUI_UNPAGE_WELCOME -!insertmacro MUI_UNPAGE_CONFIRM -!insertmacro MUI_UNPAGE_INSTFILES -!insertmacro MUI_UNPAGE_FINISH - -; Language selection -!if "${LANG}" == "Chinese" - !insertmacro MUI_LANGUAGE "SimpChinese" -!else - !insertmacro MUI_LANGUAGE "English" -!endif - -!insertmacro GetOptions - -; Version Info -VIProductVersion "${VERSION}${BETAVERSION}" - -; don't localize these: -VIAddVersionKey "ProductName" "void Image Viewer" -VIAddVersionKey "Comments" "" -VIAddVersionKey "CompanyName" "" -VIAddVersionKey "LegalTrademarks" "" -VIAddVersionKey "LegalCopyright" "Copyright (c) 2025 David Carpenter" -VIAddVersionKey "FileDescription" "void Image Viewer Setup" - -VIAddVersionKey "FileVersion" "${VERSION}${BETAVERSION}.${TARGETMACHINE}.${LANG_CODE}" -VIAddVersionKey "ProductVersion" "${VERSION}${BETAVERSION}.${TARGETMACHINE}.${LANG_CODE}" - -Function .onInit - - ; init options with language-specific files. - !insertmacro INSTALLOPTIONS_EXTRACT "${INSTALL_OPTIONS_FILE}" - !insertmacro INSTALLOPTIONS_EXTRACT "${INSTALL_OPTIONS2_FILE}" - - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - ; remember last install dir. - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - ClearErrors - - ; use the appropriate reg view. - ; dont install to the previous x86 location C:\Program Files (x86) if we are x64 - -!ifdef x64 - SetRegView 64 -!endif - - ReadRegStr $R2 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\voidImageViewer" 'UninstallString' - -!ifdef x64 - SetRegView 32 -!endif - - IfErrors no_existing_install_dir - - ClearErrors - system::Call 'Shlwapi::PathRemoveFileSpec(tR2R2) i.r1' - IfErrors no_existing_install_dir - - StrCpy $INSTDIR $R2 - -no_existing_install_dir: - - ; get the existing ini filename. - StrCpy $existing_ini_filename "$APPDATA\voidImageViewer\voidImageViewer.ini" - - ; Check if appdata is set to zero - ; $INSTDIR is the existing install location (or the default one if it does not exist) - ReadINIStr $0 "$INSTDIR\voidImageViewer.ini" "voidImageViewer" "appdata" - StrCmp $0 "0" 0 skip_check_app_data - StrCpy $existing_ini_filename "$INSTDIR\voidImageViewer.ini" - !insertmacro MUI_INSTALLOPTIONS_WRITE "${INSTALL_OPTIONS_FILE}" "Field 2" "State" "0" - !insertmacro MUI_INSTALLOPTIONS_WRITE "${INSTALL_OPTIONS_FILE}" "Field 3" "State" "1" - -skip_check_app_data: - - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - ; localization - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -!ifdef x64 - - ; check if OS is x64 capable. - System::Call "kernel32::GetCurrentProcess() i .s" - System::Call "kernel32::IsWow64Process(i s, *i .r0)" - IntCmp $0 0 is32 - goto is64 - -is32: - - MessageBox MB_YESNOCANCEL|MB_ICONEXCLAMATION "OS is not x64.$\nInstall anyway?" IDYES is64 - Abort - -is64: - -!endif ; !ifdef x64 - -FunctionEnd - -Function un.onInit - - ; get the existing ini filename. - StrCpy $existing_ini_filename "$APPDATA\voidImageViewer\voidImageViewer.ini" - - ; Check if appdata is set to zero - ; $INSTDIR is the existing install location - ReadINIStr $0 "$INSTDIR\voidImageViewer.ini" "voidImageViewer" "appdata" - StrCmp $0 "0" 0 skip_check_app_data - StrCpy $existing_ini_filename "$INSTDIR\voidImageViewer.ini" - -skip_check_app_data: - -FunctionEnd - -; sections -Section "voidImageViewer" SECTION_VOIDIMAGEVIEWER - - ; init - StrCpy $admin_install_options "" - StrCpy $user_install_options "" - - ; app data - !insertmacro MUI_INSTALLOPTIONS_READ $R0 "${INSTALL_OPTIONS_FILE}" "Field 2" "State" - strcmp $R0 "0" no_app_data - StrCpy $admin_install_options "$admin_install_options /appdata" - Goto skip_app_data - -no_app_data: - - ; this option is special, we MUST unset any option that voidImageViewer was previously installed with. - StrCpy $admin_install_options "$admin_install_options /noappdata" - -skip_app_data: - - ; startmenu - !insertmacro MUI_INSTALLOPTIONS_READ $R0 "${INSTALL_OPTIONS2_FILE}" "Field 1" "State" - strcmp $R0 "0" no_startmenu - StrCpy $admin_install_options "$admin_install_options /startmenu" - Goto skip_startmenu - -no_startmenu: - - StrCpy $admin_install_options "$admin_install_options /nostartmenu" - -skip_startmenu: - - ; BMP Associations - !insertmacro MUI_INSTALLOPTIONS_READ $R0 "${INSTALL_OPTIONS2_FILE}" "Field 3" "State" - strcmp $R0 "0" no_bmp_association - StrCpy $user_install_options "$user_install_options /bmp" - Goto skip_bmp_association - -no_bmp_association: - - StrCpy $user_install_options "$user_install_options /nobmp" - -skip_bmp_association: - - ; GIF Associations - !insertmacro MUI_INSTALLOPTIONS_READ $R0 "${INSTALL_OPTIONS2_FILE}" "Field 4" "State" - strcmp $R0 "0" no_gif_association - StrCpy $user_install_options "$user_install_options /gif" - Goto skip_gif_association - -no_gif_association: - - StrCpy $user_install_options "$user_install_options /nogif" - -skip_gif_association: - - ; ico Associations - !insertmacro MUI_INSTALLOPTIONS_READ $R0 "InstallOptions2.ini" "Field 5" "State" - strcmp $R0 "0" no_ico_association - StrCpy $user_install_options "$user_install_options /ico" - Goto skip_ico_association - -no_ico_association: - - StrCpy $user_install_options "$user_install_options /noico" - -skip_ico_association: - - ; jpeg Associations - !insertmacro MUI_INSTALLOPTIONS_READ $R0 "InstallOptions2.ini" "Field 6" "State" - strcmp $R0 "0" no_jpeg_association - StrCpy $user_install_options "$user_install_options /jpeg" - Goto skip_jpeg_association - -no_jpeg_association: - - StrCpy $user_install_options "$user_install_options /nojpeg" - -skip_jpeg_association: - - ; jpg Associations - !insertmacro MUI_INSTALLOPTIONS_READ $R0 "InstallOptions2.ini" "Field 7" "State" - strcmp $R0 "0" no_jpg_association - StrCpy $user_install_options "$user_install_options /jpg" - Goto skip_jpg_association - -no_jpg_association: - - StrCpy $user_install_options "$user_install_options /nojpg" - -skip_jpg_association: - - ; png Associations - !insertmacro MUI_INSTALLOPTIONS_READ $R0 "InstallOptions2.ini" "Field 8" "State" - strcmp $R0 "0" no_png_association - StrCpy $user_install_options "$user_install_options /png" - Goto skip_png_association - -no_png_association: - - StrCpy $user_install_options "$user_install_options /nopng" - -skip_png_association: - - ; tif Associations - !insertmacro MUI_INSTALLOPTIONS_READ $R0 "InstallOptions2.ini" "Field 9" "State" - strcmp $R0 "0" no_tif_association - StrCpy $user_install_options "$user_install_options /tif" - Goto skip_tif_association - -no_tif_association: - - StrCpy $user_install_options "$user_install_options /notif" - -skip_tif_association: - - ; tiff Associations - !insertmacro MUI_INSTALLOPTIONS_READ $R0 "InstallOptions2.ini" "Field 10" "State" - strcmp $R0 "0" no_tiff_association - StrCpy $user_install_options "$user_install_options /tiff" - Goto skip_tiff_association - -no_tiff_association: - - StrCpy $user_install_options "$user_install_options /notiff" - -skip_tiff_association: - - ; webp Associations - !insertmacro MUI_INSTALLOPTIONS_READ $R0 "InstallOptions2.ini" "Field 11" "State" - strcmp $R0 "0" no_webp_association - StrCpy $user_install_options "$user_install_options /webp" - Goto skip_webp_association - -no_webp_association: - - StrCpy $user_install_options "$user_install_options /nowebp" - -skip_webp_association: - - ; ---------------------------------- - ; begin voidImageViewer installation - ; ---------------------------------- - - SectionIn RO - - InitPluginsDir - SetOutPath "$pluginsdir\voidImageViewer" - - ; write out files to copy. - ; VS version and build config are configurable via defines - - !ifdef x64 - - File "..\${VS_VERSION}\x64\${BUILD_CONFIG}\voidImageViewer.exe" - - !else - - File "..\${VS_VERSION}\${BUILD_CONFIG}\voidImageViewer.exe" - - !endif - - ; File "..\Changes.txt" - WriteUninstaller "$pluginsdir\voidImageViewer\Uninstall.exe" - - ; check for command line options that will override the default install options. - ${GetOptions} $CMDLINE "/install-options" $0 - IfErrors +2 - StrCpy $admin_install_options "$admin_install_options $0" - - ; install with admin rights. - ; MessageBox MB_YESNOCANCEL|MB_ICONEXCLAMATION "ADMIN $admin_install_options" - ClearErrors - ExecWait '"$pluginsdir\voidImageViewer\voidImageViewer.exe" /install "$INSTDIR" /install-options "$admin_install_options"' $0 - IfErrors exec_admin_error - IntCmp $0 0 exec_admin_ok - -exec_admin_error: - - MessageBox MB_OK|MB_ICONSTOP "Failed to execute admin command" - -exec_admin_ok: - - ClearErrors - ExecWait '"$INSTDIR\voidImageViewer.exe" $user_install_options' $0 - IfErrors exec_install_options_error - IntCmp $0 0 exec_install_options_ok - -exec_install_options_error: - - MessageBox MB_OK|MB_ICONSTOP "Failed to execute install options" - -exec_install_options_ok: - -SectionEnd - -Section "Uninstall" - - ; Make sure $InstDir is not the current directory so we can remove it - SetOutPath $Temp - - ; copy voidImageViewer.exe to temp folder. - CopyFiles /SILENT $INSTDIR\voidImageViewer.exe $Temp\voidImageViewer.exe - - ; run uninstaller with admin rights - ; this will uninstall any localized shortcuts etc.. - ; this also removes the service if installed - ; which is something we can not do easily from the nsis installer. - ; do this before we try to terminate the app. - ExecWait '"$Temp\voidImageViewer.exe" /uninstall "$INSTDIR"' - - ; delete temp voidImageViewer - Delete "$Temp\voidImageViewer.exe" - -SectionEnd - -Function InstallOptions - - !insertmacro INSTALLOPTIONS_INITDIALOG "${INSTALL_OPTIONS_FILE}" - - !insertmacro MUI_HEADER_TEXT "Select Install Options" "Choose any additional install options." - - !insertmacro INSTALLOPTIONS_SHOW - -FunctionEnd - -Function InstallOptions2 - - !insertmacro INSTALLOPTIONS_INITDIALOG "${INSTALL_OPTIONS2_FILE}" - - !insertmacro MUI_HEADER_TEXT "Select Install Options" "Choose any additional install options." - - !insertmacro INSTALLOPTIONS_SHOW - -FunctionEnd - +; +; Copyright 2025 voidtools / David Carpenter +; +; Multi-language and multi-VS version support added by hesphoros (2026) +; Unified single-file bilingual (English + Simplified Chinese) installer (2026) +; +; Permission is hereby granted, free of charge, to any person obtaining a copy +; of this software and associated documentation files (the "Software"), to deal +; in the Software without restriction, including without limitation the rights +; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +; copies of the Software, and to permit persons to whom the Software is +; furnished to do so, subject to the following conditions: +; +; The above copyright notice and this permission notice shall be included in all +; copies or substantial portions of the Software. +; +; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +; SOFTWARE. +; + +; defines +!verbose 3 + +; Visual Studio version configuration +; Can be overridden via command line: makensis.exe /DVS_VERSION=vs2026 installer.nsi +; Supported versions: vs2019, vs2026 +!ifndef VS_VERSION + !define VS_VERSION "vs2026" ; Default VS version +!endif + +; Build configuration (Release, Debug, etc.) +!ifndef BUILD_CONFIG + !define BUILD_CONFIG "Release" ; Default build configuration +!endif + +; Source location of voidImageViewer.exe. +; Override with /DVIV_EXE_DIR= when the exe is not in the default +; project output directory (used by CI builds). +!ifndef VIV_EXE_DIR + !ifdef x64 + !define VIV_EXE_DIR "..\${VS_VERSION}\x64\${BUILD_CONFIG}" + !else + !define VIV_EXE_DIR "..\${VS_VERSION}\${BUILD_CONFIG}" + !endif +!endif + +; we need admin access to write to program files and registry (associations). +; the application elevates itself when required. +RequestExecutionLevel user + +CRCCheck On +XPStyle on + +; includes +!include "MUI.nsh" + +!include "version.nsh" + +!include WinMessages.nsh +!include InstallOptions.nsh +!include FileFunc.nsh + +!ifdef x64 + + !define TARGETMACHINE "x64" + InstallDir "$PROGRAMFILES64\voidImageViewer" + +!else + + !define TARGETMACHINE "x86" + InstallDir "$PROGRAMFILES\voidImageViewer" + +!endif + +; vars + +Var existing_ini_filename +Var admin_install_options +Var user_install_options + +BrandingText "void Image Viewer ${DISPLAYVERSION} (${TARGETMACHINE}) Setup" + +; settings /SOLID will save a few KBs +SetCompressor /SOLID lzma +Name "void Image Viewer" + +; unified output file. the installer is bilingual, no language code in the name. +OutFile "voidImageViewer-${DISPLAYVERSION}-${TARGETMACHINE}-Setup.exe" + +; MUI settings +!define MUI_ICON "..\res\voidImageViewer.ico" + +; remember the selected installer language for future installs and uninstalls. +; always show the language dialog too (preselecting the remembered language): +; without ALWAYSSHOW an upgrade install silently reuses the remembered +; language and the user never sees a way to switch it. +!define MUI_LANGDLL_ALWAYSSHOW +!define MUI_LANGDLL_REGISTRY_ROOT "HKCU" +!define MUI_LANGDLL_REGISTRY_KEY "Software\voidImageViewer" +!define MUI_LANGDLL_REGISTRY_VALUENAME "Installer Language" + +; pages +!insertmacro MUI_PAGE_LICENSE "$(LicenseData)" + +!insertmacro MUI_PAGE_DIRECTORY + +; options page +Page custom InstallOptions +Page custom InstallOptions2 + +!insertmacro MUI_PAGE_INSTFILES + +; offer to run void Image Viewer after a successful install. +!define MUI_FINISHPAGE_RUN "$INSTDIR\voidImageViewer.exe" + +!insertmacro MUI_PAGE_FINISH + +;!insertmacro MUI_UNPAGE_WELCOME +!insertmacro MUI_UNPAGE_CONFIRM +!insertmacro MUI_UNPAGE_INSTFILES +!insertmacro MUI_UNPAGE_FINISH + +; installer languages (the first language is the fallback). +; MUI language macros must come after the page macros. +!insertmacro MUI_LANGUAGE "English" +!insertmacro MUI_LANGUAGE "SimpChinese" + +; per language license data. (name, language id, license file) +LicenseLangString LicenseData ${LANG_ENGLISH} "installer_license_English.txt" +LicenseLangString LicenseData ${LANG_SIMPCHINESE} "installer_license_Chinese.txt" + +; localized installer messages. +LangString MsgSelectOptionsTitle ${LANG_ENGLISH} "Select Install Options" +LangString MsgSelectOptionsTitle ${LANG_SIMPCHINESE} "选择安装选项" +LangString MsgSelectOptionsSub ${LANG_ENGLISH} "Choose any additional install options." +LangString MsgSelectOptionsSub ${LANG_SIMPCHINESE} "选择其他安装选项。" +LangString MsgOsNotX64 ${LANG_ENGLISH} "OS is not x64.$\nInstall anyway?" +LangString MsgOsNotX64 ${LANG_SIMPCHINESE} "当前操作系统不是 64 位。$\n仍然要安装吗?" +LangString MsgExecAdminFailed ${LANG_ENGLISH} "Failed to execute admin command" +LangString MsgExecAdminFailed ${LANG_SIMPCHINESE} "执行管理员安装命令失败" +LangString MsgExecOptionsFailed ${LANG_ENGLISH} "Failed to execute install options" +LangString MsgExecOptionsFailed ${LANG_SIMPCHINESE} "执行安装选项失败" + +!insertmacro GetOptions + +; Version Info +VIProductVersion "${VERSION}" + +; don't localize these: +VIAddVersionKey "ProductName" "void Image Viewer" +VIAddVersionKey "Comments" "" +VIAddVersionKey "CompanyName" "" +VIAddVersionKey "LegalTrademarks" "" +VIAddVersionKey "LegalCopyright" "Copyright (c) 2025 David Carpenter" +VIAddVersionKey "FileDescription" "void Image Viewer Setup" + +VIAddVersionKey "FileVersion" "${DISPLAYVERSION}" +VIAddVersionKey "ProductVersion" "${DISPLAYVERSION}" + +Function .onInit + + ; show the language selection dialog first. + ; the selection is remembered in HKCU and reused by the uninstaller. + !insertmacro MUI_LANGDLL_DISPLAY + + ; extract the installer option pages for both languages. + ; the english files provide the "active" page names, the chinese pages + ; are copied over the active ones when chinese is selected. + !insertmacro INSTALLOPTIONS_EXTRACT "InstallOptions.ini" + !insertmacro INSTALLOPTIONS_EXTRACT "InstallOptions2.ini" + !insertmacro INSTALLOPTIONS_EXTRACT "InstallOptions_Chinese.ini" + !insertmacro INSTALLOPTIONS_EXTRACT "InstallOptions2_Chinese.ini" + + ; switch the active installer option pages to the selected language. + StrCmp $LANGUAGE ${LANG_SIMPCHINESE} 0 language_pages_done + CopyFiles /SILENT "$PLUGINSDIR\InstallOptions_Chinese.ini" "$PLUGINSDIR\InstallOptions.ini" + CopyFiles /SILENT "$PLUGINSDIR\InstallOptions2_Chinese.ini" "$PLUGINSDIR\InstallOptions2.ini" + language_pages_done: + + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ; remember last install dir. + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + ClearErrors + + ; use the appropriate reg view. + ; dont install to the previous x86 location C:\Program Files (x86) if we are x64 + +!ifdef x64 + SetRegView 64 +!endif + + ReadRegStr $R2 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\voidImageViewer" 'UninstallString' + +!ifdef x64 + SetRegView 32 +!endif + + IfErrors no_existing_install_dir + + ; the exe writes a quoted UninstallString (safe with spaces in the + ; path): strip the leading quote so PathRemoveFileSpec sees a plain + ; file spec (it removes through the trailing quote). + StrCpy $R3 $R2 1 + StrCmp $R3 '"' 0 +2 + StrCpy $R2 $R2 "" 1 + + ClearErrors + system::Call 'Shlwapi::PathRemoveFileSpec(tR2R2) i.r1' + IfErrors no_existing_install_dir + + StrCpy $INSTDIR $R2 + +no_existing_install_dir: + + ; get the existing ini filename. + StrCpy $existing_ini_filename "$APPDATA\voidImageViewer\voidImageViewer.ini" + + ; Check if appdata is set to zero + ; $INSTDIR is the existing install location (or the default one if it does not exist) + ReadINIStr $0 "$INSTDIR\voidImageViewer.ini" "voidImageViewer" "appdata" + StrCmp $0 "0" 0 skip_check_app_data + StrCpy $existing_ini_filename "$INSTDIR\voidImageViewer.ini" + !insertmacro MUI_INSTALLOPTIONS_WRITE "InstallOptions.ini" "Field 2" "State" "0" + !insertmacro MUI_INSTALLOPTIONS_WRITE "InstallOptions.ini" "Field 3" "State" "1" + +skip_check_app_data: + + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ; localization + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +!ifdef x64 + + ; check if OS is x64 capable. + System::Call "kernel32::GetCurrentProcess() i .s" + System::Call "kernel32::IsWow64Process(i s, *i .r0)" + IntCmp $0 0 is32 + goto is64 + +is32: + + MessageBox MB_YESNOCANCEL|MB_ICONEXCLAMATION "$(MsgOsNotX64)" IDYES is64 + Abort + +is64: + +!endif ; !ifdef x64 + +FunctionEnd + +Function un.onInit + + ; use the language that was selected during the install. + !insertmacro MUI_UNGETLANGUAGE + + ; get the existing ini filename. + StrCpy $existing_ini_filename "$APPDATA\voidImageViewer\voidImageViewer.ini" + + ; Check if appdata is set to zero + ; $INSTDIR is the existing install location + ReadINIStr $0 "$INSTDIR\voidImageViewer.ini" "voidImageViewer" "appdata" + StrCmp $0 "0" 0 skip_check_app_data + StrCpy $existing_ini_filename "$INSTDIR\voidImageViewer.ini" + +skip_check_app_data: + +FunctionEnd + +; sections +Section "voidImageViewer" SECTION_VOIDIMAGEVIEWER + + ; init + StrCpy $admin_install_options "" + StrCpy $user_install_options "" + + ; app data + !insertmacro MUI_INSTALLOPTIONS_READ $R0 "InstallOptions.ini" "Field 2" "State" + strcmp $R0 "0" no_app_data + StrCpy $admin_install_options "$admin_install_options /appdata" + Goto skip_app_data + +no_app_data: + + ; this option is special, we MUST unset any option that voidImageViewer was previously installed with. + StrCpy $admin_install_options "$admin_install_options /noappdata" + +skip_app_data: + + ; the application language is intentionally NOT forwarded from the + ; installer any more: a fresh install starts in "auto" (follows the + ; system language; the viewer options offer auto/english/chinese). + ; the installer language only localizes the installer itself. + + ; startmenu + !insertmacro MUI_INSTALLOPTIONS_READ $R0 "InstallOptions2.ini" "Field 1" "State" + strcmp $R0 "0" no_startmenu + StrCpy $admin_install_options "$admin_install_options /startmenu" + Goto skip_startmenu + +no_startmenu: + + StrCpy $admin_install_options "$admin_install_options /nostartmenu" + +skip_startmenu: + + ; BMP Associations + !insertmacro MUI_INSTALLOPTIONS_READ $R0 "InstallOptions2.ini" "Field 3" "State" + strcmp $R0 "0" no_bmp_association + StrCpy $user_install_options "$user_install_options /bmp" + Goto skip_bmp_association + +no_bmp_association: + + StrCpy $user_install_options "$user_install_options /nobmp" + +skip_bmp_association: + + ; GIF Associations + !insertmacro MUI_INSTALLOPTIONS_READ $R0 "InstallOptions2.ini" "Field 4" "State" + strcmp $R0 "0" no_gif_association + StrCpy $user_install_options "$user_install_options /gif" + Goto skip_gif_association + +no_gif_association: + + StrCpy $user_install_options "$user_install_options /nogif" + +skip_gif_association: + + ; ico Associations + !insertmacro MUI_INSTALLOPTIONS_READ $R0 "InstallOptions2.ini" "Field 5" "State" + strcmp $R0 "0" no_ico_association + StrCpy $user_install_options "$user_install_options /ico" + Goto skip_ico_association + +no_ico_association: + + StrCpy $user_install_options "$user_install_options /noico" + +skip_ico_association: + + ; jpeg Associations + !insertmacro MUI_INSTALLOPTIONS_READ $R0 "InstallOptions2.ini" "Field 6" "State" + strcmp $R0 "0" no_jpeg_association + StrCpy $user_install_options "$user_install_options /jpeg" + Goto skip_jpeg_association + +no_jpeg_association: + + StrCpy $user_install_options "$user_install_options /nojpeg" + +skip_jpeg_association: + + ; jpg Associations + !insertmacro MUI_INSTALLOPTIONS_READ $R0 "InstallOptions2.ini" "Field 7" "State" + strcmp $R0 "0" no_jpg_association + StrCpy $user_install_options "$user_install_options /jpg" + Goto skip_jpg_association + +no_jpg_association: + + StrCpy $user_install_options "$user_install_options /nojpg" + +skip_jpg_association: + + ; png Associations + !insertmacro MUI_INSTALLOPTIONS_READ $R0 "InstallOptions2.ini" "Field 8" "State" + strcmp $R0 "0" no_png_association + StrCpy $user_install_options "$user_install_options /png" + Goto skip_png_association + +no_png_association: + + StrCpy $user_install_options "$user_install_options /nopng" + +skip_png_association: + + ; tif Associations + !insertmacro MUI_INSTALLOPTIONS_READ $R0 "InstallOptions2.ini" "Field 9" "State" + strcmp $R0 "0" no_tif_association + StrCpy $user_install_options "$user_install_options /tif" + Goto skip_tif_association + +no_tif_association: + + StrCpy $user_install_options "$user_install_options /notif" + +skip_tif_association: + + ; tiff Associations + !insertmacro MUI_INSTALLOPTIONS_READ $R0 "InstallOptions2.ini" "Field 10" "State" + strcmp $R0 "0" no_tiff_association + StrCpy $user_install_options "$user_install_options /tiff" + Goto skip_tiff_association + +no_tiff_association: + + StrCpy $user_install_options "$user_install_options /notiff" + +skip_tiff_association: + + ; webp Associations + !insertmacro MUI_INSTALLOPTIONS_READ $R0 "InstallOptions2.ini" "Field 11" "State" + strcmp $R0 "0" no_webp_association + StrCpy $user_install_options "$user_install_options /webp" + Goto skip_webp_association + +no_webp_association: + + StrCpy $user_install_options "$user_install_options /nowebp" + +skip_webp_association: + + ; emf Associations (the metafile pair joined the viewer in 1.1.12; + ; the exe-side install switches are generic over the extension + ; table, so /emf and /noemf work like every other format) + !insertmacro MUI_INSTALLOPTIONS_READ $R0 "InstallOptions2.ini" "Field 12" "State" + strcmp $R0 "0" no_emf_association + StrCpy $user_install_options "$user_install_options /emf" + Goto skip_emf_association + +no_emf_association: + + StrCpy $user_install_options "$user_install_options /noemf" + +skip_emf_association: + + ; wmf Associations + !insertmacro MUI_INSTALLOPTIONS_READ $R0 "InstallOptions2.ini" "Field 13" "State" + strcmp $R0 "0" no_wmf_association + StrCpy $user_install_options "$user_install_options /wmf" + Goto skip_wmf_association + +no_wmf_association: + + StrCpy $user_install_options "$user_install_options /nowmf" + +skip_wmf_association: + + ; ---------------------------------- + ; begin voidImageViewer installation + ; ---------------------------------- + + SectionIn RO + + InitPluginsDir + SetOutPath "$pluginsdir\voidImageViewer" + + ; write out files to copy. + ; VS version and build config are configurable via defines + + File "${VIV_EXE_DIR}\voidImageViewer.exe" + File "..\Changes.txt" + WriteUninstaller "$pluginsdir\voidImageViewer\Uninstall.exe" + + ; check for command line options that will override the default install options. + ${GetOptions} $CMDLINE "/install-options" $0 + IfErrors +2 + StrCpy $admin_install_options "$admin_install_options $0" + + ; install with admin rights. + ; MessageBox MB_YESNOCANCEL|MB_ICONEXCLAMATION "ADMIN $admin_install_options" + ClearErrors + ExecWait '"$pluginsdir\voidImageViewer\voidImageViewer.exe" /install "$INSTDIR" /install-options "$admin_install_options"' $0 + IfErrors exec_admin_error + IntCmp $0 0 exec_admin_ok + +exec_admin_error: + + MessageBox MB_OK|MB_ICONSTOP "$(MsgExecAdminFailed)" + +exec_admin_ok: + + ClearErrors + ExecWait '"$INSTDIR\voidImageViewer.exe" $user_install_options' $0 + IfErrors exec_install_options_error + IntCmp $0 0 exec_install_options_ok + +exec_install_options_error: + + MessageBox MB_OK|MB_ICONSTOP "$(MsgExecOptionsFailed)" + +exec_install_options_ok: + +SectionEnd + +Section "Uninstall" + + ; Make sure $InstDir is not the current directory so we can remove it + SetOutPath $Temp + + ; copy voidImageViewer.exe to temp folder. + CopyFiles /SILENT $INSTDIR\voidImageViewer.exe $Temp\voidImageViewer.exe + + ; run uninstaller with admin rights + ; this will uninstall any localized shortcuts etc.. + ; this also removes the service if installed + ; which is something we can not do easily from the nsis installer. + ; do this before we try to terminate the app. + ExecWait '"$Temp\voidImageViewer.exe" /uninstall "$INSTDIR"' + + ; delete temp voidImageViewer + Delete "$Temp\voidImageViewer.exe" + +SectionEnd + +Function InstallOptions + + !insertmacro INSTALLOPTIONS_INITDIALOG "InstallOptions.ini" + + !insertmacro MUI_HEADER_TEXT "$(MsgSelectOptionsTitle)" "$(MsgSelectOptionsSub)" + + !insertmacro INSTALLOPTIONS_SHOW + +FunctionEnd + +Function InstallOptions2 + + !insertmacro INSTALLOPTIONS_INITDIALOG "InstallOptions2.ini" + + !insertmacro MUI_HEADER_TEXT "$(MsgSelectOptionsTitle)" "$(MsgSelectOptionsSub)" + + !insertmacro INSTALLOPTIONS_SHOW + +FunctionEnd diff --git a/nsis/installer_license_Chinese.txt b/nsis/installer_license_Chinese.txt index 6f8ce68c..169c3045 100644 --- a/nsis/installer_license_Chinese.txt +++ b/nsis/installer_license_Chinese.txt @@ -1,4 +1,4 @@ - + void Image Viewer 版权所有 (C) 2025 David Carpenter diff --git a/nsis/version.nsh b/nsis/version.nsh index 6e65d04c..7db8e576 100644 --- a/nsis/version.nsh +++ b/nsis/version.nsh @@ -1,3 +1,15 @@ -!define VERSION "1.0.0.15" -!define BETAVERSION "" -!define VERSIONYEAR "2026" +; the single source of truth for the version is src/version.h: +; this file derives everything from it at compile time, so bumping the +; version means editing exactly one file (plus Changes.txt). +!searchparse /noerrors /file "..\src\version.h" `#define VERSION_MAJOR ` VIV_VER_MAJOR +!searchparse /noerrors /file "..\src\version.h" `#define VERSION_MINOR ` VIV_VER_MINOR +!searchparse /noerrors /file "..\src\version.h" `#define VERSION_REVISION ` VIV_VER_REVISION +!searchparse /noerrors /file "..\src\version.h" `#define VERSION_BUILD ` VIV_VER_BUILD +!searchparse /noerrors /file "..\src\version.h" `#define VERSION_YEAR ` VIV_VER_YEAR +!searchparse /noerrors /file "..\src\version.h" `#define VERSION_TYPE "` VIV_VER_TYPE `"` +!searchparse /noerrors /file "..\src\version.h" `#define VERSION_STRING "` VIV_VER_STRING `"` + +!define VERSION "${VIV_VER_MAJOR}.${VIV_VER_MINOR}.${VIV_VER_REVISION}.${VIV_VER_BUILD}" +!define BETAVERSION "${VIV_VER_TYPE}" +!define DISPLAYVERSION "${VIV_VER_STRING}" +!define VERSIONYEAR "${VIV_VER_YEAR}" diff --git a/res/1to1-32bit.ico b/res/1to1-32bit.ico deleted file mode 100644 index 6eba7a8c..00000000 Binary files a/res/1to1-32bit.ico and /dev/null differ diff --git a/res/1to1-8bit.ico b/res/1to1-8bit.ico deleted file mode 100644 index 58222510..00000000 Binary files a/res/1to1-8bit.ico and /dev/null differ diff --git a/res/bestfit.ico b/res/bestfit.ico deleted file mode 100644 index cc4ccaa0..00000000 Binary files a/res/bestfit.ico and /dev/null differ diff --git a/res/next.ico b/res/next.ico deleted file mode 100644 index 079c7e27..00000000 Binary files a/res/next.ico and /dev/null differ diff --git a/res/pause.ico b/res/pause.ico deleted file mode 100644 index 94234a39..00000000 Binary files a/res/pause.ico and /dev/null differ diff --git a/res/play.ico b/res/play.ico deleted file mode 100644 index 2f5b6d34..00000000 Binary files a/res/play.ico and /dev/null differ diff --git a/res/prev.ico b/res/prev.ico deleted file mode 100644 index a37df641..00000000 Binary files a/res/prev.ico and /dev/null differ diff --git a/res/resource.h b/res/resource.h index e3639f70..58ad9229 100644 --- a/res/resource.h +++ b/res/resource.h @@ -13,15 +13,8 @@ #define IDD_CUSTOM_RATE 109 #define IDD_CONTROLS 110 #define IDB_BITMAP1 112 -#define IDI_PREV 116 -#define IDI_PLAY 117 -#define IDI_NEXT 118 -#define IDI_PAUSE 119 #define IDD_ABOUT 121 #define IDD_EDIT_KEY 123 -#define IDI_ICON2 124 -#define IDI_1TO1 124 -#define IDI_BESTFIT 126 #define IDD_RENAME 127 #define IDD_JUMPTO 128 #define IDD_EVERYTHING 129 @@ -83,6 +76,8 @@ #define IDC_EDIT1 1045 #define IDC_EVERYTHING_EDIT 1046 #define IDC_WEBP 1047 +#define IDC_EMF 1048 +#define IDC_WMF 1049 #define IDC_PRELOAD_NEXT_IMAGE 1048 #define IDC_CACHE_LAST_IMAGE 1049 #define IDC_AUTO_ZOOM 1050 @@ -91,14 +86,59 @@ #define IDC_SHRINK_BLIT_MODE_STATIC 1053 #define IDC_MAGNIFY_BLIT_MODE_STATIC 1054 +// control id aliases. +// (upstream master renamed these ids in code, but not in this file yet.) +#define IDC_ADD_KEY_BUTTON IDC_ADD_KEY +#define IDC_EDIT_KEY_BUTTON IDC_EDIT_KEY +#define IDC_REMOVE_KEY_BUTTON IDC_REMOVE_KEY +#define IDC_CACHE_LAST_IMAGE_STATIC IDC_CACHE_LAST_IMAGE +#define IDC_PRELOAD_NEXT_IMAGE_STATIC IDC_PRELOAD_NEXT_IMAGE +#define IDC_LOOP_ANIMATIONS_ONCE_STATIC IDC_LOOP_ANIMATIONS_ONCE +#define IDC_LEFTCLICKACTION_COMBOBOX IDC_LEFTCLICKACTION +#define IDC_RIGHTCLICKACTION_COMBOBOX IDC_RIGHTCLICKACTION +#define IDC_MOUSEWHEELACTION_COMBOBOX IDC_MOUSEWHEELACTION +#define IDC_AUTO_SIZE_WINDOW_COMBOBOX IDC_COMBO4 +#define IDC_CUSTOM_RATE_TYPE_COMBOBOX IDC_CUSTOM_RATE_TYPE_COMBO +#define IDC_SHRINK_BLIT_MODE_COMBOBOX IDC_COMBO1 +#define IDC_MAGNIFY_BLIT_MODE_COMBOBOX IDC_COMBO2 +#define IDC_TITLE_BAR_FORMAT_COMBOBOX IDC_TITLE_BAR_FORMAT +#define IDC_WINDOWEDBACKGROUNDCOLOR_BUTTON IDC_WINDOWEDBACKGROUNDCOLOR +#define IDC_FULLSCREENBACKGROUNDCOLOR_BUTTON IDC_FULLSCREENBACKGROUNDCOLOR +#define IDC_SEARCH_EVERYTHING_RANDOM_CHECKBOX IDC_SEARCH_EVERYTHING_RANDOM + +// new ids for controls that are localized at runtime. +#define IDC_ASSOCIATIONS_GROUPBOX 1055 +#define IDC_SETTINGS_FOR_SELECTED_COMMAND_STATIC 1056 +#define IDC_LEFT_CLICK_ACTION_STATIC 1057 +#define IDC_RIGHT_CLICK_ACTION_STATIC 1058 +#define IDC_MOUSE_WHEEL_ACTION_STATIC 1059 +#define IDC_COMMANDS_STATIC 1060 +#define IDC_CUSTOM_RATE_STATIC 1061 +#define IDC_EDIT_KEYBOARD_SHORTCUT_KEY_STATIC 1062 +#define IDC_EDIT_KEYBOARD_SHORTCUT_KEY_CURRENTLY_USED_BY_STATIC 1063 +#define IDC_TITLE_BAR_FORMAT_STATIC 1064 +#define IDC_WINDOWEDBACKGROUNDCOLOR_STATIC 1065 +#define IDC_FULLSCREENBACKGROUNDCOLOR_STATIC 1066 +#define IDC_LANGUAGE_STATIC 1067 +#define IDC_LANGUAGE 1068 +#define IDC_DARKMODE_STATIC 1069 +#define IDC_DARKMODE 1070 + +// new ids for the about band chrome (the template round): two separator +// lines and the button strip face, declared before the buttons in the +// idd_about template so they sit under them in the z order. +#define IDC_ABOUTBAND 1073 +#define IDC_ABOUTLINE1 1074 +#define IDC_ABOUTLINE2 1075 + // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NO_MFC 1 -#define _APS_NEXT_RESOURCE_VALUE 130 +#define _APS_NEXT_RESOURCE_VALUE 131 #define _APS_NEXT_COMMAND_VALUE 40048 -#define _APS_NEXT_CONTROL_VALUE 1055 +#define _APS_NEXT_CONTROL_VALUE 1076 #define _APS_NEXT_SYMED_VALUE 109 #endif #endif diff --git a/res/voidImageViewer.Manifest b/res/voidImageViewer.Manifest index 4227a91c..cdaae284 100644 --- a/res/voidImageViewer.Manifest +++ b/res/voidImageViewer.Manifest @@ -14,10 +14,39 @@ + + + + + + + + + + + + + + true + + +PerMonitorV2, PerMonitor + diff --git a/res/voidImageViewer.aps b/res/voidImageViewer.aps deleted file mode 100644 index 460e43f6..00000000 Binary files a/res/voidImageViewer.aps and /dev/null differ diff --git a/res/voidImageViewer.rc b/res/voidImageViewer.rc index b138421b..e4930e12 100644 --- a/res/voidImageViewer.rc +++ b/res/voidImageViewer.rc @@ -1,3 +1,5 @@ +// the single source of truth for the version is src/version.h +#include "../src/version.h" // Microsoft Visual C++ generated resource script. // #include "resource.h" @@ -26,55 +28,61 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // Dialog // -IDD_GENERAL DIALOGEX 0, 0, 194, 180 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS +IDD_GENERAL DIALOGEX 0, 0, 194, 242 +STYLE DS_SETFONT | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 0, 0, 0x0 +FONT 9, "Segoe UI", 400, 0, 0 BEGIN CONTROL "&Store settings in %APPDATA%\\voidImageViewer",IDC_APPDATA, "Button",BS_AUTOCHECKBOX | WS_TABSTOP,0,0,186,10 CONTROL "Allow multiple &instances",IDC_MULTIPLE_INSTANCES, "Button",BS_AUTOCHECKBOX | WS_TABSTOP,0,18,186,10 CONTROL "Start &menu shortcuts",IDC_STARTMENU,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,0,36,186,10 - GROUPBOX "Associations",IDC_STATIC,0,54,54,124 - CONTROL "&BMP",IDC_BMP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,66,42,10 - CONTROL "&GIF",IDC_GIF,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,78,42,10 - CONTROL "IC&O",IDC_ICO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,90,42,10 - CONTROL "JP&EG",IDC_JPEG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,102,42,10 - CONTROL "&JPG",IDC_JPG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,114,42,10 - CONTROL "&PNG",IDC_PNG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,126,42,10 - CONTROL "&TIF",IDC_TIF,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,138,42,10 - CONTROL "TIF&F",IDC_TIFF,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,150,42,10 - CONTROL "&WEBP",IDC_WEBP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,162,42,10 - PUSHBUTTON "Check &All",IDC_CHECKALL,60,60,54,14 - PUSHBUTTON "Check &None",IDC_CHECKNONE,60,78,54,14 + LTEXT "Langua&ge:",IDC_LANGUAGE_STATIC,0,54,54,12,SS_CENTERIMAGE + COMBOBOX IDC_LANGUAGE,54,54,132,87,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Dark &mode:",IDC_DARKMODE_STATIC,0,70,54,12,SS_CENTERIMAGE + COMBOBOX IDC_DARKMODE,54,70,132,87,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + GROUPBOX "Associations",IDC_ASSOCIATIONS_GROUPBOX,0,90,54,148 + CONTROL "&BMP",IDC_BMP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,102,42,10 + CONTROL "&GIF",IDC_GIF,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,114,42,10 + CONTROL "IC&O",IDC_ICO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,126,42,10 + CONTROL "JP&EG",IDC_JPEG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,138,42,10 + CONTROL "&JPG",IDC_JPG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,150,42,10 + CONTROL "&PNG",IDC_PNG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,162,42,10 + CONTROL "&TIF",IDC_TIF,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,174,42,10 + CONTROL "TIF&F",IDC_TIFF,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,186,42,10 + CONTROL "&WEBP",IDC_WEBP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,198,42,10 + CONTROL "&EMF",IDC_EMF,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,210,42,10 + CONTROL "&WMF",IDC_WMF,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,222,42,10 + PUSHBUTTON "Check &All",IDC_CHECKALL,60,96,54,14 + PUSHBUTTON "Check &None",IDC_CHECKNONE,60,114,54,14 END -IDD_OPTIONS DIALOGEX 0, 0, 310, 271 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU +IDD_OPTIONS DIALOGEX 0, 0, 310, 295 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_CONTROLPARENT CAPTION "Options - Void Image Viewer" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 +FONT 9, "Segoe UI", 400, 0, 0 BEGIN - DEFPUSHBUTTON "OK",IDOK,198,252,50,14,WS_GROUP - PUSHBUTTON "Cancel",IDCANCEL,252,252,50,14 - CONTROL "",IDC_TREE1,"SysTreeView32",TVS_SHOWSELALWAYS | TVS_TRACKSELECT | WS_BORDER | WS_TABSTOP,6,6,84,240 - CONTROL "",IDC_TAB1,"SysTabControl32",WS_TABSTOP,96,6,210,240 - CONTROL "",IDC_TAB2,"SysTabControl32",WS_TABSTOP,96,6,210,240 - CONTROL "",IDC_TAB3,"SysTabControl32",WS_TABSTOP,96,6,210,240 - LTEXT "Static",IDC_PAGEPLACEHOLDER,106,26,186,214,NOT WS_VISIBLE + DEFPUSHBUTTON "OK",IDOK,198,276,50,14,WS_GROUP + PUSHBUTTON "Cancel",IDCANCEL,252,276,50,14 + CONTROL "",IDC_TREE1,"SysTreeView32",TVS_SHOWSELALWAYS | TVS_TRACKSELECT | WS_BORDER | WS_TABSTOP,6,6,84,264 + CONTROL "",IDC_TAB1,"SysTabControl32",WS_TABSTOP,96,6,210,264 + CONTROL "",IDC_TAB2,"SysTabControl32",WS_TABSTOP,96,6,210,264 + CONTROL "",IDC_TAB3,"SysTabControl32",WS_TABSTOP,96,6,210,264 + LTEXT "Static",IDC_PAGEPLACEHOLDER,106,26,186,238,NOT WS_VISIBLE END IDD_VIEW DIALOGEX 0, 0, 194, 183 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS +STYLE DS_SETFONT | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 0, 0, 0x0 +FONT 9, "Segoe UI", 400, 0, 0 BEGIN LTEXT "&Shrink blit mode:",IDC_SHRINK_BLIT_MODE_STATIC,0,0,74,12,SS_CENTERIMAGE COMBOBOX IDC_COMBO1,74,0,119,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP LTEXT "&Magnify blit mode:",IDC_MAGNIFY_BLIT_MODE_STATIC,0,19,74,8 COMBOBOX IDC_COMBO2,74,17,119,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "&Title bar format:",IDC_STATIC,0,36,74,8 + LTEXT "&Title bar format:",IDC_TITLE_BAR_FORMAT_STATIC,0,36,74,8 COMBOBOX IDC_TITLE_BAR_FORMAT,74,34,119,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP CONTROL "Auto si&ze window:",IDC_AUTO_ZOOM,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,0,53,74,10 COMBOBOX IDC_COMBO4,74,51,60,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP @@ -82,26 +90,26 @@ BEGIN "Button",BS_AUTOCHECKBOX | WS_TABSTOP,0,70,192,10 CONTROL "Preload &next image",IDC_PRELOAD_NEXT_IMAGE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,0,87,192,10 CONTROL "Cache &last image",IDC_CACHE_LAST_IMAGE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,0,103,192,10 - LTEXT "&Windowed background color:",IDC_STATIC,0,122,96,8 + LTEXT "&Windowed background color:",IDC_WINDOWEDBACKGROUNDCOLOR_STATIC,0,122,96,8 PUSHBUTTON "",IDC_WINDOWEDBACKGROUNDCOLOR,96,120,50,14,BS_BITMAP - LTEXT "&Fullscreen background color:",IDC_STATIC,0,140,96,8 + LTEXT "&Fullscreen background color:",IDC_FULLSCREENBACKGROUNDCOLOR_STATIC,0,140,96,8 PUSHBUTTON "",IDC_FULLSCREENBACKGROUNDCOLOR,96,138,50,14,BS_BITMAP END IDD_CONTROLS DIALOGEX 0, 0, 194, 216 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS +STYLE DS_SETFONT | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 0, 0, 0x0 +FONT 9, "Segoe UI", 400, 0, 0 BEGIN - LTEXT "&Left click action:",IDC_STATIC,0,0,54,12,SS_CENTERIMAGE + LTEXT "&Left click action:",IDC_LEFT_CLICK_ACTION_STATIC,0,0,54,12,SS_CENTERIMAGE COMBOBOX IDC_LEFTCLICKACTION,74,0,119,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "&Right click action:",IDC_STATIC,0,19,63,8 + LTEXT "&Right click action:",IDC_RIGHT_CLICK_ACTION_STATIC,0,19,63,8 COMBOBOX IDC_RIGHTCLICKACTION,74,17,119,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "&Mouse wheel action:",IDC_STATIC,0,36,72,8 + LTEXT "&Mouse wheel action:",IDC_MOUSE_WHEEL_ACTION_STATIC,0,36,72,8 COMBOBOX IDC_MOUSEWHEELACTION,74,34,119,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "&Commands:",IDC_STATIC,0,53,57,8 + LTEXT "&Commands:",IDC_COMMANDS_STATIC,0,53,57,8 LISTBOX IDC_COMMANDS_LIST,0,64,193,78,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP - GROUPBOX "Settings for selected command",IDC_STATIC,0,148,193,67 + GROUPBOX "Settings for selected command",IDC_SETTINGS_FOR_SELECTED_COMMAND_STATIC,0,148,193,67 LISTBOX IDC_KEYS_LIST,7,158,125,50,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP PUSHBUTTON "&Add...",IDC_ADD_KEY,138,158,50,14 PUSHBUTTON "&Edit...",IDC_EDIT_KEY,137,177,50,14 @@ -109,22 +117,25 @@ BEGIN END IDD_CUSTOM_RATE DIALOGEX 0, 0, 202, 63 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU CAPTION "Set Custom Rate" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 +FONT 9, "Segoe UI", 400, 0, 0 BEGIN EDITTEXT IDC_CUSTOM_RATE_EDIT,54,12,66,12,ES_AUTOHSCROLL | ES_NUMBER,WS_EX_RIGHT DEFPUSHBUTTON "OK",IDOK,90,36,48,14 PUSHBUTTON "Cancel",IDCANCEL,144,36,48,14 - LTEXT "&Custom rate:",IDC_STATIC,6,14,45,8 + LTEXT "&Custom rate:",IDC_CUSTOM_RATE_STATIC,6,14,45,8 COMBOBOX IDC_CUSTOM_RATE_TYPE_COMBO,126,12,66,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP END IDD_ABOUT DIALOGEX 0, 0, 228, 189 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU CAPTION "About void Image Viewer" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 +FONT 9, "Segoe UI", 400, 0, 0 BEGIN + LTEXT "",IDC_ABOUTLINE1,0,163,228,1 + LTEXT "",IDC_ABOUTLINE2,0,164,228,1 + LTEXT "",IDC_ABOUTBAND,0,165,228,24 DEFPUSHBUTTON "OK",IDOK,120,168,50,14 PUSHBUTTON "Cancel",IDCANCEL,174,168,50,14 LTEXT "",IDC_ABOUTBACK,0,0,228,54 @@ -137,22 +148,22 @@ BEGIN END IDD_EDIT_KEY DIALOGEX 0, 0, 186, 119 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Edit Keyboard Shortcut" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 +FONT 9, "Segoe UI", 400, 0, 0 BEGIN - LTEXT "Shortcut &key:",IDC_STATIC,7,7,44,8 + LTEXT "Shortcut &key:",IDC_EDIT_KEYBOARD_SHORTCUT_KEY_STATIC,7,7,44,8 EDITTEXT IDC_EDIT_KEY_EDIT,7,17,172,14,ES_AUTOHSCROLL | ES_WANTRETURN - LTEXT "Shortcut key currently used by:",IDC_STATIC,7,36,102,8 + LTEXT "Shortcut key currently used by:",IDC_EDIT_KEYBOARD_SHORTCUT_KEY_CURRENTLY_USED_BY_STATIC,7,36,102,8 LISTBOX IDC_EDIT_KEY_CURRENTLY_USED_BY_LIST,7,47,172,43,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP DEFPUSHBUTTON "OK",IDOK,70,98,50,14 PUSHBUTTON "Cancel",IDCANCEL,129,98,50,14 END IDD_RENAME DIALOGEX 0, 0, 186, 51 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Rename" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 +FONT 9, "Segoe UI", 400, 0, 0 BEGIN EDITTEXT IDC_RENAME_EDIT,7,7,172,14,ES_AUTOHSCROLL DEFPUSHBUTTON "OK",IDOK,74,30,50,14 @@ -161,10 +172,10 @@ BEGIN END IDD_JUMPTO DIALOGEX 0, 0, 187, 229 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME EXSTYLE WS_EX_CONTROLPARENT CAPTION "Jump To" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 +FONT 9, "Segoe UI", 400, 0, 0 BEGIN EDITTEXT IDC_JUMPTO_EDIT,7,7,173,14,ES_AUTOHSCROLL | WS_CLIPSIBLINGS | WS_CLIPCHILDREN LISTBOX IDC_JUMPTO_LIST,7,29,173,170,WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VSCROLL | WS_TABSTOP @@ -173,9 +184,9 @@ BEGIN END IDD_EVERYTHING DIALOGEX 0, 0, 186, 63 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Search Everything" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 +FONT 9, "Segoe UI", 400, 0, 0 BEGIN EDITTEXT IDC_EVERYTHING_EDIT,6,6,173,14,ES_AUTOHSCROLL CONTROL "Randomize",IDC_SEARCH_EVERYTHING_RANDOM,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,24,51,10 @@ -192,12 +203,6 @@ END // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDI_ICON1 ICON "voidImageViewer.ico" -IDI_PREV ICON "prev.ico" -IDI_PLAY ICON "play.ico" -IDI_NEXT ICON "next.ico" -IDI_PAUSE ICON "pause.ico" -IDI_1TO1 ICON "1to1-8bit.ico" -IDI_BESTFIT ICON "bestfit.ico" ///////////////////////////////////////////////////////////////////////////// // @@ -205,8 +210,8 @@ IDI_BESTFIT ICON "bestfit.ico" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,0,0,15 - PRODUCTVERSION 1,0,0,15 + FILEVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_REVISION,VERSION_BUILD + PRODUCTVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_REVISION,VERSION_BUILD FILEFLAGSMASK 0x17L #ifdef _DEBUG FILEFLAGS 0x1L @@ -222,12 +227,12 @@ BEGIN BLOCK "040904b0" BEGIN VALUE "FileDescription", "voidImageViewer" - VALUE "FileVersion", "1.0.0.15" + VALUE "FileVersion", VERSION_STRING VALUE "InternalName", "voidImageViewer" - VALUE "LegalCopyright", "Copyright 2026 voidtools" + VALUE "LegalCopyright", "Copyright (C) 2026 voidtools" VALUE "OriginalFilename", "voidImageViewer.exe" VALUE "ProductName", "voidImageViewer" - VALUE "ProductVersion", "1.0.0.15" + VALUE "ProductVersion", VERSION_STRING END END BLOCK "VarFileInfo" diff --git a/scripts/extract-theme.mjs b/scripts/extract-theme.mjs new file mode 100644 index 00000000..61418fbc --- /dev/null +++ b/scripts/extract-theme.mjs @@ -0,0 +1,80 @@ +#!/usr/bin/env node +/** + * extract_theme.mjs — transcribe the C theme table into TypeScript. + * + * reads src/viv_theme.c (the single source of the palette) and emits + * sim/theme-tokens.ts, so the page simulator can never drift from what the + * exe actually draws (the "mockup vs build" mismatch guard). + * + * usage: node scripts/extract-theme.mjs [repoRoot] + */ +import { readFileSync, writeFileSync, mkdirSync } from 'fs'; + +const root = process.argv[2] ?? '/home/z/vivp-remake2'; +const src = readFileSync(`${root}/src/viv_theme.c`, 'utf8'); + +const byte = (x) => String(x).toLowerCase().replace(/^0x/, '').padStart(2, '0'); +const rgb = (r, g, b) => '#' + byte(r) + byte(g) + byte(b); + +// parse the dark token table: RGB(0xRR,0xGG,0xBB),\t// VIV_TK_NAME +const darkRows = [...src.matchAll(/RGB\((0x[0-9A-Fa-f]{2}),(0x[0-9A-Fa-f]{2}),(0x[0-9A-Fa-f]{2})\),?\s*\/\/\s*(VIV_TK_\w+)/g)]; +const dark = {}; +for (const [, r, g, b, name] of darkRows) dark[name] = rgb(r, g, b); + +// parse the accent table: 5 rows x {base, hot, down} +const accentRows = [...src.matchAll(/\{RGB\((0x\w+),(0x\w+),(0x\w+)\),RGB\((0x\w+),(0x\w+),(0x\w+)\),RGB\((0x\w+),(0x\w+),(0x\w+)\)\},?\s*\/\/\s*(\w+)/g)]; +const accents = accentRows.map((m) => ({ + name: m[10], + base: rgb(m[1], m[2], m[3]), + hot: rgb(m[4], m[5], m[6]), + down: rgb(m[7], m[8], m[9]), +})); + +// the light side is a GetSysColor mapping — semantic constants mirrored +// from _viv_theme_light_color. +const light = { + VIV_TK_FACE: '#f0f0f0', + VIV_TK_NAV_FACE: '#f0f0f0', + VIV_TK_CHROME: '#e0e0e0', + VIV_TK_CHROME_LINE: '#a0a0a0', + VIV_TK_CHROME_MUTED: '#6d6d6d', + VIV_TK_FRAME: '#ffffff', + VIV_TK_INPUT: '#ffffff', + VIV_TK_LINE: '#a0a0a0', + VIV_TK_HOVER: '#e3e3e3', + VIV_TK_DOWN: '#a0a0a0', + VIV_TK_TEXT: '#000000', + VIV_TK_TEXT2: '#6d6d6d', + VIV_TK_TEXTOFF: '#6d6d6d', + VIV_TK_ON_ACCENT: '#ffffff', +}; + +const order = [ + 'VIV_TK_FACE', 'VIV_TK_NAV_FACE', 'VIV_TK_CHROME', 'VIV_TK_CHROME_LINE', 'VIV_TK_CHROME_MUTED', + 'VIV_TK_FRAME', 'VIV_TK_INPUT', 'VIV_TK_LINE', 'VIV_TK_HOVER', 'VIV_TK_DOWN', + 'VIV_TK_TEXT', 'VIV_TK_TEXT2', 'VIV_TK_TEXTOFF', 'VIV_TK_ACCENT', 'VIV_TK_ACCENT_HOT', + 'VIV_TK_ACCENT_DOWN', 'VIV_TK_ON_ACCENT', +]; + +const out = `// GENERATED by scripts/extract-theme.mjs from src/viv_theme.c — do not hand edit. +// the simulator renders from exactly the values the exe draws. +export type ThemeMode = 'dark' | 'light'; +export interface Accent { name: string; base: string; hot: string; down: string } + +export const ACCENTS: Accent[] = ${JSON.stringify(accents, null, 2)}; + +export const DARK_TOKENS: Record = ${JSON.stringify(dark, null, 2)}; +export const LIGHT_TOKENS: Record = ${JSON.stringify(light, null, 2)}; +export const TOKEN_ORDER: string[] = ${JSON.stringify(order, null, 2)}; + +export function themeColor(mode: ThemeMode, token: string, accent: number): string { + if (token === 'VIV_TK_ACCENT') return ACCENTS[accent].base; + if (token === 'VIV_TK_ACCENT_HOT') return ACCENTS[accent].hot; + if (token === 'VIV_TK_ACCENT_DOWN') return ACCENTS[accent].down; + return (mode === 'dark' ? DARK_TOKENS : LIGHT_TOKENS)[token] ?? '#ff00ff'; +} +`; +mkdirSync(`${root}/sim`, { recursive: true }); +writeFileSync(`${root}/sim/theme-tokens.ts`, out); +console.log('theme-tokens.ts written:', order.length, 'tokens,', accents.length, 'accents'); +console.log('dark sample:', dark['VIV_TK_FACE'], dark['VIV_TK_TEXT'], 'accent0:', accents[0]?.base); diff --git a/sim/theme-tokens.ts b/sim/theme-tokens.ts new file mode 100644 index 00000000..dcd8159b --- /dev/null +++ b/sim/theme-tokens.ts @@ -0,0 +1,99 @@ +// GENERATED by scripts/extract-theme.mjs from src/viv_theme.c — do not hand edit. +// the simulator renders from exactly the values the exe draws. +export type ThemeMode = 'dark' | 'light'; +export interface Accent { name: string; base: string; hot: string; down: string } + +export const ACCENTS: Accent[] = [ + { + "name": "azure", + "base": "#1e66e8", + "hot": "#3b7bee", + "down": "#1a57c8" + }, + { + "name": "teal", + "base": "#0e9888", + "hot": "#2fb3a2", + "down": "#0a7a6e" + }, + { + "name": "violet", + "base": "#7a5af0", + "hot": "#9378f4", + "down": "#6348ce" + }, + { + "name": "amber", + "base": "#c77420", + "hot": "#de8c36", + "down": "#a85e14" + }, + { + "name": "rose", + "base": "#d6445e", + "hot": "#e4637a", + "down": "#b93350" + } +]; + +export const DARK_TOKENS: Record = { + "VIV_TK_FACE": "#232328", + "VIV_TK_NAV_FACE": "#1b1b1f", + "VIV_TK_CHROME": "#202024", + "VIV_TK_CHROME_LINE": "#3a3a40", + "VIV_TK_CHROME_MUTED": "#707070", + "VIV_TK_FRAME": "#1b1b1e", + "VIV_TK_INPUT": "#2a2a2f", + "VIV_TK_LINE": "#3a3a40", + "VIV_TK_HOVER": "#2e2e33", + "VIV_TK_DOWN": "#38383e", + "VIV_TK_TEXT": "#e8e8ea", + "VIV_TK_TEXT2": "#9a9aa0", + "VIV_TK_TEXTOFF": "#6a6a70", + "VIV_TK_ACCENT": "#000000", + "VIV_TK_ACCENT_HOT": "#000000", + "VIV_TK_ACCENT_DOWN": "#000000", + "VIV_TK_ON_ACCENT": "#ffffff" +}; +export const LIGHT_TOKENS: Record = { + "VIV_TK_FACE": "#f0f0f0", + "VIV_TK_NAV_FACE": "#f0f0f0", + "VIV_TK_CHROME": "#e0e0e0", + "VIV_TK_CHROME_LINE": "#a0a0a0", + "VIV_TK_CHROME_MUTED": "#6d6d6d", + "VIV_TK_FRAME": "#ffffff", + "VIV_TK_INPUT": "#ffffff", + "VIV_TK_LINE": "#a0a0a0", + "VIV_TK_HOVER": "#e3e3e3", + "VIV_TK_DOWN": "#a0a0a0", + "VIV_TK_TEXT": "#000000", + "VIV_TK_TEXT2": "#6d6d6d", + "VIV_TK_TEXTOFF": "#6d6d6d", + "VIV_TK_ON_ACCENT": "#ffffff" +}; +export const TOKEN_ORDER: string[] = [ + "VIV_TK_FACE", + "VIV_TK_NAV_FACE", + "VIV_TK_CHROME", + "VIV_TK_CHROME_LINE", + "VIV_TK_CHROME_MUTED", + "VIV_TK_FRAME", + "VIV_TK_INPUT", + "VIV_TK_LINE", + "VIV_TK_HOVER", + "VIV_TK_DOWN", + "VIV_TK_TEXT", + "VIV_TK_TEXT2", + "VIV_TK_TEXTOFF", + "VIV_TK_ACCENT", + "VIV_TK_ACCENT_HOT", + "VIV_TK_ACCENT_DOWN", + "VIV_TK_ON_ACCENT" +]; + +export function themeColor(mode: ThemeMode, token: string, accent: number): string { + if (token === 'VIV_TK_ACCENT') return ACCENTS[accent].base; + if (token === 'VIV_TK_ACCENT_HOT') return ACCENTS[accent].hot; + if (token === 'VIV_TK_ACCENT_DOWN') return ACCENTS[accent].down; + return (mode === 'dark' ? DARK_TOKENS : LIGHT_TOKENS)[token] ?? '#ff00ff'; +} diff --git a/src/config.c b/src/config.c index 719eb0c1..cdb2b7d4 100644 --- a/src/config.c +++ b/src/config.c @@ -23,13 +23,22 @@ #include "viv.h" +static int _config_icompare_ascii(const utf8_t *s1,const char *lowercase_ascii_s2); static void _config_load_settings_by_location(const wchar_t *path,int is_root); static void _config_write_int(HANDLE h,const char *ascii_key,int value); static void _config_write_string(HANDLE h,const char *ascii_key,const wchar_t *s); static void _config_write_utf8(HANDLE h,const utf8_t *s); +static void _config_recent_key_name(utf8_t *buf,int index); static void _config_save_settings_by_location(const wchar_t *path,int is_root); BYTE config_appdata = 0; // store settings in %APPDATA%\voidimageviewer or in the same location as voidimageviewer.exe +BYTE config_language = 0; // ui language: 0 = auto (follow the system language), 1 = english, 2 = simplified chinese. +BYTE config_dark_mode = 2; // ui theme: 0 = light, 1 = dark, 2 = auto (follow the windows theme). +BYTE config_ui_accent = 0; // ui accent color index into the viv_theme accent table (0..4). +BYTE config_backdrop_mode = CONFIG_BACKDROP_MODE_FOLLOW; // backdrop under transparent pixels: 0 = follow window background, 1 = black, 2 = white, 3 = custom, 4 = checkerboard +BYTE config_backdrop_color_r = 128; // custom backdrop color +BYTE config_backdrop_color_g = 128; +BYTE config_backdrop_color_b = 128; BYTE config_keep_centered = 1; // when zooming out, don't recenter the image. (keep cursor under the same pixel) int config_x = 0; int config_y = 0; @@ -40,8 +49,11 @@ int config_slideshow_rate = 5000; BYTE config_allow_shrinking = 1; // prevent resizing an image below 100% BYTE config_shrink_blit_mode = CONFIG_SHRINK_BLIT_MODE_HALFTONE; // shrink filter BYTE config_mag_filter = CONFIG_MAG_FILTER_COLORONCOLOR; // magnify filter -BYTE config_nav_sort = CONFIG_NAV_SORT_DATE_MODIFIED; // current navigation sort. -BYTE config_nav_sort_ascending = 0; // sort navigation ascending or descending. +// default to sorting by filename in natural order, ascending. +// this matches the windows explorer default, so next/previous navigation +// walks the folder in the order the user sees it in explorer. +BYTE config_nav_sort = CONFIG_NAV_SORT_NAME; // current navigation sort. +BYTE config_nav_sort_ascending = 1; // sort navigation ascending or descending. BYTE config_keep_aspect_ratio = 1; // stretch images with the original aspect ratio. BYTE config_fill_window = 0; // stretch the image to fill the window BYTE config_fullscreen_fill_window = 1; // same as fill_window, except this setting is used when we are fullscreen @@ -55,6 +67,11 @@ BYTE config_frame_minus = 0; // show frame counter or remaining frames in status BYTE config_multiple_instances = 0; // all multiple instances or use a single instance. BYTE config_show_status = 1; BYTE config_show_controls = 1; +BYTE config_show_zoom_controls = 0; // show the floating zoom controls. (defaults to on for touch devices) +BYTE config_zoom_auto_hide = 1; // auto-hide the fullscreen zoom overlay when idle. +// recent files mru: newest first, at most CONFIG_RECENT_FILE_COUNT entries. +wchar_t *config_recent_files[CONFIG_RECENT_FILE_COUNT] = {0}; +int config_recent_file_count = 0; BYTE config_prevent_sleep = 1; BYTE config_loop_animations_once = 1; BYTE config_mouse_wheel_action = 0; // 0 = zoom, 1 = next/prev, 2=prev/next @@ -122,6 +139,111 @@ static void _config_load_settings_by_location(const wchar_t *path,int is_root) config_show_status = ini_get_int(ini,(const utf8_t *)"show_status",config_show_status); config_pixel_info = ini_get_int(ini,(const utf8_t *)"statusbar_pixel_info",config_pixel_info); config_show_controls = ini_get_int(ini,(const utf8_t *)"show_controls",config_show_controls); + // the digitizer probe is a first-run default only: msdn warns + // sm_digitizer has no plug-and-play awareness, so the value gets + // pinned into the ini on the first save and is never re-probed. + config_show_zoom_controls = ini_get_int(ini,(const utf8_t *)"show_zoom_controls",os_is_touch_available()); + config_zoom_auto_hide = ini_get_int(ini,(const utf8_t *)"zoom_auto_hide",config_zoom_auto_hide); + + // ui language. stored as a readable string: auto, english or chinese. + { + const utf8_t *language_value; + + language_value = ini_get_string(ini,(const utf8_t *)"language"); + + if (language_value) + { + if (_config_icompare_ascii(language_value,"english") == 0) + { + config_language = 1; + } + else + if (_config_icompare_ascii(language_value,"chinese") == 0) + { + config_language = 2; + } + else + { + // "auto" (and anything we don't understand) follows the system language. + config_language = 0; + } + } + } + + // dark mode. stored as a readable string: auto, dark or light. + { + const utf8_t *dark_mode_value; + + dark_mode_value = ini_get_string(ini,(const utf8_t *)"dark_mode"); + + if (dark_mode_value) + { + if (_config_icompare_ascii(dark_mode_value,"dark") == 0) + { + config_dark_mode = 1; + } + else + if (_config_icompare_ascii(dark_mode_value,"light") == 0) + { + config_dark_mode = 0; + } + else + { + // "auto" (and anything we don't understand) follows the windows theme. + config_dark_mode = 2; + } + } + } + + // accent color. an index into the viv_theme accent table, clamped. + config_ui_accent = (BYTE)ini_get_int(ini,(const utf8_t *)"accent_color",0); + + if (config_ui_accent >= VIV_THEME_ACCENT_COUNT) + { + config_ui_accent = 0; + } + config_backdrop_mode = ini_get_int(ini,(const utf8_t *)"backdrop_mode",config_backdrop_mode); + config_backdrop_color_r = ini_get_int(ini,(const utf8_t *)"backdrop_color_r",config_backdrop_color_r); + config_backdrop_color_g = ini_get_int(ini,(const utf8_t *)"backdrop_color_g",config_backdrop_color_g); + config_backdrop_color_b = ini_get_int(ini,(const utf8_t *)"backdrop_color_b",config_backdrop_color_b); + + // recent files mru: recent_file_0 .. recent_file_9 hold the most + // recently opened paths, newest first. the walk stops at the first + // empty slot so a hand-edited hole cannot reorder the list. + { + int i; + + for(i=0;i CONFIG_RECENT_FILE_COUNT) + { + config_recent_file_count = CONFIG_RECENT_FILE_COUNT; + } config_auto_zoom = ini_get_int(ini,(const utf8_t *)"auto_zoom",config_auto_zoom); config_auto_zoom_type = ini_get_int(ini,(const utf8_t *)"auto_zoom_type",config_auto_zoom_type); config_auto_fit_wide_mul = ini_get_int(ini,(const utf8_t *)"auto_fit_wide_mul",config_auto_fit_wide_mul); @@ -235,6 +357,39 @@ void config_load_settings(void) } +static int _config_icompare_ascii(const utf8_t *s1,const char *lowercase_ascii_s2) +{ + // case-insensitive compare of an ascii/utf-8 string against a lowercase ascii keyword. + // returns 0 when equal. + + while (*s1 && *lowercase_ascii_s2) + { + char c; + + c = (char)*s1; + + if ((c >= 'A') && (c <= 'Z')) + { + c += 'a' - 'A'; + } + + if (c != *lowercase_ascii_s2) + { + return 1; + } + + s1++; + lowercase_ascii_s2++; + } + + if (*s1 || *lowercase_ascii_s2) + { + return 1; + } + + return 0; +} + static void _config_write_int(HANDLE h,const char *ascii_key,int value) { wchar_t wbuf[STRING_SIZE]; @@ -247,8 +402,17 @@ static void _config_write_int(HANDLE h,const char *ascii_key,int value) static void _config_write_string(HANDLE h,const char *ascii_key,const wchar_t *s) { utf8_t buf[STRING_SIZE*3]; + int ret; - WideCharToMultiByte(CP_UTF8,0,s,-1,(char *)buf,STRING_SIZE*3,0,0); + // check the conversion: on failure the buffer is left unterminated and + // the writes below would read past its end (a full-width string can + // hit the boundary: STRING_SIZE wchars x 3 utf8 bytes + nul). + ret = WideCharToMultiByte(CP_UTF8,0,s,-1,(char *)buf,STRING_SIZE*3,0,0); + + if ((ret <= 0) || (ret >= (int)sizeof(buf))) + { + buf[0] = 0; + } _config_write_utf8(h,(const utf8_t *)ascii_key); _config_write_utf8(h,(const utf8_t *)"="); @@ -256,6 +420,25 @@ static void _config_write_string(HANDLE h,const char *ascii_key,const wchar_t *s _config_write_utf8(h,(const utf8_t *)"\r\n"); } +static void _config_recent_key_name(utf8_t *buf,int index) +{ + // "recent_file_0" .. "recent_file_9" + buf[0] = 'r'; + buf[1] = 'e'; + buf[2] = 'c'; + buf[3] = 'e'; + buf[4] = 'n'; + buf[5] = 't'; + buf[6] = '_'; + buf[7] = 'f'; + buf[8] = 'i'; + buf[9] = 'l'; + buf[10] = 'e'; + buf[11] = '_'; + buf[12] = (utf8_t)('0' + (index % 10)); + buf[13] = 0; +} + static void _config_write_utf8(HANDLE h,const utf8_t *s) { DWORD num_written; @@ -306,6 +489,15 @@ static void _config_save_settings_by_location(const wchar_t *path,int is_root) _config_write_int(h,"show_status",config_show_status); _config_write_int(h,"statusbar_pixel_info",config_pixel_info); _config_write_int(h,"show_controls",config_show_controls); + _config_write_int(h,"show_zoom_controls",config_show_zoom_controls); + _config_write_int(h,"zoom_auto_hide",config_zoom_auto_hide); + _config_write_string(h,"language",config_language == 1 ? L"english" : (config_language == 2 ? L"chinese" : L"auto")); + _config_write_string(h,"dark_mode",config_dark_mode == 1 ? L"dark" : (config_dark_mode == 0 ? L"light" : L"auto")); + _config_write_int(h,"accent_color",config_ui_accent); + _config_write_int(h,"backdrop_mode",config_backdrop_mode); + _config_write_int(h,"backdrop_color_r",config_backdrop_color_r); + _config_write_int(h,"backdrop_color_g",config_backdrop_color_g); + _config_write_int(h,"backdrop_color_b",config_backdrop_color_b); _config_write_int(h,"auto_zoom",config_auto_zoom); _config_write_int(h,"auto_zoom_type",config_auto_zoom_type); _config_write_int(h,"auto_fit_wide_mul",config_auto_fit_wide_mul); @@ -345,6 +537,21 @@ static void _config_save_settings_by_location(const wchar_t *path,int is_root) _config_write_int(h,"toolbar_move_window",config_toolbar_move_window); _config_write_int(h,"title_bar_format",config_title_bar_format); _config_write_int(h,"add_command_line_timeout",config_add_command_line_timeout); + + // save the recent files mru: filled slots carry paths, the rest + // are written empty so removed entries do not survive a reload. + { + int i; + + for(i=0;iwidth) * scale; + + // a sub pixel stroke renders as a faint gray blur at the small + // toolbar sizes: keep every stroke at least 1.25 device pixels wide. + if (pen_width < 1.25f) + { + pen_width = 1.25f; + } + + if (_glyphs_gdipCreatePen1(argb,pen_width,_GLYPHS_UNIT_PIXEL,&pen) == 0) + { + _glyphs_point_f_t *pts; + + // round caps: the strokes end in soft dots instead of + // square cuts, the signature of the glyph family. + _glyphs_gdipSetPenStartCap(pen,_GLYPHS_LINE_CAP_ROUND); + _glyphs_gdipSetPenEndCap(pen,_GLYPHS_LINE_CAP_ROUND); + + if (stroke->points) + { + pts = (_glyphs_point_f_t *)mem_alloc(safe_size_mul(sizeof(_glyphs_point_f_t),(size_t)stroke->point_count)); + + if (pts) + { + int pi; + + for(pi=0;pipoint_count;pi++) + { + pts[pi].x = ((float)stroke->points[pi].x) * scale; + pts[pi].y = ((float)stroke->points[pi].y) * scale; + } + + // float coordinates: the float draw api keeps the 48 grid + // geometry off the pixel lattice, so the small icons stay + // round instead of lumpy. + _glyphs_gdipDrawLinesF(graphics,pen,pts,stroke->point_count); + + mem_free(pts); + } + } + else if (stroke->ellipse) + { + // the true ellipse stroke: the ring is drawn as a + // single arc primitive instead of a sampled polyline, + // so no vertex wobble can reach the lens at any size. + _glyphs_gdipDrawEllipseF(graphics,pen,(stroke->ellipse->cx - stroke->ellipse->rx) * scale,(stroke->ellipse->cy - stroke->ellipse->ry) * scale,(stroke->ellipse->rx * 2.0f) * scale,(stroke->ellipse->ry * 2.0f) * scale); + } + else if (stroke->arc) + { + // the true arc stroke: the rotate glyph three quarter + // circle is one primitive (degrees, the same round capped + // pen), so no sampled polyline wobble can reach the curve. + _glyphs_gdipDrawArcF(graphics,pen,(stroke->arc->cx - stroke->arc->rx) * scale,(stroke->arc->cy - stroke->arc->ry) * scale,(stroke->arc->rx * 2.0f) * scale,(stroke->arc->ry * 2.0f) * scale,stroke->arc->start,stroke->arc->sweep); + } + + _glyphs_gdipDeletePen(pen); + } + } + } + + _glyphs_gdipDeleteGraphics(graphics); + } + + if (_glyphs_gdipCreateHICONFromBitmap(bitmap,&icon) != 0) + { + icon = 0; + } + + _glyphs_gdipDisposeImage(bitmap); + } + + mem_free(bits); + + return icon; +} + +HICON glyphs_icon(int glyph_id,int dark,int size) +{ + HICON icon; + int i; + + if (!_glyphs_load()) + { + return 0; + } + + if ((glyph_id < 0) || (glyph_id >= GLYPH_COUNT) || (size <= 0)) + { + return 0; + } + + for(i=0;i<_glyphs_cache_count;i++) + { + if ((_glyphs_cache[i].glyph == glyph_id) && (_glyphs_cache[i].dark == (dark ? 1 : 0)) && (_glyphs_cache[i].size == size)) + { + return _glyphs_cache[i].icon; + } + } + + // evict the oldest entry when the table is full. + if (_glyphs_cache_count == _GLYPHS_CACHE_MAX) + { + if (_glyphs_cache[0].icon) + { + DestroyIcon(_glyphs_cache[0].icon); + } + + // source and destination overlap: copymemory (memcpy) is undefined for + // overlapping ranges, movememory (memmove) is not. + os_move_memory(&_glyphs_cache[0],&_glyphs_cache[1],sizeof(_glyphs_cache[0]) * (_GLYPHS_CACHE_MAX - 1)); + + _glyphs_cache_count--; + } + + icon = _glyphs_build(glyph_id,dark ? 1 : 0,size); + + // a failed build never caches: a zero entry would shadow every retry + // (a later flush would blank that glyph for good). + if (!icon) + { + return 0; + } + + _glyphs_cache[_glyphs_cache_count].glyph = glyph_id; + _glyphs_cache[_glyphs_cache_count].dark = dark ? 1 : 0; + _glyphs_cache[_glyphs_cache_count].size = size; + _glyphs_cache[_glyphs_cache_count].icon = icon; + + return _glyphs_cache[_glyphs_cache_count++].icon; +} + +void glyphs_flush_cache(void) +{ + int i; + + for(i=0;i<_glyphs_cache_count;i++) + { + if (_glyphs_cache[i].icon) + { + DestroyIcon(_glyphs_cache[i].icon); + } + } + + _glyphs_cache_count = 0; +} + diff --git a/src/glyphs.h b/src/glyphs.h new file mode 100644 index 00000000..308a7390 --- /dev/null +++ b/src/glyphs.h @@ -0,0 +1,70 @@ +// +// Copyright 2026 voidtools / David Carpenter +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +// vector glyph icons (toolbar + zoom controls). +// drawn from a 48x48 design grid (2.5 unit round capped strokes) through +// the gdi+ flat api at any requested size and in both theme colors, +// converted to HICONs and cached per (glyph, theme, size). + +#ifndef _GLYPHS_H_INCLUDED_ +#define _GLYPHS_H_INCLUDED_ + +#ifdef __cplusplus +extern "C" { +#endif + +// glyph ids. 0..7 are the media transport / zoom set (the old toolbar image +// list order, still shared with the zoom pill); 8..15 are the remade +// toolbar's set (open, the magnifier pair, rotate, info, settings, picture +// and the gamepad for the settings window nav). +#define GLYPH_PREV 0 +#define GLYPH_PLAY 1 +#define GLYPH_PAUSE 2 +#define GLYPH_NEXT 3 +#define GLYPH_BESTFIT 4 +#define GLYPH_1TO1 5 +#define GLYPH_ZOOMOUT 6 +#define GLYPH_ZOOMIN 7 +#define GLYPH_FOLDER_OPEN 8 +#define GLYPH_MAGNIFIER_MINUS 9 +#define GLYPH_MAGNIFIER_PLUS 10 +#define GLYPH_ROTATE_CW 11 +#define GLYPH_INFO 12 +#define GLYPH_SETTINGS 13 +#define GLYPH_PICTURE 14 +#define GLYPH_GAMEPAD 15 +#define GLYPH_COUNT 16 + +// return the glyph icon at the requested size and theme. the icon is +// owned by the glyphs cache: do not destroy it. building needs gdi+; +// on failure 0 is returned and callers should skip drawing. +HICON glyphs_icon(int glyph_id,int dark,int size); + +// drop every cached icon. call when the palette or the window dpi +// changes (both are baked into the cached bitmaps). +void glyphs_flush_cache(void); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/src/ini.c b/src/ini.c index b9a866d2..726add7b 100644 --- a/src/ini.c +++ b/src/ini.c @@ -56,7 +56,7 @@ typedef struct _ini_s }_ini_t; -static int _ini_keyvalue_compare(const _ini_keyvalue_t *a,const _ini_keyvalue_t *b); +static int _ini_keyvalue_compare(const void *va,const void *vb); static _ini_keyvalue_t *_ini_keyvalue_find(ini_t *ini,const utf8_t *key); ini_t *ini_open(const wchar_t *filename,const utf8_t *ascii_section) @@ -79,12 +79,16 @@ ini_t *ini_open(const wchar_t *filename,const utf8_t *ascii_section) size = GetFileSize(h,0); - if (size) + // GetFileSize returns INVALID_FILE_SIZE on failure and for + // files over 4GB: never trust that as an allocation size. a real + // ini is a few kilobytes: anything past 16 mb is a hostile or + // corrupted file, refuse it before the allocation. + if ((size != INVALID_FILE_SIZE) && (size) && (size <= 0x1000000)) { char *buf; DWORD numread; - buf = mem_alloc(size + 1); + buf = mem_alloc(safe_size_add_one(size)); if (ReadFile(h,buf,size,&numread,NULL)) { @@ -296,7 +300,7 @@ ini_t *ini_open(const wchar_t *filename,const utf8_t *ascii_section) ini = mem_alloc(sizeof(_ini_t)); // allocate indexes - indexes = mem_alloc(sizeof(_ini_keyvalue_t *) * count); + indexes = mem_alloc(safe_size_mul_sizeof_pointer((SIZE_T)count)); // fill in indexes // and conect next to index @@ -435,13 +439,18 @@ static _ini_keyvalue_t *_ini_keyvalue_find(ini_t *ini,const utf8_t *key) } // compare two key values. -static int _ini_keyvalue_compare(const _ini_keyvalue_t *a,const _ini_keyvalue_t *b) +static int _ini_keyvalue_compare(const void *va,const void *vb) { + const _ini_keyvalue_t *a; + const _ini_keyvalue_t *b; int i; + a = (_ini_keyvalue_t *)va; + b = (_ini_keyvalue_t *)vb; + i = utf8_compare(a->key,b->key); if (i) return i; - + return a->index - b->index; } diff --git a/src/localization.c b/src/localization.c index 691e4716..42c74b20 100644 --- a/src/localization.c +++ b/src/localization.c @@ -35,23 +35,54 @@ BYTE localization_language = LOCALIZATION_LANGUAGE_ENGLISH; const utf8_t *localization_get_string(localization_id_t localization_id) { + // a bad id used to be an out-of-bounds read in release builds: the + // range check was debug only. clamp to the english fallback so a + // missed translation index degrades instead of crashing. + if ((localization_id < 0) || (localization_id >= LOCALIZATION_ID_COUNT)) + { #ifdef _DEBUG - -if ((localization_id < 0) || (localization_id >= LOCALIZATION_ID_COUNT)) -{ - debug_fatal("bad localization id %d\n",localization_id); -} - + debug_fatal("bad localization id %d\n",localization_id); #endif + return _localization_string_array_en_us[0]; + } return _localization_language_array[localization_language][localization_id]; } const utf8_t *localization_get_en_us_string(localization_id_t localization_id) { + if ((localization_id < 0) || (localization_id >= LOCALIZATION_ID_COUNT)) + { + return _localization_string_array_en_us[0]; + } + return _localization_string_array_en_us[localization_id]; } +const utf8_t *localization_get_language_name(BYTE language) +{ + // Return the name of a language in that language itself. + // Used by the options dialog so every language is listed in its own script. + + if (language < LOCALIZATION_LANGUAGE_COUNT) + { + return _localization_language_array[language][LOCALIZATION_ID_LANGUAGE]; + } + + return _localization_string_array_en_us[LOCALIZATION_ID_LANGUAGE]; +} + +void localization_set_language(BYTE language) +{ + // Explicitly select the active language. + // Invalid values are ignored (the current language is kept). + + if (language < LOCALIZATION_LANGUAGE_COUNT) + { + localization_language = language; + } +} + void localization_init(void) { // Detect system language @@ -61,11 +92,15 @@ void localization_init(void) langid = os_GetUserDefaultUILanguage(); - // Check if it's Chinese (Simplified or Traditional) + // Check if it's Chinese (Simplified or Traditional). + // the simplified table is the only chinese table we ship, so every + // chinese ui locale maps to it (best effort for traditional readers). // 0x0804 = Chinese (Simplified, PRC) + // 0x1004 = Chinese (Simplified, Singapore) // 0x0404 = Chinese (Traditional, Taiwan) // 0x0C04 = Chinese (Traditional, Hong Kong) - if ((langid == 0x0804) || (langid == 0x0404) || (langid == 0x0C04)) + // 0x1404 = Chinese (Traditional, Macau) + if ((langid == 0x0804) || (langid == 0x1004) || (langid == 0x0404) || (langid == 0x0C04) || (langid == 0x1404)) { localization_language = LOCALIZATION_LANGUAGE_CHINESE_SIMPLIFIED; } diff --git a/src/localization.h b/src/localization.h index 99248c5d..76ff40d2 100644 --- a/src/localization.h +++ b/src/localization.h @@ -32,18 +32,25 @@ enum LOCALIZATION_LANGUAGE_COUNT, }; -typedef BYTE localization_id_t; +// note: must hold LOCALIZATION_ID_COUNT values, so it is wider than a byte. +typedef unsigned short localization_id_t; -#define LOCALIZATION_ID_INVALID 255 +// LOCALIZATION_ID_INVALID is defined after the localization id enum below. // Get localized string for a command name // Returns UTF-8 encoded string const utf8_t *localization_get_string(localization_id_t localization_id); const utf8_t *localization_get_en_us_string(localization_id_t localization_id); +// Get the native name of a language (e.g. the Chinese name in Chinese script). +const utf8_t *localization_get_language_name(BYTE language); // Initialize language system (detects system language) void localization_init(void); +// Set the active language (overrides the detected system language). +// language: LOCALIZATION_LANGUAGE_* value. +void localization_set_language(BYTE language); + // String IDs for menu items and UI text enum { @@ -88,6 +95,7 @@ enum // View menu LOCALIZATION_ID_VIEW, + LOCALIZATION_ID_LAYOUT, LOCALIZATION_ID_CAPTION, LOCALIZATION_ID_FRAME, LOCALIZATION_ID_MENU, @@ -110,27 +118,10 @@ enum LOCALIZATION_ID_FILL_WINDOW, LOCALIZATION_ID_ONE_TO_ONE, LOCALIZATION_ID_BEST_FIT, - LOCALIZATION_ID_PAN_SCAN, - LOCALIZATION_ID_INCREASE_SIZE, - LOCALIZATION_ID_DECREASE_SIZE, - LOCALIZATION_ID_INCREASE_WIDTH, - LOCALIZATION_ID_DECREASE_WIDTH, - LOCALIZATION_ID_INCREASE_HEIGHT, - LOCALIZATION_ID_DECREASE_HEIGHT, LOCALIZATION_ID_ZOOM, LOCALIZATION_ID_ZOOM_IN, LOCALIZATION_ID_ZOOM_OUT, LOCALIZATION_ID_RESET, - LOCALIZATION_ID_MOVE_UP, - LOCALIZATION_ID_MOVE_DOWN, - LOCALIZATION_ID_MOVE_LEFT, - LOCALIZATION_ID_MOVE_RIGHT, - LOCALIZATION_ID_MOVE_UP_LEFT, - LOCALIZATION_ID_MOVE_UP_RIGHT, - LOCALIZATION_ID_MOVE_DOWN_LEFT, - LOCALIZATION_ID_MOVE_DOWN_RIGHT, - LOCALIZATION_ID_MOVE_CENTER, - LOCALIZATION_ID_PANSCAN_RESET, LOCALIZATION_ID_ON_TOP, LOCALIZATION_ID_ALWAYS, LOCALIZATION_ID_WHILE_PLAYING_OR_ANIMATING, @@ -233,6 +224,8 @@ enum LOCALIZATION_ID_OPTIONS_GENERAL_DIALOG, LOCALIZATION_ID_OPTIONS_VIEW_DIALOG, LOCALIZATION_ID_OPTIONS_CONTROLS_DIALOG, + LOCALIZATION_ID_OPTIONS_LANGUAGE_STATIC, + LOCALIZATION_ID_LANGUAGE_AUTO, LOCALIZATION_ID_OK_BUTTON, LOCALIZATION_ID_CANCEL_BUTTON, LOCALIZATION_ID_STORE_SETTINGS_APPDATA, @@ -317,10 +310,96 @@ enum LOCALIZATION_ID_ASSOCIATION_DESCRIPTION_TIF, LOCALIZATION_ID_ASSOCIATION_DESCRIPTION_TIFF, LOCALIZATION_ID_ASSOCIATION_DESCRIPTION_WEBP, + LOCALIZATION_ID_ASSOCIATION_DESCRIPTION_EMF, + LOCALIZATION_ID_ASSOCIATION_DESCRIPTION_WMF, + + LOCALIZATION_ID_ZOOM_CONTROLS, + LOCALIZATION_ID_TOOLBAR_ZOOM_OUT_BUTTON, + LOCALIZATION_ID_TOOLBAR_ZOOM_IN_BUTTON, + LOCALIZATION_ID_ZOOMUI_TOOLTIP_ZOOM_OUT, + LOCALIZATION_ID_ZOOMUI_TOOLTIP_ZOOM_IN, + + // fullscreen overlay bar buttons + the auto hide menu item + LOCALIZATION_ID_ZOOMUI_TOOLTIP_PREV, + LOCALIZATION_ID_ZOOMUI_TOOLTIP_PLAY, + LOCALIZATION_ID_ZOOMUI_TOOLTIP_PAUSE, + LOCALIZATION_ID_ZOOMUI_TOOLTIP_NEXT, + LOCALIZATION_ID_ZOOM_AUTO_HIDE, + + LOCALIZATION_ID_SAVE_AS, + LOCALIZATION_ID_SAVE_AS_CAPTION, + LOCALIZATION_ID_SAVE_AS_FAILED, + LOCALIZATION_ID_SAVE_AS_PNG, + LOCALIZATION_ID_SAVE_AS_JPEG, + LOCALIZATION_ID_SAVE_AS_BMP, + + LOCALIZATION_ID_OPTIONS_DARK_MODE_STATIC, + LOCALIZATION_ID_DARK_MODE_AUTO, + LOCALIZATION_ID_DARK_MODE_LIGHT, + LOCALIZATION_ID_DARK_MODE_DARK, + + // what shows under the transparent pixels of an image with alpha (not + // the canvas around the image: that color is the windowed background) + LOCALIZATION_ID_BACKDROP, + LOCALIZATION_ID_BACKDROP_FOLLOW, + LOCALIZATION_ID_BACKDROP_BLACK, + LOCALIZATION_ID_BACKDROP_WHITE, + LOCALIZATION_ID_BACKDROP_CUSTOM, + LOCALIZATION_ID_BACKDROP_CHECKERBOARD, + // recent files (mru) file submenu + LOCALIZATION_ID_RECENT_FILES, + LOCALIZATION_ID_RECENT_FILES_EMPTY, + LOCALIZATION_ID_RECENT_FILES_CLEAR, + + // desktop wallpaper confirmation + LOCALIZATION_ID_SET_DESKTOP_WALLPAPER_CAPTION, + LOCALIZATION_ID_SET_DESKTOP_WALLPAPER_MESSAGE, + + // adaptive status bar size units + LOCALIZATION_ID_STATUS_BAR_SIZE_BYTES_FORMAT, + LOCALIZATION_ID_STATUS_BAR_SIZE_KB_FORMAT, + LOCALIZATION_ID_STATUS_BAR_SIZE_MB_FORMAT, + LOCALIZATION_ID_STATUS_BAR_SIZE_GB_FORMAT, + + // view menu: the canvas color picker item (the mat around the image) + LOCALIZATION_ID_WINDOWED_BACKGROUND_COLOR_MENU, + + // the gui remake round: the settings window, toolbar labels, status formats + LOCALIZATION_ID_SETTINGS, + LOCALIZATION_ID_SETTINGS_PAGE_GENERAL, + LOCALIZATION_ID_SETTINGS_PAGE_VIEW, + LOCALIZATION_ID_SETTINGS_PAGE_CONTROLS, + LOCALIZATION_ID_SETTINGS_SECTION_INTERFACE, + LOCALIZATION_ID_SETTINGS_LANGUAGE, + LOCALIZATION_ID_SETTINGS_LANGUAGE_FOLLOW_SYSTEM, + LOCALIZATION_ID_SETTINGS_THEME, + LOCALIZATION_ID_SETTINGS_SECTION_STARTUP, + LOCALIZATION_ID_SETTINGS_ALLOW_MULTIPLE, + LOCALIZATION_ID_SETTINGS_ALLOW_MULTIPLE_DESC, + LOCALIZATION_ID_SETTINGS_STARTUP_SHORTCUT, + LOCALIZATION_ID_SETTINGS_STARTUP_SHORTCUT_DESC, + LOCALIZATION_ID_SETTINGS_SECTION_ASSOCIATIONS, + LOCALIZATION_ID_SETTINGS_ASSOCIATIONS_DESC, + LOCALIZATION_ID_SETTINGS_SELECT_ALL, + LOCALIZATION_ID_SETTINGS_OK, + LOCALIZATION_ID_SETTINGS_CANCEL, + LOCALIZATION_ID_TOOLBAR_OPEN, + LOCALIZATION_ID_TOOLBAR_ROTATE, + LOCALIZATION_ID_TOOLBAR_IMAGE_INFO, + LOCALIZATION_ID_STATUS_BAR_POSITION_FORMAT, + LOCALIZATION_ID_STATUS_BAR_DIMENSIONS_FORMAT, + LOCALIZATION_ID_STATUS_BAR_RGB_FORMAT, + LOCALIZATION_ID_MSGBOX_YES, + LOCALIZATION_ID_MSGBOX_NO, + LOCALIZATION_ID_ACCENT_COLOR, LOCALIZATION_ID_COUNT, }; +// an id that is guaranteed to never be a valid string id. +// (used by menu table entries that are separators and draw no text.) +#define LOCALIZATION_ID_INVALID LOCALIZATION_ID_COUNT + extern BYTE localization_language; #ifdef __cplusplus diff --git a/src/localization_en_us.h b/src/localization_en_us.h index 5747262c..1a57d2c6 100644 --- a/src/localization_en_us.h +++ b/src/localization_en_us.h @@ -65,6 +65,7 @@ static const utf8_t *_localization_string_array_en_us[LOCALIZATION_ID_COUNT] = // View menu "&View", // LOCALIZATION_ID_VIEW, + "La&yout", // LOCALIZATION_ID_LAYOUT, "Caption", // LOCALIZATION_ID_CAPTION, "Frame", // LOCALIZATION_ID_FRAME, "&Menu", // LOCALIZATION_ID_MENU, @@ -87,27 +88,10 @@ static const utf8_t *_localization_string_array_en_us[LOCALIZATION_ID_COUNT] = "&Fill Window", // LOCALIZATION_ID_FILL_WINDOW, "1:1", // LOCALIZATION_ID_ONE_TO_ONE, "&Best Fit", // LOCALIZATION_ID_BEST_FIT, - "Pa&n && Scan", // LOCALIZATION_ID_PAN_SCAN, - "&Increase Size", // LOCALIZATION_ID_INCREASE_SIZE, - "&Decrease Size", // LOCALIZATION_ID_DECREASE_SIZE, - "I&ncrease Width", // LOCALIZATION_ID_INCREASE_WIDTH, - "D&ecrease Width", // LOCALIZATION_ID_DECREASE_WIDTH, - "In&crease Height", // LOCALIZATION_ID_INCREASE_HEIGHT, - "De&cre&ase Height", // LOCALIZATION_ID_DECREASE_HEIGHT, "&Zoom", // LOCALIZATION_ID_ZOOM, "Zoom &In", // LOCALIZATION_ID_ZOOM_IN, "Zoom &Out", // LOCALIZATION_ID_ZOOM_OUT, "&Reset", // LOCALIZATION_ID_RESET, - "Move &Up", // LOCALIZATION_ID_MOVE_UP, - "Move &Down", // LOCALIZATION_ID_MOVE_DOWN, - "Move &Left", // LOCALIZATION_ID_MOVE_LEFT, - "Move &Right", // LOCALIZATION_ID_MOVE_RIGHT, - "Move Up Left", // LOCALIZATION_ID_MOVE_UP_LEFT, - "Move Up Right", // LOCALIZATION_ID_MOVE_UP_RIGHT, - "Move Down Left", // LOCALIZATION_ID_MOVE_DOWN_LEFT, - "Move Down Right", // LOCALIZATION_ID_MOVE_DOWN_RIGHT, - "Move Cen&ter", // LOCALIZATION_ID_MOVE_CENTER, - "Re&set", // LOCALIZATION_ID_PANSCAN_RESET, "On &Top", // LOCALIZATION_ID_ON_TOP, "&Always", // LOCALIZATION_ID_ALWAYS, "&While Playing Slideshow or Animating", // LOCALIZATION_ID_WHILE_PLAYING_OR_ANIMATING, @@ -198,7 +182,7 @@ static const utf8_t *_localization_string_array_en_us[LOCALIZATION_ID_COUNT] = "File not found.", // LOCALIZATION_ID_STATUS_BAR_FILE_NOT_FOUND, "Failed to load image.", // LOCALIZATION_ID_STATUS_BAR_FAILED_TO_LOAD_IMAGE, "Slideshow playing", // LOCALIZATION_ID_STATUS_BAR_SLIDESHOW_PLAYING, - "Pos %0.3f %0.3f, Zoom %0.3f %0.3f, Aspect Ratio %0.3f", // LOCALIZATION_ID_STATUS_BAR_POS_ZOOM_FORMAT, + "Zoom %d%%", // LOCALIZATION_ID_STATUS_BAR_POS_ZOOM_FORMAT, "Animation rate %0.3f", // LOCALIZATION_ID_STATUS_BAR_ANIMATION_RATE_FORMAT, "Slideshow rate %d %s", // LOCALIZATION_ID_STATUS_BAR_SLIDESHOW_RATE_FORMAT, "minutes", // LOCALIZATION_ID_STATUS_BAR_MINUTES, @@ -210,6 +194,8 @@ static const utf8_t *_localization_string_array_en_us[LOCALIZATION_ID_COUNT] = "General", // LOCALIZATION_ID_OPTIONS_GENERAL_DIALOG, "View", // LOCALIZATION_ID_OPTIONS_VIEW_DIALOG, "Controls", // LOCALIZATION_ID_OPTIONS_CONTROLS_DIALOG, + "Langua&ge:", // LOCALIZATION_ID_OPTIONS_LANGUAGE_STATIC, + "Auto (system)", // LOCALIZATION_ID_LANGUAGE_AUTO, "OK", // LOCALIZATION_ID_OK_BUTTON, "Cancel", // LOCALIZATION_ID_CANCEL_BUTTON, "&Store settings in %APPDATA%\\voidImageViewer", // LOCALIZATION_ID_STORE_SETTINGS_APPDATA, @@ -285,13 +271,84 @@ static const utf8_t *_localization_string_array_en_us[LOCALIZATION_ID_COUNT] = "Move To", // LOCALIZATION_ID_MOVE_TO_CAPTION, // Association descriptions - "Bitmap Image", - "Animated GIF Image", - "Icon File", - "JPEG Image", - "JPEG Image", - "PNG Image", - "TIFF Image", - "TIFF Image", - "WebP Image", + "Bitmap Image", // LOCALIZATION_ID_ASSOCIATION_DESCRIPTION_BMP + "Animated GIF Image", // LOCALIZATION_ID_ASSOCIATION_DESCRIPTION_GIF + "Icon File", // LOCALIZATION_ID_ASSOCIATION_DESCRIPTION_ICO + "JPEG Image", // LOCALIZATION_ID_ASSOCIATION_DESCRIPTION_JPEG + "JPEG Image", // LOCALIZATION_ID_ASSOCIATION_DESCRIPTION_JPG + "PNG Image", // LOCALIZATION_ID_ASSOCIATION_DESCRIPTION_PNG + "TIFF Image", // LOCALIZATION_ID_ASSOCIATION_DESCRIPTION_TIF + "TIFF Image", // LOCALIZATION_ID_ASSOCIATION_DESCRIPTION_TIFF + "WebP Image", // LOCALIZATION_ID_ASSOCIATION_DESCRIPTION_WEBP + "Enhanced Metafile Image", // LOCALIZATION_ID_ASSOCIATION_DESCRIPTION_EMF + "Windows Metafile Image", // LOCALIZATION_ID_ASSOCIATION_DESCRIPTION_WMF + + // zoom controls (touch / floating) + "Zoom &Controls", // LOCALIZATION_ID_ZOOM_CONTROLS, + "Zoom Out", // LOCALIZATION_ID_TOOLBAR_ZOOM_OUT_BUTTON, + "Zoom In", // LOCALIZATION_ID_TOOLBAR_ZOOM_IN_BUTTON, + "Zoom out", // LOCALIZATION_ID_ZOOMUI_TOOLTIP_ZOOM_OUT, + "Zoom in", // LOCALIZATION_ID_ZOOMUI_TOOLTIP_ZOOM_IN, + "Previous", // LOCALIZATION_ID_ZOOMUI_TOOLTIP_PREV, + "Play", // LOCALIZATION_ID_ZOOMUI_TOOLTIP_PLAY, + "Pause", // LOCALIZATION_ID_ZOOMUI_TOOLTIP_PAUSE, + "Next", // LOCALIZATION_ID_ZOOMUI_TOOLTIP_NEXT, + "Auto-&Hide Zoom Controls", // LOCALIZATION_ID_ZOOM_AUTO_HIDE, + "Save &As...", // LOCALIZATION_ID_SAVE_AS, + "Save Image", // LOCALIZATION_ID_SAVE_AS_CAPTION, + "Failed to save image", // LOCALIZATION_ID_SAVE_AS_FAILED, + "PNG Image", // LOCALIZATION_ID_SAVE_AS_PNG, + "JPEG Image", // LOCALIZATION_ID_SAVE_AS_JPEG, + "BMP Image", // LOCALIZATION_ID_SAVE_AS_BMP, + "Dark &mode:", // LOCALIZATION_ID_OPTIONS_DARK_MODE_STATIC, + "Automatic (follow Windows)", // LOCALIZATION_ID_DARK_MODE_AUTO, + "Light", // LOCALIZATION_ID_DARK_MODE_LIGHT, + "Dark", // LOCALIZATION_ID_DARK_MODE_DARK, + + // what shows under the transparent pixels of an image with alpha + "&Transparency backdrop", // LOCALIZATION_ID_BACKDROP, + "Follow &window background color", // LOCALIZATION_ID_BACKDROP_FOLLOW, + "&Black", // LOCALIZATION_ID_BACKDROP_BLACK, + "&White", // LOCALIZATION_ID_BACKDROP_WHITE, + "&Custom color...", // LOCALIZATION_ID_BACKDROP_CUSTOM, + "&Checkerboard", // LOCALIZATION_ID_BACKDROP_CHECKERBOARD, + + "Recent &Files", // LOCALIZATION_ID_RECENT_FILES + "(empty)", // LOCALIZATION_ID_RECENT_FILES_EMPTY + "Clear Recent &Files", // LOCALIZATION_ID_RECENT_FILES_CLEAR + "Set Desktop Wallpaper", // LOCALIZATION_ID_SET_DESKTOP_WALLPAPER_CAPTION + "Set the current image as the desktop wallpaper?", // LOCALIZATION_ID_SET_DESKTOP_WALLPAPER_MESSAGE + "%s B", // LOCALIZATION_ID_STATUS_BAR_SIZE_BYTES_FORMAT + " KB", // LOCALIZATION_ID_STATUS_BAR_SIZE_KB_FORMAT + " MB", // LOCALIZATION_ID_STATUS_BAR_SIZE_MB_FORMAT + " GB", // LOCALIZATION_ID_STATUS_BAR_SIZE_GB_FORMAT + "Windowed &background color...", // LOCALIZATION_ID_WINDOWED_BACKGROUND_COLOR_MENU + // the gui remake round: the settings window, toolbar labels, status formats + "Settings", // LOCALIZATION_ID_SETTINGS + "General", // LOCALIZATION_ID_SETTINGS_PAGE_GENERAL + "View", // LOCALIZATION_ID_SETTINGS_PAGE_VIEW + "Controls", // LOCALIZATION_ID_SETTINGS_PAGE_CONTROLS + "Interface", // LOCALIZATION_ID_SETTINGS_SECTION_INTERFACE + "Language", // LOCALIZATION_ID_SETTINGS_LANGUAGE + "Follow system", // LOCALIZATION_ID_SETTINGS_LANGUAGE_FOLLOW_SYSTEM + "Theme", // LOCALIZATION_ID_SETTINGS_THEME + "Startup & window", // LOCALIZATION_ID_SETTINGS_SECTION_STARTUP + "Allow multiple instances", // LOCALIZATION_ID_SETTINGS_ALLOW_MULTIPLE + "Open several viewer windows at the same time", // LOCALIZATION_ID_SETTINGS_ALLOW_MULTIPLE_DESC + "Create a startup shortcut", // LOCALIZATION_ID_SETTINGS_STARTUP_SHORTCUT + "Add void Image Viewer PLUS to the system startup", // LOCALIZATION_ID_SETTINGS_STARTUP_SHORTCUT_DESC + "File associations", // LOCALIZATION_ID_SETTINGS_SECTION_ASSOCIATIONS + "Choose the image formats to associate", // LOCALIZATION_ID_SETTINGS_ASSOCIATIONS_DESC + "Select all", // LOCALIZATION_ID_SETTINGS_SELECT_ALL + "OK", // LOCALIZATION_ID_SETTINGS_OK + "Cancel", // LOCALIZATION_ID_SETTINGS_CANCEL + "Open", // LOCALIZATION_ID_TOOLBAR_OPEN + "Rotate", // LOCALIZATION_ID_TOOLBAR_ROTATE + "Image info", // LOCALIZATION_ID_TOOLBAR_IMAGE_INFO + "%d / %d", // LOCALIZATION_ID_STATUS_BAR_POSITION_FORMAT + "%u × %u", // LOCALIZATION_ID_STATUS_BAR_DIMENSIONS_FORMAT + "RGB %d, %d, %d", // LOCALIZATION_ID_STATUS_BAR_RGB_FORMAT + "Yes", // LOCALIZATION_ID_MSGBOX_YES + "No", // LOCALIZATION_ID_MSGBOX_NO + "Accent color", // LOCALIZATION_ID_ACCENT_COLOR }; diff --git a/src/localization_zh_cn.h b/src/localization_zh_cn.h index 3d135697..3a30ee5f 100644 --- a/src/localization_zh_cn.h +++ b/src/localization_zh_cn.h @@ -19,280 +19,310 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // + // Chinese (Simplified) localization // Save as UTF-8 without BOM. static const utf8_t *_localization_string_array_zh_cn[LOCALIZATION_ID_COUNT] = { - // Language "简体中文", // LOCALIZATION_ID_LANGUAGE - - // Application name "void Image Viewer", // LOCALIZATION_ID_APP_NAME + "文件(&F)", // LOCALIZATION_ID_FILE + "打开文件(&O)...", // LOCALIZATION_ID_OPEN_FILE + "打开文件夹(&F)...", // LOCALIZATION_ID_OPEN_FOLDER + "打开 Everything 搜索(&S)...", // LOCALIZATION_ID_OPEN_EVERYTHING_SEARCH + "添加文件(&A)...", // LOCALIZATION_ID_ADD_FILE + "添加文件夹...", // LOCALIZATION_ID_ADD_FOLDER + "添加 Everything 搜索...", // LOCALIZATION_ID_ADD_EVERYTHING_SEARCH + "打开文件位置(&L)...", // LOCALIZATION_ID_OPEN_FILE_LOCATION + "编辑(&E)...", // LOCALIZATION_ID_EDIT + "预览(&V)...", // LOCALIZATION_ID_PREVIEW + "打印(&P)...", // LOCALIZATION_ID_PRINT + "设为桌面壁纸(&D)", // LOCALIZATION_ID_SET_DESKTOP_WALLPAPER + "关闭(&C)", // LOCALIZATION_ID_CLOSE + "删除(&D)", // LOCALIZATION_ID_DELETE + "删除到回收站", // LOCALIZATION_ID_DELETE_RECYCLE + "永久删除", // LOCALIZATION_ID_DELETE_PERMANENTLY + "重命名(&M)", // LOCALIZATION_ID_RENAME + "属性(&P)", // LOCALIZATION_ID_PROPERTIES + "退出(&X)", // LOCALIZATION_ID_EXIT + "编辑(&E)", // LOCALIZATION_ID_EDIT_MENU + "剪切(&T)", // LOCALIZATION_ID_CUT + "复制(&C)", // LOCALIZATION_ID_COPY + "复制文件名", // LOCALIZATION_ID_COPY_FILENAME + "复制图片(&Y)", // LOCALIZATION_ID_COPY_IMAGE + "粘贴(&P)", // LOCALIZATION_ID_PASTE + "顺时针旋转(&K)", // LOCALIZATION_ID_ROTATE_CLOCKWISE + "逆时针旋转(&N)", // LOCALIZATION_ID_ROTATE_COUNTERCLOCKWISE + "复制到文件夹(&F)...", // LOCALIZATION_ID_COPY_TO + "移动到文件夹(&V)...", // LOCALIZATION_ID_MOVE_TO + "视图(&V)", // LOCALIZATION_ID_VIEW + "布局(&L)", // LOCALIZATION_ID_LAYOUT + "标题栏", // LOCALIZATION_ID_CAPTION + "边框", // LOCALIZATION_ID_FRAME + "菜单(&M)", // LOCALIZATION_ID_MENU + "状态栏(&B)", // LOCALIZATION_ID_STATUS_BAR + "工具栏(&C)", // LOCALIZATION_ID_CONTROLS + "布局预设(&P)", // LOCALIZATION_ID_PRESET + "极简(&M)", // LOCALIZATION_ID_MINIMAL + "紧凑(&C)", // LOCALIZATION_ID_COMPACT + "标准(&N)", // LOCALIZATION_ID_NORMAL + "全屏(&F)", // LOCALIZATION_ID_FULLSCREEN + "幻灯片放映(&S)", // LOCALIZATION_ID_SLIDESHOW + "窗口大小(&W)", // LOCALIZATION_ID_VIEW_WINDOW_SIZE + "50%", // LOCALIZATION_ID_VIEW_WINDOW_SIZE_50_PERCENT + "100%", // LOCALIZATION_ID_VIEW_WINDOW_SIZE_100_PERCENT + "200%", // LOCALIZATION_ID_VIEW_WINDOW_SIZE_200_PERCENT + "自动调整窗口(&A)", // LOCALIZATION_ID_VIEW_WINDOW_SIZE_AUTO_FIT + "刷新(&R)", // LOCALIZATION_ID_REFRESH + "允许缩小图片(&A)", // LOCALIZATION_ID_ALLOW_SHRINKING + "保持宽高比(&K)", // LOCALIZATION_ID_KEEP_ASPECT_RATIO + "拉伸填满窗口(&F)", // LOCALIZATION_ID_FILL_WINDOW + "1:1", // LOCALIZATION_ID_ONE_TO_ONE + "适应窗口(&B)", // LOCALIZATION_ID_BEST_FIT + "缩放(&Z)", // LOCALIZATION_ID_ZOOM + "放大(&I)", // LOCALIZATION_ID_ZOOM_IN + "缩小(&O)", // LOCALIZATION_ID_ZOOM_OUT + "重置缩放(&R)", // LOCALIZATION_ID_RESET + "窗口置顶(&T)", // LOCALIZATION_ID_ON_TOP + "总是置顶(&A)", // LOCALIZATION_ID_ALWAYS + "播放时置顶(&W)", // LOCALIZATION_ID_WHILE_PLAYING_OR_ANIMATING + "从不置顶(&N)", // LOCALIZATION_ID_NEVER + "选项(&O)...", // LOCALIZATION_ID_OPTIONS + "幻灯片放映(&S)", // LOCALIZATION_ID_SLIDESHOW_MENU + "播放/暂停(&P)", // LOCALIZATION_ID_PLAY_PAUSE + "切换间隔(&R)", // LOCALIZATION_ID_RATE + "缩短间隔(&D)", // LOCALIZATION_ID_DECREASE_RATE + "加长间隔(&I)", // LOCALIZATION_ID_INCREASE_RATE + "250 毫秒", // LOCALIZATION_ID_RATE_250_MILLISECONDS + "500 毫秒", // LOCALIZATION_ID_RATE_500_MILLISECONDS + "&1 秒", // LOCALIZATION_ID_RATE_1_SECOND + "&2 秒", // LOCALIZATION_ID_RATE_2_SECONDS + "&3 秒", // LOCALIZATION_ID_RATE_3_SECONDS + "&4 秒", // LOCALIZATION_ID_RATE_4_SECONDS + "&5 秒", // LOCALIZATION_ID_RATE_5_SECONDS + "&6 秒", // LOCALIZATION_ID_RATE_6_SECONDS + "&7 秒", // LOCALIZATION_ID_RATE_7_SECONDS + "&8 秒", // LOCALIZATION_ID_RATE_8_SECONDS + "&9 秒", // LOCALIZATION_ID_RATE_9_SECONDS + "1&0 秒", // LOCALIZATION_ID_RATE_10_SECONDS + "20 秒", // LOCALIZATION_ID_RATE_20_SECONDS + "30 秒", // LOCALIZATION_ID_RATE_30_SECONDS + "40 秒", // LOCALIZATION_ID_RATE_40_SECONDS + "50 秒", // LOCALIZATION_ID_RATE_50_SECONDS + "1 分钟", // LOCALIZATION_ID_RATE_1_MINUTE + "自定义...", // LOCALIZATION_ID_CUSTOM + "动画(&A)", // LOCALIZATION_ID_ANIMATION + "播放/暂停(&P)", // LOCALIZATION_ID_ANIMATION_PLAY_PAUSE + "快进(&F)", // LOCALIZATION_ID_ANIMATION_JUMP_FORWARD + "快退(&B)", // LOCALIZATION_ID_ANIMATION_JUMP_BACKWARD + "小幅快进(&F)", // LOCALIZATION_ID_ANIMATION_SHORT_JUMP_FORWARD + "小幅快退(&B)", // LOCALIZATION_ID_ANIMATION_SHORT_JUMP_BACKWARD + "大幅快进(&F)", // LOCALIZATION_ID_ANIMATION_LONG_JUMP_FORWARD + "大幅快退(&B)", // LOCALIZATION_ID_ANIMATION_LONG_JUMP_BACKWARD + "下一帧(&S)", // LOCALIZATION_ID_ANIMATION_FRAME_STEP + "上一帧(&V)", // LOCALIZATION_ID_ANIMATION_PREVIOUS_FRAME + "第一帧(&I)", // LOCALIZATION_ID_ANIMATION_FIRST_FRAME + "最后一帧(&L)", // LOCALIZATION_ID_ANIMATION_LAST_FRAME + "减慢(&D)", // LOCALIZATION_ID_ANIMATION_DECREASE_RATE + "加快(&I)", // LOCALIZATION_ID_ANIMATION_INCREASE_RATE + "恢复默认速度(&E)", // LOCALIZATION_ID_ANIMATION_RESET_RATE + "导航(&N)", // LOCALIZATION_ID_NAVIGATE + "下一张(&N)", // LOCALIZATION_ID_NEXT + "上一张(&P)", // LOCALIZATION_ID_PREVIOUS + "第一张(&H)", // LOCALIZATION_ID_HOME + "最后一张(&E)", // LOCALIZATION_ID_END + "排序(&S)", // LOCALIZATION_ID_SORT + "按名称(&N)", // LOCALIZATION_ID_SORT_NAME + "按完整路径(&P)", // LOCALIZATION_ID_SORT_FULL_PATH + "按大小(&S)", // LOCALIZATION_ID_SORT_SIZE + "按修改时间(&M)", // LOCALIZATION_ID_SORT_DATE_MODIFIED + "按创建时间(&C)", // LOCALIZATION_ID_SORT_DATE_CREATED + "升序(&A)", // LOCALIZATION_ID_SORT_ASCENDING + "降序(&D)", // LOCALIZATION_ID_SORT_DESCENDING + "随机顺序", // LOCALIZATION_ID_SHUFFLE + "跳转到(&J)...", // LOCALIZATION_ID_JUMP_TO + "帮助(&H)", // LOCALIZATION_ID_HELP + "帮助(&H)", // LOCALIZATION_ID_HELP_MENU + "命令行选项(&C)", // LOCALIZATION_ID_COMMAND_LINE_OPTIONS + "主页(&P)", // LOCALIZATION_ID_HOME_PAGE + "捐赠(&D)", // LOCALIZATION_ID_DONATE + "关于(&A)", // LOCALIZATION_ID_ABOUT + "https://www.voidtools.com/support/voidimageviewer/", // LOCALIZATION_ID_HELP_SUPPORT_URL + "https://www.voidtools.com/donate/", // LOCALIZATION_ID_HELP_DONATE_URL + "https://www.voidtools.com/", // LOCALIZATION_ID_HELP_WEBSITE_URL + "上一张", // LOCALIZATION_ID_TOOLBAR_PREVIOUS_IMAGE_BUTTON + "下一张", // LOCALIZATION_ID_TOOLBAR_NEXT_IMAGE_BUTTON + "播放", // LOCALIZATION_ID_TOOLBAR_PLAY_SLIDESHOW_BUTTON + "暂停", // LOCALIZATION_ID_TOOLBAR_PAUSE_SLIDESHOW_BUTTON + "适应窗口", // LOCALIZATION_ID_TOOLBAR_BEST_FIT_BUTTON + "原始大小", // LOCALIZATION_ID_TOOLBAR_ACTUAL_SIZE_BUTTON + "预加载中", // LOCALIZATION_ID_STATUS_BAR_PRELOAD + "加载中...", // LOCALIZATION_ID_STATUS_BAR_LOADING + "找不到文件。", // LOCALIZATION_ID_STATUS_BAR_FILE_NOT_FOUND + "图片加载失败。", // LOCALIZATION_ID_STATUS_BAR_FAILED_TO_LOAD_IMAGE + "幻灯片放映中", // LOCALIZATION_ID_STATUS_BAR_SLIDESHOW_PLAYING + "缩放 %d%%", // LOCALIZATION_ID_STATUS_BAR_POS_ZOOM_FORMAT + "动画速度 %0.3f", // LOCALIZATION_ID_STATUS_BAR_ANIMATION_RATE_FORMAT + "幻灯片间隔 %d %s", // LOCALIZATION_ID_STATUS_BAR_SLIDESHOW_RATE_FORMAT + "分钟", // LOCALIZATION_ID_STATUS_BAR_MINUTES + "秒", // LOCALIZATION_ID_STATUS_BAR_SECONDS + "毫秒", // LOCALIZATION_ID_STATUS_BAR_MILLISECONDS + "void Image Viewer 选项", // LOCALIZATION_ID_OPTIONS_CAPTION + "常规", // LOCALIZATION_ID_OPTIONS_GENERAL_DIALOG + "视图", // LOCALIZATION_ID_OPTIONS_VIEW_DIALOG + "操作", // LOCALIZATION_ID_OPTIONS_CONTROLS_DIALOG + "语言(&L):", // LOCALIZATION_ID_OPTIONS_LANGUAGE_STATIC + "自动(跟随系统)", // LOCALIZATION_ID_LANGUAGE_AUTO + "确定", // LOCALIZATION_ID_OK_BUTTON + "取消", // LOCALIZATION_ID_CANCEL_BUTTON + "把设置保存到 %APPDATA%\\voidImageViewer(&S)", // LOCALIZATION_ID_STORE_SETTINGS_APPDATA + "允许多开(&I)", // LOCALIZATION_ID_ALLOW_MULTIPLE_INSTANCES + "开始菜单快捷方式(&M)", // LOCALIZATION_ID_STARTMENU_SHORTCUTS + "文件关联", // LOCALIZATION_ID_ASSOCIATIONS + "全选(&A)", // LOCALIZATION_ID_CHECK_ALL + "全不选(&N)", // LOCALIZATION_ID_CHECK_NONE + "缩小时插值(&S):", // LOCALIZATION_ID_SHRINK_BLIT_MODE_STATIC + "放大时插值(&M):", // LOCALIZATION_ID_MAGNIFY_BLIT_MODE + "最近邻", // LOCALIZATION_ID_BLIT_MODE_NEAREST_COMBOBOXITEM + "双线性", // LOCALIZATION_ID_BLIT_MODE_LINEAR_COMBOBOXITEM + "自动调整窗口(&Z):", // LOCALIZATION_ID_OPTIONS_VIEW_AUTO_SIZE_WINDOW_STATIC + "50%", // LOCALIZATION_ID_OPTIONS_VIEW_AUTO_SIZE_WINDOW_50_PERCENT_COMBOBOXITEM + "100%", // LOCALIZATION_ID_OPTIONS_VIEW_AUTO_SIZE_WINDOW_100_PERCENT_COMBOBOXITEM + "200%", // LOCALIZATION_ID_OPTIONS_VIEW_AUTO_SIZE_WINDOW_200_PERCENT_COMBOBOXITEM + "适应图像", // LOCALIZATION_ID_OPTIONS_VIEW_AUTO_SIZE_WINDOW_AUTO_FIT_COMBOBOXITEM + "幻灯片放映时动画至少完整播放一次(&P)", // LOCALIZATION_ID_PLAY_ANIMATIONS_ONCE_STATIC + "预加载下一张图片(&N)", // LOCALIZATION_ID_PRELOAD_NEXT_IMAGE_STATIC + "缓存上一张图片(&L)", // LOCALIZATION_ID_CACHE_LAST_IMAGE_STATIC + "窗口背景颜色(&W):", // LOCALIZATION_ID_WINDOWED_BACKGROUND_COLOR_STATIC + "全屏背景颜色(&F):", // LOCALIZATION_ID_FULLSCREEN_BACKGROUND_COLOR_STATIC + "左键操作(&L):", // LOCALIZATION_ID_LEFT_CLICK_ACTION_STATIC + "右键操作(&R):", // LOCALIZATION_ID_RIGHT_CLICK_ACTION_STATIC + "鼠标滚轮操作(&M):", // LOCALIZATION_ID_MOUSE_WHEEL_ACTION_STATIC + "命令(&C):", // LOCALIZATION_ID_COMMANDS_STATIC + "所选命令的设置", // LOCALIZATION_ID_SETTINGS_FOR_SELECTED_COMMAND + "添加(&A)...", // LOCALIZATION_ID_ADD_KEY_BUTTON + "编辑(&E)...", // LOCALIZATION_ID_EDIT_KEY_BUTTON + "移除(&V)", // LOCALIZATION_ID_REMOVE_KEY_BUTTON + "添加快捷键", // LOCALIZATION_ID_ADD_KEYBOARD_SHORTCUT_CAPTION + "编辑快捷键", // LOCALIZATION_ID_EDIT_KEYBOARD_SHORTCUT_CAPTION + "快捷键(&K):", // LOCALIZATION_ID_SHORTCUT_KEY + "当前占用此快捷键的命令:", // LOCALIZATION_ID_SHORTCUT_KEY_CURRENTLY_USED_BY + "移除(&V)", // LOCALIZATION_ID_REMOVE + "设置自定义间隔", // LOCALIZATION_ID_SET_CUSTOM_RATE_CAPTION + "间隔(&C):", // LOCALIZATION_ID_CUSTOM_RATE_STATIC + "分钟", // LOCALIZATION_ID_CUSTOM_RATE_MINUTES + "秒", // LOCALIZATION_ID_CUSTOM_RATE_SECONDS + "毫秒", // LOCALIZATION_ID_CUSTOM_RATE_MILLISECONDS + "关于 void Image Viewer", // LOCALIZATION_ID_ABOUT_CAPTION + "重命名", // LOCALIZATION_ID_RENAME_CAPTION + "跳转到", // LOCALIZATION_ID_JUMP_TO_TITLE + "搜索 Everything", // LOCALIZATION_ID_SEARCH_EVERYTHING + "版权所有 © %d voidtools", // LOCALIZATION_ID_ABOUT_COPYRIGHT_FORMAT + "support@voidtools.com", // LOCALIZATION_ID_ABOUT_EMAIL + "www.voidtools.com", // LOCALIZATION_ID_ABOUT_WEBSITE + "打开图片", // LOCALIZATION_ID_OPEN_IMAGE_CAPTION + "所有图片文件", // LOCALIZATION_ID_OPEN_ALL_IMAGE_FILES + "所有文件", // LOCALIZATION_ID_OPEN_ALL_FILES + "滚动", // LOCALIZATION_ID_OPTIONS_ACTION_SCROLL_COMBOBOXITEM + "播放/暂停幻灯片", // LOCALIZATION_ID_OPTIONS_ACTION_PLAY_PAUSE_SLIDESHOW_COMBOBOXITEM + "播放/暂停动画", // LOCALIZATION_ID_OPTIONS_ACTION_PLAY_PAUSE_ANIMATION_COMBOBOXITEM + "放大", // LOCALIZATION_ID_OPTIONS_ACTION_ZOOM_IN_COMBOBOXITEM + "下一张图片", // LOCALIZATION_ID_OPTIONS_ACTION_NEXT_IMAGE_COMBOBOXITEM + "1:1 拖动查看", // LOCALIZATION_ID_OPTIONS_ACTION_ONE_TO_ONE_SCROLL_COMBOBOXITEM + "拖动图片或移动窗口", // LOCALIZATION_ID_OPTIONS_ACTION_SCROLL_MOVE_WINDOW_COMBOBOXITEM + "右键菜单", // LOCALIZATION_ID_OPTIONS_ACTION_CONTEXT_MENU_COMBOBOXITEM + "缩小", // LOCALIZATION_ID_OPTIONS_ACTION_ZOOM_OUT_COMBOBOXITEM + "上一张图片", // LOCALIZATION_ID_OPTIONS_ACTION_PREVIOUS_IMAGE_COMBOBOXITEM + "缩放", // LOCALIZATION_ID_OPTIONS_ACTION_ZOOM_COMBOBOXITEM + "下一张/上一张", // LOCALIZATION_ID_OPTIONS_ACTION_NEXT_PREV_COMBOBOXITEM + "上一张/下一张", // LOCALIZATION_ID_OPTIONS_ACTION_PREV_NEXT_COMBOBOXITEM + "标题栏格式(&T):", // LOCALIZATION_ID_OPTIONS_TITLE_BAR_FORMAT_STATIC + "完整路径", // LOCALIZATION_ID_OPTIONS_TITLE_BAR_FORMAT_FULL_PATH_COMBOBOXITEM + "仅文件名", // LOCALIZATION_ID_OPTIONS_TITLE_BAR_FORMAT_FILENAME_ONLY_COMBOBOXITEM + "不显示", // LOCALIZATION_ID_OPTIONS_TITLE_BAR_FORMAT_NONE_COMBOBOXITEM + "Everything 不可用。", // LOCALIZATION_ID_EVERYTHING_NOT_AVAILABLE_MESSAGE + "添加 Everything 搜索", // LOCALIZATION_ID_EVERYTHING_ADD_EVERYTHING_SEARCH_CAPTION + "加载 Everything 搜索", // LOCALIZATION_ID_EVERYTHING_LOAD_EVERYTHING_SEARCH_CAPTION + "随机排序", // LOCALIZATION_ID_RANDOMIZE + "复制到文件夹", // LOCALIZATION_ID_COPY_TO_CAPTION + "移动到文件夹", // LOCALIZATION_ID_MOVE_TO_CAPTION + "位图图像", // LOCALIZATION_ID_ASSOCIATION_DESCRIPTION_BMP + "GIF 动画图像", // LOCALIZATION_ID_ASSOCIATION_DESCRIPTION_GIF + "图标文件", // LOCALIZATION_ID_ASSOCIATION_DESCRIPTION_ICO + "JPEG 图像", // LOCALIZATION_ID_ASSOCIATION_DESCRIPTION_JPEG + "JPEG 图像", // LOCALIZATION_ID_ASSOCIATION_DESCRIPTION_JPG + "PNG 图像", // LOCALIZATION_ID_ASSOCIATION_DESCRIPTION_PNG + "TIFF 图像", // LOCALIZATION_ID_ASSOCIATION_DESCRIPTION_TIF + "TIFF 图像", // LOCALIZATION_ID_ASSOCIATION_DESCRIPTION_TIFF + "WebP 图像", // LOCALIZATION_ID_ASSOCIATION_DESCRIPTION_WEBP + "增强图元文件图像", // LOCALIZATION_ID_ASSOCIATION_DESCRIPTION_EMF + "Windows 图元文件图像", // LOCALIZATION_ID_ASSOCIATION_DESCRIPTION_WMF + "显示缩放按钮(&Z)", // LOCALIZATION_ID_ZOOM_CONTROLS + "缩小", // LOCALIZATION_ID_TOOLBAR_ZOOM_OUT_BUTTON + "放大", // LOCALIZATION_ID_TOOLBAR_ZOOM_IN_BUTTON + "缩小", // LOCALIZATION_ID_ZOOMUI_TOOLTIP_ZOOM_OUT + "放大", // LOCALIZATION_ID_ZOOMUI_TOOLTIP_ZOOM_IN + "上一张", // LOCALIZATION_ID_ZOOMUI_TOOLTIP_PREV + "播放", // LOCALIZATION_ID_ZOOMUI_TOOLTIP_PLAY + "暂停", // LOCALIZATION_ID_ZOOMUI_TOOLTIP_PAUSE + "下一张", // LOCALIZATION_ID_ZOOMUI_TOOLTIP_NEXT + "自动隐藏缩放按钮(&H)", // LOCALIZATION_ID_ZOOM_AUTO_HIDE + "另存为(&A)...", // LOCALIZATION_ID_SAVE_AS + "保存图片", // LOCALIZATION_ID_SAVE_AS_CAPTION + "保存图片失败", // LOCALIZATION_ID_SAVE_AS_FAILED + "PNG 图片", // LOCALIZATION_ID_SAVE_AS_PNG + "JPEG 图片", // LOCALIZATION_ID_SAVE_AS_JPEG + "BMP 图片", // LOCALIZATION_ID_SAVE_AS_BMP + "深色模式(&M):", // LOCALIZATION_ID_OPTIONS_DARK_MODE_STATIC + "自动(跟随 Windows)", // LOCALIZATION_ID_DARK_MODE_AUTO + "浅色", // LOCALIZATION_ID_DARK_MODE_LIGHT + "深色", // LOCALIZATION_ID_DARK_MODE_DARK - // File menu - "文件(&F)", // LOCALIZATION_ID_FILE, - "打开文件(&O)...", // LOCALIZATION_ID_OPEN_FILE, - "打开文件夹(&F)...", // LOCALIZATION_ID_OPEN_FOLDER, - "打开 Everything 搜索(&S)...", // LOCALIZATION_ID_OPEN_EVERYTHING_SEARCH, - "添加文件(&A)...", // LOCALIZATION_ID_ADD_FILE, - "添加文件夹...", // LOCALIZATION_ID_ADD_FOLDER, - "添加 Everything 搜索...", // LOCALIZATION_ID_ADD_EVERYTHING_SEARCH, - "打开文件位置(&L)...", // LOCALIZATION_ID_OPEN_FILE_LOCATION, - "编辑(&E)...", // LOCALIZATION_ID_EDIT, - "预览(&V)...", // LOCALIZATION_ID_PREVIEW, - "打印(&P)...", // LOCALIZATION_ID_PRINT, - "设置为桌面壁纸(&D)", // LOCALIZATION_ID_SET_DESKTOP_WALLPAPER, - "关闭(&C)", // LOCALIZATION_ID_CLOSE, - "删除(&D)", // LOCALIZATION_ID_DELETE, - "删除(回收站)", // LOCALIZATION_ID_DELETE_RECYCLE, - "删除(永久)", // LOCALIZATION_ID_DELETE_PERMANENTLY, - "重命名(&M)", // LOCALIZATION_ID_RENAME, - "属性(&P)", // LOCALIZATION_ID_PROPERTIES, - "退出(&X)", // LOCALIZATION_ID_EXIT, - - // Edit menu - "编辑(&E)", // LOCALIZATION_ID_EDIT_MENU, - "剪切(&T)", // LOCALIZATION_ID_CUT, - "复制(&C)", // LOCALIZATION_ID_COPY, - "复制文件名", // LOCALIZATION_ID_COPY_FILENAME, - "复制图像(&Y)", // LOCALIZATION_ID_COPY_IMAGE, - "粘贴(&P)", // LOCALIZATION_ID_PASTE, - "顺时针旋转(&K)", // LOCALIZATION_ID_ROTATE_CLOCKWISE, - "逆时针旋转(&N)", // LOCALIZATION_ID_ROTATE_COUNTERCLOCKWISE, - "复制到文件夹(&F)...", // LOCALIZATION_ID_COPY_TO, - "移动到文件夹(&V)...", // LOCALIZATION_ID_MOVE_TO, - - // View menu - "视图(&V)", // LOCALIZATION_ID_VIEW, - "标题栏", // LOCALIZATION_ID_CAPTION, - "边框", // LOCALIZATION_ID_FRAME, - "菜单(&M)", // LOCALIZATION_ID_MENU, - "状态栏(&B)", // LOCALIZATION_ID_STATUS_BAR, - "控件(&C)", // LOCALIZATION_ID_CONTROLS, - "预设(&P)", // LOCALIZATION_ID_PRESET, - "最小(&M)", // LOCALIZATION_ID_MINIMAL, - "紧凑(&C)", // LOCALIZATION_ID_COMPACT, - "正常(&N)", // LOCALIZATION_ID_NORMAL, - "全屏(&F)", // LOCALIZATION_ID_FULLSCREEN, - "幻灯片(&S)", // LOCALIZATION_ID_SLIDESHOW, - "窗口大小(&W)", // LOCALIZATION_ID_VIEW_WINDOW_SIZE, - "50%", // LOCALIZATION_ID_VIEW_WINDOW_SIZE_50_PERCENT, - "100%", // LOCALIZATION_ID_VIEW_WINDOW_SIZE_100_PERCENT, - "200%", // LOCALIZATION_ID_VIEW_WINDOW_SIZE_200_PERCENT, - "自动适应(&A)", // LOCALIZATION_ID_VIEW_WINDOW_SIZE_AUTO_FIT, - "刷新(&R)", // LOCALIZATION_ID_REFRESH, - "允许缩小(&A)", // LOCALIZATION_ID_ALLOW_SHRINKING, - "保持纵横比(&K)", // LOCALIZATION_ID_KEEP_ASPECT_RATIO, - "填充窗口(&F)", // LOCALIZATION_ID_FILL_WINDOW, - "1:1", // LOCALIZATION_ID_ONE_TO_ONE, - "最佳适应(&B)", // LOCALIZATION_ID_BEST_FIT, - "平移和扫描(&N)", // LOCALIZATION_ID_PAN_SCAN, - "增大尺寸(&I)", // LOCALIZATION_ID_INCREASE_SIZE, - "减小尺寸(&D)", // LOCALIZATION_ID_DECREASE_SIZE, - "增加宽度(&W)", // LOCALIZATION_ID_INCREASE_WIDTH, - "减小宽度(&W)", // LOCALIZATION_ID_DECREASE_WIDTH, - "增加高度(&H)", // LOCALIZATION_ID_INCREASE_HEIGHT, - "减小高度(&E)", // LOCALIZATION_ID_DECREASE_HEIGHT, - "缩放(&Z)", // LOCALIZATION_ID_ZOOM, - "放大(&I)", // LOCALIZATION_ID_ZOOM_IN, - "缩小(&O)", // LOCALIZATION_ID_ZOOM_OUT, - "重置(&R)", // LOCALIZATION_ID_RESET, - "向上移动(&U)", // LOCALIZATION_ID_MOVE_UP, - "向下移动(&D)", // LOCALIZATION_ID_MOVE_DOWN, - "向左移动(&L)", // LOCALIZATION_ID_MOVE_LEFT, - "向右移动(&R)", // LOCALIZATION_ID_MOVE_RIGHT, - "向左上移动", // LOCALIZATION_ID_MOVE_UP_LEFT, - "向右上移动", // LOCALIZATION_ID_MOVE_UP_RIGHT, - "向左下移动", // LOCALIZATION_ID_MOVE_DOWN_LEFT, - "向右下移动", // LOCALIZATION_ID_MOVE_DOWN_RIGHT, - "居中(&C)", // LOCALIZATION_ID_MOVE_CENTER, - "重置(&S)", // LOCALIZATION_ID_PANSCAN_RESET, - "置顶(&T)", // LOCALIZATION_ID_ON_TOP, - "总是(&A)", // LOCALIZATION_ID_ALWAYS, - "播放幻灯片或动画时(&W)", // LOCALIZATION_ID_WHILE_PLAYING_OR_ANIMATING, - "从不(&N)", // LOCALIZATION_ID_NEVER, - "选项(&O)...", // LOCALIZATION_ID_OPTIONS, - - // Slideshow menu - "幻灯片(&S)", // LOCALIZATION_ID_SLIDESHOW_MENU, - "播放/暂停(&P)", // LOCALIZATION_ID_PLAY_PAUSE, - "速率(&R)", // LOCALIZATION_ID_RATE, - "降低速率(&D)", // LOCALIZATION_ID_DECREASE_RATE, - "提高速率(&I)", // LOCALIZATION_ID_INCREASE_RATE, - "250 毫秒", // LOCALIZATION_ID_RATE_250_MILLISECONDS, - "500 毫秒", // LOCALIZATION_ID_RATE_500_MILLISECONDS, - "&1 秒", // LOCALIZATION_ID_RATE_1_SECOND, - "&2 秒", // LOCALIZATION_ID_RATE_2_SECONDS, - "&3 秒", // LOCALIZATION_ID_RATE_3_SECONDS, - "&4 秒", // LOCALIZATION_ID_RATE_4_SECONDS, - "&5 秒", // LOCALIZATION_ID_RATE_5_SECONDS, - "&6 秒", // LOCALIZATION_ID_RATE_6_SECONDS, - "&7 秒", // LOCALIZATION_ID_RATE_7_SECONDS, - "&8 秒", // LOCALIZATION_ID_RATE_8_SECONDS, - "&9 秒", // LOCALIZATION_ID_RATE_9_SECONDS, - "1&0 秒", // LOCALIZATION_ID_RATE_10_SECONDS, - "20 秒", // LOCALIZATION_ID_RATE_20_SECONDS, - "30 秒", // LOCALIZATION_ID_RATE_30_SECONDS, - "40 秒", // LOCALIZATION_ID_RATE_40_SECONDS, - "50 秒", // LOCALIZATION_ID_RATE_50_SECONDS, - "1 分钟", // LOCALIZATION_ID_RATE_1_MINUTE, - "自定义...", // LOCALIZATION_ID_CUSTOM, - - // Animation menu - "动画(&A)", // LOCALIZATION_ID_ANIMATION, - "播放/暂停(&P)", // LOCALIZATION_ID_ANIMATION_PLAY_PAUSE, - "向前跳转(&F)", // LOCALIZATION_ID_ANIMATION_JUMP_FORWARD, - "向后跳转(&B)", // LOCALIZATION_ID_ANIMATION_JUMP_BACKWARD, - "短距离向前跳转(&F)", // LOCALIZATION_ID_ANIMATION_SHORT_JUMP_FORWARD, - "短距离向后跳转(&B)", // LOCALIZATION_ID_ANIMATION_SHORT_JUMP_BACKWARD, - "长距离向前跳转(&F)", // LOCALIZATION_ID_ANIMATION_LONG_JUMP_FORWARD, - "长距离向后跳转(&B)", // LOCALIZATION_ID_ANIMATION_LONG_JUMP_BACKWARD, - "下一帧(&S)", // LOCALIZATION_ID_ANIMATION_FRAME_STEP, - "上一帧(&V)", // LOCALIZATION_ID_ANIMATION_PREVIOUS_FRAME, - "第一帧(&I)", // LOCALIZATION_ID_ANIMATION_FIRST_FRAME, - "最后一帧(&L)", // LOCALIZATION_ID_ANIMATION_LAST_FRAME, - "降低速率(&D)", // LOCALIZATION_ID_ANIMATION_DECREASE_RATE, - "提高速率(&I)", // LOCALIZATION_ID_ANIMATION_INCREASE_RATE, - "重置速率(&E)", // LOCALIZATION_ID_ANIMATION_RESET_RATE, - - // Navigate menu - "导航(&N)", // LOCALIZATION_ID_NAVIGATE, - "下一个(&N)", // LOCALIZATION_ID_NEXT, - "上一个(&P)", // LOCALIZATION_ID_PREVIOUS, - "首页(&H)", // LOCALIZATION_ID_HOME, - "末页(&E)", // LOCALIZATION_ID_END, - "排序(&S)", // LOCALIZATION_ID_SORT, - "名称(&N)", // LOCALIZATION_ID_SORT_NAME, - "完整路径(&P)", // LOCALIZATION_ID_SORT_FULL_PATH, - "大小(&S)", // LOCALIZATION_ID_SORT_SIZE, - "修改日期(&M)", // LOCALIZATION_ID_SORT_DATE_MODIFIED, - "创建日期(&C)", // LOCALIZATION_ID_SORT_DATE_CREATED, - "升序(&A)", // LOCALIZATION_ID_SORT_ASCENDING, - "降序(&D)", // LOCALIZATION_ID_SORT_DESCENDING, - "随机(&S)", // LOCALIZATION_ID_SHUFFLE, - "跳转到(&J)...", // LOCALIZATION_ID_JUMP_TO, - - // Help menu - "帮助(&H)", // LOCALIZATION_ID_HELP, - "帮助(&H)", // LOCALIZATION_ID_HELP_MENU, - "命令行选项(&C)", // LOCALIZATION_ID_COMMAND_LINE_OPTIONS, - "主页(&P)", // LOCALIZATION_ID_HOME_PAGE, - "捐赠(&D)", // LOCALIZATION_ID_DONATE, - "关于(&A)", // LOCALIZATION_ID_ABOUT, - "https://www.voidtools.com/support/voidimageviewer/", // LOCALIZATION_ID_HELP_SUPPORT_URL, - "https://www.voidtools.com/donate/", // LOCALIZATION_ID_HELP_DONATE, - "https://www.voidtools.com/", // LOCALIZATION_ID_HELP_WEBSITE_URL, - - // Toolbar - "上一个", // LOCALIZATION_ID_TOOLBAR_PREVIOUS_IMAGE_BUTTON, - "下一个", // LOCALIZATION_ID_TOOLBAR_NEXT_IMAGE_BUTTON, - "播放", // LOCALIZATION_ID_TOOLBAR_PLAY_SLIDESHOW_BUTTON, - "暂停", // LOCALIZATION_ID_TOOLBAR_PAUSE_SLIDESHOW_BUTTON, - "最佳适应", // LOCALIZATION_ID_TOOLBAR_BEST_FIT_BUTTON, - "实际大小", // LOCALIZATION_ID_TOOLBAR_ACTUAL_SIZE_BUTTON, - - // Status bar - "预加载", // LOCALIZATION_ID_STATUS_BAR_PRELOAD, - "加载中...", // LOCALIZATION_ID_STATUS_BAR_LOADING, - "未找到文件。", // LOCALIZATION_ID_STATUS_BAR_FILE_NOT_FOUND, - "加载图片失败。", // LOCALIZATION_ID_STATUS_BAR_FAILED_TO_LOAD_IMAGE, - "幻灯片播放中", // LOCALIZATION_ID_STATUS_BAR_SLIDESHOW_PLAYING, - "位置 %0.3f %0.3f, 缩放 %0.3f %0.3f, 宽高比 %0.3f", // LOCALIZATION_ID_STATUS_BAR_POS_ZOOM_FORMAT, - "动画速率 %0.3f", // LOCALIZATION_ID_STATUS_BAR_ANIMATION_RATE_FORMAT, - "幻灯片播放间隔 %d %s", // LOCALIZATION_ID_STATUS_BAR_SLIDESHOW_RATE_FORMAT, - "分钟", // LOCALIZATION_ID_STATUS_BAR_MINUTES, - "秒", // LOCALIZATION_ID_STATUS_BAR_SECONDS, - "毫秒", // LOCALIZATION_ID_STATUS_BAR_MILLISECONDS, - - - // Dialog strings - "选项 - void Image Viewer", // LOCALIZATION_ID_OPTIONS_CAPTION, - "常规", // LOCALIZATION_ID_OPTIONS_GENERAL_DIALOG, - "视图", // LOCALIZATION_ID_OPTIONS_VIEW_DIALOG, - "控件", // LOCALIZATION_ID_OPTIONS_CONTROLS_DIALOG, - "确定", // LOCALIZATION_ID_OK_BUTTON, - "取消", // LOCALIZATION_ID_CANCEL_BUTTON, - "在 %APPDATA%\\voidImageViewer 中存储设置(&S)", // LOCALIZATION_ID_STORE_SETTINGS_APPDATA, - "允许多个实例(&I)", // LOCALIZATION_ID_ALLOW_MULTIPLE_INSTANCES, - "开始菜单快捷方式(&M)", // LOCALIZATION_ID_STARTMENU_SHORTCUTS, - "文件关联", // LOCALIZATION_ID_ASSOCIATIONS, - "全选(&A)", // LOCALIZATION_ID_CHECK_ALL, - "全不选(&N)", // LOCALIZATION_ID_CHECK_NONE, - "缩小位图模式(&S):", // LOCALIZATION_ID_SHRINK_BLIT_MODE_STATIC, - "放大位图模式(&M):", // LOCALIZATION_ID_MAGNIFY_BLIT_MODE, - "最近邻", // LOCALIZATION_ID_BLIT_MODE_NEAREST_COMBOBOXITEM, - "线性", // LOCALIZATION_ID_BLIT_MODE_LINEAR_COMBOBOXITEM, - "自动调窗(&Z):", // LOCALIZATION_ID_OPTIONS_VIEW_AUTO_SIZE_WINDOW_STATIC, - "50%", // LOCALIZATION_ID_OPTIONS_VIEW_AUTO_SIZE_WINDOW_50_PERCENT_COMBOBOXITEM, - "100%", // LOCALIZATION_ID_OPTIONS_VIEW_AUTO_SIZE_WINDOW_100_PERCENT_COMBOBOXITEM, - "200%", // LOCALIZATION_ID_OPTIONS_VIEW_AUTO_SIZE_WINDOW_200_PERCENT_COMBOBOXITEM, - "自动适应", // LOCALIZATION_ID_OPTIONS_VIEW_AUTO_SIZE_WINDOW_AUTO_FIT_COMBOBOXITEM, - "在幻灯片中至少播放一次动画(&P)", // LOCALIZATION_ID_PLAY_ANIMATIONS_ONCE_STATIC, - "预加载下一张图像(&N)", // LOCALIZATION_ID_PRELOAD_NEXT_IMAGE_STATIC, - "缓存最后一张图像(&L)", // LOCALIZATION_ID_CACHE_LAST_IMAGE_STATIC, - "窗口背景颜色(&W):", // LOCALIZATION_ID_WINDOWED_BACKGROUND_COLOR_STATIC, - "全屏背景颜色(&F):", // LOCALIZATION_ID_FULLSCREEN_BACKGROUND_COLOR_STATIC, - "左键操作(&L):", // LOCALIZATION_ID_LEFT_CLICK_ACTION_STATIC, - "右键操作(&R):", // LOCALIZATION_ID_RIGHT_CLICK_ACTION_STATIC, - "鼠标滚轮操作(&M):", // LOCALIZATION_ID_MOUSE_WHEEL_ACTION_STATIC, - "命令(&C):", // LOCALIZATION_ID_COMMANDS_STATIC, - "所选命令的设置", // LOCALIZATION_ID_SETTINGS_FOR_SELECTED_COMMAND, - "添加(&A)...", // LOCALIZATION_ID_ADD_KEY_BUTTON, - "编辑(&E)...", // LOCALIZATION_ID_EDIT_KEY_BUTTON, - "删除(&V)", // LOCALIZATION_ID_REMOVE_KEY_BUTTON, - "添加键盘快捷键", // LOCALIZATION_ID_ADD_KEYBOARD_SHORTCUT_CAPTION, - "编辑键盘快捷键", // LOCALIZATION_ID_EDIT_KEYBOARD_SHORTCUT_CAPTION, - "快捷键(&K):", // LOCALIZATION_ID_SHORTCUT_KEY, - "当前使用此快捷键的命令:", // LOCALIZATION_ID_SHORTCUT_KEY_CURRENTLY_USED_BY, - "删除(&V)", // LOCALIZATION_ID_REMOVE, - "设置自定义速率", // LOCALIZATION_ID_SET_CUSTOM_RATE_CAPTION, - "自定义速率(&C):", // LOCALIZATION_ID_CUSTOM_RATE_STATIC, - "分钟", // LOCALIZATION_ID_CUSTOM_RATE_MINUTES, - "秒", // LOCALIZATION_ID_CUSTOM_RATE_SECONDS, - "毫秒", // LOCALIZATION_ID_CUSTOM_RATE_MILLISECONDS, - "关于 void Image Viewer", // LOCALIZATION_ID_ABOUT_CAPTION, - "重命名", // LOCALIZATION_ID_RENAME_CAPTION, - "跳转到", // LOCALIZATION_ID_JUMP_TO_TITLE, - "搜索 Everything", // LOCALIZATION_ID_SEARCH_EVERYTHING, - "版权所有 © %d voidtools", // LOCALIZATION_ID_ABOUT_COPYRIGHT_FORMAT, - "support@voidtools.com", // LOCALIZATION_ID_ABOUT_EMAIL, - "www.voidtools.com", // LOCALIZATION_ID_ABOUT_WEBSITE, - "打开图像", // LOCALIZATION_ID_OPEN_IMAGE_CAPTION, - "所有图像文件", // LOCALIZATION_ID_OPEN_ALL_IMAGE_FILES, - "所有文件", // LOCALIZATION_ID_OPEN_ALL_FILES, - "滚动", // LOCALIZATION_ID_OPTIONS_ACTION_SCROLL_COMBOBOXITEM, - "播放/暂停幻灯片", // LOCALIZATION_ID_OPTIONS_ACTION_PLAY_PAUSE_SLIDESHOW_COMBOBOXITEM, - "播放/暂停动画", // LOCALIZATION_ID_OPTIONS_ACTION_PLAY_PAUSE_ANIMATION_COMBOBOXITEM, - "放大", // LOCALIZATION_ID_OPTIONS_ACTION_ZOOM_IN_COMBOBOXITEM, - "下一张图像", // LOCALIZATION_ID_OPTIONS_ACTION_NEXT_IMAGE_COMBOBOXITEM, - "1:1 滚动", // LOCALIZATION_ID_OPTIONS_ACTION_ONE_TO_ONE_SCROLL_COMBOBOXITEM, - "滚动/移动窗口", // LOCALIZATION_ID_OPTIONS_ACTION_SCROLL_MOVE_WINDOW_COMBOBOXITEM, - "上下文菜单", // LOCALIZATION_ID_OPTIONS_ACTION_CONTEXT_MENU_COMBOBOXITEM, - "缩小", // LOCALIZATION_ID_OPTIONS_ACTION_ZOOM_OUT_COMBOBOXITEM, - "上一张图像", // LOCALIZATION_ID_OPTIONS_ACTION_PREVIOUS_IMAGE_COMBOBOXITEM, - "缩放", // LOCALIZATION_ID_OPTIONS_ACTION_ZOOM_COMBOBOXITEM, - "下一张/上一张", // LOCALIZATION_ID_OPTIONS_ACTION_NEXT_PREV_COMBOBOXITEM, - "上一张/下一张", // LOCALIZATION_ID_OPTIONS_ACTION_PREV_NEXT_COMBOBOXITEM, - "标题栏格式(&T):", // LOCALIZATION_ID_OPTIONS_TITLE_BAR_FORMAT_STATIC, - "完整路径", // LOCALIZATION_ID_OPTIONS_TITLE_BAR_FORMAT_FULL_PATH_COMBOBOXITEM, - "仅文件名", // LOCALIZATION_ID_OPTIONS_TITLE_BAR_FORMAT_FILENAME_ONLY_COMBOBOXITEM, - "无", // LOCALIZATION_ID_OPTIONS_TITLE_BAR_FORMAT_NONE_COMBOBOXITEM, - "Everything 不可用", // LOCALIZATION_ID_EVERYTHING_NOT_AVAILABLE_MESSAGE, - "添加 Everything 搜索", // LOCALIZATION_ID_EVERYTHING_ADD_EVERYTHING_SEARCH_CAPTION, - "加载 Everything 搜索", // LOCALIZATION_ID_EVERYTHING_LOAD_EVERYTHING_SEARCH_CAPTION, - "随机化", // LOCALIZATION_ID_RANDOMIZE, - "复制到", // LOCALIZATION_ID_COPY_TO_CAPTION, - "移动到", // LOCALIZATION_ID_MOVE_TO_CAPTION, + // 透明像素下的垫色(不是图片四周的画布颜色) + "透明背景(&T)", // LOCALIZATION_ID_BACKDROP + "跟随窗口背景色(&F)", // LOCALIZATION_ID_BACKDROP_FOLLOW + "黑色(&B)", // LOCALIZATION_ID_BACKDROP_BLACK + "白色(&W)", // LOCALIZATION_ID_BACKDROP_WHITE + "自定义颜色(&C)...", // LOCALIZATION_ID_BACKDROP_CUSTOM + "棋盘格(&K)", // LOCALIZATION_ID_BACKDROP_CHECKERBOARD - // Association descriptions - "Bitmap Image", - "Animated GIF Image", - "Icon File", - "JPEG Image", - "JPEG Image", - "PNG Image", - "TIFF Image", - "TIFF Image", - "WebP Image", + "最近打开的文件(&F)", // LOCALIZATION_ID_RECENT_FILES + "(空)", // LOCALIZATION_ID_RECENT_FILES_EMPTY + "清除最近文件列表(&C)", // LOCALIZATION_ID_RECENT_FILES_CLEAR + "设置桌面壁纸", // LOCALIZATION_ID_SET_DESKTOP_WALLPAPER_CAPTION + "将当前图片设置为桌面壁纸?", // LOCALIZATION_ID_SET_DESKTOP_WALLPAPER_MESSAGE + "%s B", // LOCALIZATION_ID_STATUS_BAR_SIZE_BYTES_FORMAT + " KB", // LOCALIZATION_ID_STATUS_BAR_SIZE_KB_FORMAT + " MB", // LOCALIZATION_ID_STATUS_BAR_SIZE_MB_FORMAT + " GB", // LOCALIZATION_ID_STATUS_BAR_SIZE_GB_FORMAT + "窗口背景颜色(&B)...", // LOCALIZATION_ID_WINDOWED_BACKGROUND_COLOR_MENU + // gui 重制轮:设置窗口、工具栏文案、状态栏格式 + "设置", // LOCALIZATION_ID_SETTINGS + "常规", // LOCALIZATION_ID_SETTINGS_PAGE_GENERAL + "查看", // LOCALIZATION_ID_SETTINGS_PAGE_VIEW + "控制", // LOCALIZATION_ID_SETTINGS_PAGE_CONTROLS + "界面", // LOCALIZATION_ID_SETTINGS_SECTION_INTERFACE + "语言", // LOCALIZATION_ID_SETTINGS_LANGUAGE + "跟随系统", // LOCALIZATION_ID_SETTINGS_LANGUAGE_FOLLOW_SYSTEM + "主题", // LOCALIZATION_ID_SETTINGS_THEME + "启动与窗口", // LOCALIZATION_ID_SETTINGS_SECTION_STARTUP + "允许多个实例", // LOCALIZATION_ID_SETTINGS_ALLOW_MULTIPLE + "同时打开多个窗口查看不同的图片", // LOCALIZATION_ID_SETTINGS_ALLOW_MULTIPLE_DESC + "开机时创建快捷方式", // LOCALIZATION_ID_SETTINGS_STARTUP_SHORTCUT + "在系统启动时将 void Image Viewer PLUS 添加到启动项", // LOCALIZATION_ID_SETTINGS_STARTUP_SHORTCUT_DESC + "文件关联", // LOCALIZATION_ID_SETTINGS_SECTION_ASSOCIATIONS + "选择要关联的图像文件格式", // LOCALIZATION_ID_SETTINGS_ASSOCIATIONS_DESC + "全部选中", // LOCALIZATION_ID_SETTINGS_SELECT_ALL + "确定", // LOCALIZATION_ID_SETTINGS_OK + "取消", // LOCALIZATION_ID_SETTINGS_CANCEL + "打开", // LOCALIZATION_ID_TOOLBAR_OPEN + "旋转", // LOCALIZATION_ID_TOOLBAR_ROTATE + "图像信息", // LOCALIZATION_ID_TOOLBAR_IMAGE_INFO + "%d / %d", // LOCALIZATION_ID_STATUS_BAR_POSITION_FORMAT + "%u × %u", // LOCALIZATION_ID_STATUS_BAR_DIMENSIONS_FORMAT + "RGB %d, %d, %d", // LOCALIZATION_ID_STATUS_BAR_RGB_FORMAT + "是", // LOCALIZATION_ID_MSGBOX_YES + "否", // LOCALIZATION_ID_MSGBOX_NO + "强调色", // LOCALIZATION_ID_ACCENT_COLOR }; diff --git a/src/mem.c b/src/mem.c index f04c3a17..acbcb05d 100644 --- a/src/mem.c +++ b/src/mem.c @@ -235,12 +235,14 @@ void mem_free_debug(const char *file,int line,void *p) mem_debug_initialized = 1; } - mem_usage -= HeapSize(GetProcessHeap(),0,(((mem_debug_t *)p)-1)); - + // a null free used to dereference the header inside heapsize before + // this guard could ever run. debug_fatal is noreturn. if (!p) { debug_fatal("INVALID FREE from %s(%d): %p",file,line,p); } + + mem_usage -= HeapSize(GetProcessHeap(),0,(((mem_debug_t *)p)-1)); { int magici; diff --git a/src/os.c b/src/os.c index 4d2d7ac8..14797b73 100644 --- a/src/os.c +++ b/src/os.c @@ -110,6 +110,7 @@ static IShellItem *_os_get_shellitem(const ITEMIDLIST *pidl); HINSTANCE os_hinstance = 0; DWORD os_major_version = 0; // 4 = 9x/nt, 5 = xp,2k,server2k3, 6 = vista DWORD os_minor_version = 0; +DWORD os_build_number = 0; // the real build number (valid with the supportedOS manifest guid list) char os_is_nt = 0; BOOL (WINAPI *os_CreateTimerQueueTimer)(PHANDLE phNewTimer,HANDLE TimerQueue,WAITORTIMERCALLBACK Callback,PVOID Parameter,DWORD DueTime,DWORD Period,ULONG Flags) = 0; BOOL (WINAPI *os_DeleteTimerQueueTimer)(HANDLE TimerQueue,HANDLE Timer,HANDLE CompletionEvent) = 0; @@ -119,6 +120,9 @@ BOOL (WINAPI *os_GetFileAttributesExW)(LPCWSTR lpFileName,GET_FILEEX_INFO_LEVELS BOOL (WINAPI *_os_IsDebuggerPresent)(void) = 0; EXECUTION_STATE (WINAPI *os_SetThreadExecutionState)( EXECUTION_STATE esFlags) = NULL; LANGID (WINAPI *os_GetUserDefaultUILanguage)(void) = NULL; +BOOL (WINAPI *os_SetGestureConfig)(HWND hwnd,DWORD reserved,UINT cIDs,os_GestureConfig_t *configs,UINT cbSize) = NULL; +BOOL (WINAPI *os_GetGestureInfo)(void *gesture_info_handle,os_GestureInfo_t *gesture_info) = NULL; +BOOL (WINAPI *os_CloseGestureInfoHandle)(void *gesture_info_handle) = NULL; HRESULT (WINAPI *os_SHOpenFolderAndSelectItems)(LPCITEMIDLIST pidlFolder,UINT cidl,LPCITEMIDLIST *apidl,DWORD dwFlags) = 0; int (WINAPI *os_GdiplusStartup)(OUT ULONG_PTR *token,const os_GdiplusStartupInput_t *input,void *output) = 0; VOID (WINAPI *os_GdiplusShutdown)(ULONG_PTR token) = 0; @@ -130,6 +134,7 @@ int (__stdcall *os_GdipImageGetFrameDimensionsCount)(void *image, UINT* count) = int (__stdcall *os_GdipImageGetFrameDimensionsList)(void *image, GUID* dimensionIDs,UINT count) = 0; int (__stdcall *os_GdipImageGetFrameCount)(void *image, const GUID* dimensionID,UINT* count) = 0; int (__stdcall *os_GdipGetPropertyItemSize)(void *image, PROPID propId, UINT* size) = 0; +int (__stdcall *os_GdipGetImageThumbnail)(void *image,UINT thumb_wide,UINT thumb_high,void **thumb_image,void *callback,void *callback_data) = 0; int (__stdcall *os_GdipGetPropertyItem)(void *image, PROPID propId,UINT propSize,void *buffer) = 0; int (__stdcall *os_GdipImageSelectActiveFrame)(void *image, const GUID* dimensionID,UINT frameIndex) = 0; int (__stdcall *os_GdipGetImageFlags)(void *image, UINT *flags) = 0; @@ -142,15 +147,81 @@ int (__stdcall *os_GdipSetPixelOffsetMode)(void* graphics,int pixelOffsetMode) = int (__stdcall *os_GdipSetSmoothingMode)(void *graphics, int smoothingMode) = 0; int (__stdcall *os_GdipDrawImageRectI)(void *graphics, void *image, INT x, INT y,INT width, INT height) = 0; int (__stdcall *os_GdipDeleteGraphics)(void *graphics) = 0; +int (__stdcall *os_GdipCreateBitmapFromHBITMAP)(HBITMAP hbitmap,HPALETTE hpalette,void **bitmap) = 0; +int (__stdcall *os_GdipSaveImageToFile)(void *image,const wchar_t *filename,const GUID *clsidEncoder,const void *encoderParams) = 0; +int (__stdcall *os_GdipGetImageEncodersSize)(unsigned int *numCodecs,unsigned int *size) = 0; +int (__stdcall *os_GdipGetImageEncoders)(unsigned int numCodecs,unsigned int size,void *encoders) = 0; BOOL (STDAPICALLTYPE *os_IsUserAnAdmin)(void) = 0; HRESULT (__stdcall *os_EnableThemeDialogTexture)(HWND hwnd, DWORD dwFlags) = 0; static unsigned int (__cdecl *_os_controlfp)(unsigned int _NewValue,unsigned int _Mask) = 0; BOOL (WINAPI *os_ChangeWindowMessageFilterEx)(HWND hWnd,UINT message,DWORD action,void *pChangeFilterStruct) = 0; DWORD (WINAPI *os_GetLayout)(HDC hdc) = 0; +// windows 10 (1809+) dark mode exports, resolved by ordinal at runtime. +typedef int (__stdcall *OS_SetPreferredAppMode_fn)(int mode); +typedef void (__stdcall *OS_FlushMenuThemes_fn)(void); +typedef void (__stdcall *OS_RefreshImmersiveColorPolicyState_fn)(void); +typedef int (__stdcall *OS_ShouldAppsUseDarkMode_fn)(void); +typedef int (__stdcall *OS_AllowDarkModeForWindow_fn)(HWND hwnd,int allow); +typedef HRESULT (__stdcall *OS_DwmSetWindowAttribute_fn)(HWND hwnd,DWORD attribute,const void *value,DWORD size); +static OS_SetPreferredAppMode_fn _os_SetPreferredAppMode = 0; +static OS_FlushMenuThemes_fn _os_FlushMenuThemes = 0; +static OS_RefreshImmersiveColorPolicyState_fn _os_RefreshImmersiveColorPolicyState = 0; +static OS_ShouldAppsUseDarkMode_fn _os_ShouldAppsUseDarkMode = 0; +static OS_AllowDarkModeForWindow_fn _os_AllowDarkModeForWindow = 0; +static OS_DwmSetWindowAttribute_fn _os_DwmSetWindowAttribute = 0; + +typedef HRESULT (__stdcall *OS_SetWindowTheme_fn)(HWND hwnd,const wchar_t *sub_app_name,const wchar_t *sub_id_list); +static OS_SetWindowTheme_fn _os_SetWindowTheme = 0; +// the theme part metrics for the custom drawn glyph labels (the same +// dynamic pattern as the theme class calls above). +typedef HANDLE (__stdcall *OS_OpenThemeData_fn)(HWND hwnd,const wchar_t *class_list); +typedef HRESULT (__stdcall *OS_CloseThemeData_fn)(HANDLE theme); +typedef HRESULT (__stdcall *OS_GetThemePartSize_fn)(HANDLE theme,HDC hdc,int part,int state,const RECT *rect,int size_type,SIZE *size); +static OS_OpenThemeData_fn _os_OpenThemeData = 0; +static OS_CloseThemeData_fn _os_CloseThemeData = 0; +static OS_GetThemePartSize_fn _os_GetThemePartSize = 0; +typedef HRESULT (__stdcall *OS_DrawThemeBackground_fn)(HANDLE theme,HDC hdc,int part,int state,const RECT *rect); +static OS_DrawThemeBackground_fn _os_DrawThemeBackground = 0; + +// registry reads for a stable dark mode detection: the undocumented uxtheme +// probe returns wrong values on some windows 10 1903+ builds, the personalize +// registry value is the documented source the shell itself follows. +typedef LONG (__stdcall *OS_RegOpenKeyExW_fn)(HKEY key,const wchar_t *name,DWORD options,DWORD access,HKEY *result); +typedef LONG (__stdcall *OS_RegQueryValueExW_fn)(HKEY key,const wchar_t *name,DWORD *reserved,DWORD *type,unsigned char *data,DWORD *size); +typedef LONG (__stdcall *OS_RegCloseKey_fn)(HKEY key); +static OS_RegOpenKeyExW_fn _os_RegOpenKeyExW = 0; +static OS_RegQueryValueExW_fn _os_RegQueryValueExW = 0; +static OS_RegCloseKey_fn _os_RegCloseKey = 0; +typedef LONG (__stdcall *OS_RegDeleteKeyExW_fn)(HKEY key,const wchar_t *name,REGSAM access,DWORD reserved); +static OS_RegDeleteKeyExW_fn _os_RegDeleteKeyExW = 0; +static HMODULE _os_advapi32_hmodule = 0; + +// cached dark state: the ui queries the dark mode in paint paths, so the +// system is probed once and the cache is dropped on setting changes. +static int _os_dark_cache_valid = 0; +static int _os_dark_cache_dark = 0; + static HMONITOR (WINAPI *_os_MonitorFromWindow)(HWND hwnd,DWORD dwFlags) = 0; static HMONITOR (WINAPI *_os_MonitorFromRect)(LPCRECT lprc,DWORD dwFlags) = 0; static HMONITOR (WINAPI *_os_MonitorFromPoint)(POINT pt,DWORD dwFlags) = 0; +// windows 10 1607+: per window dpi query, used by os_window_update_dpi(). +static UINT (WINAPI *_os_GetDpiForWindow)(HWND hwnd) = 0; +// windows 10 1703+: process wide dpi awareness claim, used when the +// embedded manifest is missing or was stripped. +static BOOL (WINAPI *_os_SetProcessDpiAwarenessContext)(HANDLE context) = 0; +// windows 10 1607+: per thread dpi awareness claim, same purpose. +static HANDLE (WINAPI *_os_SetThreadDpiAwarenessContext)(HANDLE context) = 0; +// windows 8.1: shcore fallback. +static HRESULT (WINAPI *_os_SetProcessDpiAwareness)(int value) = 0; +static HMODULE _os_shcore_hmodule = 0; +// windows vista / 7: the classic system aware claim - the only dpi api +// those systems carry. +static BOOL (WINAPI *_os_SetProcessDPIAware)(void) = 0; + +// windows 10 1607+: dpi aware system parameters, used by os_menu_font(). +static BOOL (WINAPI *_os_SystemParametersInfoForDpi)(UINT action,UINT param,void *pvparam,UINT winini,UINT dpi) = 0; + int os_logical_wide = 96; int os_logical_high = 96; static const GUID _os_IID_IShellItem = {0x43826d1e,0xe718,0x42ee,{0xbc,0x55,0xa1,0xe2,0x61,0xc3,0x7b,0xfe}}; @@ -168,18 +239,21 @@ static HMODULE _os_UxTheme_hmodule = 0; static HMODULE _os_gdiplus_hmodule = 0; static HMODULE _os_ucrtbase_hmodule = 0; static HMODULE _os_gdi32_hmodule = 0; +static HMODULE _os_dwmapi_hmodule = 0; void os_zero_memory(void *data,int size) { ZeroMemory(data,size); } -void os_copy_memory(void *d,const void *s,int size) +// size_t lengths: the clipboard dib paste copies stride*height bytes, +// which crosses int_max inside the 64-bit pixel budget. +void os_copy_memory(void *d,const void *s,SIZE_T size) { CopyMemory(d,s,size); } -void os_move_memory(void *d,const void *s,int size) +void os_move_memory(void *d,const void *s,SIZE_T size) { MoveMemory(d,s,size); } @@ -716,8 +790,14 @@ void os_RegisterClassEx(UINT style,WNDPROC lpfnWndProc,HICON hIcon,HCURSOR hCurs wcex.lpfnWndProc = lpfnWndProc; wcex.hInstance = os_hinstance; wcex.hIcon = hIcon; - wcex.hCursor = LoadCursor(NULL,IDC_ARROW); - wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + // the wrapper honored neither the cursor nor the brush it was given: + // every class registered with the light window brush (white), so the + // rebar slabs, the zoomui tray and any bypassing erase flashed white + // in the dark ui no matter what the callers wrote. the parameters are + // the contract now - a caller that wants the classic faces passes + // them, a caller that paints its own face passes no brush at all. + wcex.hCursor = hCursor; + wcex.hbrBackground = hbrBackground; wcex.lpszClassName = name_wbuf; wcex.hIconSm = hIconSm; @@ -803,6 +883,7 @@ void os_init(void) os_major_version = (char)osvi.dwMajorVersion; os_minor_version = (char)osvi.dwMinorVersion; + os_build_number = osvi.dwBuildNumber; os_is_nt = (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT); debug_printf("os %d\n",os_major_version); @@ -860,15 +941,113 @@ void os_init(void) if (_os_user32_hmodule) { os_ChangeWindowMessageFilterEx = (void *)GetProcAddress(_os_user32_hmodule,"ChangeWindowMessageFilterEx"); + os_SetGestureConfig = (void *)GetProcAddress(_os_user32_hmodule,"SetGestureConfig"); + os_GetGestureInfo = (void *)GetProcAddress(_os_user32_hmodule,"GetGestureInfo"); + os_CloseGestureInfoHandle = (void *)GetProcAddress(_os_user32_hmodule,"CloseGestureInfoHandle"); _os_MonitorFromWindow = (void *)GetProcAddress(_os_user32_hmodule,"MonitorFromWindow"); _os_MonitorFromRect = (void *)GetProcAddress(_os_user32_hmodule,"MonitorFromRect"); _os_MonitorFromPoint = (void *)GetProcAddress(_os_user32_hmodule,"MonitorFromPoint"); + _os_GetDpiForWindow = (void *)GetProcAddress(_os_user32_hmodule,"GetDpiForWindow"); + _os_SystemParametersInfoForDpi = (void *)GetProcAddress(_os_user32_hmodule,"SystemParametersInfoForDpi"); + _os_SetThreadDpiAwarenessContext = (void *)GetProcAddress(_os_user32_hmodule,"SetThreadDpiAwarenessContext"); + _os_SetProcessDpiAwarenessContext = (void *)GetProcAddress(_os_user32_hmodule,"SetProcessDpiAwarenessContext"); + _os_SetProcessDPIAware = (void *)GetProcAddress(_os_user32_hmodule,"SetProcessDPIAware"); + } + + // dpi awareness: the embedded manifest normally declares per monitor + // v2 (res/voidImageViewer.Manifest, merged by the vs linker through + // AdditionalManifestFiles; a viv.exe.manifest next to the exe covers + // manifest-less builds). the runtime claim below is the safety net + // for a manifest-less binary (repackaged or stripped exes): without + // it the process stays dpi unaware, the system bitmap-stretches every + // window at high dpi and the ui turns blurry and oversized. + // the claim must happen before the first window exists: os_init is + // exactly that point, and the GetProcAddress block above must come + // first -- this used to sit before the pointers were resolved and + // silently never fired. + // each tier is a guarded no-op on systems without the api: + // win10 1703+ process wide, win10 1607+ per thread (covers the ui + // thread this process creates every window on), win 8.1 shcore + // process claim, and win 7 / vista close the chain with the classic + // setprocessdpiaware claim - without that last tier a manifest-less + // binary on 7 stayed fully unaware and the system bitmap-stretched + // everything (the manifest carries the same ladder through its dual + // dpiAware / dpiAwareness declaration). + if (_os_SetProcessDpiAwarenessContext) + { + // DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 = ((DPI_CONTEXT_HANDLE)-4) + _os_SetProcessDpiAwarenessContext((HANDLE)-4); + } + else if (_os_SetThreadDpiAwarenessContext) + { + _os_SetThreadDpiAwarenessContext((HANDLE)-4); + } + else + { + int claimed; + + claimed = 0; + + _os_shcore_hmodule = LoadLibraryA("shcore.dll"); + + if (_os_shcore_hmodule) + { + _os_SetProcessDpiAwareness = (void *)GetProcAddress(_os_shcore_hmodule,"SetProcessDpiAwareness"); + + // PROCESS_PER_MONITOR_DPI_AWARE = 2. + if (_os_SetProcessDpiAwareness) + { + _os_SetProcessDpiAwareness(2); + + claimed = 1; + } + } + + // win 7 / vista: the classic claim. a manifest-declared process + // is already aware - the call fails harmlessly there. + if ((!claimed) && (_os_SetProcessDPIAware)) + { + _os_SetProcessDPIAware(); + } } _os_UxTheme_hmodule = LoadLibraryA("UxTheme.dll"); if (_os_UxTheme_hmodule) { os_EnableThemeDialogTexture = (void *)GetProcAddress(_os_UxTheme_hmodule,"EnableThemeDialogTexture"); + + // the dark explorer visual style for dialog controls (named export). + _os_SetWindowTheme = (void *)GetProcAddress(_os_UxTheme_hmodule,"SetWindowTheme"); + + // windows 10 dark mode: uxtheme exports these by ordinal only. on + // windows 7/8 and pre-1809 builds they do not resolve and every dark + // function below quietly does nothing. + _os_SetPreferredAppMode = (void *)GetProcAddress(_os_UxTheme_hmodule,MAKEINTRESOURCEA(135)); + _os_FlushMenuThemes = (void *)GetProcAddress(_os_UxTheme_hmodule,MAKEINTRESOURCEA(136)); + _os_RefreshImmersiveColorPolicyState = (void *)GetProcAddress(_os_UxTheme_hmodule,MAKEINTRESOURCEA(104)); + _os_ShouldAppsUseDarkMode = (void *)GetProcAddress(_os_UxTheme_hmodule,MAKEINTRESOURCEA(132)); + _os_AllowDarkModeForWindow = (void *)GetProcAddress(_os_UxTheme_hmodule,MAKEINTRESOURCEA(133)); + // the button part metrics (the glyph label offset). + _os_OpenThemeData = (void *)GetProcAddress(_os_UxTheme_hmodule,"OpenThemeData"); + _os_CloseThemeData = (void *)GetProcAddress(_os_UxTheme_hmodule,"CloseThemeData"); + _os_GetThemePartSize = (void *)GetProcAddress(_os_UxTheme_hmodule,"GetThemePartSize"); + _os_DrawThemeBackground = (void *)GetProcAddress(_os_UxTheme_hmodule,"DrawThemeBackground"); + + } + + _os_dwmapi_hmodule = LoadLibraryA("dwmapi.dll"); + if (_os_dwmapi_hmodule) + { + _os_DwmSetWindowAttribute = (void *)GetProcAddress(_os_dwmapi_hmodule,"DwmSetWindowAttribute"); + } + + // advapi32: registry reads for the dark mode detection. + _os_advapi32_hmodule = LoadLibraryA("advapi32.dll"); + if (_os_advapi32_hmodule) + { + _os_RegOpenKeyExW = (void *)GetProcAddress(_os_advapi32_hmodule,"RegOpenKeyExW"); + _os_RegQueryValueExW = (void *)GetProcAddress(_os_advapi32_hmodule,"RegQueryValueExW"); + _os_RegCloseKey = (void *)GetProcAddress(_os_advapi32_hmodule,"RegCloseKey"); } // set "floating point to int mode" to truncate @@ -887,7 +1066,7 @@ void os_init(void) _os_gdi32_hmodule = LoadLibraryA("gdi32.dll"); if (_os_gdi32_hmodule) { - os_GetLayout = (void *)GetProcAddress(_os_user32_hmodule,"GetLayout"); + os_GetLayout = (void *)GetProcAddress(_os_gdi32_hmodule,"GetLayout"); } _os_gdiplus_hmodule = LoadLibraryA("gdiplus.dll"); @@ -903,6 +1082,11 @@ void os_init(void) os_GdipImageGetFrameDimensionsList = (void *)_os_get_proc_address(_os_gdiplus_hmodule,"GdipImageGetFrameDimensionsList"); os_GdipImageGetFrameCount = (void *)_os_get_proc_address(_os_gdiplus_hmodule,"GdipImageGetFrameCount"); os_GdipGetPropertyItemSize = (void *)_os_get_proc_address(_os_gdiplus_hmodule,"GdipGetPropertyItemSize"); + // optional: gdi+ serves the embedded exif thumbnail without decoding + // the full image, but not every gdiplus.dll exports GdipGetImageThumbnail. + // a missing export must never be fatal at startup (it would kill the + // /install self-install step), the progressive preview quietly turns off. + os_GdipGetImageThumbnail = (void *)GetProcAddress(_os_gdiplus_hmodule,"GdipGetImageThumbnail"); os_GdipGetPropertyItem = (void *)_os_get_proc_address(_os_gdiplus_hmodule,"GdipGetPropertyItem"); os_GdipImageSelectActiveFrame = (void *)_os_get_proc_address(_os_gdiplus_hmodule,"GdipImageSelectActiveFrame"); os_GdipGetImageFlags = (void *)_os_get_proc_address(_os_gdiplus_hmodule,"GdipGetImageFlags"); @@ -915,6 +1099,730 @@ void os_init(void) os_GdipSetSmoothingMode = (void *)_os_get_proc_address(_os_gdiplus_hmodule,"GdipSetSmoothingMode"); os_GdipDrawImageRectI = (void *)_os_get_proc_address(_os_gdiplus_hmodule,"GdipDrawImageRectI"); os_GdipDeleteGraphics = (void *)_os_get_proc_address(_os_gdiplus_hmodule,"GdipDeleteGraphics"); + os_GdipCreateBitmapFromHBITMAP = (void *)_os_get_proc_address(_os_gdiplus_hmodule,"GdipCreateBitmapFromHBITMAP"); + os_GdipSaveImageToFile = (void *)_os_get_proc_address(_os_gdiplus_hmodule,"GdipSaveImageToFile"); + os_GdipGetImageEncodersSize = (void *)_os_get_proc_address(_os_gdiplus_hmodule,"GdipGetImageEncodersSize"); + os_GdipGetImageEncoders = (void *)_os_get_proc_address(_os_gdiplus_hmodule,"GdipGetImageEncoders"); + } +} + +// is a touch digitizer available? +// (integrated or external touch screen) +int os_is_touch_available(void) +{ + int sm; + + // SM_DIGITIZER = 94 + sm = GetSystemMetrics(94); + + if (!sm) + { + return 0; + } + + // NID_READY = 0x80, NID_INTEGRATED_TOUCH = 0x01, NID_EXTERNAL_TOUCH = + // 0x02 (and NID_INTEGRATED_PEN = 0x04 - the pen does not belong in the + // mask: a pen-only digitizer passed the old probe and an external-only + // touch screen failed it). nid_ready alone is set by any ready + // digitizer (pens included): ask for an actual touch screen - the + // integrated or the external one - and only while the digitizer is + // ready. msdn + // also warns sm_digitizer has no plug-and-play awareness, so callers + // treat this as a first-run default, never a permanent configuration. + return ((sm & 0x80) && (sm & (0x01 | 0x02))) ? 1 : 0; +} + +int os_reg_delete_key_ex(HKEY hkey,const wchar_t *name,REGSAM access) +{ + // regdeletekeyw cannot delete from the alternate registry view (msdn: + // "cannot be used to access an alternate registry view") and + // regdeletekeyexw is vista+, so it resolves lazily here: the uninstall + // path runs before os_init populates the runtime table. a missing api + // (32-bit xp) reports failure and the caller falls back to + // regdeletekeyw. + if (!_os_RegDeleteKeyExW) + { + HMODULE module; + + module = GetModuleHandleA("advapi32.dll"); + + if (module) + { + _os_RegDeleteKeyExW = (void *)GetProcAddress(module,"RegDeleteKeyExW"); + } + } + + if (_os_RegDeleteKeyExW) + { + return (_os_RegDeleteKeyExW(hkey,name,access,0) == ERROR_SUCCESS) ? 1 : 0; + } + + return 0; +} + +// GDI+ encoder parameter structures. (locally defined, mirrors the gdiplus ABI) +typedef struct +{ + GUID Guid; // encoder parameter GUID. + unsigned long NumberOfValues; // number of values pointed to by Value. + unsigned long Type; // value type. (4 = long) + void *Value; // pointer to the value. +} os_EncoderParameter_t; + +typedef struct +{ + unsigned int Count; // number of parameters. + os_EncoderParameter_t Parameter[1]; +} os_EncoderParameters_t; + +// GDI+ image codec info. (locally defined, mirrors the gdiplus ABI) +typedef struct +{ + GUID Clsid; + GUID FormatID; + const wchar_t *CodecName; + const wchar_t *DllName; + const wchar_t *FormatDescription; + const wchar_t *FilenameExtension; + const wchar_t *MimeType; + unsigned long Flags; + unsigned long Version; + unsigned long SigCount; + unsigned long SigSize; + const void *SigPattern; + const void *SigMask; +} os_ImageCodecInfo_t; + +// ascii, case-insensitive wide string compare. returns 0 if equal. +static int _os_icompare_w(const wchar_t *a,const wchar_t *b) +{ + while ((*a) && (*b)) + { + wchar_t ca; + wchar_t cb; + + ca = *a; + cb = *b; + + if ((ca >= 'A') && (ca <= 'Z')) + { + ca = ca + 'a' - 'A'; + } + + if ((cb >= 'A') && (cb <= 'Z')) + { + cb = cb + 'a' - 'A'; + } + + if (ca != cb) + { + return 1; + } + + a++; + b++; + } + + if (*a != *b) + { + return 1; + } + + return 0; +} + +// save a HBITMAP to a file with the GDI+ built-in encoders. +// format: 0 = png, 1 = jpeg, 2 = bmp. +// returns 1 on success. +int os_save_hbitmap(HBITMAP hbitmap,const wchar_t *filename,int format) +{ + int ret; + void *image; + + ret = 0; + image = 0; + + if (os_GdipCreateBitmapFromHBITMAP) + { + if (os_GdipCreateBitmapFromHBITMAP(hbitmap,0,&image) == 0) + { + if (image) + { + const wchar_t *mime; + + // mime type of the built-in encoder for the target format. + mime = (format == 1) ? L"image/jpeg" : ((format == 2) ? L"image/bmp" : L"image/png"); + + // find the encoder CLSID for this mime type. + if ((os_GdipGetImageEncodersSize) && (os_GdipGetImageEncoders) && (os_GdipSaveImageToFile)) + { + unsigned int num; + unsigned int size; + + num = 0; + size = 0; + + if (os_GdipGetImageEncodersSize(&num,&size) == 0) + { + if ((num) && (size)) + { + os_ImageCodecInfo_t *codecs; + + codecs = (os_ImageCodecInfo_t *)mem_alloc(size); + + if (codecs) + { + os_zero_memory(codecs,size); + + if (os_GdipGetImageEncoders(num,size,codecs) == 0) + { + unsigned int i; + + for(i=0;i= 0) && (x < rect.right - rect.left)) - { - int i; - int count; - - count = (int)SendMessage(statusbar_hwnd,SB_GETPARTS,0,(LPARAM)NULL); - - if (count > 0) - { - for(i=0;i= rect.left) && (x < rect.right)) - { - return i; - } - } - } - } - - // simple? - return 0; - } - - return -1; -} - int os_is_windows_7_or_later(void) { if (os_major_version > 6) @@ -1407,6 +2291,30 @@ int os_is_windows_8_or_later(void) return 0; } +// true when the comctl dark explorer control classes actually render dark: +// windows 10 1903 (build 18362) and later. older builds accept the calls +// but keep the light control rendering, so the dialog fallbacks (owner +// drawn buttons and combos) carry the dark ui alone on those builds. +int os_dark_controls_supported(void) +{ + if (!os_is_nt) + { + return 0; + } + + if (os_major_version > 10) + { + return 1; + } + + if (os_major_version == 10) + { + return (os_build_number >= 18362) ? 1 : 0; + } + + return 0; +} + // windows creates funky regions if left > right HRGN os_CreateRectRgn(int left,int top,int right,int bottom) @@ -1544,8 +2452,10 @@ int os_get_orientation(const wchar_t *filename) ret = 0; +#ifdef _MSC_VER __try { +#endif if (_os_SHGetPropertyStoreFromIDList) { ITEMIDLIST *pidl; @@ -1612,11 +2522,13 @@ int os_get_orientation(const wchar_t *filename) { debug_printf((const utf8_t *)"no SHGetPropertyStoreFromIDList\n") ; } +#ifdef _MSC_VER } __except(EXCEPTION_EXECUTE_HANDLER) { debug_printf((const utf8_t *)"IPropertyStore::GetValue exception %08x\n",GetExceptionCode()); } +#endif return ret; } diff --git a/src/os.h b/src/os.h index 8c008717..37e85b4d 100644 --- a/src/os.h +++ b/src/os.h @@ -44,8 +44,8 @@ typedef struct os_GdiplusStartupInput_s }os_GdiplusStartupInput_t; void os_zero_memory(void *data,int size); -void os_copy_memory(void *d,const void *s,int size); -void os_move_memory(void *d,const void *s,int size); +void os_copy_memory(void *d,const void *s,SIZE_T size); +void os_move_memory(void *d,const void *s,SIZE_T size); void os_qsort(void **base,uintptr_t count,int (*compare)(const void *a,const void *b)); void os_make_rect_completely_visible(HWND hwnd,RECT *prect); void os_MonitorRectFromWindow(HWND hwnd,int is_fullscreen,RECT *out_monitor_rect); @@ -75,9 +75,9 @@ VIV_UINT64 os_get_tick_count(void); VIV_UINT64 os_get_tick_freq(void); void os_get_monitor_rect_from_window(HWND hwnd,RECT *monitor_rect,int fullscreen); WNDPROC os_set_window_proc(HWND hwnd,WNDPROC proc); -int os_statusbar_index_from_x(HWND statusbar_hwnd,int x); int os_is_windows_7_or_later(void); int os_is_windows_8_or_later(void); +int os_dark_controls_supported(void); HRGN os_CreateRectRgn(int left,int top,int right,int bottom); HRGN os_mirror_region(HRGN hrgn,int wide); void os_fill_clamped_rect(HDC hdc,int left,int top,int right,int bottom,int clamp_left,int clamp_top,int clamp_right,int clamp_bottom,HBRUSH hbrush); @@ -108,6 +108,10 @@ extern int (__stdcall *os_GdipImageGetFrameDimensionsCount)(void *image, UINT* c extern int (__stdcall *os_GdipImageGetFrameDimensionsList)(void *image, GUID* dimensionIDs,UINT count); extern int (__stdcall *os_GdipImageGetFrameCount)(void *image, const GUID* dimensionID,UINT* count); extern int (__stdcall *os_GdipGetPropertyItemSize)(void *image, PROPID propId, UINT* size); +// note: the real gdiplus flat api is GdipGetImageThumbnail(image,w,h,**out,cb,cb_data): +// the out image is the 4th parameter. loaded optionally (see os.c), older or +// stripped gdiplus builds may not export it at all. +extern int (__stdcall *os_GdipGetImageThumbnail)(void *image,UINT thumb_wide,UINT thumb_high,void **thumb_image,void *callback,void *callback_data); extern int (__stdcall *os_GdipGetPropertyItem)(void *image, PROPID propId,UINT propSize,void *buffer); extern int (__stdcall *os_GdipImageSelectActiveFrame)(void *image, const GUID* dimensionID,UINT frameIndex); extern int (__stdcall *os_GdipGetImageFlags)(void *image, UINT *flags); @@ -120,11 +124,76 @@ extern int (__stdcall *os_GdipSetPixelOffsetMode)(void* graphics,int pixelOffset extern int (__stdcall *os_GdipSetSmoothingMode)(void *graphics, int smoothingMode); extern int (__stdcall *os_GdipDrawImageRectI)(void *graphics, void *image, INT x, INT y,INT width, INT height); extern int (__stdcall *os_GdipDeleteGraphics)(void *graphics); +extern int (__stdcall *os_GdipCreateBitmapFromHBITMAP)(HBITMAP hbitmap,HPALETTE hpalette,void **bitmap); +extern int (__stdcall *os_GdipSaveImageToFile)(void *image,const wchar_t *filename,const GUID *clsidEncoder,const void *encoderParams); +extern int (__stdcall *os_GdipGetImageEncodersSize)(unsigned int *numCodecs,unsigned int *size); +extern int (__stdcall *os_GdipGetImageEncoders)(unsigned int numCodecs,unsigned int size,void *encoders); +int os_save_hbitmap(HBITMAP hbitmap,const wchar_t *filename,int format); extern BOOL (WINAPI *os_CreateTimerQueueTimer)(PHANDLE phNewTimer,HANDLE TimerQueue,WAITORTIMERCALLBACK Callback,PVOID Parameter,DWORD DueTime,DWORD Period,ULONG Flags); extern BOOL (WINAPI *os_DeleteTimerQueueTimer)(HANDLE TimerQueue,HANDLE Timer,HANDLE CompletionEvent); extern BOOL (WINAPI *os_GetFileAttributesExW)(LPCWSTR lpFileName,GET_FILEEX_INFO_LEVELS fInfoLevelId,LPVOID lpFileInformation); extern BOOL (STDAPICALLTYPE *os_IsUserAnAdmin)(void); extern HRESULT (__stdcall *os_EnableThemeDialogTexture)(HWND hwnd, DWORD dwFlags); +// windows dark mode support. every function quietly does nothing on windows +// versions without the dark mode apis (older than windows 10 1809). +// mode 0 = light, 1 = dark, 2 = follow the system theme. +extern int os_dark_system_dark(void); +extern void os_dark_set_app_mode(int mode); +extern void os_dark_titlebar(HWND hwnd,int dark); +extern void os_dark_refresh(void); +// drop the cached system dark state so the next os_dark_system_dark() +// call re-reads it (WM_SETTINGCHANGE / WM_THEMECHANGED). + +// set the DarkMode_Explorer visual style on a window (dialog controls and +// tabs draw dark with it). returns 1 when the style was applied. +extern int os_dark_window_theme(HWND hwnd); + +// combobox dark parts: the common dialog class (windows 10 1903+). + +extern int os_dark_combobox_theme(HWND hwnd); +// the light counterpart: back to the standard explorer visual style +// when the ui flips back to light. +extern int os_light_window_theme(HWND hwnd); + +// the button theme for the custom drawn glyph faces: one open per +// dialog lifetime, closed on the way out (uxtheme is loaded +// dynamically, so the handle type stays generic). +extern HANDLE os_theme_open_button(HWND hwnd); +extern void os_theme_close(HANDLE theme); +// the size of a button part in pixels: 1 when the theme and the part +// are available (the visual styles off leave the handle null). +extern int os_theme_part_size(HANDLE theme,HDC hdc,int part,int state,int *wide,int *high); +// draw a button part state into a rect: 1 when the theme drew it. +extern int os_theme_draw_part(HANDLE theme,HDC hdc,int part,int state,const RECT *rect); +// the vssym32 button part and state values the glyph drawing uses +// (uxtheme is loaded dynamically, so the constants live here). +#define OS_BP_RADIOBUTTON 2 +#define OS_BP_CHECKBOX 3 +// the checkbox part states (cbs_*). +#define OS_BS_UNCHECKEDNORMAL 1 +#define OS_BS_UNCHECKEDHOT 2 +#define OS_BS_UNCHECKEDPRESSED 3 +#define OS_BS_UNCHECKEDDISABLED 4 +#define OS_BS_CHECKEDNORMAL 5 +#define OS_BS_CHECKEDHOT 6 +#define OS_BS_CHECKEDPRESSED 7 +#define OS_BS_CHECKEDDISABLED 8 +#define OS_BS_MIXEDNORMAL 9 +#define OS_BS_MIXEDHOT 10 +#define OS_BS_MIXEDPRESSED 11 +#define OS_BS_MIXEDDISABLED 12 +// the radiobutton part states (rbs_*). +#define OS_RBS_UNCHECKEDNORMAL 1 +#define OS_RBS_UNCHECKEDHOT 2 +#define OS_RBS_UNCHECKEDPRESSED 3 +#define OS_RBS_UNCHECKEDDISABLED 4 +#define OS_RBS_CHECKEDNORMAL 5 +#define OS_RBS_CHECKEDHOT 6 +#define OS_RBS_CHECKEDPRESSED 7 +#define OS_RBS_CHECKEDDISABLED 8 + +extern int os_allow_dark_mode_for_window(HWND hwnd,int allow); +extern void os_dark_invalidate(void); extern BOOL (WINAPI *os_ChangeWindowMessageFilterEx)(HWND hWnd,UINT message,DWORD action,void *pChangeFilterStruct); extern DWORD (WINAPI *os_GetLayout)(HDC hdc); extern EXECUTION_STATE (WINAPI *os_SetThreadExecutionState)( EXECUTION_STATE esFlags); @@ -132,6 +201,69 @@ extern LANGID (WINAPI *os_GetUserDefaultUILanguage)(void); extern int os_logical_wide; extern int os_logical_high; +// refresh os_logical_wide / os_logical_high from the window's monitor dpi +// (per monitor v2). returns 1 when the values changed. +int os_window_update_dpi(HWND hwnd); + +// the system menu font at the current window dpi (menu bar owner draw). +int os_menu_font(LOGFONTW *lf); +// the dpi of a window: getdpiforwindow when the os provides it, the +// tracked window dpi otherwise. +int os_window_dpi(HWND hwnd); +// fill lf with the message font (the dialog base font) at the window +// own dpi: segoe ui on an english system, the locale native ui face +// (microsoft yahei ui on a chinese one) - no glyph fallback for the +// cjk labels. returns 1 on success. +int os_dialog_font(LOGFONTW *lf,HWND hwnd); + +// windows 11 chrome: rounded corners + a caption color matching the canvas. +// returns 0 on windows 10 and older so the caller can fall back to its own +// frame. the first call latches the platform answer. +int os_window_modern_chrome(HWND hwnd,COLORREF caption_color); +int os_menu_modern_chrome(HWND hwnd,COLORREF border_color); + +// the latched platform answer from the chrome probes: 1 on windows 11 +// (the modern attributes landed), 0 before the first probe or on older +// windows. register-time decisions (the drop shadow class style) read it. +int os_is_win11(void); + +// touch / gesture support (Windows 7+) +// self-declared, binary compatible structures. +// (avoids _WIN32_WINNT gating in older SDKs) + +typedef struct os_GestureConfig_s +{ + DWORD dwID; + DWORD dwWant; + DWORD dwBlock; + +}os_GestureConfig_t; + +typedef struct os_GestureInfo_s +{ + UINT cbSize; + DWORD dwFlags; + DWORD dwID; + HWND hwndTarget; + POINTS ptsLocation; + DWORD dwInstanceID; + DWORD dwSequenceID; + VIV_UINT64 ullArguments; + UINT cbExtraArgs; + +}os_GestureInfo_t; + +extern BOOL (WINAPI *os_SetGestureConfig)(HWND hwnd,DWORD reserved,UINT cIDs,os_GestureConfig_t *configs,UINT cbSize); +extern BOOL (WINAPI *os_GetGestureInfo)(void *gesture_info_handle,os_GestureInfo_t *gesture_info); +extern BOOL (WINAPI *os_CloseGestureInfoHandle)(void *gesture_info_handle); + +int os_is_touch_available(void); + +// vista+ regdeletekeyexw, resolved lazily (see os.c). returns 1 when the +// key was deleted, 0 when the api is missing or the delete failed: +// regdeletekeyw cannot reach the alternate registry view. +int os_reg_delete_key_ex(HKEY hkey,const wchar_t *name,REGSAM access); + #ifdef __cplusplus } #endif diff --git a/src/safe_size.c b/src/safe_size.c index 2f8aa5af..d13bf65a 100644 --- a/src/safe_size.c +++ b/src/safe_size.c @@ -27,6 +27,7 @@ // MUST be used when allocating memory. #include "viv.h" +#include // SIZE_MAX // safely add two values. // SIZE_MAX is used as an invalid value. @@ -80,7 +81,7 @@ SIZE_T safe_size_mul_sizeof_pointer(SIZE_T a) } // safely multiply a by sizeof(wchar_t) -// returns a + sizeof(wchar_t) +// returns a * sizeof(wchar_t) // returns SIZE_MAX if an overflow occurs. SIZE_T safe_size_mul_sizeof_wchar(SIZE_T a) { diff --git a/src/small_pool.h b/src/small_pool.h index 93e64f38..dfa5d976 100644 --- a/src/small_pool.h +++ b/src/small_pool.h @@ -39,7 +39,9 @@ typedef struct small_pool_chunk_s { struct small_pool_chunk_s *next; - // enforce 8-byte alignment. + // enforce 8-byte alignment of the chunk header (and so of the chunk + // data). this says nothing about the bump allocations themselves: + // small_pool_alloc does not round sizes up. VIV_UINT64 padding1; }; diff --git a/src/string.c b/src/string.c index 6be147fe..cd22d6a1 100644 --- a/src/string.c +++ b/src/string.c @@ -45,7 +45,7 @@ wchar_t *string_alloc(const wchar_t *s) wchar_t *p; wlen = string_get_length(s); - p = (wchar_t *)mem_alloc((wlen + 1) * sizeof(wchar_t)); + p = (wchar_t *)mem_alloc(safe_size_mul_sizeof_wchar(safe_size_add_one(wlen))); CopyMemory(p,s,(wlen + 1) * sizeof(wchar_t)); @@ -59,7 +59,7 @@ wchar_t *string_alloc_utf8(const utf8_t *s) wlen = MultiByteToWideChar(CP_UTF8,0,s,-1,0,0); - p = (wchar_t *)mem_alloc((wlen + 1) * sizeof(wchar_t)); + p = (wchar_t *)mem_alloc(safe_size_mul_sizeof_wchar(safe_size_add_one(wlen))); MultiByteToWideChar(CP_UTF8,0,s,-1,p,wlen+1); @@ -90,6 +90,12 @@ void string_copy_with_bufsize(wchar_t *d,SIZE_T bufsize,const wchar_t *s) { uintptr_t size; + // bufsize 0 would wrap to SIZE_MAX below. + if (!bufsize) + { + return; + } + size = bufsize - 1; while(*s) @@ -108,7 +114,12 @@ void string_copy_with_bufsize(wchar_t *d,SIZE_T bufsize,const wchar_t *s) void string_copy_utf8_string(wchar_t *buf,const utf8_t *s) { - MultiByteToWideChar(CP_UTF8,0,s,-1,buf,STRING_SIZE); + // MultiByteToWideChar leaves the output unterminated when the + // conversion fails: make sure the buffer is always a string. + if (!MultiByteToWideChar(CP_UTF8,0,s,-1,buf,STRING_SIZE)) + { + buf[0] = 0; + } } void string_cat(wchar_t *buf,const wchar_t *s) @@ -801,7 +812,7 @@ wchar_t *string_skip_ws(const wchar_t *p) return (wchar_t *)p; } -wchar_t *string_get_word(wchar_t *p,wchar_t *buf) +wchar_t *string_get_word(wchar_t *p,wchar_t *buf,int buf_size) { wchar_t *d; int is_quote; @@ -814,7 +825,13 @@ wchar_t *string_get_word(wchar_t *p,wchar_t *buf) if ((*p == '"') && (p[1] == '"')) { p += 2; - *d++ = '"'; + + // the word is longer than the destination: stop at the + // capacity, the rest of the word is skipped below. + if (d - buf < buf_size - 1) + { + *d++ = '"'; + } } else if (*p == '"') @@ -829,7 +846,12 @@ wchar_t *string_get_word(wchar_t *p,wchar_t *buf) } else { - *d++ = *p; + // keep skipping the word, only copy what fits. + if (d - buf < buf_size - 1) + { + *d++ = *p; + } + p++; } } diff --git a/src/string.h b/src/string.h index becf072a..463e8060 100644 --- a/src/string.h +++ b/src/string.h @@ -54,7 +54,7 @@ void string_copy_double_null(wchar_t *buf,wchar_t *s); void string_remove_extension(wchar_t *buf); wchar_t *string_get_extension(const wchar_t *s); wchar_t *string_skip_ws(const wchar_t *p); -wchar_t *string_get_word(wchar_t *p,wchar_t *buf); +wchar_t *string_get_word(wchar_t *p,wchar_t *buf,int buf_size); int string_get_appdata_voidimageviewer_path(wchar_t *wbuf); BOOL string_is_dot(const wchar_t *s); diff --git a/src/utf8.c b/src/utf8.c index ec96d662..ad0ce18b 100644 --- a/src/utf8.c +++ b/src/utf8.c @@ -152,7 +152,7 @@ utf8_t *utf8_alloc_utf8_n(const char *s,uintptr_t size_in_bytes) { utf8_t *p; - p = mem_alloc(size_in_bytes + 1); + p = mem_alloc(safe_size_add_one(size_in_bytes)); os_copy_memory(p,s,size_in_bytes); p[size_in_bytes] = 0; diff --git a/src/version.h b/src/version.h index ea4550ee..f3598bdd 100644 --- a/src/version.h +++ b/src/version.h @@ -1,6 +1,10 @@ -#define VERSION_YEAR 2026 -#define VERSION_MAJOR 1 -#define VERSION_MINOR 0 -#define VERSION_REVISION 0 -#define VERSION_BUILD 15 -#define VERSION_TYPE "" +#define VERSION_YEAR 2026 +#define VERSION_MAJOR 1 +#define VERSION_MINOR 1 +#define VERSION_REVISION 12 + +#define VERSION_BUILD 60 + +#define VERSION_TYPE "" + +#define VERSION_STRING "1.1.12" diff --git a/src/viv.c b/src/viv.c index deff4526..1bcfdb9f 100644 --- a/src/viv.c +++ b/src/viv.c @@ -200,8 +200,6 @@ // *opening a non existing filename should show an error message: "File Not Found". eg: viv.exe "c:\non-existing-folder\foo.jpg" -also added "failed to load image" message for bad images. // *hide mouse on hover. // *using wrong registry key in _viv_install_association_by_extension. -// *vs2005 and vs2019 solutions in separate dirs. -// *remove crt.c and other unused c files. // 1.0.0.12 // *fixed a gdi leak when freeing mipmaps // *fixed a gdi leak when refreshing. @@ -244,174 +242,51 @@ // *rename no to conflict should keep the rename dialog shown so user can continue with a different name. -#define _VIV_WM_REPLY (WM_USER+1) -#define _VIV_WM_RETRY_RANDOM_EVERYTHING_SEARCH (WM_USER+2) - -#define _VIV_ASSOCIATION_BMP 0x00000001 -#define _VIV_ASSOCIATION_GIF 0x00000002 -#define _VIV_ASSOCIATION_ICO 0x00000004 -#define _VIV_ASSOCIATION_JPEG 0x00000008 -#define _VIV_ASSOCIATION_JPG 0x00000010 -#define _VIV_ASSOCIATION_PNG 0x00000020 -#define _VIV_ASSOCIATION_TIF 0x00000040 -#define _VIV_ASSOCIATION_TIFF 0x00000080 -#define _VIV_ASSOCIATION_WEBP 0x00000100 - -#define _VIV_ZOOM_MAX 16 - -#define BCM_SETSHIELD 0x0000160C - -#ifdef VERSION_X64 - #define VERSION_TARGET_MACHINE "(x64)" -#else - #ifdef VERSION_ARM - #define VERSION_TARGET_MACHINE "(ARM)" - #else - #ifdef VERSION_ARM64 - #define VERSION_TARGET_MACHINE "(ARM64)" - #else - #ifdef VERSION_X86 - #define VERSION_TARGET_MACHINE "(x86)" - #else - #error unknown target machine. - #endif - #endif - #endif -#endif - -#define _VIV_DEFAULT_SHUFFLE_ALLOCATED (65536 / sizeof(_viv_playlist_t *)) - -#define VIV_YEAR_STRING2(x) #x -#define VIV_YEAR_STRING(x) VIV_YEAR_STRING2(x) // _VIV_STRETCH_BLT_STITCH_SIZE * 3.1 (pan+zoom) * 16 (zoom) MUST BE < 32768 -#define _VIV_STRETCH_BLT_STITCH_SIZE 512 #include "viv.h" +#include "viv_state.h" +#include "viv_recent.h" +#include "viv_playlist.h" +#include "viv_load.h" +#include "viv_anim.h" +#include "viv_render.h" +#include "viv_chrome.h" +#include "viv_menubar.h" +#include "viv_dark.h" +#include "viv_dialogs.h" +#include "viv_view.h" +#include "viv_install.h" +#include "viv_menu.h" +#include "viv_wndproc.h" +#include "viv_selfshot.h" + +// the recent-files mru command ids run VIV_ID_FILE_RECENT_0 .. +count-1 and +// the menu builder emits ids straight off that base. this compile-time check +// locks the enum block and CONFIG_RECENT_FILE_COUNT together: raising one +// without the other fails the build instead of silently emitting command ids +// owned by unrelated entries. +typedef char _viv_recent_id_block_matches_count[(VIV_ID_FILE_RECENT_9 - VIV_ID_FILE_RECENT_0 + 1 == CONFIG_RECENT_FILE_COUNT) ? 1 : -1]; + + +// theme change message and tooltip color messages. (not defined in older SDKs) + +// per monitor dpi change message. (not defined in older SDKs) -enum -{ - _VIV_COPYDATA_COMMAND_LINE, - _VIV_COPYDATA_OPEN_EVERYTHING_SEARCH, - _VIV_COPYDATA_ADD_EVERYTHING_SEARCH, - _VIV_COPYDATA_RANDOM_EVERYTHING_SEARCH, -}; -enum -{ - _VIV_DOING_NOTHING, - _VIV_DOING_SCROLL, - _VIV_DOING_MSCROLL, - _VIV_DOING_1TO1SCROLL, -}; -enum -{ - _VIV_REPLY_LOAD_IMAGE_COMPLETE = 0, - _VIV_REPLY_LOAD_IMAGE_FAILED, - _VIV_REPLY_LOAD_IMAGE_FIRST_FRAME, - _VIV_REPLY_LOAD_IMAGE_ADDITIONAL_FRAME, -}; -enum -{ - _VIV_MENU_ROOT=0, - _VIV_MENU_FILE, - _VIV_MENU_EDIT, - _VIV_MENU_VIEW, - _VIV_MENU_VIEW_PRESET, - _VIV_MENU_VIEW_WINDOW_SIZE, - _VIV_MENU_VIEW_PANSCAN, - _VIV_MENU_VIEW_ZOOM, - _VIV_MENU_VIEW_ONTOP, - _VIV_MENU_SLIDESHOW, - _VIV_MENU_SLIDESHOW_RATE, - _VIV_MENU_ANIMATION, - _VIV_MENU_NAVIGATE, - _VIV_MENU_NAVIGATE_SORT, - _VIV_MENU_NAVIGATE_PLAYLIST, - _VIV_MENU_HELP, - _VIV_MENU_COUNT, -}; -#define _VIV_HIDE_CURSOR_DELAY 2000 // a file descriptor or find data // to describe the image. -/* -typedef struct _viv_fd_s -{ - unsigned __int64 id; // unique playlist id. - unsigned __int64 date_modified; - unsigned __int64 size; - unsigned __int64 date_created; - - // filename follows. - // utf8_t filename[...]; - -}_viv_fd_t; -*/ -// a reply from the image load thread -typedef struct _viv_reply_s -{ - struct _viv_reply_s *next; - DWORD type; - DWORD size; - // data follows - -}_viv_reply_t; - -// a mipmap level -typedef struct _viv_mip_s -{ -// int wide; -// int high; - HBITMAP hbitmap; - struct _viv_mip_s *mipmap; - -}_viv_mipmap_t; -// a frame in the image. -// there might be more than one. -typedef struct _viv_frame_s -{ - HBITMAP hbitmap; - - // next mipmap level. - // NULL if not computed. - _viv_mipmap_t *mipmap; - - // frame delay in milliseconds. - DWORD delay; - -}_viv_frame_t; -typedef struct _viv_reply_load_image_first_frame_s -{ - UINT wide; - UINT high; - UINT frame_count; - _viv_frame_t frame; - -}_viv_reply_load_image_first_frame_t; -typedef struct _viv_playlist_s -{ - struct _viv_playlist_s *next; - struct _viv_playlist_s *prev; - WIN32_FIND_DATA fd; - -}_viv_playlist_t; -typedef struct _viv_command_s -{ - localization_id_t localization_id; - WORD flags; - BYTE menu_id; - WORD command_id; -}_viv_command_t; typedef struct _viv_default_key_s { @@ -420,382 +295,135 @@ typedef struct _viv_default_key_s }_viv_default_key_t; -typedef struct _viv_nav_item_s -{ - WIN32_FIND_DATA fd; - struct _viv_nav_item_s *next; - -}_viv_nav_item_t; -typedef struct _viv_webp_s -{ - DWORD wide; - DWORD high; - HDC screen_hdc; - HDC mem_hdc; - int has_alpha; - int frame_index; - DWORD frame_count; - DWORD last_delay; - int orientation; - -}_viv_webp_t; -typedef struct _viv_name_mapping_s -{ - UINT count; - SHNAMEMAPPING *mappings; -}_viv_name_mapping_t; - -static void _viv_update_title(void); -static void _viv_on_size(void); -static LRESULT CALLBACK _viv_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); -static LRESULT CALLBACK _viv_fullscreen_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); -static void _viv_command_with_is_key_repeat(int command,int is_key_repeat); -static void _viv_command(int command); -static int _viv_process_install_command_line_options(wchar_t *cl); -static void _viv_process_command_line(wchar_t *cl); + static int _viv_init(int nCmdShow); -static void _viv_kill(void); -static void _viv_exit(void); -static int _viv_next(int prev,int reset_slideshow_timer,int is_preload,int wait_for_current_load); -static void _viv_home(int end,int is_preload); -static int _viv_is_valid_filename(WIN32_FIND_DATA *fd); +void _viv_kill(void); +void _viv_exit(void); static int _viv_is_msg(MSG *msg); -static void _viv_view_set(int view_x,int view_y,int invalidate); -static void _viv_slideshow(void); -static void _viv_toggle_fullscreen(void); -static void _viv_get_render_size(int *prw,int *prh); -static void _viv_set_custom_rate(void); -static void _viv_set_rate(int rate); -static void _viv_rename(void); -static void _viv_delete(int permanently); -static void _viv_copy(int cut); -static void _viv_copy_filename(void); -static void _viv_set_clipboard_image(void); -static void _viv_copy_image(void); -static int _viv_is_key_state(int control,int shift,int alt); -static CLIPFORMAT _viv_get_CF_PREFERREDDROPEFFECT(void); -static void _viv_pause(void); -static int _viv_fd_compare(const WIN32_FIND_DATA *a,const WIN32_FIND_DATA *b); -static void _viv_open(WIN32_FIND_DATA *fd,int is_preload); -static BOOL _viv_open_from_filename(const wchar_t *filename); -static void _viv_increase_rate(int dec); -static void _viv_file_preview(void); -static void _viv_file_print(void); -static void _viv_file_set_desktop_wallpaper(void); -static void _viv_edit_rotate(int counterclockwise); -static void _viv_file_edit(void); -static void _viv_open_file_location(void); -static void _viv_properties(void); -static void _viv_doing_cancel(void); -static const char *_viv_get_copydata_string(const char *p,const char *e,wchar_t *buf,int bufsize); -static void _viv_blank(void); -static void _viv_options(void); -static INT_PTR CALLBACK _viv_options_proc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam); -static INT_PTR CALLBACK _viv_options_general_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); -static INT_PTR CALLBACK _viv_options_view_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); -static INT_PTR CALLBACK _viv_options_controls_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); -static void _viv_install_association_by_extension(const char *association,const char *description,const char *icon_location); -static void _viv_uninstall_association_by_extension(const char *association); -static int _viv_is_association(const char *association); -static int _viv_get_registry_string(HKEY hkey,const utf8_t *value,wchar_t *wbuf,int size_in_wchars); -static int _viv_set_registry_string(HKEY hkey,const utf8_t *value,const wchar_t *wbuf); -static void _viv_check_menus(HMENU hmenu); -static void _viv_increase_animation_rate(int dec); -static void _viv_reset_animation_rate(void); -static void _viv_timer_start(void); -static void _viv_mousemove(void); -static void _viv_update_src_pixel(int force,int update_statusbar); -static void _viv_animation_pause(void); -static void _viv_frame_step(void); -static void _viv_frame_prev(void); -static void _viv_view_1to1(void); -static void _viv_playlist_clearall(void); -static void _viv_playlist_add_current_if_empty(void); -static _viv_playlist_t *_viv_playlist_add(const WIN32_FIND_DATA *fd); -static void _viv_playlist_add_path(const wchar_t *full_path_and_filename); -static void _viv_playlist_add_filename(const wchar_t *filename); -static void _viv_playlist_delete(const WIN32_FIND_DATA *fd); -static void _viv_playlist_rename(const wchar_t *old_filename,const wchar_t *new_filename); -static void _viv_timer_stop(void); -static int _viv_is_window_maximized(HWND hwnd); -static INT_PTR CALLBACK _viv_custom_rate_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); -static INT_PTR CALLBACK _viv_about_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); -static void _viv_update_frame(void); -static void _viv_update_ontop(void); -static void _viv_update_prevent_sleep(void); -static void _viv_dst_pos_set(int x,int y); -static void _viv_dst_zoom_set(int x,int y); -static void _viv_frame_skip(int size); -static DWORD WINAPI _viv_load_image_thread_proc(void *param); -static _viv_reply_t *_viv_reply_add(DWORD type,DWORD size,void *data); -static void _viv_reply_clear_all(void); -static void _viv_reply_free(_viv_reply_t *e); -static void _viv_controls_show(int show); -static void _viv_status_show(int show); -static void _viv_status_update(void); -static void _viv_status_set(int part,const wchar_t *text); -static int _viv_get_status_high(void); -static int _viv_get_controls_high(void); -static LRESULT CALLBACK _viv_rebar_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); -static LRESULT CALLBACK _viv_status_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); -static int _viv_toolbar_get_wide(void); -static void _viv_toolbar_update_buttons(void); -static void _viv_status_set_temp_text(wchar_t *text); -static void _viv_status_update_temp_pos_zoom(void); -static void _viv_status_update_temp_animation_rate(void); -static void _viv_zoom_in(int out,int have_xy,int x,int y); -static void _viv_status_update_slideshow_rate(void); -static void _viv_options_treeview_changed(HWND hwnd); -static void _viv_command_line_options(void); -static void _viv_install_association(DWORD flags); -static void _viv_uninstall_association(DWORD flags); -static void _viv_view_scroll(int mx,int my); -static void _viv_options_update_sheild(HWND hwnd); -static void _viv_update_color_button_bitmap(HWND hwnd); -static void _viv_delete_color_button_bitmap(HWND hwnd); -static int _viv_convert_menu_ini_name_ch(int ch); -static utf8_t *_viv_cat_command_menu_ini_name_path(utf8_t *buf,int menu_index); -static void _viv_get_menu_display_name(wchar_t *buf,const utf8_t *menu_name); -static void _viv_get_command_name(wchar_t *wbuf,int command_index); -static int _viv_command_index_from_command_id(int command_id); -static void _viv_cat_command_menu_path(wchar_t *wbuf,int menu_index); -static int _viv_vk_to_text(wchar_t *wbuf,int vk); -static void _viv_cat_key_mod(wchar_t *wbuf,int vk,const utf8_t *default_keytext); -static void _viv_get_key_text(wchar_t *wbuf,DWORD keyflags); -static HMENU _viv_create_menu(void); -static void _viv_key_add(struct _viv_key_list_s *key_list,int command_index,DWORD keyflags); -static void _viv_key_clear(struct _viv_key_list_s *key_list,int command_index); -static void _viv_key_list_copy(struct _viv_key_list_s *dst,const struct _viv_key_list_s *src); -static void _viv_key_clear_all(struct _viv_key_list_s *list); -static void _viv_key_list_init(struct _viv_key_list_s *list); -static void _viv_options_key_list_sel_change(HWND hwnd,int previous_key_index); -static void _viv_options_remove_key(HWND hwnd); -static void _viv_options_edit_key(HWND hwnd,int key_index); -static INT_PTR CALLBACK _viv_edit_key_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); -static LRESULT CALLBACK _viv_edit_key_edit_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); -static int _viv_get_current_key_mod_flags(void); -static void _viv_options_edit_key_changed(HWND hwnd); -static void _viv_edit_key_set_key(HWND hwnd,DWORD key_flags); -static void _viv_key_remove(struct _viv_key_list_s *keylist,int command_index,DWORD keyflags); -static void _viv_edit_key_remove_currently_used_by(struct _viv_key_list_s *keylist,DWORD keyflags); -static void _viv_close_existing_process(void); -static void _viv_uninstall_delete_file(const wchar_t *path,const utf8_t *filename); -static int _viv_is_start_menu_shortcuts(void); -static void _viv_install_start_menu_shortcuts(void); -static void _viv_uninstall_start_menu_shortcuts(void); -static void _viv_append_admin_param(wchar_t *wbuf,const utf8_t *param); -static void _viv_install_copy_file(const wchar_t *install_path,const wchar_t *temp_path,const utf8_t *filename,int critical); -static INT_PTR CALLBACK _viv_rename_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); -static void _viv_shuffle_playlist(void); -static void _viv_show_jumpto(void); -static LRESULT CALLBACK _viv_jumpto_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); -static void _viv_jumpto_on_size(HWND hwnd); -static void _viv_jumpto_on_search(HWND hwnd); -static void _viv_jumpto_open_sel(HWND hwnd); -static void _viv_nav_item_free_all(void); -static void _viv_nav_item_add(WIN32_FIND_DATA *fd); -static int _viv_nav_compare(const _viv_nav_item_t *a,const _viv_nav_item_t *b); -static void _viv_add_current_path_to_playlist(void); -static void _viv_search_everything(int add); -static int _viv_send_everything_search(HWND parent,int add,int randomize,const wchar_t *search); -static INT_PTR CALLBACK _viv_search_everything_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); -static int _viv_playlist_shuffle_index_from_fd(const WIN32_FIND_DATA *fd); -static void _viv_do_initial_shuffle(void); -static _viv_playlist_t *_viv_playlist_from_fd(const WIN32_FIND_DATA *fd); -static int _viv_compare_id(const WIN32_FIND_DATA *a,const WIN32_FIND_DATA *b); -static int _viv_fd_compare_name(const WIN32_FIND_DATA *a,const WIN32_FIND_DATA *b); -static int _viv_fd_compare_path_and_name(const WIN32_FIND_DATA *a,const WIN32_FIND_DATA *b); -static void _viv_update_1to1_scroll(int x,int y); -static HBITMAP _viv_orientate_hbitmap(HBITMAP hbitmap,int counterclockwise); -static void _viv_send_random_everything_search(void); -static void _viv_do_mousewheel_action(int action,int delta,int x,int y); -static void _viv_mipmap_free(_viv_mipmap_t *mipmap); +CLIPFORMAT _viv_get_CF_PREFERREDDROPEFFECT(void); + static void _viv_queue_clear(void); -static void _viv_clear(void); -static void _viv_process_pending_clear(void); -static void _viv_clear_loading_preload(void); -static void _viv_clear_preload(void); -static void _viv_clear_preload_frames(void); -static HBITMAP _viv_get_mipmap(HBITMAP hbitmap,int image_wide,int image_high,int render_wide,int render_high,int *pmip_wide,int *pmip_high,_viv_mipmap_t **out_mip); -static void _viv_preload_next(void); -static void _viv_start_first_frame(void); -static void _viv_activate_preload(void); -static int _viv_webp_info_proc(_viv_webp_t *viv_webp,DWORD frame_count,DWORD wide,DWORD high,int has_alpha); -static int _viv_webp_frame_proc(_viv_webp_t *viv_webp,BYTE *pixels,int delay); -static void _viv_clear_frames(_viv_frame_t *frames,int loaded_count); -static void viv_copy_current_image_to_last_image(void); -static void _viv_activate_last(void); -static void _viv_clear_last(void); -static void _viv_refresh(void); -static void _viv_show_cursor(void); -static void _viv_hide_cursor(void); -static int _viv_should_show_cursor(void); -static void _viv_update_show_cursor(void); -static void _viv_start_hide_cursor_timer(void); static int _viv_main(int nCmdShow); -static void _viv_get_exe_filename(wchar_t filename[STRING_SIZE]); -static void _viv_do_left_click_action(int action); -static void _viv_start_move_window(void); -static int _viv_ceil(double x); -static void _viv_center_listbox_item(HWND listbox_hwnd,int item_index); -static void _viv_stretch_blt(HDC dst_hdc,int dst_x,int dst_y,int dst_wide,int dst_high,HDC src_hdc,int src_wide,int src_high,int clip_x,int clip_y,int clip_wide,int clip_high); -static BOOL _viv_StretchBltStitch(HDC hdcDest,int xDest,int yDest,int wDest,int hDest,HDC hdcSrc,int xSrc,int ySrc,int wSrc,int hSrc,DWORD rop,int clip_x,int clip_y,int clip_wide,int clip_high); -static BOOL _viv_get_src_pixel_pos(int client_x,int client_y,POINT *out_src_pt); -static void _viv_get_src_pixel_rgb(int src_x,int src_y,COLORREF *out_colorref); -static int _viv_clamp_zoom_pos(int zoom_pos); -static void _viv_open_preload(void); -//static void _viv_get_tooltip(void); -//static void _viv_tooltip_hide(void); -//static void _viv_tooltip_update(void); -//static void _viv_tooltip_update_track_position(void); -static int _viv_safe_copy_data(const void *base,SIZE_T src_size,const void *src,void *dst,SIZE_T dst_size); - -static HMODULE _viv_stobject_hmodule = 0; -static _viv_playlist_t *_viv_playlist_start = 0; -static _viv_playlist_t *_viv_playlist_last = 0; -static int _viv_playlist_count = 0; -static _viv_playlist_t **_viv_playlist_shuffle_indexes = 0; -static int _viv_playlist_shuffle_allocated = 0; -static LARGE_INTEGER _viv_playlist_id = {0}; -static HWND _viv_hwnd = 0; -static HWND _viv_status_hwnd = 0; -static HWND _viv_toolbar_hwnd = 0; -static HWND _viv_rebar_hwnd = 0; -//static HWND _viv_tooltip_hwnd = 0; -static HIMAGELIST _viv_toolbar_image_list = 0; + +HMODULE _viv_stobject_hmodule = 0; +_viv_playlist_t *_viv_playlist_start = 0; +int _viv_playlist_count = 0; +_viv_playlist_t **_viv_playlist_shuffle_indexes = 0; +int _viv_playlist_shuffle_allocated = 0; +HWND _viv_hwnd = 0; +HWND _viv_status_hwnd = 0; + +// the status pane texts. the panes are owner drawn (dark ui support): +// the control hands the pane index back in each WM_DRAWITEM item data +// and the text is drawn from this store. declared here: the status bar +// creation (_viv_status_show) flushes it long before _viv_status_set is +// reached in the file. +wchar_t _viv_status_part_text[_VIV_STATUS_PART_MAX][STRING_SIZE]; static HANDLE _viv_mutex = 0; -static float _viv_animation_rates[] = {0.125000f,0.142857f,0.166667f,0.200000f,0.250000f,0.333333f,0.500000f,0.571429f,0.666667f,0.800000f,1.000000f,1.250000f,1.500000f,1.750000f,2.000000f,3.000000f,4.000000f,5.000000f,6.000000f,7.000000f,8.000000f}; // fixed animation rates -#define _VIV_ANIMATION_RATE_MAX (sizeof(_viv_animation_rates) / sizeof(float)) -#define _VIV_ANIMATION_RATE_ONE 10 -static int _viv_animation_rate_pos = _VIV_ANIMATION_RATE_ONE; -static BYTE _viv_animation_play = 1; // play or pause animations -static BYTE _viv_1to1 = 0; // temporarily show the image with 100% scaling -static BYTE _viv_have_old_zoom = 0; // restore this zoom level after leaving 1:1 mode. -static int _viv_old_zoom_pos = 0; // restore this zoom level after leaving 1:1 mode. +float _viv_animation_rates[] = {0.125000f,0.142857f,0.166667f,0.200000f,0.250000f,0.333333f,0.500000f,0.571429f,0.666667f,0.800000f,1.000000f,1.250000f,1.500000f,1.750000f,2.000000f,3.000000f,4.000000f,5.000000f,6.000000f,7.000000f,8.000000f}; // fixed animation rates +typedef char _viv_animation_rates_count_assert[(sizeof(_viv_animation_rates) / sizeof(float) == _VIV_ANIMATION_RATE_MAX) ? 1 : -1]; // the count literal pins the table +int _viv_animation_rate_pos = _VIV_ANIMATION_RATE_ONE; +BYTE _viv_animation_play = 1; // play or pause animations +BYTE _viv_1to1 = 0; // temporarily show the image with 100% scaling +BYTE _viv_have_old_zoom = 0; // restore this zoom level after leaving 1:1 mode. WIN32_FIND_DATA *_viv_current_fd = 0; // the current image find data including the full path and filename. WIN32_FIND_DATA *_viv_preload_fd = 0; -static int _viv_view_x = 0; // the current image offset in pixels -static int _viv_view_y = 0; // the current image offset in pixels -static double _viv_view_ix = 0.0; // the current image offset in percent, used when resizing the window -static double _viv_view_iy = 0.0; // the current image offset in percent, used when resizing the window -static int _viv_zoom_pos = 0; // the current zoom level -//static float _viv_zoom_presets[_VIV_ZOOM_MAX] = {0.004815f,0.019215f,0.043060f,0.076120f,0.118079f,0.168530f,0.226989f,0.292893f,0.365607f,0.444430f,0.528603f,0.617316f,0.709715f,0.804909f,0.901983f,1.000000f}; // (1 - cos(((float)(x+1) * 1.570796f) / _VIV_ZOOM_MAX)) // this is missing cos((1 * 1.570796f) / _VIV_ZOOM_MAX), which is too small -static float _viv_zoom_presets[_VIV_ZOOM_MAX] = {0.0000,0.0100,0.0225,0.0379,0.0569,0.0806,0.1098,0.1461,0.1909,0.2465,0.3154,0.4007,0.5063,0.6372,0.7993,1.0000}; // 0.01 - 0.2 curve +int _viv_view_x = 0; // the current image offset in pixels +int _viv_view_y = 0; // the current image offset in pixels +double _viv_view_ix = 0.0; // the current image offset in percent, used when resizing the window +double _viv_view_iy = 0.0; // the current image offset in percent, used when resizing the window +int _viv_zoom_pos = 0; // the current zoom level +// the zoom ladder is computed in _viv_init(): each step is a 1% multiplicative +// zoom increase (1.01x) from the best fit size (pos 0). the reachable top is +// measured at runtime (see _viv_zoom_pos_max): the first step that reaches +// the 16x size cap for the current image and window. +float _viv_zoom_scales[_VIV_ZOOM_MAX]; static ULONG_PTR os_GdiplusToken; // gdiplus handle -static int _viv_image_wide = 0; // current image width -static int _viv_image_high = 0; // current image width -static int _viv_frame_count = 0; // current image frame count, 1 for static image, > 1 for animation -static int _viv_frame_loaded_count = 0; // number of loaded frames, can be less than _viv_frame_count -static int _viv_frame_position = 0; // the current frame position -static BYTE _viv_frame_looped = 0; // all frames have been displayed for this animation -static BYTE _viv_is_slideshow_timeup = 0; // the slideshow timer has expired, but we are still showing an animation at least once. -static _viv_frame_t *_viv_frames = 0; // the frames that make up an image, could be more than one for animations. -static VIV_UINT64 _viv_timer_tick = 0; // the current tick for the current frame. -static BYTE _viv_is_animation_timer = 0; // animation timer started? -static VIV_UINT64 _viv_animation_timer_tick_start = 0; // the current start tick -static BYTE _viv_doing = _VIV_DOING_NOTHING; // current mouse action, such as drag to scroll image -static int _viv_doing_x; -static int _viv_doing_y; -static int _viv_mdoing_x; -static int _viv_mdoing_y; -static BYTE _viv_fullscreen_is_maxed = 0; -static BYTE _viv_is_fullscreen = 0; -static RECT _viv_fullscreen_rect; -static int _viv_fullscreen_zoom_offset = 0; -static BYTE _viv_is_slideshow = 0; -static BYTE _viv_is_hide_cursor_timer = 0; +BYTE _viv_image_is_low_res = 0; // 1 = the displayed image is a progressive preview frame +int _viv_image_wide = 0; // current image width +int _viv_image_high = 0; // current image width +int _viv_frame_count = 0; // current image frame count, 1 for static image, > 1 for animation +int _viv_frame_loaded_count = 0; // number of loaded frames, can be less than _viv_frame_count +int _viv_frame_position = 0; // the current frame position +BYTE _viv_frame_looped = 0; // all frames have been displayed for this animation +BYTE _viv_is_slideshow_timeup = 0; // the slideshow timer has expired, but we are still showing an animation at least once. +_viv_frame_t *_viv_frames = 0; // the frames that make up an image, could be more than one for animations. +VIV_UINT64 _viv_timer_tick = 0; // the current tick for the current frame. +BYTE _viv_is_animation_timer = 0; // animation timer started? +VIV_UINT64 _viv_animation_timer_tick_start = 0; // the current start tick +BYTE _viv_doing = _VIV_DOING_NOTHING; // current mouse action, such as drag to scroll image +int _viv_doing_x; +int _viv_doing_y; +BYTE _viv_fullscreen_is_maxed = 0; +BYTE _viv_is_fullscreen = 0; +BYTE _viv_is_slideshow = 0; +BYTE _viv_is_hide_cursor_timer = 0; static CLIPFORMAT _viv_CF_PREFERREDDROPEFFECT = 0; // copy or move? clipboard operation -static WORD _viv_slideshow_rate_presets[] = {250,500,1000,2000,3000,4000,5000,6000,7000,8000,9000,10000,20000,30000,40000,50000,60000}; -#define _VIV_SLIDESHOW_RATE_PRESET_COUNT (sizeof(_viv_slideshow_rate_presets) / sizeof(WORD)) -static BYTE _viv_is_cursor_shown = 1; -static int _viv_mousemove_x = -1; -static int _viv_mousemove_y = -1; -static BYTE _viv_in_popup_menu = 0; -static GUID _viv_FrameDimensionTime = {0x6aedbd6d,0x3fb5,0x418a,{0x83,0xa6,0x7f,0x45,0x22,0x9d,0xc8,0x72}}; -static HMENU _viv_hmenu = 0; -static int _viv_dst_pos_x = 500; -static int _viv_dst_pos_y = 500; -#define _VIV_DST_ZOOM_MAX 139 -static float *_viv_dst_zoom_values; -#define _VIV_DST_ZOOM_ONE 82 -static int _viv_dst_zoom_x_pos = _VIV_DST_ZOOM_ONE; -static int _viv_dst_zoom_y_pos = _VIV_DST_ZOOM_ONE; -static CRITICAL_SECTION _viv_cs; -static HANDLE _viv_load_image_thread = 0; -static BYTE _viv_load_is_preload = 0; -static wchar_t *_viv_load_image_filename = 0; -static WIN32_FIND_DATA *_viv_load_image_next_fd = NULL; -static BYTE _viv_load_image_next_is_preload = 0; -static volatile int _viv_load_image_terminate = 0; -static _viv_reply_t *_viv_reply_start = 0; -static _viv_reply_t *_viv_reply_last = 0; -static wchar_t *_viv_status_temp_text = 0; -static localization_id_t _viv_options_page_localization_id_array[] = {LOCALIZATION_ID_OPTIONS_GENERAL_DIALOG,LOCALIZATION_ID_OPTIONS_VIEW_DIALOG,LOCALIZATION_ID_OPTIONS_CONTROLS_DIALOG}; -static int _viv_options_tab_ids[] = {IDC_TAB1,IDC_TAB2,IDC_TAB3}; -static int _viv_options_dialog_ids[] = {IDD_GENERAL,IDD_VIEW,IDD_CONTROLS}; -#define _VIV_OPTIONS_PAGE_COUNT (sizeof(_viv_options_dialog_ids) / sizeof(int)) -static int _viv_options_page_ids[] = {VIV_ID_OPTIONS_GENERAL,VIV_ID_OPTIONS_VIEW,VIV_ID_OPTIONS_CONTROLS}; -static DLGPROC _viv_options_page_procs[] = {_viv_options_general_proc,_viv_options_view_proc,_viv_options_controls_proc}; -static HFONT _viv_about_hfont = 0; -static wchar_t *_viv_last_open_file = 0; -static wchar_t *_viv_last_open_folder = 0; -static _viv_nav_item_t **_viv_nav_items = 0; -static _viv_nav_item_t *__viv_nav_item_start = 0; -static _viv_nav_item_t *_viv_nav_item_last = 0; -static int _viv_nav_item_count = 0; -static wchar_t *_viv_random = 0; // temp shuffle. -static DWORD _viv_random_tot_results = 0xffffffff; -static DWORD _viv_everything_request_flags = 0; -static BYTE _viv_is_timer_queue_timer = 0; -static HANDLE _viv_timer_queue_timer_handle; -static BYTE _viv_is_animation_timer_event = 0; -static BYTE _viv_is_animation_paint = 0; -static BYTE _viv_preload_state = 0; // 0 = loading, 1=complete, 2=failed -static int _viv_preload_image_wide = 0; // current image width -static int _viv_preload_image_high = 0; // current image height -static int _viv_preload_frame_count = 0; // current image frame count, 1 for static image, > 1 for animation -static int _viv_preload_frame_loaded_count = 0; // number of loaded frames, can be less than _viv_frame_count -static _viv_frame_t *_viv_preload_frames = 0; // the frames that make up an image, could be more than one for animations. -static BYTE _viv_last_is_prev = 0; // preload next or previous? -static BYTE _viv_preload_is_prev = 0; // preload next or previous? -static BYTE _viv_should_activate_preload_on_load = 0; -static int _viv_load_render_wide = 0; -static int _viv_load_render_high = 0; -static _viv_frame_t *_viv_pending_clear_frames = NULL; -static int _viv_pending_clear_frame_loaded_count = 0; -static WIN32_FIND_DATA *_viv_last_fd = 0; // the last find data including the full path and filename. -static WIN32_FIND_DATA *_viv_frame_fd = 0; // the frame fd, may differ to the current fd because we change the title before the frames are loaded. -static WIN32_FIND_DATA *_viv_load_fd = 0; // the load fd -static int _viv_last_image_wide = 0; // last image width -static int _viv_last_image_high = 0; // last image height -static int _viv_last_frame_count = 0; // last image frame count, 1 for static image, > 1 for animation (all frames are loaded) -static _viv_frame_t *_viv_last_frames = 0; // the last frames that make up an image, could be more than one for animations. -static BYTE _viv_load_image_allow_draw = 0; // allow the image to show if it loaded successfully after the load was terminated. -static LRESULT (CALLBACK *_viv_old_status_proc)(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) = NULL; // old status bar proc -static BYTE _viv_prevent_on_size = 0; // don't process WM_SIZE changes. -static BYTE _viv_file_not_found = 0; // the current file was not found. -filename is shown in the window caption. -static BYTE _viv_load_failed = 0; // the current file failed to load. -filename is shown in the window caption. -static BYTE _viv_is_tracking_mouse = 0; // currently tracking mouse movement over our window. -static BYTE _viv_is_mouseover = 0; // mouse is currently over our window. -static BYTE _viv_prevent_on_deactivate = 0; // prevent handling of deactivate in WM_ACTIVATE. -static BYTE _viv_jump_ret = 0; -static int _viv_load_frame_count = 0; // the number of frames loaded, while loading. -static int _viv_src_pixel_x = -1; -static int _viv_src_pixel_y = -1; -static BYTE _viv_src_pixel_r = 0; -static BYTE _viv_src_pixel_g = 0; -static BYTE _viv_src_pixel_b = 0; -static BYTE _viv_is_prevent_sleep = 0; +BYTE _viv_is_cursor_shown = 1; +int _viv_mousemove_x = -1; +int _viv_mousemove_y = -1; +BYTE _viv_in_popup_menu = 0; +HMENU _viv_hmenu = 0; +int _viv_dst_pos_x = 500; +int _viv_dst_pos_y = 500; +CRITICAL_SECTION _viv_cs; +HANDLE _viv_load_image_thread = 0; +BYTE _viv_load_is_preload = 0; +wchar_t *_viv_load_image_filename = 0; +WIN32_FIND_DATA *_viv_load_image_next_fd = NULL; +BYTE _viv_load_image_next_is_preload = 0; +volatile int _viv_load_image_terminate = 0; +_viv_reply_t *_viv_reply_start = 0; +_viv_reply_t *_viv_reply_last = 0; +wchar_t *_viv_status_temp_text = 0; +int _viv_options_page_ids[] = {VIV_ID_OPTIONS_GENERAL,VIV_ID_OPTIONS_VIEW,VIV_ID_OPTIONS_CONTROLS}; +HFONT _viv_about_hfont = 0; +wchar_t *_viv_last_open_file = 0; +wchar_t *_viv_last_open_folder = 0; +_viv_nav_item_t **_viv_nav_items = 0; +_viv_nav_item_t *__viv_nav_item_start = 0; +int _viv_nav_item_count = 0; +wchar_t *_viv_random = 0; // temp shuffle. +DWORD _viv_random_tot_results = 0xffffffff; +BYTE _viv_is_animation_timer_event = 0; +BYTE _viv_preload_state = 0; // 0 = loading, 1=complete, 2=failed +int _viv_preload_image_wide = 0; // current image width +int _viv_preload_image_high = 0; // current image height +int _viv_preload_frame_count = 0; // current image frame count, 1 for static image, > 1 for animation +int _viv_preload_frame_loaded_count = 0; // number of loaded frames, can be less than _viv_frame_count +_viv_frame_t *_viv_preload_frames = 0; // the frames that make up an image, could be more than one for animations. +BYTE _viv_last_is_prev = 0; // preload next or previous? +BYTE _viv_should_activate_preload_on_load = 0; +int _viv_load_render_wide = 0; +int _viv_load_render_high = 0; +WIN32_FIND_DATA *_viv_last_fd = 0; // the last find data including the full path and filename. +WIN32_FIND_DATA *_viv_frame_fd = 0; // the frame fd, may differ to the current fd because we change the title before the frames are loaded. +WIN32_FIND_DATA *_viv_load_fd = 0; // the load fd +int _viv_last_frame_count = 0; // last image frame count, 1 for static image, > 1 for animation (all frames are loaded) +_viv_frame_t *_viv_last_frames = 0; // the last frames that make up an image, could be more than one for animations. +BYTE _viv_load_image_allow_draw = 0; // allow the image to show if it loaded successfully after the load was terminated. +BYTE _viv_file_not_found = 0; // the current file was not found. -filename is shown in the window caption. +BYTE _viv_load_failed = 0; // the current file failed to load. -filename is shown in the window caption. +BYTE _viv_is_tracking_mouse = 0; // currently tracking mouse movement over our window. +BYTE _viv_is_mouseover = 0; // mouse is currently over our window. +BYTE _viv_prevent_on_deactivate = 0; // prevent handling of deactivate in WM_ACTIVATE. +int _viv_load_frame_count = 0; // the number of frames loaded, while loading. +int _viv_src_pixel_x = -1; +int _viv_src_pixel_y = -1; +BYTE _viv_src_pixel_r = 0; +BYTE _viv_src_pixel_g = 0; +BYTE _viv_src_pixel_b = 0; static DWORD last_process_command_line_tick; static BYTE got_last_process_command_line_tick = 0; //static BYTE _viv_is_alt = 0; + // MF_OWNERDRAW = don't show in menu. -static _viv_command_t _viv_commands[] = +_viv_command_t _viv_commands[] = { {LOCALIZATION_ID_FILE,MF_POPUP,_VIV_MENU_ROOT,_VIV_MENU_FILE}, @@ -811,6 +439,7 @@ static _viv_command_t _viv_commands[] = {LOCALIZATION_ID_PREVIEW,MF_STRING,_VIV_MENU_FILE,VIV_ID_FILE_PREVIEW}, {LOCALIZATION_ID_PRINT,MF_STRING,_VIV_MENU_FILE,VIV_ID_FILE_PRINT}, {LOCALIZATION_ID_SET_DESKTOP_WALLPAPER,MF_STRING,_VIV_MENU_FILE,VIV_ID_FILE_SET_DESKTOP_WALLPAPER}, + {LOCALIZATION_ID_SAVE_AS,MF_STRING,_VIV_MENU_FILE,VIV_ID_FILE_SAVE_AS}, {LOCALIZATION_ID_CLOSE,MF_STRING|MF_OWNERDRAW,_VIV_MENU_FILE,VIV_ID_FILE_CLOSE}, // this just clears the image. {LOCALIZATION_ID_INVALID,MF_SEPARATOR,_VIV_MENU_FILE,0}, {LOCALIZATION_ID_DELETE,MF_STRING|MF_DELETE,_VIV_MENU_FILE,VIV_ID_FILE_DELETE}, @@ -818,6 +447,7 @@ static _viv_command_t _viv_commands[] = {LOCALIZATION_ID_DELETE_PERMANENTLY,MF_STRING|MF_OWNERDRAW,_VIV_MENU_FILE,VIV_ID_FILE_DELETE_PERMANENTLY}, {LOCALIZATION_ID_RENAME,MF_STRING,_VIV_MENU_FILE,VIV_ID_FILE_RENAME}, {LOCALIZATION_ID_PROPERTIES,MF_STRING,_VIV_MENU_FILE,VIV_ID_FILE_PROPERTIES}, + {LOCALIZATION_ID_OPTIONS,MF_STRING,_VIV_MENU_FILE,VIV_ID_VIEW_OPTIONS}, {LOCALIZATION_ID_INVALID,MF_SEPARATOR,_VIV_MENU_FILE,0}, {LOCALIZATION_ID_EXIT,MF_STRING,_VIV_MENU_FILE,VIV_ID_FILE_EXIT}, @@ -837,60 +467,56 @@ static _viv_command_t _viv_commands[] = {LOCALIZATION_ID_VIEW,MF_POPUP,_VIV_MENU_ROOT,_VIV_MENU_VIEW}, - {LOCALIZATION_ID_CAPTION,MF_STRING|MF_OWNERDRAW,_VIV_MENU_VIEW,VIV_ID_VIEW_CAPTION}, - {LOCALIZATION_ID_FRAME,MF_STRING|MF_OWNERDRAW,_VIV_MENU_VIEW,VIV_ID_VIEW_THICKFRAME}, - {LOCALIZATION_ID_MENU,MF_STRING,_VIV_MENU_VIEW,VIV_ID_VIEW_MENU}, - {LOCALIZATION_ID_STATUS_BAR,MF_STRING,_VIV_MENU_VIEW,VIV_ID_VIEW_STATUS}, - {LOCALIZATION_ID_CONTROLS,MF_STRING,_VIV_MENU_VIEW,VIV_ID_VIEW_CONTROLS}, - {LOCALIZATION_ID_PRESET,MF_POPUP,_VIV_MENU_VIEW,_VIV_MENU_VIEW_PRESET}, + {LOCALIZATION_ID_LAYOUT,MF_POPUP,_VIV_MENU_VIEW,_VIV_MENU_VIEW_LAYOUT}, + {LOCALIZATION_ID_CAPTION,MF_STRING,_VIV_MENU_VIEW_LAYOUT,VIV_ID_VIEW_CAPTION}, + {LOCALIZATION_ID_FRAME,MF_STRING,_VIV_MENU_VIEW_LAYOUT,VIV_ID_VIEW_THICKFRAME}, + {LOCALIZATION_ID_MENU,MF_STRING,_VIV_MENU_VIEW_LAYOUT,VIV_ID_VIEW_MENU}, + {LOCALIZATION_ID_STATUS_BAR,MF_STRING,_VIV_MENU_VIEW_LAYOUT,VIV_ID_VIEW_STATUS}, + {LOCALIZATION_ID_CONTROLS,MF_STRING,_VIV_MENU_VIEW_LAYOUT,VIV_ID_VIEW_CONTROLS}, + {LOCALIZATION_ID_ZOOM_CONTROLS,MF_STRING,_VIV_MENU_VIEW_LAYOUT,VIV_ID_VIEW_ZOOM_CONTROLS}, + {LOCALIZATION_ID_ZOOM_AUTO_HIDE,MF_STRING,_VIV_MENU_VIEW_LAYOUT,VIV_ID_VIEW_ZOOM_AUTO_HIDE}, + {LOCALIZATION_ID_INVALID,MF_SEPARATOR,_VIV_MENU_VIEW_LAYOUT,0}, + {LOCALIZATION_ID_PRESET,MF_POPUP,_VIV_MENU_VIEW_LAYOUT,_VIV_MENU_VIEW_PRESET}, {LOCALIZATION_ID_MINIMAL,MF_STRING,_VIV_MENU_VIEW_PRESET,VIV_ID_VIEW_PRESET_1}, {LOCALIZATION_ID_COMPACT,MF_STRING,_VIV_MENU_VIEW_PRESET,VIV_ID_VIEW_PRESET_2}, {LOCALIZATION_ID_NORMAL,MF_STRING,_VIV_MENU_VIEW_PRESET,VIV_ID_VIEW_PRESET_3}, {LOCALIZATION_ID_INVALID,MF_SEPARATOR,_VIV_MENU_VIEW,0}, {LOCALIZATION_ID_FULLSCREEN,MF_STRING,_VIV_MENU_VIEW,VIV_ID_VIEW_FULLSCREEN}, {LOCALIZATION_ID_SLIDESHOW,MF_STRING,_VIV_MENU_VIEW,VIV_ID_VIEW_SLIDESHOW}, + {LOCALIZATION_ID_REFRESH,MF_STRING,_VIV_MENU_VIEW,VIV_ID_VIEW_REFRESH}, + {LOCALIZATION_ID_INVALID,MF_SEPARATOR,_VIV_MENU_VIEW,0}, {LOCALIZATION_ID_VIEW_WINDOW_SIZE,MF_POPUP,_VIV_MENU_VIEW,_VIV_MENU_VIEW_WINDOW_SIZE}, {LOCALIZATION_ID_VIEW_WINDOW_SIZE_50_PERCENT,MF_STRING,_VIV_MENU_VIEW_WINDOW_SIZE,VIV_ID_VIEW_WINDOW_SIZE_50}, {LOCALIZATION_ID_VIEW_WINDOW_SIZE_100_PERCENT,MF_STRING,_VIV_MENU_VIEW_WINDOW_SIZE,VIV_ID_VIEW_WINDOW_SIZE_100}, {LOCALIZATION_ID_VIEW_WINDOW_SIZE_200_PERCENT,MF_STRING,_VIV_MENU_VIEW_WINDOW_SIZE,VIV_ID_VIEW_WINDOW_SIZE_200}, {LOCALIZATION_ID_VIEW_WINDOW_SIZE_AUTO_FIT,MF_STRING,_VIV_MENU_VIEW_WINDOW_SIZE,VIV_ID_VIEW_WINDOW_SIZE_AUTO_FIT}, - {LOCALIZATION_ID_REFRESH,MF_STRING,_VIV_MENU_VIEW,VIV_ID_VIEW_REFRESH}, - {LOCALIZATION_ID_INVALID,MF_SEPARATOR,_VIV_MENU_VIEW,0}, - {LOCALIZATION_ID_ALLOW_SHRINKING,MF_STRING,_VIV_MENU_VIEW,VIV_ID_VIEW_ALLOW_SHRINKING}, - {LOCALIZATION_ID_KEEP_ASPECT_RATIO,MF_STRING,_VIV_MENU_VIEW,VIV_ID_VIEW_KEEP_ASPECT_RATIO}, - {LOCALIZATION_ID_FILL_WINDOW,MF_STRING,_VIV_MENU_VIEW,VIV_ID_VIEW_FILL_WINDOW}, - {LOCALIZATION_ID_ONE_TO_ONE,MF_STRING,_VIV_MENU_VIEW,VIV_ID_VIEW_1TO1}, - {LOCALIZATION_ID_BEST_FIT,MF_STRING|MF_OWNERDRAW,_VIV_MENU_VIEW,VIV_ID_VIEW_BESTFIT}, {LOCALIZATION_ID_INVALID,MF_SEPARATOR,_VIV_MENU_VIEW,0}, - {LOCALIZATION_ID_PAN_SCAN,MF_POPUP,_VIV_MENU_VIEW,_VIV_MENU_VIEW_PANSCAN}, - {LOCALIZATION_ID_INCREASE_SIZE,MF_STRING,_VIV_MENU_VIEW_PANSCAN,VIV_ID_VIEW_PANSCAN_INCREASE_SIZE}, - {LOCALIZATION_ID_DECREASE_SIZE,MF_STRING,_VIV_MENU_VIEW_PANSCAN,VIV_ID_VIEW_PANSCAN_DECREASE_SIZE}, - {LOCALIZATION_ID_INCREASE_WIDTH,MF_STRING,_VIV_MENU_VIEW_PANSCAN,VIV_ID_VIEW_PANSCAN_INCREASE_WIDTH}, - {LOCALIZATION_ID_DECREASE_WIDTH,MF_STRING,_VIV_MENU_VIEW_PANSCAN,VIV_ID_VIEW_PANSCAN_DECREASE_WIDTH}, - {LOCALIZATION_ID_INCREASE_HEIGHT,MF_STRING,_VIV_MENU_VIEW_PANSCAN,VIV_ID_VIEW_PANSCAN_INCREASE_HEIGHT}, - {LOCALIZATION_ID_DECREASE_HEIGHT,MF_STRING,_VIV_MENU_VIEW_PANSCAN,VIV_ID_VIEW_PANSCAN_DECREASE_HEIGHT}, + // all zoom related commands live in one submenu. {LOCALIZATION_ID_ZOOM,MF_POPUP,_VIV_MENU_VIEW,_VIV_MENU_VIEW_ZOOM}, {LOCALIZATION_ID_ZOOM_IN,MF_STRING,_VIV_MENU_VIEW_ZOOM,VIV_ID_VIEW_ZOOM_IN}, {LOCALIZATION_ID_ZOOM_OUT,MF_STRING,_VIV_MENU_VIEW_ZOOM,VIV_ID_VIEW_ZOOM_OUT}, + {LOCALIZATION_ID_INVALID,MF_SEPARATOR,_VIV_MENU_VIEW_ZOOM,0}, + {LOCALIZATION_ID_ONE_TO_ONE,MF_STRING,_VIV_MENU_VIEW_ZOOM,VIV_ID_VIEW_1TO1}, + {LOCALIZATION_ID_BEST_FIT,MF_STRING,_VIV_MENU_VIEW_ZOOM,VIV_ID_VIEW_BESTFIT}, {LOCALIZATION_ID_RESET,MF_STRING,_VIV_MENU_VIEW_ZOOM,VIV_ID_VIEW_ZOOM_RESET}, - {LOCALIZATION_ID_INVALID,MF_SEPARATOR,_VIV_MENU_VIEW_PANSCAN,0}, - {LOCALIZATION_ID_MOVE_UP,MF_STRING,_VIV_MENU_VIEW_PANSCAN,VIV_ID_VIEW_PANSCAN_MOVE_UP}, - {LOCALIZATION_ID_MOVE_DOWN,MF_STRING,_VIV_MENU_VIEW_PANSCAN,VIV_ID_VIEW_PANSCAN_MOVE_DOWN}, - {LOCALIZATION_ID_MOVE_LEFT,MF_STRING,_VIV_MENU_VIEW_PANSCAN,VIV_ID_VIEW_PANSCAN_MOVE_LEFT}, - {LOCALIZATION_ID_MOVE_RIGHT,MF_STRING,_VIV_MENU_VIEW_PANSCAN,VIV_ID_VIEW_PANSCAN_MOVE_RIGHT}, - {LOCALIZATION_ID_MOVE_UP_LEFT,MF_STRING|MF_OWNERDRAW,_VIV_MENU_VIEW_PANSCAN,VIV_ID_VIEW_PANSCAN_MOVE_UP_LEFT}, - {LOCALIZATION_ID_MOVE_UP_RIGHT,MF_STRING|MF_OWNERDRAW,_VIV_MENU_VIEW_PANSCAN,VIV_ID_VIEW_PANSCAN_MOVE_UP_RIGHT}, - {LOCALIZATION_ID_MOVE_DOWN_LEFT,MF_STRING|MF_OWNERDRAW,_VIV_MENU_VIEW_PANSCAN,VIV_ID_VIEW_PANSCAN_MOVE_DOWN_LEFT}, - {LOCALIZATION_ID_MOVE_DOWN_RIGHT,MF_STRING|MF_OWNERDRAW,_VIV_MENU_VIEW_PANSCAN,VIV_ID_VIEW_PANSCAN_MOVE_DOWN_RIGHT}, - {LOCALIZATION_ID_MOVE_CENTER,MF_STRING,_VIV_MENU_VIEW_PANSCAN,VIV_ID_VIEW_PANSCAN_MOVE_CENTER}, - {LOCALIZATION_ID_INVALID,MF_SEPARATOR,_VIV_MENU_VIEW_PANSCAN,0}, - {LOCALIZATION_ID_PANSCAN_RESET,MF_STRING,_VIV_MENU_VIEW_PANSCAN,VIV_ID_VIEW_PANSCAN_RESET}, + {LOCALIZATION_ID_INVALID,MF_SEPARATOR,_VIV_MENU_VIEW,0}, + {LOCALIZATION_ID_ALLOW_SHRINKING,MF_STRING,_VIV_MENU_VIEW,VIV_ID_VIEW_ALLOW_SHRINKING}, + {LOCALIZATION_ID_KEEP_ASPECT_RATIO,MF_STRING,_VIV_MENU_VIEW,VIV_ID_VIEW_KEEP_ASPECT_RATIO}, + {LOCALIZATION_ID_FILL_WINDOW,MF_STRING,_VIV_MENU_VIEW,VIV_ID_VIEW_FILL_WINDOW}, {LOCALIZATION_ID_INVALID,MF_SEPARATOR,_VIV_MENU_VIEW,0}, {LOCALIZATION_ID_ON_TOP,MF_POPUP,_VIV_MENU_VIEW,_VIV_MENU_VIEW_ONTOP}, {LOCALIZATION_ID_ALWAYS,MF_STRING|MFT_RADIOCHECK,_VIV_MENU_VIEW_ONTOP,VIV_ID_VIEW_ONTOP_ALWAYS}, {LOCALIZATION_ID_WHILE_PLAYING_OR_ANIMATING,MF_STRING|MFT_RADIOCHECK,_VIV_MENU_VIEW_ONTOP,VIV_ID_VIEW_ONTOP_WHILE_PLAYING_OR_ANIMATING}, {LOCALIZATION_ID_NEVER,MF_STRING|MFT_RADIOCHECK,_VIV_MENU_VIEW_ONTOP,VIV_ID_VIEW_ONTOP_NEVER}, - {LOCALIZATION_ID_OPTIONS,MF_STRING,_VIV_MENU_VIEW,VIV_ID_VIEW_OPTIONS}, + {LOCALIZATION_ID_INVALID,MF_SEPARATOR,_VIV_MENU_VIEW,0}, + {LOCALIZATION_ID_WINDOWED_BACKGROUND_COLOR_MENU,MF_STRING,_VIV_MENU_VIEW,VIV_ID_VIEW_WINDOWED_BACKGROUND_COLOR}, + {LOCALIZATION_ID_BACKDROP,MF_POPUP,_VIV_MENU_VIEW,_VIV_MENU_VIEW_BACKDROP}, + {LOCALIZATION_ID_BACKDROP_FOLLOW,MF_STRING|MFT_RADIOCHECK,_VIV_MENU_VIEW_BACKDROP,VIV_ID_VIEW_BACKDROP_FOLLOW}, + {LOCALIZATION_ID_BACKDROP_BLACK,MF_STRING|MFT_RADIOCHECK,_VIV_MENU_VIEW_BACKDROP,VIV_ID_VIEW_BACKDROP_BLACK}, + {LOCALIZATION_ID_BACKDROP_WHITE,MF_STRING|MFT_RADIOCHECK,_VIV_MENU_VIEW_BACKDROP,VIV_ID_VIEW_BACKDROP_WHITE}, + {LOCALIZATION_ID_BACKDROP_CUSTOM,MF_STRING|MFT_RADIOCHECK,_VIV_MENU_VIEW_BACKDROP,VIV_ID_VIEW_BACKDROP_CUSTOM}, + {LOCALIZATION_ID_BACKDROP_CHECKERBOARD,MF_STRING|MFT_RADIOCHECK,_VIV_MENU_VIEW_BACKDROP,VIV_ID_VIEW_BACKDROP_CHECKERBOARD}, + {LOCALIZATION_ID_SLIDESHOW_MENU,MF_POPUP,_VIV_MENU_ROOT,_VIV_MENU_SLIDESHOW}, {LOCALIZATION_ID_PLAY_PAUSE,MF_STRING,_VIV_MENU_SLIDESHOW,VIV_ID_SLIDESHOW_PAUSE}, {LOCALIZATION_ID_INVALID,MF_SEPARATOR,_VIV_MENU_SLIDESHOW,0}, @@ -964,8 +590,8 @@ static _viv_command_t _viv_commands[] = {LOCALIZATION_ID_INVALID,MF_SEPARATOR,_VIV_MENU_HELP,0}, {LOCALIZATION_ID_ABOUT,MF_STRING,_VIV_MENU_HELP,VIV_ID_HELP_ABOUT}, }; +typedef char _viv_commands_count_assert[(sizeof(_viv_commands) / sizeof(_viv_command_t) == _VIV_COMMAND_COUNT) ? 1 : -1]; // the count literal pins the table -#define _VIV_COMMAND_COUNT (sizeof(_viv_commands) / sizeof(_viv_command_t)) _viv_default_key_t _viv_default_keys[] = { @@ -974,11 +600,12 @@ _viv_default_key_t _viv_default_keys[] = {VIV_ID_FILE_OPEN_EVERYTHING_SEARCH,CONFIG_KEYFLAG_CTRL | 'E'}, {VIV_ID_FILE_ADD_FILE,CONFIG_KEYFLAG_CTRL | CONFIG_KEYFLAG_SHIFT | 'O'}, {VIV_ID_FILE_ADD_FOLDER,CONFIG_KEYFLAG_CTRL | CONFIG_KEYFLAG_SHIFT | 'B'}, - {VIV_ID_FILE_ADD_EVERYTHING_SEARCH,CONFIG_KEYFLAG_CTRL | CONFIG_KEYFLAG_SHIFT | 'E'}, + {VIV_ID_FILE_ADD_EVERYTHING_SEARCH,CONFIG_KEYFLAG_CTRL | CONFIG_KEYFLAG_ALT | 'E'}, {VIV_ID_FILE_OPEN_FILE_LOCATION,CONFIG_KEYFLAG_CTRL | VK_RETURN}, -// {VIV_ID_FILE_EDIT,CONFIG_KEYFLAG_CTRL | 'E'}, + {VIV_ID_FILE_SAVE_AS,CONFIG_KEYFLAG_CTRL | 'S'}, + {VIV_ID_FILE_EDIT,CONFIG_KEYFLAG_CTRL | CONFIG_KEYFLAG_SHIFT | 'E'}, // the everything search keeps plain ctrl+e; everything-add moved to ctrl+alt+e so the editor can take ctrl+shift+e {VIV_ID_FILE_PRINT,CONFIG_KEYFLAG_CTRL | 'P'}, -// {VIV_ID_FILE_SET_DESKTOP_WALLPAPER,CONFIG_KEYFLAG_CTRL | 'D'}, // this needs a confirmation dialog + {VIV_ID_FILE_SET_DESKTOP_WALLPAPER,CONFIG_KEYFLAG_CTRL | 'D'}, // safe again: the handler asks before it touches the desktop {VIV_ID_FILE_CLOSE,CONFIG_KEYFLAG_CTRL | 'W'}, {VIV_ID_FILE_DELETE_RECYCLE,VK_DELETE}, {VIV_ID_FILE_DELETE_PERMANENTLY,CONFIG_KEYFLAG_SHIFT | VK_DELETE}, @@ -998,22 +625,6 @@ _viv_default_key_t _viv_default_keys[] = {VIV_ID_VIEW_WINDOW_SIZE_100,CONFIG_KEYFLAG_ALT | '2'}, {VIV_ID_VIEW_WINDOW_SIZE_200,CONFIG_KEYFLAG_ALT | '3'}, {VIV_ID_VIEW_WINDOW_SIZE_AUTO_FIT,CONFIG_KEYFLAG_ALT | '4'}, - {VIV_ID_VIEW_PANSCAN_INCREASE_SIZE,VK_NUMPAD9}, - {VIV_ID_VIEW_PANSCAN_DECREASE_SIZE,VK_NUMPAD1}, - {VIV_ID_VIEW_PANSCAN_INCREASE_WIDTH,VK_NUMPAD6}, - {VIV_ID_VIEW_PANSCAN_DECREASE_WIDTH,VK_NUMPAD4}, - {VIV_ID_VIEW_PANSCAN_INCREASE_HEIGHT,VK_NUMPAD8}, - {VIV_ID_VIEW_PANSCAN_DECREASE_HEIGHT,VK_NUMPAD2}, - {VIV_ID_VIEW_PANSCAN_MOVE_UP,CONFIG_KEYFLAG_CTRL | VK_NUMPAD8}, - {VIV_ID_VIEW_PANSCAN_MOVE_DOWN,CONFIG_KEYFLAG_CTRL | VK_NUMPAD2}, - {VIV_ID_VIEW_PANSCAN_MOVE_LEFT,CONFIG_KEYFLAG_CTRL | VK_NUMPAD4}, - {VIV_ID_VIEW_PANSCAN_MOVE_RIGHT,CONFIG_KEYFLAG_CTRL | VK_NUMPAD6}, - {VIV_ID_VIEW_PANSCAN_MOVE_UP_LEFT,CONFIG_KEYFLAG_CTRL | VK_NUMPAD7}, - {VIV_ID_VIEW_PANSCAN_MOVE_UP_RIGHT,CONFIG_KEYFLAG_CTRL | VK_NUMPAD9}, - {VIV_ID_VIEW_PANSCAN_MOVE_DOWN_LEFT,CONFIG_KEYFLAG_CTRL | VK_NUMPAD1}, - {VIV_ID_VIEW_PANSCAN_MOVE_DOWN_RIGHT,CONFIG_KEYFLAG_CTRL | VK_NUMPAD3}, - {VIV_ID_VIEW_PANSCAN_MOVE_CENTER,CONFIG_KEYFLAG_CTRL | VK_NUMPAD5}, - {VIV_ID_VIEW_PANSCAN_RESET,VK_NUMPAD5}, {VIV_ID_VIEW_ZOOM_IN,VK_OEM_PLUS}, {VIV_ID_VIEW_ZOOM_IN,VK_ADD}, {VIV_ID_VIEW_ZOOM_IN,CONFIG_KEYFLAG_CTRL | VK_ADD}, @@ -1022,7 +633,7 @@ _viv_default_key_t _viv_default_keys[] = {VIV_ID_VIEW_ZOOM_OUT,CONFIG_KEYFLAG_CTRL | VK_SUBTRACT}, {VIV_ID_VIEW_ZOOM_RESET,CONFIG_KEYFLAG_CTRL | '0'}, {VIV_ID_VIEW_ONTOP_ALWAYS,CONFIG_KEYFLAG_CTRL | 'T'}, - {VIV_ID_VIEW_OPTIONS,'O'}, + {VIV_ID_VIEW_OPTIONS,CONFIG_KEYFLAG_CTRL | VK_OEM_COMMA}, // ctrl+comma, the modern options key: a bare o opened a modal on every stray keypress {VIV_ID_VIEW_REFRESH,VK_F5}, {VIV_ID_SLIDESHOW_PAUSE,VK_SPACE}, {VIV_ID_SLIDESHOW_RATE_DEC,VK_DOWN}, @@ -1050,86 +661,6 @@ _viv_default_key_t _viv_default_keys[] = #define _VIV_DEFAULT_KEY_COUNT (sizeof(_viv_default_keys) / sizeof(_viv_default_key_t)) -WORD _viv_context_menu_items[] = -{ - VIV_ID_NAV_NEXT, - VIV_ID_NAV_PREV, - 0, - VIV_ID_VIEW_FULLSCREEN, - VIV_ID_SLIDESHOW_PAUSE, - _VIV_MENU_SLIDESHOW_RATE, - VIV_ID_SLIDESHOW_RATE_DEC, - VIV_ID_SLIDESHOW_RATE_INC, - 0, - VIV_ID_SLIDESHOW_RATE_250, - VIV_ID_SLIDESHOW_RATE_500, - VIV_ID_SLIDESHOW_RATE_1000, - VIV_ID_SLIDESHOW_RATE_2000, - VIV_ID_SLIDESHOW_RATE_3000, - VIV_ID_SLIDESHOW_RATE_4000, - VIV_ID_SLIDESHOW_RATE_5000, - VIV_ID_SLIDESHOW_RATE_6000, - VIV_ID_SLIDESHOW_RATE_7000, - VIV_ID_SLIDESHOW_RATE_8000, - VIV_ID_SLIDESHOW_RATE_9000, - VIV_ID_SLIDESHOW_RATE_10000, - VIV_ID_SLIDESHOW_RATE_20000, - VIV_ID_SLIDESHOW_RATE_30000, - VIV_ID_SLIDESHOW_RATE_40000, - VIV_ID_SLIDESHOW_RATE_50000, - VIV_ID_SLIDESHOW_RATE_60000, - VIV_ID_SLIDESHOW_RATE_CUSTOM, - _VIV_MENU_SLIDESHOW_RATE, - 0, - VIV_ID_VIEW_MENU, - 0, - VIV_ID_VIEW_ALLOW_SHRINKING, - VIV_ID_VIEW_KEEP_ASPECT_RATIO, - VIV_ID_VIEW_FILL_WINDOW, - VIV_ID_VIEW_1TO1, -// VIV_ID_VIEW_SLIDESHOW, - 0, - _VIV_MENU_NAVIGATE_SORT, - VIV_ID_NAV_SORT_NAME, - VIV_ID_NAV_SORT_FULL_PATH, - VIV_ID_NAV_SORT_SIZE, - VIV_ID_NAV_SORT_DATE_MODIFIED, - VIV_ID_NAV_SORT_DATE_CREATED, - 0, - VIV_ID_NAV_SORT_ASCENDING, - VIV_ID_NAV_SORT_DESCENDING, - _VIV_MENU_NAVIGATE_SORT, - 0, - VIV_ID_FILE_OPEN_FILE_LOCATION, - VIV_ID_FILE_SET_DESKTOP_WALLPAPER, - VIV_ID_FILE_EDIT, - VIV_ID_FILE_PRINT, - VIV_ID_FILE_PREVIEW, - 0, - VIV_ID_EDIT_ROTATE_90, - VIV_ID_EDIT_ROTATE_270, - 0, - VIV_ID_EDIT_CUT, - VIV_ID_EDIT_COPY, - VIV_ID_EDIT_COPY_IMAGE, - 0, - VIV_ID_FILE_DELETE, - VIV_ID_FILE_RENAME, - 0, - VIV_ID_FILE_PROPERTIES, - VIV_ID_VIEW_OPTIONS, - 0, - VIV_ID_FILE_EXIT, -}; - -#define _VIV_CONEXT_MENU_ITEM_COUNT (sizeof(_viv_context_menu_items) / sizeof(WORD)) - -typedef struct _viv_key_list_s -{ - config_key_t *start[_VIV_COMMAND_COUNT]; - config_key_t *last[_VIV_COMMAND_COUNT]; - -}_viv_key_list_t; _viv_key_list_t *_viv_key_list = 0; @@ -1144,7 +675,10 @@ const char *_viv_association_extensions[] = "tif", "tiff", "webp", + "emf", + "wmf", }; +typedef char _viv_association_extensions_count_assert[(sizeof(_viv_association_extensions) / sizeof(_viv_association_extensions[0]) == _VIV_ASSOCIATION_COUNT) ? 1 : -1]; // the count literal pins the table // registry description. const localization_id_t _viv_association_description_localization_id_array[] = @@ -1158,6 +692,8 @@ const localization_id_t _viv_association_description_localization_id_array[] = LOCALIZATION_ID_ASSOCIATION_DESCRIPTION_TIF, LOCALIZATION_ID_ASSOCIATION_DESCRIPTION_TIFF, LOCALIZATION_ID_ASSOCIATION_DESCRIPTION_WEBP, + LOCALIZATION_ID_ASSOCIATION_DESCRIPTION_EMF, + LOCALIZATION_ID_ASSOCIATION_DESCRIPTION_WMF, }; const char *_viv_association_icon_locations[] = @@ -1171,22 +707,11 @@ const char *_viv_association_icon_locations[] = NULL, NULL, NULL, + NULL, + NULL, }; -const WORD _viv_association_dlg_item_id[] = -{ - IDC_BMP, - IDC_GIF, - IDC_ICO, - IDC_JPEG, - IDC_JPG, - IDC_PNG, - IDC_TIF, - IDC_TIFF, - IDC_WEBP, -}; -#define _VIV_ASSOCIATION_COUNT (sizeof(_viv_association_extensions) / sizeof(const wchar_t *)) #ifdef VERSION_X86 @@ -1215,13990 +740,1531 @@ HMODULE LoadUnicowsProc(void) #endif -static void _viv_update_title(void) -{ - wchar_t window_title[STRING_SIZE+STRING_SIZE]; - const wchar_t *filename; - - window_title[0] = 0; - filename = L""; - switch(config_title_bar_format) - { - case 0: // full path - filename = _viv_current_fd->cFileName; - break; - case 1: // filename only - default: - filename = string_get_filename_part(_viv_current_fd->cFileName); - break; - - case 2: // none - break; - } - - if (*filename) - { - string_cat(window_title,filename); - string_cat_utf8(window_title," - "); - } - - string_cat_utf8(window_title,localization_get_string(LOCALIZATION_ID_APP_NAME)); - - SetWindowTextW(_viv_hwnd,window_title); -} -static void _viv_mipmap_free(_viv_mipmap_t *mipmap) -{ - DeleteObject(mipmap->hbitmap); - - if (mipmap->mipmap) - { - _viv_mipmap_free(mipmap->mipmap); - } - - mem_free(mipmap); -} -// clearing is really slow. -// delay this until after the new image is shown. -// we add the clear to a queue which is cleared with _viv_process_pending_clear. -// _viv_process_pending_clear should be called after the new frame is shown. -static void _viv_clear(void) -{ - _viv_pending_clear_frames = _viv_frames; - _viv_pending_clear_frame_loaded_count = _viv_frame_loaded_count; - _viv_frames = NULL; - _viv_frame_fd->cFileName[0] = 0; - - _viv_timer_stop(); - - _viv_frame_position = 0; - _viv_frame_looped = 0; - _viv_is_slideshow_timeup = 0; - _viv_frame_count = 0; - _viv_frame_loaded_count = 0; - _viv_zoom_pos = 0; - _viv_view_x = 0; - _viv_view_y = 0; - _viv_view_ix = 0.0; - _viv_view_iy = 0.0; - _viv_1to1 = 0; - _viv_have_old_zoom = 0; - _viv_image_wide = 0; - _viv_image_high = 0; - _viv_animation_play = 1; -} -static void _viv_clear_frames(_viv_frame_t *frames,int loaded_count) -{ - int i; - - for(i=0;icFileName[0] = 0; -} -static BOOL _viv_open_from_filename(const wchar_t *filename) -{ - BOOL ret; - WIN32_FIND_DATA fd; - HANDLE h; - wchar_t full_path_and_filename[STRING_SIZE]; - wchar_t cwd[STRING_SIZE]; - ret = FALSE; - GetCurrentDirectory(STRING_SIZE,cwd); - string_path_combine(full_path_and_filename,cwd,filename); -debug_printf("open filename: %S\n",full_path_and_filename); - - if ((os_GetFileAttributesExW) && (os_GetFileAttributesExW(full_path_and_filename,GetFileExInfoStandard,&fd))) - { - fd.dwReserved0 = 0; - fd.dwReserved1 = 0; - - ret = TRUE; - if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - { - // add subfolders and subsubfolders... - _viv_playlist_add_path(full_path_and_filename); - _viv_home(0,0); - } - else - { - string_copy(fd.cFileName,full_path_and_filename); - - _viv_open(&fd,0); - } - } - else - { - h = FindFirstFile(full_path_and_filename,&fd); - if (h != INVALID_HANDLE_VALUE) - { - wchar_t path[STRING_SIZE]; - - ret = TRUE; - string_get_path_part(path,full_path_and_filename); - - for(;;) - { - string_path_combine(full_path_and_filename,path,fd.cFileName); - - if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - { - _viv_playlist_add_path(full_path_and_filename); - } - else - { - string_copy(fd.cFileName,full_path_and_filename); - _viv_playlist_add(&fd); - } - - if (!FindNextFile(h,&fd)) - { - break; - } - } - _viv_home(0,0); - - FindClose(h); - } - } - - return ret; -} -// _viv_load_image_thread will be NULL if is_preload is 1. -static void _viv_open(WIN32_FIND_DATA *fd,int is_preload) -{ -debug_printf("open: %S last %S frame %S is_preload %d\n",fd->cFileName,_viv_last_fd->cFileName,_viv_frame_fd->cFileName,is_preload); -if ((_viv_load_image_thread) && (_viv_load_image_filename)) +void _viv_exit(void) { -debug_printf("CURRENTLY LOADING %S preload %d\n",_viv_load_image_filename,_viv_load_is_preload); + _viv_load_image_terminate = 1; + // the deferred recent-files save folds into the exit write below (the + // debounce timer never gets to fire once the quit is posted). + _viv_recent_save_fold(); + + config_save_settings(config_appdata); + PostQuitMessage(0); } - if (!is_preload) - { - if (_viv_file_not_found) - { - _viv_file_not_found = 0; - - _viv_status_update(); - } +// cached backbuffer used for double buffered painting. +HDC _viv_paint_hdc = 0; - if (_viv_load_failed) - { - _viv_load_failed = 0; +HBRUSH _viv_dialog_dark_hbrush = 0; // dark dialog background brush, lazy created +// a cached dark chrome brush for the toolbar strip. which: 0 = the strip +// face (0x252525, one step above the canvas), 1 = the separator shadow +// line (0x454545), 2 = the separator highlight line (0x707070), +// 3 = the menu bar face (0x202020: the canvas and dark system menu +// color). the zoom bar uses the same palette. created lazily, released +// in _viv_kill with the other cached brushes. +HBRUSH _viv_dark_chrome_hbrushes[4]; - _viv_status_update(); - } - } - if ((is_preload) && (_viv_last_frames) && (string_compare(_viv_last_fd->cFileName,fd->cFileName) == 0)) - { - // don't preload if its the same as last cache. - // this can occur if you have a playlist or folder with only 2 items. - return; - } - else - if ((!is_preload) && (_viv_last_frames) && (string_compare(_viv_last_fd->cFileName,fd->cFileName) == 0)) - { - // activate last cache - // don't activate preload. - _viv_should_activate_preload_on_load = 0; - - // stop loading - debug_printf("SET TERMINATE (LAST)\n"); - _viv_load_image_allow_draw = 0; - _viv_load_image_terminate = 1; - - if (_viv_load_image_next_fd) - { - mem_free(_viv_load_image_next_fd); - - _viv_load_image_next_fd = NULL; - } +// a cached light chrome brush for the toolbar strip lines. the light strip +// face is the system menu color (it matches the light menu bar exactly and +// tracks the theme for free), but the flat separator lines are fixed subtle +// grays like the dark palette: 0 = the shadow line, 1 = the highlight line. +// released in _viv_kill with the dark chrome brushes. - _viv_preload_fd->cFileName[0] = 0; - - _viv_status_update(); - _viv_activate_last(); +HBRUSH _viv_about_light_hbrushes[2]; - _viv_preload_next(); - return; - } - else - if ((!is_preload) && (_viv_load_is_preload) && (*_viv_preload_fd->cFileName) && (string_compare(_viv_preload_fd->cFileName,fd->cFileName) == 0)) - { - _viv_open_preload(); +HBRUSH _viv_backdrop_solid_hbrush = 0; // backdrop solid color brush, cached +COLORREF _viv_backdrop_solid_color = 0; // the color the solid brush was created with +HBRUSH _viv_backdrop_checker_hbrush = 0; // checkerboard pattern brush, cached +HBITMAP _viv_backdrop_checker_hbitmap = 0; // the pattern bitmap (owned while the brush lives) +int _viv_backdrop_checker_cell = 0; // the cell size the pattern was built with - return; + +static void _viv_apply_config_language(void) +{ + // apply the language setting from the config file. + // config_language: 0 = auto (keep the detected system language), 1 = english, 2 = simplified chinese. + + if (config_language == 1) + { + localization_set_language(LOCALIZATION_LANGUAGE_ENGLISH); } else - if ((!is_preload) && (_viv_load_image_thread) && (_viv_load_image_filename) && (string_compare(_viv_load_image_filename,fd->cFileName) == 0)) + if (config_language == 2) { - debug_printf("already loading...\n"); - // already loading this one.. - return; + localization_set_language(LOCALIZATION_LANGUAGE_CHINESE_SIMPLIFIED); } +} + + +void _viv_process_command_line(wchar_t *cl) +{ + wchar_t *p; + wchar_t buf[STRING_SIZE]; + wchar_t single[STRING_SIZE]; + int file_count; + int start_slideshow; + int start_fullscreen; + int start_window; + int window_x; + int window_y; + int window_wide; + int window_high; + int set_window_rect; + RECT rect; + int start_maximized; + int is_add; + + debug_printf("cl: %S\n",cl); - // clear any existing preload and start a fresh one. - _viv_clear_preload(); + start_slideshow = 0; + start_fullscreen = 0; + start_window = 0; + start_maximized = 0; + is_add = 0; + p = cl; + file_count = 0; + single[0] = 0; + set_window_rect = 0; + + GetWindowRect(_viv_hwnd,&rect); + window_x = rect.left; + window_y = rect.top; + window_wide = rect.right - rect.left; + window_high = rect.bottom - rect.top; - if (_viv_load_image_thread) + if (config_add_command_line_timeout) { - // already loading a different image. - // add it to the queue and cancel this one. - debug_printf("SET TERMINATE (next)\n"); - _viv_load_image_terminate = 1; - - if (_viv_load_image_next_fd) + if (got_last_process_command_line_tick) { - mem_free(_viv_load_image_next_fd); + if ((GetTickCount() - last_process_command_line_tick) < (DWORD)config_add_command_line_timeout) + { + // don't add if nothing is loaded. + if (*_viv_current_fd->cFileName) + { + is_add = 1; + } + } } - - _viv_load_image_next_fd = (WIN32_FIND_DATA *)mem_alloc(sizeof(WIN32_FIND_DATA)); - os_copy_memory(_viv_load_image_next_fd,fd,sizeof(WIN32_FIND_DATA)); - _viv_load_image_next_is_preload = is_preload; - - _viv_status_update(); } - else - { - DWORD thread_id; -// int rw; -// int rh; - RECT rect; - - GetClientRect(_viv_hwnd,&rect); + + p = string_skip_ws(p); + + // skip exe filename + p = string_get_word(p,buf,STRING_SIZE); + p = string_skip_ws(p); -// _viv_get_render_size(&rw,&rh); + // skip first parameter. + for(;;) + { + wchar_t *bufstart; + BOOL was_quote; - _viv_load_image_allow_draw = 1; - _viv_load_image_terminate = 0; - - if (_viv_load_image_filename) + // no more text? + if (!*p) { - mem_free(_viv_load_image_filename); + break; } - _viv_load_image_filename = string_alloc(fd->cFileName); - _viv_load_is_preload = is_preload; - _viv_preload_is_prev = _viv_last_is_prev; - _viv_preload_state = 0; - _viv_should_activate_preload_on_load = 0; - _viv_load_render_wide = rect.right - rect.left; - _viv_load_render_high = rect.bottom - rect.top - _viv_get_status_high() - _viv_get_controls_high(); - _viv_load_frame_count = 0; - os_copy_memory(_viv_load_fd,fd,sizeof(WIN32_FIND_DATA)); - - if (is_preload) + was_quote = FALSE; + if (*p == '"') { - os_copy_memory(_viv_preload_fd,fd,sizeof(WIN32_FIND_DATA)); + was_quote = TRUE; } - -debug_printf("LOAD %S is_preload %d\n",_viv_load_image_filename,is_preload); - - _viv_load_image_thread = CreateThread(NULL,0,_viv_load_image_thread_proc,0,0,&thread_id); - - _viv_status_update(); - } - - if (!is_preload) - { - os_copy_memory(_viv_current_fd,fd,sizeof(WIN32_FIND_DATA)); - - _viv_update_title(); - } -} - -static void _viv_on_size(void) -{ - if (!_viv_prevent_on_size) - { - RECT rect; - int wide; - int high; - - GetClientRect(_viv_hwnd,&rect); - wide = rect.right - rect.left; - high = rect.bottom - rect.top; - if (!IsIconic(_viv_hwnd)) - { - if (!_viv_is_fullscreen) - { - int is_maximized; - - is_maximized = _viv_is_window_maximized(_viv_hwnd); - - config_maximized = is_maximized; - - if (!is_maximized) - { - RECT window_rect; - - GetWindowRect(_viv_hwnd,&window_rect); - - config_wide = window_rect.right - window_rect.left; - config_high = window_rect.bottom - window_rect.top; - } - } - } + p = string_get_word(p,buf,STRING_SIZE); + p = string_skip_ws(p); - if (_viv_status_hwnd) - { - _viv_status_update(); - - SendMessage(_viv_status_hwnd,WM_SIZE,0,0); - - high -= _viv_get_status_high(); - } - - if (_viv_toolbar_hwnd) - { - int toolbar_wide; - - toolbar_wide = _viv_toolbar_get_wide(); - - SetWindowPos(_viv_rebar_hwnd,0,0,high - _viv_get_controls_high(),wide,_viv_get_controls_high(),SWP_NOZORDER|SWP_NOACTIVATE); - SetWindowPos(_viv_toolbar_hwnd,0,(wide / 2) - (toolbar_wide /2),6,toolbar_wide,_viv_get_controls_high() - 6,SWP_NOZORDER|SWP_NOACTIVATE); - - high -= _viv_get_controls_high(); - } + bufstart = buf; + // treat switches with a '.' as a filename. + if ((!was_quote) && ((*bufstart == '/') || (*bufstart == '-')) && (!string_is_dot(buf))) { - - int rw; - int rh; - double new_view_x; - double new_view_y; - - _viv_get_render_size(&rw,&rh); - - new_view_x = (int)(((_viv_view_ix * rw) / _viv_image_wide) + 0.5) + (((_viv_dst_pos_x - 250) * (wide*2)) / 1000) - (wide / 2) - (rw / 2); - new_view_y = (int)(((_viv_view_iy * rh) / _viv_image_high) + 0.5) + (((_viv_dst_pos_y - 250) * (high*2)) / 1000) - (high / 2) - (rh / 2); - - debug_printf("RESTORE VIEW x %d y %d ix %d iy %d rw %d rh %d wide %d high %d\n",(int)(new_view_x),(int)(new_view_y),(int)_viv_view_ix,(int)_viv_view_iy,rw,rh,wide,high) ; - // _viv_view_set((int)(_viv_view_ix * (double)rw),(int)(_viv_view_iy * (double)rh),1); - _viv_view_set((int)new_view_x,(int)new_view_y,1); - } - - _viv_toolbar_update_buttons(); - } -} - -static void _viv_command(int command_id) -{ - _viv_command_with_is_key_repeat(command_id,0); -} - -static void _viv_command_with_is_key_repeat(int command_id,int is_key_repeat) -{ - // Parse the menu selections: - switch (command_id) - { - case VIV_ID_VIEW_ZOOM_IN: - _viv_zoom_in(0,0,0,0); - break; - - case VIV_ID_VIEW_ZOOM_OUT: - _viv_zoom_in(1,0,0,0); - break; - - case VIV_ID_VIEW_ZOOM_RESET: - _viv_1to1 = 0; - _viv_zoom_pos = 0; - _viv_view_set(_viv_view_x,_viv_view_y,1); - InvalidateRect(_viv_hwnd,0,FALSE); - break; - - case VIV_ID_HELP_HELP: - ShellExecuteA(_viv_hwnd,NULL,localization_get_string(LOCALIZATION_ID_HELP_SUPPORT_URL),NULL,NULL,SW_SHOWNORMAL); - break; - - case VIV_ID_HELP_COMMAND_LINE_OPTIONS: - _viv_command_line_options(); - break; - - case VIV_ID_HELP_DONATE: - ShellExecuteA(_viv_hwnd,NULL,localization_get_string(LOCALIZATION_ID_HELP_DONATE_URL),NULL,NULL,SW_SHOWNORMAL); - break; - - case VIV_ID_HELP_ABOUT: - DialogBox(os_hinstance,MAKEINTRESOURCE(IDD_ABOUT),_viv_hwnd,_viv_about_proc); - break; - - case VIV_ID_HELP_WEBSITE: - ShellExecuteA(_viv_hwnd,NULL,localization_get_string(LOCALIZATION_ID_HELP_WEBSITE_URL),NULL,NULL,SW_SHOWNORMAL); - break; - - case VIV_ID_FILE_EXIT: - _viv_exit(); - break; - - case VIV_ID_NAV_PREV: - _viv_next(1,1,0,is_key_repeat); - break; - - case VIV_ID_NAV_NEXT: - _viv_next(0,1,0,is_key_repeat); - break; - - case VIV_ID_NAV_HOME: - _viv_home(0,0); - break; - - case VIV_ID_NAV_END: - _viv_home(1,0); - break; - - case VIV_ID_NAV_SHUFFLE: - config_shuffle = !config_shuffle; + bufstart++; - if (!config_shuffle) + if (string_icompare_lowercase_ascii(bufstart,"slideshow") == 0) { - // create a new shuffle list. - if (_viv_playlist_shuffle_indexes) - { - mem_free(_viv_playlist_shuffle_indexes); - - _viv_playlist_shuffle_indexes = 0; - _viv_playlist_shuffle_allocated = 0; - } + start_slideshow = 1; } - - // clear preload - _viv_clear_loading_preload(); - _viv_clear_preload(); - _viv_clear_last(); - - // preload again. - if (!_viv_load_image_thread) + else + if (string_icompare_lowercase_ascii(bufstart,"fullscreen") == 0) { - _viv_preload_next(); + start_fullscreen = 1; + start_window = 0; } - break; - - case VIV_ID_NAV_SORT_NAME: - case VIV_ID_NAV_SORT_SIZE: - case VIV_ID_NAV_SORT_DATE_MODIFIED: - case VIV_ID_NAV_SORT_DATE_CREATED: - case VIV_ID_NAV_SORT_FULL_PATH: - - if (config_nav_sort == command_id - VIV_ID_NAV_SORT_NAME) + else + if (string_icompare_lowercase_ascii(bufstart,"window") == 0) { - config_nav_sort_ascending = !config_nav_sort_ascending; + start_fullscreen = 0; + start_window = 1; } else + if (string_icompare_lowercase_ascii(bufstart,"maximized") == 0) { - switch(command_id) - { - case VIV_ID_NAV_SORT_NAME: - config_nav_sort = CONFIG_NAV_SORT_NAME; - config_nav_sort_ascending = 1; - break; - - case VIV_ID_NAV_SORT_FULL_PATH: - config_nav_sort = CONFIG_NAV_SORT_FULL_PATH_AND_FILENAME; - config_nav_sort_ascending = 1; - break; - - case VIV_ID_NAV_SORT_DATE_MODIFIED: - config_nav_sort = CONFIG_NAV_SORT_DATE_MODIFIED; - config_nav_sort_ascending = 0; - break; - - case VIV_ID_NAV_SORT_DATE_CREATED: - config_nav_sort = CONFIG_NAV_SORT_DATE_CREATED; - config_nav_sort_ascending = 0; - break; - - case VIV_ID_NAV_SORT_SIZE: - config_nav_sort = CONFIG_NAV_SORT_SIZE; - config_nav_sort_ascending = 0; - break; - } + start_fullscreen = 0; + start_window = 1; + start_maximized = 1; } - - // clear preload and last - _viv_clear_loading_preload(); - _viv_clear_preload(); - _viv_clear_last(); - - break; - - case VIV_ID_NAV_SORT_ASCENDING: - config_nav_sort_ascending = 1; - - // clear preload and last - _viv_clear_loading_preload(); - _viv_clear_preload(); - _viv_clear_last(); - - break; - - case VIV_ID_NAV_SORT_DESCENDING: - config_nav_sort_ascending = 0; - - // clear preload and last - _viv_clear_loading_preload(); - _viv_clear_preload(); - _viv_clear_last(); - - break; - - case VIV_ID_SLIDESHOW_PLAY_ONLY: - if (!_viv_is_slideshow) + else + if (string_icompare_lowercase_ascii(bufstart,"ontop") == 0) { - _viv_pause(); + _viv_command(VIV_ID_VIEW_ONTOP_ALWAYS); } - break; - - case VIV_ID_SLIDESHOW_PAUSE_ONLY: - if (_viv_is_slideshow) + else + if (string_icompare_lowercase_ascii(bufstart,"shuffle") == 0) { - _viv_pause(); + config_shuffle = 1; } - break; - - case VIV_ID_SLIDESHOW_STOP: - if (_viv_is_slideshow) + else + if (string_icompare_lowercase_ascii(bufstart,"everything") == 0) { - _viv_pause(); + p = string_get_word(p,buf,STRING_SIZE); + p = string_skip_ws(p); + + _viv_send_everything_search(0,0,0,buf); } - break; - - case VIV_ID_SLIDESHOW_PAUSE: - _viv_pause(); - break; - - case VIV_ID_SLIDESHOW_RATE_DEC: - _viv_increase_rate(1); - break; - - case VIV_ID_SLIDESHOW_RATE_INC: - _viv_increase_rate(0); - break; - - case VIV_ID_ANIMATION_PLAY_PAUSE: - _viv_animation_pause(); - break; - - case VIV_ID_ANIMATION_JUMP_FORWARD_MEDIUM: - _viv_frame_skip(config_medium_jump); - break; - - case VIV_ID_ANIMATION_JUMP_BACKWARD_MEDIUM: - _viv_frame_skip(-config_medium_jump); - break; - - case VIV_ID_ANIMATION_JUMP_FORWARD_SHORT: - _viv_frame_skip(config_short_jump); - break; - - case VIV_ID_ANIMATION_JUMP_BACKWARD_SHORT: - _viv_frame_skip(-config_short_jump); - break; - - case VIV_ID_ANIMATION_JUMP_FORWARD_LONG: - _viv_frame_skip(config_long_jump); - break; - - case VIV_ID_ANIMATION_JUMP_BACKWARD_LONG: - _viv_frame_skip(-config_long_jump); - break; - - case VIV_ID_ANIMATION_FRAME_STEP: - _viv_frame_step(); - break; - - case VIV_ID_ANIMATION_FRAME_PREV: - _viv_frame_prev(); - break; - - case VIV_ID_ANIMATION_FRAME_HOME: - _viv_frame_looped = 0; - - if (_viv_animation_play) + else + if (string_icompare_lowercase_ascii(bufstart,"random") == 0) { - _viv_animation_play = 0; + p = string_get_word(p,buf,STRING_SIZE); + p = string_skip_ws(p); + + _viv_send_everything_search(0,0,1,buf); } - - if (_viv_frame_count > 1) + else + if (string_icompare_lowercase_ascii(bufstart,"minimal") == 0) { - _viv_frame_position = 0; - _viv_animation_timer_tick_start = os_get_tick_count(); - _viv_timer_tick = 0; - - _viv_update_src_pixel(1,0); - _viv_status_update(); - - InvalidateRect(_viv_hwnd,NULL,FALSE); - UpdateWindow(_viv_hwnd); + _viv_command(VIV_ID_VIEW_PRESET_1); } - - break; - - case VIV_ID_ANIMATION_FRAME_END: - - _viv_frame_looped = 0; - - if (_viv_animation_play) + else + if (string_icompare_lowercase_ascii(bufstart,"compact") == 0) { - _viv_animation_play = 0; + _viv_command(VIV_ID_VIEW_PRESET_2); } - - if (_viv_frame_count > 1) + else + if (string_icompare_lowercase_ascii(bufstart,"x") == 0) { - _viv_frame_position = _viv_frame_loaded_count - 1; - _viv_animation_timer_tick_start = os_get_tick_count(); - _viv_timer_tick = 0; - - _viv_update_src_pixel(1,0); - _viv_status_update(); - - InvalidateRect(_viv_hwnd,NULL,FALSE); - UpdateWindow(_viv_hwnd); + p = string_get_word(p,buf,STRING_SIZE); + p = string_skip_ws(p); + + window_x = string_to_int(buf); + set_window_rect = 1; } - - break; - - case VIV_ID_ANIMATION_RATE_DEC: - _viv_increase_animation_rate(1); - break; - - case VIV_ID_ANIMATION_RATE_INC: - _viv_increase_animation_rate(0); - break; - - case VIV_ID_ANIMATION_RATE_RESET: - _viv_reset_animation_rate(); - break; - - case VIV_ID_SLIDESHOW_RATE_250: _viv_set_rate(250); break; - case VIV_ID_SLIDESHOW_RATE_500: _viv_set_rate(500); break; - case VIV_ID_SLIDESHOW_RATE_1000: _viv_set_rate(1000); break; - case VIV_ID_SLIDESHOW_RATE_2000: _viv_set_rate(2000); break; - case VIV_ID_SLIDESHOW_RATE_3000: _viv_set_rate(3000); break; - case VIV_ID_SLIDESHOW_RATE_4000: _viv_set_rate(4000); break; - case VIV_ID_SLIDESHOW_RATE_5000: _viv_set_rate(5000); break; - case VIV_ID_SLIDESHOW_RATE_6000: _viv_set_rate(6000); break; - case VIV_ID_SLIDESHOW_RATE_7000: _viv_set_rate(7000); break; - case VIV_ID_SLIDESHOW_RATE_8000: _viv_set_rate(8000); break; - case VIV_ID_SLIDESHOW_RATE_9000: _viv_set_rate(9000); break; - case VIV_ID_SLIDESHOW_RATE_10000: _viv_set_rate(10000); break; - case VIV_ID_SLIDESHOW_RATE_20000: _viv_set_rate(20000); break; - case VIV_ID_SLIDESHOW_RATE_30000: _viv_set_rate(30000); break; - case VIV_ID_SLIDESHOW_RATE_40000: _viv_set_rate(40000); break; - case VIV_ID_SLIDESHOW_RATE_50000: _viv_set_rate(50000); break; - case VIV_ID_SLIDESHOW_RATE_60000: _viv_set_rate(60000); break; - case VIV_ID_SLIDESHOW_RATE_CUSTOM: _viv_set_custom_rate(); break; - - case VIV_ID_VIEW_CAPTION: - config_show_caption = !config_show_caption; - _viv_update_frame(); - break; - - case VIV_ID_VIEW_THICKFRAME: - config_show_thickframe = !config_show_thickframe; - _viv_update_frame(); - break; - - case VIV_ID_VIEW_MENU: - config_show_menu = !config_show_menu; - _viv_update_frame(); - break; - - case VIV_ID_VIEW_STATUS: - config_show_status = !config_show_status; - _viv_update_frame(); - break; - - case VIV_ID_VIEW_CONTROLS: - config_show_controls = !config_show_controls; - _viv_update_frame(); - break; - - case VIV_ID_VIEW_PRESET_1: - config_show_menu = 0; - config_show_status = 0; - config_show_controls = 0; - config_show_caption = 0; - config_show_thickframe = 0; - _viv_update_frame(); - break; - - case VIV_ID_VIEW_PRESET_2: - config_show_menu = 0; - config_show_status = 0; - config_show_controls = 0; - config_show_caption = 0; - config_show_thickframe = 1; - _viv_update_frame(); - break; - - case VIV_ID_VIEW_PRESET_3: - config_show_menu = 1; - config_show_status = 1; - config_show_controls = 1; - config_show_caption = 1; - config_show_thickframe = 1; - _viv_update_frame(); - break; - - case VIV_ID_VIEW_REFRESH: - _viv_refresh(); - break; - - case VIV_ID_VIEW_ALLOW_SHRINKING: - _viv_1to1 = 0; - config_allow_shrinking = !config_allow_shrinking; - - _viv_on_size(); - InvalidateRect(_viv_hwnd,0,FALSE); - - break; - - case VIV_ID_VIEW_KEEP_ASPECT_RATIO: - _viv_1to1 = 0; - config_keep_aspect_ratio = !config_keep_aspect_ratio; - - _viv_on_size(); - InvalidateRect(_viv_hwnd,0,FALSE); - break; - - case VIV_ID_VIEW_FILL_WINDOW: - - _viv_1to1 = 0; - if (_viv_is_fullscreen) + else + if (string_icompare_lowercase_ascii(bufstart,"y") == 0) { - config_fullscreen_fill_window = !config_fullscreen_fill_window; - } + p = string_get_word(p,buf,STRING_SIZE); + p = string_skip_ws(p); + + window_y = string_to_int(buf); + set_window_rect = 1; + } else + if (string_icompare_lowercase_ascii(bufstart,"width") == 0) { - config_fill_window = !config_fill_window; + p = string_get_word(p,buf,STRING_SIZE); + p = string_skip_ws(p); + + window_wide = string_to_int(buf); + set_window_rect = 1; } - - _viv_on_size(); - InvalidateRect(_viv_hwnd,0,FALSE); - break; - - case VIV_ID_VIEW_FULLSCREEN: - - _viv_toggle_fullscreen(); - break; - - case VIV_ID_VIEW_1TO1: - _viv_view_1to1(); - break; - - case VIV_ID_VIEW_BESTFIT: - _viv_zoom_pos = 0; - _viv_1to1 = 0; - _viv_view_set(0,0,1); - InvalidateRect(_viv_hwnd,0,FALSE); - break; - - case VIV_ID_VIEW_SLIDESHOW: - - _viv_slideshow(); - - break; - - case VIV_ID_VIEW_WINDOW_SIZE_50: - case VIV_ID_VIEW_WINDOW_SIZE_100: - case VIV_ID_VIEW_WINDOW_SIZE_200: - case VIV_ID_VIEW_WINDOW_SIZE_AUTO_FIT: - if (_viv_is_fullscreen) - { - _viv_toggle_fullscreen(); - } - - // get out of fullscreen mode. - if (_viv_is_window_maximized(_viv_hwnd)) - { - ShowWindow(_viv_hwnd,SW_RESTORE); - } - - if (((_viv_image_wide) && (_viv_image_high)) || (command_id == VIV_ID_VIEW_WINDOW_SIZE_AUTO_FIT)) - { - RECT rect; - int wide; - int high; - int client_wide; - int client_high; - int midx; - int midy; - RECT monitor_rect; - RECT window_rect; - RECT client_rect; - - - GetWindowRect(_viv_hwnd,&rect); - midx = (rect.left + rect.right) / 2; - midy = (rect.top + rect.bottom) / 2; - - rect.left = 0; - rect.top = 0; - - switch(command_id) - { - case VIV_ID_VIEW_WINDOW_SIZE_50: - rect.right = _viv_image_wide / 2; - rect.bottom = _viv_image_high / 2; - break; - - case VIV_ID_VIEW_WINDOW_SIZE_100: - rect.right = _viv_image_wide; - rect.bottom = _viv_image_high; - break; - - case VIV_ID_VIEW_WINDOW_SIZE_200: - rect.right = _viv_image_wide * 2; - rect.bottom = _viv_image_high * 2; - break; - - case VIV_ID_VIEW_WINDOW_SIZE_AUTO_FIT: - - // use full screen to calculate auto-fit size. - os_MonitorRectFromWindow(_viv_hwnd,1,&monitor_rect); - - if (config_auto_fit_wide_div) - { - rect.right = ((monitor_rect.right - monitor_rect.left) * config_auto_fit_wide_mul) / config_auto_fit_wide_div; - } - - if (config_auto_fit_high_div) - { - rect.bottom = ((monitor_rect.bottom - monitor_rect.top) * config_auto_fit_high_mul) / config_auto_fit_high_div; - } - - break; - } - - client_wide = rect.right - rect.left; - client_high = rect.bottom - rect.top + _viv_get_status_high() + _viv_get_controls_high(); - - AdjustWindowRect(&rect,GetWindowStyle(_viv_hwnd),GetMenu(_viv_hwnd) ? TRUE : FALSE); - -debug_printf("%d %d | %d %d %d %d\n",midx,midy,rect.left,rect.top,rect.right,rect.bottom); - - wide = rect.right - rect.left; - high = rect.bottom - rect.top + _viv_get_status_high() + _viv_get_controls_high(); - - os_MonitorRectFromWindow(_viv_hwnd,0,&monitor_rect); - - if (wide > monitor_rect.right - monitor_rect.left) - { - wide = monitor_rect.right - monitor_rect.left; - } - - if (high > monitor_rect.bottom - monitor_rect.top) - { - high = monitor_rect.bottom - monitor_rect.top; - } - - rect.left = midx - (wide / 2); - rect.top = midy - (high / 2); - rect.right = midx - (wide / 2) + wide; - rect.bottom = midy - (high / 2) + high; - - os_make_rect_completely_visible(_viv_hwnd,&rect); - -debug_printf("SWP %d %d %d %d\n",rect.left,rect.top,rect.right - rect.left,rect.bottom - rect.top); - - // filling the window with White before SetWindowPos prevents garbage from showing. - // the white flash is worse than the garbage. - SetWindowPos(_viv_hwnd,0,rect.left,rect.top,rect.right - rect.left,rect.bottom - rect.top,SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOCOPYBITS); - - // re-get the window size. - GetWindowRect(_viv_hwnd,&window_rect); - - if ((window_rect.right - window_rect.left > wide) || (window_rect.bottom - window_rect.top > high)) - { - // window is larger than requested. - // reposition with new width/height. - wide = window_rect.right - window_rect.left; - high = window_rect.bottom - window_rect.top; - - rect.left = midx - (wide / 2); - rect.top = midy - (high / 2); - rect.right = midx - (wide / 2) + wide; - rect.bottom = midy - (high / 2) + high; - - os_make_rect_completely_visible(_viv_hwnd,&rect); - - debug_printf("SWP2 %d %d %d %d\n",rect.left,rect.top,rect.right - rect.left,rect.bottom - rect.top) ; - - SetWindowPos(_viv_hwnd,0,rect.left,rect.top,rect.right - rect.left,rect.bottom - rect.top,SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOCOPYBITS); - - // re-get the window size. - GetWindowRect(_viv_hwnd,&window_rect); - } - - // re-get the client rect. - - GetClientRect(_viv_hwnd,&client_rect); - - if ((client_wide > client_rect.right - client_rect.left) || (client_high > client_rect.bottom - client_rect.top)) - { - // client rect is too small, adjust... - wide = (window_rect.right - window_rect.left); - high = (window_rect.bottom - window_rect.top); - - if (client_wide > client_rect.right - client_rect.left) - { - wide += client_wide - (client_rect.right - client_rect.left); - } - - if (client_high > client_rect.bottom - client_rect.top) - { - high += client_high - (client_rect.bottom - client_rect.top); - } - - rect.left = midx - (wide / 2); - rect.top = midy - (high / 2); - rect.right = midx - (wide / 2) + wide; - rect.bottom = midy - (high / 2) + high; - - os_make_rect_completely_visible(_viv_hwnd,&rect); - - // avoid the 2nd SetWindowPos call if nothing changes. - if ((rect.left != window_rect.left) || (rect.top != window_rect.top) || (rect.right != window_rect.right) || (rect.bottom != window_rect.bottom)) - { - //SWP3 0 0 3174 5113 - debug_printf("SWP3 %d %d %d %d\n",rect.left,rect.top,rect.right - rect.left,rect.bottom - rect.top) ; - - SetWindowPos(_viv_hwnd,0,rect.left,rect.top,rect.right - rect.left,rect.bottom - rect.top,SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOCOPYBITS); - } - } - } - break; - - case VIV_ID_VIEW_PANSCAN_INCREASE_SIZE: - _viv_dst_zoom_set(_viv_dst_zoom_x_pos + 1,_viv_dst_zoom_y_pos + 1); - break; - - case VIV_ID_VIEW_PANSCAN_DECREASE_SIZE: - _viv_dst_zoom_set(_viv_dst_zoom_x_pos - 1,_viv_dst_zoom_y_pos - 1); - break; - - case VIV_ID_VIEW_PANSCAN_INCREASE_WIDTH: - _viv_dst_zoom_set(_viv_dst_zoom_x_pos + 1,_viv_dst_zoom_y_pos); - break; - - case VIV_ID_VIEW_PANSCAN_DECREASE_WIDTH: - _viv_dst_zoom_set(_viv_dst_zoom_x_pos - 1,_viv_dst_zoom_y_pos); - break; - - case VIV_ID_VIEW_PANSCAN_INCREASE_HEIGHT: - _viv_dst_zoom_set(_viv_dst_zoom_x_pos,_viv_dst_zoom_y_pos + 1); - break; - - case VIV_ID_VIEW_PANSCAN_DECREASE_HEIGHT: - _viv_dst_zoom_set(_viv_dst_zoom_x_pos,_viv_dst_zoom_y_pos - 1); - break; - - case VIV_ID_VIEW_PANSCAN_MOVE_RIGHT: - _viv_dst_pos_set(_viv_dst_pos_x + 5,_viv_dst_pos_y); - break; - - case VIV_ID_VIEW_PANSCAN_MOVE_LEFT: - _viv_dst_pos_set(_viv_dst_pos_x - 5,_viv_dst_pos_y); - break; - - case VIV_ID_VIEW_PANSCAN_MOVE_UP: - _viv_dst_pos_set(_viv_dst_pos_x,_viv_dst_pos_y - 5); - break; - - case VIV_ID_VIEW_PANSCAN_MOVE_DOWN: - _viv_dst_pos_set(_viv_dst_pos_x,_viv_dst_pos_y + 5); - break; - - case VIV_ID_VIEW_PANSCAN_MOVE_UP_LEFT: - _viv_dst_pos_set(_viv_dst_pos_x - 5,_viv_dst_pos_y - 5); - break; - - case VIV_ID_VIEW_PANSCAN_MOVE_UP_RIGHT: - _viv_dst_pos_set(_viv_dst_pos_x + 5,_viv_dst_pos_y - 5); - break; - - case VIV_ID_VIEW_PANSCAN_MOVE_DOWN_LEFT: - _viv_dst_pos_set(_viv_dst_pos_x - 5,_viv_dst_pos_y + 5); - break; - - case VIV_ID_VIEW_PANSCAN_MOVE_DOWN_RIGHT: - _viv_dst_pos_set(_viv_dst_pos_x + 5,_viv_dst_pos_y + 5); - break; - - case VIV_ID_VIEW_PANSCAN_MOVE_CENTER: - _viv_dst_pos_x = 500; - _viv_dst_pos_y = 500; - InvalidateRect(_viv_hwnd,NULL,FALSE); - _viv_status_update_temp_pos_zoom(); - break; - - case VIV_ID_VIEW_PANSCAN_RESET: - _viv_dst_pos_x = 500; - _viv_dst_pos_y = 500; - InvalidateRect(_viv_hwnd,NULL,FALSE); - _viv_dst_zoom_set(_VIV_DST_ZOOM_ONE,_VIV_DST_ZOOM_ONE); - break; - - case VIV_ID_VIEW_ONTOP_ALWAYS: - config_ontop = !config_ontop; - _viv_update_ontop(); - break; - - case VIV_ID_VIEW_ONTOP_WHILE_PLAYING_OR_ANIMATING: - config_ontop = 2; - _viv_update_ontop(); - break; - - case VIV_ID_VIEW_ONTOP_NEVER: - config_ontop = 0; - _viv_update_ontop(); - break; - - case VIV_ID_VIEW_OPTIONS: - _viv_options(); - break; - - case VIV_ID_EDIT_COPY: - _viv_copy(0); - break; - - case VIV_ID_EDIT_COPY_FILENAME: - _viv_copy_filename(); - break; - - case VIV_ID_EDIT_COPY_IMAGE: - _viv_copy_image(); - break; - - case VIV_ID_EDIT_PASTE: - SendMessage(_viv_hwnd,WM_PASTE,0,0); - break; - - case VIV_ID_EDIT_CUT: - _viv_copy(1); - break; - - case VIV_ID_FILE_OPEN_FILE: - case VIV_ID_FILE_ADD_FILE: - { - OPENFILENAME ofn; - wchar_t tobuf[STRING_SIZE+1]; - wchar_t filter_wbuf[STRING_SIZE]; - wchar_t title_wbuf[STRING_SIZE]; - - os_zero_memory(&ofn,sizeof(OPENFILENAME)); - - string_copy(tobuf,_viv_last_open_file ? _viv_last_open_file : L""); - - string_printf(filter_wbuf,"%s (*.bmp;*.gif;*.ico;*.jpeg;*.jpg;*.png;*.tif;*.tiff;*.webp)%c*.bmp;*.gif;*.ico;*.jpeg;*.jpg;*.png;*.tif;*.tiff;*.webp%c%s (*.*)%c*.*%c",localization_get_string(LOCALIZATION_ID_OPEN_ALL_IMAGE_FILES),0,0,localization_get_string(LOCALIZATION_ID_OPEN_ALL_FILES),0,0); - - string_copy_utf8_string(title_wbuf,localization_get_string(LOCALIZATION_ID_OPEN_IMAGE_CAPTION)); - - ofn.lStructSize = sizeof(OPENFILENAME); - ofn.hwndOwner = _viv_hwnd; - ofn.hInstance = os_hinstance; - ofn.lpstrFilter = filter_wbuf; - ofn.nFilterIndex = 1; - ofn.lpstrFile = tobuf; - ofn.nMaxFile = STRING_SIZE; - ofn.lpstrTitle = title_wbuf; - ofn.Flags = OFN_ENABLESIZING | OFN_NOCHANGEDIR; - - if (GetOpenFileName(&ofn)) - { - if (_viv_random) - { - mem_free(_viv_random); - - _viv_random = 0; - } - - if (command_id == VIV_ID_FILE_OPEN_FILE) - { - _viv_playlist_clearall(); - - _viv_open_from_filename(ofn.lpstrFile); - } - else - { - // add current? - _viv_playlist_add_current_if_empty(); - - _viv_playlist_add_filename(ofn.lpstrFile); - } - - if (_viv_last_open_file) - { - mem_free(_viv_last_open_file); - } - - _viv_last_open_file = string_alloc(ofn.lpstrFile); - } - } - break; - - case VIV_ID_FILE_OPEN_FOLDER: - case VIV_ID_FILE_ADD_FOLDER: - - { - wchar_t filename[STRING_SIZE]; - - string_copy(filename,_viv_last_open_folder ? _viv_last_open_folder : L""); - - if (os_browse_for_folder(_viv_hwnd,filename)) - { - if (_viv_random) - { - mem_free(_viv_random); - - _viv_random = 0; - } - - if (command_id == VIV_ID_FILE_OPEN_FOLDER) - { - _viv_playlist_clearall(); - } - else - { - _viv_playlist_add_current_if_empty(); - } - - _viv_playlist_add_path(filename); - - if (_viv_last_open_folder) - { - mem_free(_viv_last_open_folder); - } - - _viv_last_open_folder = string_alloc(filename); - - if (command_id == VIV_ID_FILE_OPEN_FOLDER) - { - _viv_home(0,0); - } - } - } - - break; - - case VIV_ID_FILE_DELETE: - _viv_delete((GetKeyState(VK_SHIFT) < 0) ? 1 : 0); - break; - - case VIV_ID_FILE_DELETE_RECYCLE: - _viv_delete(0); - break; - - case VIV_ID_FILE_DELETE_PERMANENTLY: - _viv_delete(1); - break; - - case VIV_ID_FILE_RENAME: - _viv_rename(); - break; - - case VIV_ID_NAV_JUMPTO: - _viv_show_jumpto(); - break; - - case VIV_ID_FILE_PREVIEW: - _viv_file_preview(); - break; - - case VIV_ID_FILE_PRINT: - _viv_file_print(); - break; - - case VIV_ID_FILE_SET_DESKTOP_WALLPAPER: - _viv_file_set_desktop_wallpaper(); - break; - - case VIV_ID_EDIT_ROTATE_270: - _viv_edit_rotate(1); - break; - - case VIV_ID_EDIT_ROTATE_90: - _viv_edit_rotate(0); - break; - - case VIV_ID_FILE_CLOSE: - _viv_blank(); - break; - - case VIV_ID_FILE_EDIT: - _viv_file_edit(); - break; - - case VIV_ID_FILE_OPEN_FILE_LOCATION: - _viv_open_file_location(); - break; - - case VIV_ID_FILE_OPEN_EVERYTHING_SEARCH: - _viv_search_everything(0); - break; - - case VIV_ID_FILE_ADD_EVERYTHING_SEARCH: - _viv_search_everything(1); - break; - - case VIV_ID_FILE_PROPERTIES: - _viv_properties(); - break; - - case VIV_ID_EDIT_COPY_TO: - case VIV_ID_EDIT_MOVE_TO: - { - if (*_viv_current_fd->cFileName) - { - OPENFILENAME ofn; - wchar_t tobuf[STRING_SIZE+1]; - wchar_t filter_wbuf[STRING_SIZE]; - wchar_t title_wbuf[STRING_SIZE]; - - os_zero_memory(&ofn,sizeof(OPENFILENAME)); - - string_copy(tobuf,_viv_current_fd->cFileName); - - string_printf(filter_wbuf,"%s (*.*)%c*.*%c",localization_get_string(LOCALIZATION_ID_OPEN_ALL_FILES),0,0); - - string_copy_utf8_string(title_wbuf,localization_get_string(command_id == VIV_ID_EDIT_COPY_TO ? LOCALIZATION_ID_COPY_TO_CAPTION : LOCALIZATION_ID_MOVE_TO_CAPTION)); - - ofn.lStructSize = sizeof(OPENFILENAME); - ofn.hwndOwner = _viv_hwnd; - ofn.hInstance = os_hinstance; - ofn.lpstrFilter = filter_wbuf; - ofn.nFilterIndex = 1; - ofn.lpstrFile = tobuf; - ofn.nMaxFile = STRING_SIZE; - ofn.lpstrTitle = title_wbuf; - ofn.Flags = OFN_ENABLESIZING | OFN_OVERWRITEPROMPT | OFN_NOCHANGEDIR; - - if (GetSaveFileName(&ofn)) - { - SHFILEOPSTRUCT shfileop; - wchar_t frombuf[STRING_SIZE+1]; - - tobuf[string_get_length(tobuf) + 1] = 0; - - os_zero_memory(&shfileop,sizeof(SHFILEOPSTRUCT)); - - string_copy(frombuf,_viv_current_fd->cFileName); - frombuf[string_get_length(frombuf) + 1] = 0; - - shfileop.hwnd = _viv_hwnd; - shfileop.wFunc = command_id == VIV_ID_EDIT_COPY_TO ? FO_COPY : FO_MOVE; - shfileop.pFrom = frombuf; - shfileop.pTo = tobuf; - shfileop.fFlags = FOF_ALLOWUNDO; - - SHFileOperation(&shfileop); - } - } - - break; - } - } -} - -static void _viv_exit(void) -{ - _viv_load_image_terminate = 1; - config_save_settings(config_appdata); - PostQuitMessage(0); -} - -static LRESULT CALLBACK _viv_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) -{ - switch (msg) - { - case WM_NCHITTEST: - - if (!_viv_is_fullscreen) - { - if (DefWindowProc(hwnd,msg,wParam,lParam) == HTCLIENT) - { - if (!config_show_thickframe) - { - int x; - int y; - RECT rect; - - GetWindowRect(hwnd,&rect); - - x = GET_X_LPARAM(lParam); - y = GET_Y_LPARAM(lParam); - - if (x < rect.left + GetSystemMetrics(SM_CXSIZEFRAME)) - { - if (y < rect.top + GetSystemMetrics(SM_CYSIZEFRAME)) - { - return HTTOPLEFT; - } - if (y > rect.bottom - GetSystemMetrics(SM_CYSIZEFRAME)) - { - return HTBOTTOMLEFT; - } - - return HTLEFT; - } - else - if (x > rect.right - GetSystemMetrics(SM_CXSIZEFRAME)) - { - if (y < rect.top + GetSystemMetrics(SM_CYSIZEFRAME)) - { - return HTTOPRIGHT; - } - if (y > rect.bottom - GetSystemMetrics(SM_CYSIZEFRAME)) - { - return HTBOTTOMRIGHT; - } - - return HTRIGHT; - } - else - if (y < rect.top + GetSystemMetrics(SM_CYSIZEFRAME)) - { - if (x < rect.left + GetSystemMetrics(SM_CXSIZEFRAME) + GetSystemMetrics(SM_CXSIZEFRAME)) - { - return HTTOPLEFT; - } - if (x > rect.right - GetSystemMetrics(SM_CXSIZEFRAME) - GetSystemMetrics(SM_CXSIZEFRAME)) - { - return HTTOPRIGHT; - } - - return HTTOP; - } - if (y > rect.bottom - GetSystemMetrics(SM_CYSIZEFRAME)) - { - if (x < rect.left + GetSystemMetrics(SM_CXSIZEFRAME) + GetSystemMetrics(SM_CXSIZEFRAME)) - { - return HTBOTTOMLEFT; - } - if (x > rect.right - GetSystemMetrics(SM_CXSIZEFRAME) - GetSystemMetrics(SM_CXSIZEFRAME)) - { - return HTBOTTOMRIGHT; - } - - return HTBOTTOM; - } - } - } - } - - break; - - case WM_NCLBUTTONDOWN: - - if (config_toolbar_move_window) - { - if (wParam == HTMENU) - { - HMENU hmenu; - - hmenu = GetMenu(hwnd); - - if (hmenu) - { - POINT pt; - - pt.x = GET_X_LPARAM(lParam); - pt.y = GET_Y_LPARAM(lParam); - - if (MenuItemFromPoint(hwnd,hmenu,pt) == -1) - { - _viv_start_move_window(); - - return 0; - } - } - } - } - - if (!_viv_is_fullscreen) - { - if (!config_show_thickframe) - { - DWORD flag; - - flag = 0; - - switch(wParam) - { - case HTTOP: - flag = WMSZ_TOP; - break; - case HTTOPLEFT: - flag = WMSZ_TOPLEFT; - break; - case HTTOPRIGHT: - flag = WMSZ_TOPRIGHT; - break; - case HTLEFT: - flag = WMSZ_LEFT; - break; - case HTRIGHT: - flag = WMSZ_RIGHT; - break; - case HTBOTTOM: - flag = WMSZ_BOTTOM; - break; - case HTBOTTOMLEFT: - flag = WMSZ_BOTTOMLEFT; - break; - case HTBOTTOMRIGHT: - flag = WMSZ_BOTTOMRIGHT; - break; - } - - if (flag) - { - PostMessage(hwnd,WM_SYSCOMMAND,(SC_SIZE | flag),lParam); - return 0; - } - } - } - - break; - - case WM_DESTROY: - // don't free the menu again. - _viv_hmenu = 0; - break; - - case WM_QUERYENDSESSION: - return TRUE; - - case WM_ENDSESSION: - if (wParam) - { - // save settings on logout. - config_save_settings(config_appdata); - } - return 0; - - case _VIV_WM_RETRY_RANDOM_EVERYTHING_SEARCH: - _viv_send_random_everything_search(); - break; - - case _VIV_WM_REPLY: - { - _viv_reply_t *e; - - EnterCriticalSection(&_viv_cs); - e = _viv_reply_start; - _viv_reply_start = 0; - _viv_reply_last = 0; - LeaveCriticalSection(&_viv_cs); - - while(e) - { - _viv_reply_t *next_e; - - next_e = e->next; - - switch(e->type) - { - case _VIV_REPLY_LOAD_IMAGE_COMPLETE: - case _VIV_REPLY_LOAD_IMAGE_FAILED: - - { - int allow_preload_next; - - allow_preload_next = 0; - - debug_printf((e->type == _VIV_REPLY_LOAD_IMAGE_FAILED) ? "_VIV_REPLY_LOAD_IMAGE_FAILED\n" : "_VIV_REPLY_LOAD_IMAGE_COMPLETE\n"); - - if (_viv_load_image_terminate) - { - debug_printf("LOADED/FAILED TERMINATE\n"); - // do nothing. - // let terminator handle it. - } - else - { - if (_viv_load_is_preload) - { - if (e->type == _VIV_REPLY_LOAD_IMAGE_FAILED) - { - if (_viv_should_activate_preload_on_load) - { - // preload next below.. - allow_preload_next = 1; - - _viv_load_failed = 1; - _viv_clear(); - _viv_start_first_frame(); - _viv_process_pending_clear(); - - // we update status below. - } - - _viv_preload_state = 2; - } - else - { - if (_viv_should_activate_preload_on_load) - { - // preload next below.. - allow_preload_next = 1; - - _viv_activate_preload(); - } - - _viv_preload_state = 1; - - // we update status below. - } - } - else - { - allow_preload_next = 1; - - if (e->type == _VIV_REPLY_LOAD_IMAGE_FAILED) - { - _viv_load_failed = 1; - _viv_clear(); - _viv_start_first_frame(); - _viv_process_pending_clear(); - - // we update status below. - } - } - } - - if (_viv_load_image_thread) - { - CloseHandle(_viv_load_image_thread); - - _viv_load_image_thread = 0; - } - - if (_viv_load_image_filename) - { - mem_free(_viv_load_image_filename); - - _viv_load_image_filename = 0; - } - - if (_viv_load_image_next_fd) - { - WIN32_FIND_DATA *fd; - - fd = _viv_load_image_next_fd; - _viv_load_image_next_fd = NULL; - -debug_printf("NEXT AFTER LOAD %S\n",fd->cFileName); - _viv_open(fd,_viv_load_image_next_is_preload); - - mem_free(fd); - } - - _viv_status_update(); - _viv_toolbar_update_buttons(); - - // preload next - if (allow_preload_next) - { - _viv_preload_next(); - } - } - - break; - - case _VIV_REPLY_LOAD_IMAGE_FIRST_FRAME: - - { - _viv_reply_load_image_first_frame_t *first_frame; - - debug_printf("_VIV_REPLY_LOAD_IMAGE_FIRST_FRAME is preload %d activate %d\n",_viv_load_is_preload,_viv_should_activate_preload_on_load); - - first_frame = (_viv_reply_load_image_first_frame_t *)(e + 1); - - // always show the first frame. - // if we check for the terminate flag and hold down right, we might never see an image. - // - // make sure we terminate the preload, otherwise it might get shown unexpectedly. - - if ((_viv_load_image_terminate) && (!_viv_load_image_allow_draw) && (!((_viv_load_is_preload) && (_viv_should_activate_preload_on_load)))) - { - debug_printf("FIRST FRAME TERMINATE\n"); - if (first_frame->frame.hbitmap) - { - DeleteObject(first_frame->frame.hbitmap); - - first_frame->frame.hbitmap = NULL; - } - - if (first_frame->frame.mipmap) - { - _viv_mipmap_free(first_frame->frame.mipmap); - - first_frame->frame.mipmap = NULL; - } - } - else - { - if ((_viv_load_is_preload) && (_viv_should_activate_preload_on_load)) - { - // _viv_should_activate_preload_on_load was set to 1 AFTER we started loading and before the first frame loaded. - // just load as normal.. - _viv_load_is_preload = 0; - _viv_status_update(); - } - - _viv_load_frame_count = 1; - - if (_viv_load_is_preload) - { - _viv_clear_preload_frames(); - - _viv_preload_image_wide = first_frame->wide; - _viv_preload_image_high = first_frame->high; - _viv_preload_frame_count = first_frame->frame_count; - - // allocate hbitmaps. - _viv_preload_frames = (_viv_frame_t *)mem_alloc(sizeof(_viv_frame_t) * _viv_preload_frame_count); - _viv_preload_frames[0].hbitmap = first_frame->frame.hbitmap; - _viv_preload_frames[0].mipmap = first_frame->frame.mipmap; - _viv_preload_frames[0].delay = first_frame->frame.delay; - - first_frame->frame.hbitmap = 0; - first_frame->frame.mipmap = NULL; - _viv_preload_frame_loaded_count = 1; - - _viv_status_update(); - } - else - { - // copy the image, not the filename. - viv_copy_current_image_to_last_image(); - - _viv_clear(); - - _viv_image_wide = first_frame->wide; - _viv_image_high = first_frame->high; - _viv_frame_count = first_frame->frame_count; - - // allocate hbitmaps. - _viv_frames = mem_alloc(sizeof(_viv_frame_t) * _viv_frame_count); - _viv_frames[0].hbitmap = first_frame->frame.hbitmap; - _viv_frames[0].mipmap = first_frame->frame.mipmap; - _viv_frames[0].delay = first_frame->frame.delay; - os_copy_memory(_viv_frame_fd,_viv_load_fd,sizeof(WIN32_FIND_DATA)); - - first_frame->frame.hbitmap = 0; - first_frame->frame.mipmap = NULL; - _viv_frame_loaded_count = 1; - - _viv_start_first_frame(); - - _viv_process_pending_clear(); - } - } - } - - break; - - case _VIV_REPLY_LOAD_IMAGE_ADDITIONAL_FRAME: - - { - _viv_frame_t *additional_frame; - - additional_frame = (_viv_frame_t *)(e + 1); - - debug_printf("_VIV_REPLY_LOAD_IMAGE_ADDITIONAL_FRAME %d preload %d activate %d\n",_viv_load_is_preload ? _viv_preload_frame_loaded_count : _viv_frame_loaded_count,_viv_load_is_preload,_viv_should_activate_preload_on_load); - - if ((_viv_load_image_terminate) && (!_viv_load_image_allow_draw) && (!((_viv_load_is_preload) && (_viv_should_activate_preload_on_load)))) - { - debug_printf("ADDITIONAL FRAME TERMINATE\n"); - if (additional_frame->hbitmap) - { - DeleteObject(additional_frame->hbitmap); - - additional_frame->hbitmap = NULL; - } - - if (additional_frame->mipmap) - { - _viv_mipmap_free(additional_frame->mipmap); - - additional_frame->mipmap = NULL; - } - } - else - { - if ((_viv_load_is_preload) && (_viv_should_activate_preload_on_load)) - { - // _viv_should_activate_preload_on_load was set to 1 AFTER we started loading and before the first frame loaded. - // just load as normal.. - _viv_load_is_preload = 0; - _viv_activate_preload(); - _viv_status_update(); - } - - if (_viv_load_is_preload) - { - // we could have been cleared. - if (_viv_preload_frames) - { - _viv_preload_frames[_viv_preload_frame_loaded_count].hbitmap = additional_frame->hbitmap; - _viv_preload_frames[_viv_preload_frame_loaded_count].mipmap = additional_frame->mipmap; - _viv_preload_frames[_viv_preload_frame_loaded_count].delay = additional_frame->delay; - - _viv_preload_frame_loaded_count++; - - additional_frame->hbitmap = 0; - additional_frame->mipmap = 0; - } - } - else - { - // we could have been cleared. - if (_viv_frames) - { - // make sure we check the frame count too - // incase we get an event from an old load. - if (_viv_frame_loaded_count < _viv_frame_count) - { - _viv_frames[_viv_frame_loaded_count].hbitmap = additional_frame->hbitmap; - _viv_frames[_viv_frame_loaded_count].mipmap = additional_frame->mipmap; - _viv_frames[_viv_frame_loaded_count].delay = additional_frame->delay; - - _viv_frame_loaded_count++; - - ((_viv_frame_t *)(e + 1))->hbitmap = 0; - ((_viv_frame_t *)(e + 1))->mipmap = 0; - } - } - } - - _viv_load_frame_count++; - } - } - - break; - } - - _viv_reply_free(e); - - e = next_e; - } - - break; - } - - case WM_INITMENU: - { - HMENU hmenu; - - hmenu = GetMenu(hwnd); - - _viv_check_menus(hmenu); - - break; - } - - case WM_DROPFILES: - { - wchar_t filename[STRING_SIZE]; - DWORD count; - int is_shift; - - if (_viv_random) - { - mem_free(_viv_random); - - _viv_random = 0; - } - - is_shift = (GetKeyState(VK_SHIFT) < 0); - if (is_shift) - { - // add current? - _viv_playlist_add_current_if_empty(); - } - else - { - _viv_playlist_clearall(); - } - - count = DragQueryFile((HDROP)wParam,0xFFFFFFFF,0,0); - - if ((count >= 2) || (is_shift)) - { - DWORD i; - - for(i=0;i 1) - { - if (!_viv_frame_looped) - { - _viv_is_slideshow_timeup = 1; - - break; - } - } - } - - _viv_next(0,0,0,0); - } - - break; - - case VIV_ID_HIDE_CURSOR_TIMER: - if (_viv_is_hide_cursor_timer) - { - if (!_viv_should_show_cursor()) - { - _viv_hide_cursor(); - } - } - break; - - case VIV_ID_ANIMATION_TIMER: - { - if ((_viv_is_animation_timer) && (_viv_frame_count)) - { - VIV_UINT64 elapsed; - VIV_UINT64 tick; - int invalidate; - VIV_UINT64 freq; - - invalidate = 0; - - tick = os_get_tick_count(); - freq = os_get_tick_freq(); - - elapsed = tick - _viv_animation_timer_tick_start; - _viv_animation_timer_tick_start = tick; - - // what happened? - // don't elapse more than one second at a time. - if (elapsed > freq) - { - elapsed = freq; - } - - if (_viv_animation_play) - { - DWORD frames_skipped; -//debug_printf("%p %p\n",_viv_timer_tick,elapsed) ; - - _viv_timer_tick += elapsed; - - frames_skipped = 0; - - for(;;) - { - DWORD delay; - VIV_UINT64 performance_counter_delay; - - delay = _viv_frames[_viv_frame_position].delay * (1.0f/_viv_animation_rates[_viv_animation_rate_pos]); - - if (!delay) - { - delay = 1; - } - - performance_counter_delay = (delay * freq) / 1000; - - // debug_printf("delay %d\n",delay); - - if (_viv_timer_tick >= performance_counter_delay) - { - //debug_printf("%d %d error %d %d\n",(DWORD)_viv_timer_tick,(DWORD)freq,(DWORD)(_viv_timer_tick - performance_counter_delay),(DWORD)(((_viv_timer_tick - performance_counter_delay) * 1000) / freq)); - - if (_viv_frame_loaded_count != _viv_frame_count) - { - if (_viv_frame_position + 1 >= _viv_frame_loaded_count) - { - // ignore this tick - frames_skipped++; - _viv_timer_tick = 0; - break; - } - } - - _viv_frame_position++; - if (_viv_frame_position == _viv_frame_count) - { - _viv_frame_looped = 1; - _viv_frame_position = 0; - - if (config_loop_animations_once) - { - if (_viv_is_slideshow_timeup) - { - _viv_next(0,1,0,0); - - break; - } - } - } - - if (invalidate) - { - frames_skipped++; - } - - invalidate = 1; - - _viv_timer_tick -= performance_counter_delay; - } - else - { - break; - } - } - - if (frames_skipped) - { - debug_printf("frames skipped %d\n",frames_skipped); - } - } - -//debug_printf("_viv_frame_position %u\n",_viv_frame_position); - if (invalidate) - { - _viv_update_src_pixel(1,0); - _viv_status_update(); - InvalidateRect(hwnd,0,FALSE); - - if (_viv_is_animation_paint) - { - debug_printf("paint frame dropped\n"); - } - - _viv_is_animation_paint = 1; - //UpdateWindow(hwnd); - } - } - - _viv_is_animation_timer_event = 0; - - break; - } - } - - break; - - case WM_LBUTTONDBLCLK: - - _viv_show_cursor(); - _viv_update_show_cursor(); - - // 0 = scroll, 1 = play/pause slideshow, 2 = play/pause animation, 3=zoom in, 4=next, 5=1:1 scroll - switch(config_left_click_action) - { - case 0: - case 1: - case 2: - case 5: - case 6: - _viv_toggle_fullscreen(); - break; - - default: - _viv_do_left_click_action(config_left_click_action); - break; - } - break; - - case WM_LBUTTONDOWN: - - _viv_show_cursor(); - _viv_update_show_cursor(); - - _viv_do_left_click_action(config_left_click_action); - - break; - - case WM_MBUTTONDOWN: - if (_viv_doing == _VIV_DOING_NOTHING) - { - SetCapture(hwnd); - _viv_doing = _VIV_DOING_MSCROLL; - _viv_doing_x = GET_X_LPARAM(lParam); - _viv_doing_y = GET_Y_LPARAM(lParam); - { - POINT pt; - GetCursorPos(&pt); - - _viv_mdoing_x = pt.x; - _viv_mdoing_y = pt.y; - } - ShowCursor(FALSE); - } - break; - - case WM_RBUTTONDOWN: - case WM_RBUTTONDBLCLK: - - switch(config_right_click_action) - { - case 1: - _viv_zoom_in(1,1,GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam)); - return 0; - - case 2: - _viv_next(1,1,0,0); - return 0; - } - - break; - - case WM_RBUTTONUP: - - switch(config_right_click_action) - { - case 1: - return 0; - - case 2: - return 0; - } - - break; - - case WM_CONTEXTMENU: - { - HMENU hmenu; - POINT pt; - DWORD tpm_flags; - - tpm_flags = 0; - - pt.x = GET_X_LPARAM(lParam); - pt.y = GET_Y_LPARAM(lParam); - - if ((pt.x == -1) && (pt.y == -1)) - { - RECT rect; - - GetWindowRect(hwnd,&rect); - - pt.x = (rect.right + rect.left) / 2; - pt.y = (rect.bottom + rect.top) / 2; - - tpm_flags |= TPM_VCENTERALIGN | TPM_CENTERALIGN; - } - - hmenu = CreatePopupMenu(); - - { - int i; - HMENU submenu; - HMENU curmenu; - WORD submenuid; - int was_seperator; - - submenuid = 0; - curmenu = hmenu; - was_seperator = 1; - - for(i=0;i<_VIV_CONEXT_MENU_ITEM_COUNT;i++) - { - if (_viv_context_menu_items[i] > _VIV_MENU_COUNT) - { - switch (_viv_context_menu_items[i]) - { - case VIV_ID_FILE_PREVIEW: - // this doesn't exist on Windows 8 or later. - if (os_is_windows_8_or_later()) - { - continue; - } - break; - } - - if ((_viv_context_menu_items[i] != VIV_ID_VIEW_MENU) || (!config_show_menu)) - { - int command_index; - - command_index = _viv_command_index_from_command_id(_viv_context_menu_items[i]); - - // its a command - if (command_index != -1) - { - int key_command_index; - wchar_t text_wbuf[STRING_SIZE]; - wchar_t key_text[STRING_SIZE]; - - key_command_index = command_index; - - switch(_viv_commands[command_index].command_id) - { - case VIV_ID_SLIDESHOW_PAUSE: - string_copy_utf8_string(text_wbuf,localization_get_string(LOCALIZATION_ID_PLAY_PAUSE)); - break; - - default: - string_copy_utf8_string(text_wbuf,localization_get_string(_viv_commands[command_index].localization_id)); - break; - - } - - switch (_viv_commands[command_index].command_id) - { - - case VIV_ID_FILE_DELETE: - key_command_index = _viv_command_index_from_command_id(VIV_ID_FILE_DELETE_RECYCLE); - break; - - } - - if (key_command_index >= 0) - { - if (_viv_key_list->start[key_command_index]) - { - _viv_get_key_text(key_text,_viv_key_list->start[key_command_index]->key); - - string_cat_utf8(text_wbuf,(const utf8_t *)"\t"); - string_cat(text_wbuf,key_text); - } - } - - AppendMenu(curmenu,_viv_commands[command_index].flags & (~(MF_DELETE|MF_OWNERDRAW)),_viv_commands[command_index].command_id,text_wbuf); - was_seperator = 0; - } - } - } - else - if (_viv_context_menu_items[i]) - { - if (submenuid == _viv_context_menu_items[i]) - { - // pop submenu - curmenu = hmenu; - submenuid = 0; - } - else - { - int command_index; - - command_index = _viv_command_index_from_command_id(_viv_context_menu_items[i]); - if (command_index != -1) - { - wchar_t text_wbuf[STRING_SIZE]; - - // push submenu - switch(_viv_context_menu_items[i]) - { - case _VIV_MENU_SLIDESHOW_RATE: - string_copy_utf8_string(text_wbuf,localization_get_string(LOCALIZATION_ID_RATE)); - break; - - default: - string_copy_utf8_string(text_wbuf,localization_get_string(_viv_commands[command_index].localization_id)); - break; - } - - submenuid = _viv_context_menu_items[i]; - submenu = CreatePopupMenu(); - AppendMenu(curmenu,MF_POPUP,(UINT_PTR)submenu,text_wbuf); - curmenu = submenu; - was_seperator = 0; - } - } - } - else - { - // seperator - if (!was_seperator) - { - AppendMenu(curmenu,MF_SEPARATOR,0,0); - - was_seperator = 1; - } - } - } - } - - _viv_check_menus(hmenu); - - _viv_show_cursor(); - - _viv_in_popup_menu = 1; - - TrackPopupMenu(hmenu,tpm_flags,pt.x,pt.y,0,hwnd,0); - - // start the hide cursor timer again. - _viv_in_popup_menu = 0; - _viv_update_show_cursor(); - - DestroyMenu(hmenu); - - break; - } - - case WM_ACTIVATE: - - if (wParam == WA_INACTIVE) - { - if (!_viv_prevent_on_deactivate) - { - _viv_show_cursor(); - } - } - else - { - _viv_update_show_cursor(); - } - break; - - case WM_MOUSELEAVE: - - _viv_is_tracking_mouse = 0; - _viv_is_mouseover = 0; - - _viv_mousemove_x = -1; - _viv_mousemove_y = -1; - - if ((-1 != _viv_src_pixel_x) || (-1 != _viv_src_pixel_y)) - { - _viv_src_pixel_x = -1; - _viv_src_pixel_y = -1; - - if (config_pixel_info) - { - _viv_status_update(); - } - } - - _viv_show_cursor(); -// _viv_tooltip_hide(); - _viv_update_src_pixel(0,1); - - break; - - case WM_MOUSEMOVE: - - if (!_viv_is_tracking_mouse) - { - TRACKMOUSEEVENT tme; - - // ui must come first, as TrackMouseEvent can SEND WM_MOUSELEAVE - _viv_is_tracking_mouse = 1; - - tme.cbSize = sizeof(TRACKMOUSEEVENT); - tme.dwFlags = TME_LEAVE; - tme.dwHoverTime = 0; - tme.hwndTrack = hwnd; - - _TrackMouseEvent(&tme); - } - - _viv_is_mouseover = 1; - - _viv_mousemove(); - - switch(_viv_doing) - { - case _VIV_DOING_MSCROLL: - - { - int mx; - int my; - POINT pt; - GetCursorPos(&pt); - - mx = _viv_mdoing_x - pt.x; - my = _viv_mdoing_y - pt.y; - - if ((mx) || (my)) - { - SetCursorPos(_viv_mdoing_x,_viv_mdoing_y); - } - } - - break; - - case _VIV_DOING_SCROLL: - - { - int mx; - int my; - int x; - int y; - - x = GET_X_LPARAM(lParam); - y = GET_Y_LPARAM(lParam); - - mx = x - _viv_doing_x; - my = y - _viv_doing_y; - - _viv_doing_x = x; - _viv_doing_y = y; - - if ((mx) || (my)) - { - _viv_view_scroll(mx,my); - // UpdateWindow(hwnd); - } - } - - break; - - case _VIV_DOING_1TO1SCROLL: - - _viv_update_1to1_scroll(GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam)); - - break; - } - - _viv_update_src_pixel(0,1); - - break; - - case WM_LBUTTONUP: - case WM_MBUTTONUP: - - _viv_doing_cancel(); - - break; - - case WM_MOUSEWHEEL: - { - _viv_do_mousewheel_action(_viv_get_current_key_mod_flags() == CONFIG_KEYFLAG_CTRL ? config_ctrl_mouse_wheel_action : config_mouse_wheel_action,GET_WHEEL_DELTA_WPARAM(wParam),GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam)); - - break; - } - - case WM_COPYDATA: - { - COPYDATASTRUCT *cds; - - cds = (COPYDATASTRUCT *)lParam; - - switch(cds->dwData) - { - // execute command line options - case _VIV_COPYDATA_COMMAND_LINE: - { - DWORD showcmd; - const char *p; - const char *e; - wchar_t cl[STRING_SIZE]; - - SetForegroundWindow(hwnd); - - p = (char *)cds->lpData; - e = p + cds->cbData; - - // is there a show command ? - if (e-p >= sizeof(DWORD)) - { - wchar_t cwd[STRING_SIZE]; - - showcmd = *(DWORD *)p; - p += sizeof(DWORD); - - p = _viv_get_copydata_string(p,e,cl,STRING_SIZE); - p = _viv_get_copydata_string(p,e,cwd,STRING_SIZE); - - debug_printf("set cwd %S\n",cwd); - SetCurrentDirectory(cwd); - - _viv_process_command_line(cl); - - ShowWindow(hwnd,showcmd); - } - - return 1; - } - - // Everything reply - case _VIV_COPYDATA_RANDOM_EVERYTHING_SEARCH: - { - EVERYTHING_IPC_ITEM2 *items; - - debug_printf("%d / %d results\n",((EVERYTHING_IPC_LIST2 *)cds->lpData)->numitems,((EVERYTHING_IPC_LIST2 *)cds->lpData)->totitems); - - items = (EVERYTHING_IPC_ITEM2 *)(((EVERYTHING_IPC_LIST2 *)cds->lpData) + 1); - - if (((EVERYTHING_IPC_LIST2 *)cds->lpData)->numitems) - { - if (items[0].flags & EVERYTHING_IPC_FOLDER) - { - // add this folder ? -// _viv_playlist_add_path(full_path_and_filename); - } - else - { - DWORD filename_len; - char *p; - - // EVERYTHING_IPC_QUERY2_REQUEST_FULL_PATH_AND_NAME - p = ((char *)cds->lpData) + items[0].data_offset; - - filename_len = *(DWORD *)p; - if (filename_len < MAX_PATH) - { - WIN32_FIND_DATA fd; - - p += sizeof(DWORD); - - os_zero_memory(&fd,sizeof(WIN32_FIND_DATA)); - - os_copy_memory(fd.cFileName,(wchar_t *)p,filename_len * sizeof(wchar_t)); - fd.cFileName[filename_len] = 0; - - if (_viv_is_valid_filename(&fd)) - { - p += (filename_len + 1) * sizeof(wchar_t); - - // EVERYTHING_IPC_QUERY2_REQUEST_SIZE - if (_viv_everything_request_flags & EVERYTHING_IPC_QUERY2_REQUEST_SIZE) - { - fd.nFileSizeLow = *(DWORD *)p; - p += sizeof(DWORD); - fd.nFileSizeHigh = *(DWORD *)p; - p += sizeof(DWORD); - } - - // EVERYTHING_IPC_QUERY2_REQUEST_DATE_CREATED - if (_viv_everything_request_flags & EVERYTHING_IPC_QUERY2_REQUEST_DATE_CREATED) - { - fd.ftCreationTime.dwLowDateTime = *(DWORD *)p; - p += sizeof(DWORD); - fd.ftCreationTime.dwHighDateTime = *(DWORD *)p; - p += sizeof(DWORD); - } - - // EVERYTHING_IPC_QUERY2_REQUEST_DATE_MODIFIED - if (_viv_everything_request_flags & EVERYTHING_IPC_QUERY2_REQUEST_DATE_MODIFIED) - { - fd.ftLastWriteTime.dwLowDateTime = *(DWORD *)p; - p += sizeof(DWORD); - fd.ftLastWriteTime.dwHighDateTime = *(DWORD *)p; - p += sizeof(DWORD); - } - - _viv_open(&fd,0); - } - } - } - } - else - if (((EVERYTHING_IPC_LIST2 *)cds->lpData)->totitems) - { - // our random index was too high, try again. - _viv_random_tot_results = ((EVERYTHING_IPC_LIST2 *)cds->lpData)->totitems; - - PostMessage(hwnd,_VIV_WM_RETRY_RANDOM_EVERYTHING_SEARCH,0,0); - } - - break; - } - - // Everything reply - case _VIV_COPYDATA_OPEN_EVERYTHING_SEARCH: - case _VIV_COPYDATA_ADD_EVERYTHING_SEARCH: - { - DWORD i; - EVERYTHING_IPC_ITEM2 *items; - - if (_viv_random) - { - mem_free(_viv_random); - - _viv_random = 0; - } - - if (cds->dwData == _VIV_COPYDATA_OPEN_EVERYTHING_SEARCH) - { - _viv_playlist_clearall(); - } - else - { - _viv_playlist_add_current_if_empty(); - } - - debug_printf("%d / %d results\n",((EVERYTHING_IPC_LIST2 *)cds->lpData)->numitems,((EVERYTHING_IPC_LIST2 *)cds->lpData)->totitems); - - items = (EVERYTHING_IPC_ITEM2 *)(((EVERYTHING_IPC_LIST2 *)cds->lpData) + 1); - - for(i=0;i<((EVERYTHING_IPC_LIST2 *)cds->lpData)->numitems;i++) - { - if (items[i].flags & EVERYTHING_IPC_FOLDER) - { - // add this folder ? -// _viv_playlist_add_path(full_path_and_filename); - } - else - { - DWORD filename_len; - char *p; - - // EVERYTHING_IPC_QUERY2_REQUEST_FULL_PATH_AND_NAME - p = ((char *)cds->lpData) + items[i].data_offset; - - filename_len = *(DWORD *)p; - if (filename_len < MAX_PATH) - { - WIN32_FIND_DATA fd; - - p += sizeof(DWORD); - - os_zero_memory(&fd,sizeof(WIN32_FIND_DATA)); - - os_copy_memory(fd.cFileName,(wchar_t *)p,filename_len * sizeof(wchar_t)); - fd.cFileName[filename_len] = 0; - - if (_viv_is_valid_filename(&fd)) - { - p += (filename_len + 1) * sizeof(wchar_t); - - // EVERYTHING_IPC_QUERY2_REQUEST_SIZE - if (_viv_everything_request_flags & EVERYTHING_IPC_QUERY2_REQUEST_SIZE) - { - fd.nFileSizeLow = *(DWORD *)p; - p += sizeof(DWORD); - fd.nFileSizeHigh = *(DWORD *)p; - p += sizeof(DWORD); - } - - // EVERYTHING_IPC_QUERY2_REQUEST_DATE_CREATED - if (_viv_everything_request_flags & EVERYTHING_IPC_QUERY2_REQUEST_DATE_CREATED) - { - fd.ftCreationTime.dwLowDateTime = *(DWORD *)p; - p += sizeof(DWORD); - fd.ftCreationTime.dwHighDateTime = *(DWORD *)p; - p += sizeof(DWORD); - } - - // EVERYTHING_IPC_QUERY2_REQUEST_DATE_MODIFIED - if (_viv_everything_request_flags & EVERYTHING_IPC_QUERY2_REQUEST_DATE_MODIFIED) - { - fd.ftLastWriteTime.dwLowDateTime = *(DWORD *)p; - p += sizeof(DWORD); - fd.ftLastWriteTime.dwHighDateTime = *(DWORD *)p; - p += sizeof(DWORD); - } - - _viv_playlist_add(&fd); - } - } - } - } - - if (cds->dwData == _VIV_COPYDATA_OPEN_EVERYTHING_SEARCH) - { - _viv_home(0,0); - } - - break; - } - } - - break; - } - - case WM_CLOSE: - _viv_exit(); - return 0; - - case WM_SYSCOMMAND: - - switch(wParam) - { - case SC_MONITORPOWER: - case SC_SCREENSAVE: - - // prevent sleep / monitor power off. - - if (config_prevent_sleep) - { - if (_viv_is_slideshow) - { - return 0; - } - - if (_viv_is_animation_timer) - { - if (_viv_animation_play) - { - return 0; - } - } - } - - break; - } - break; - - case WM_SIZE: - - _viv_on_size(); - - break; - - case WM_MOVE: - { - if (!IsIconic(hwnd)) - { - if (!IsMaximized(hwnd)) - { - if (!_viv_is_fullscreen) - { - RECT rect; - - GetWindowRect(hwnd,&rect); - - config_x = rect.left; - config_y = rect.top; - } - } - } - - break; - } - - case WM_NOTIFY: - - switch(((NMHDR *)lParam)->idFrom) - { - case VIV_ID_STATUS: - - if (_viv_status_hwnd) - { - - switch(((NMHDR *)lParam)->code) - { - case NM_CLICK: - { - int item; - - item = ((NMMOUSE *)lParam)->dwItemSpec; - - // if we hit nothing use the last part. - if (item < 0) - { - item = (int)SendMessage(_viv_status_hwnd,SB_GETPARTS,0,0) - 1; - } - - switch(item) - { - case 1: - config_frame_minus = !config_frame_minus; - _viv_status_update(); - break; - - default: - break; - } - - break; - } - } - } - - break; - } - - break; - - case WM_COMMAND: - { - _viv_command(LOWORD(wParam)); - - break; - } - - case WM_PASTE: - - debug_printf("paste\n"); - - if (OpenClipboard(hwnd)) - { - HGLOBAL hglobal; - - // try a hdrop - hglobal = GetClipboardData(CF_HDROP); - - if (hglobal) - { - HDROP hdrop; - - hdrop = (HDROP)GlobalLock(hglobal); - if (hdrop) - { - SendMessage(hwnd,WM_DROPFILES,(WPARAM)hdrop,0); - - GlobalUnlock(hglobal); - } - } - - CloseClipboard(); - } - - break; - - case WM_PAINT: - { - RECT rect; - int wide; - int high; - PAINTSTRUCT ps; - - // paint the image. - // - // we get a list of RECTs that describe the update region. - // we only want to render inside these RECTs as they are likely to be small (scrolling) - // avoid stretching the entire image on each paint. - // - // for shrink-stretching we set a HDC user clipping rect. - // StretchBlt appears to honor this clipping RECT, the whole image is not stretched and is much faster. - // - // for magnify-stretching we use our own stretch function that avoids - // stretching the entire image. - // StretchBlt DOES NOT honor the clipping RECT when magnifying. - - GetClientRect(hwnd,&rect); - wide = rect.right - rect.left; - high = rect.bottom - rect.top - _viv_get_status_high() - _viv_get_controls_high(); - - if (BeginPaint(hwnd,&ps)) - { - HRGN update_hrgn; - - update_hrgn = os_CreateRectRgn(0,0,0,0); - - // get visible region - // this MUST be done between begin and end paint. - GetRandomRgn(ps.hdc,update_hrgn,SYSRGN); - - if (os_is_nt) - { - POINT pt; - - GetDCOrgEx(ps.hdc,&pt); - OffsetRgn(update_hrgn,-pt.x,-pt.y); - } - - // mirror - if ((os_GetLayout) && (os_GetLayout(ps.hdc) & LAYOUT_RTL)) - { - HRGN mirror_hrgn; - RECT rect; - - GetClientRect(hwnd,&rect); - - mirror_hrgn = os_mirror_region(update_hrgn,rect.right - rect.left); - - DeleteObject(update_hrgn); - - update_hrgn = mirror_hrgn; - } - -//debug_printf("WM_PAINT\n") ; - if ((wide) && (high)) - { - int rx; - int ry; - int rw; - int rh; - - rx = 0; - ry = 0; - rw = 0; - rh = 0; - - // controls. - /* - if (_viv_get_controls_high()) - { - rect.left = 0; - rect.top = high; - rect.right = wide; - rect.bottom = rect.top + _viv_get_controls_high(); - - FillRect(ps.hdc,&rect,(HBRUSH)(COLOR_WINDOW+1)); - ExcludeClipRect(ps.hdc,rect.left,rect.top,rect.right,rect.bottom); - } - */ - if (_viv_frame_count) - { - HDC mem_hdc; - - _viv_get_render_size(&rw,&rh); - - rw = (int)(rw * _viv_dst_zoom_values[_viv_dst_zoom_x_pos]); - rh = (int)(rh * _viv_dst_zoom_values[_viv_dst_zoom_y_pos]); - - #if 0 - if (_viv_zoom_pos == 1) - { - if ((rw < _viv_image_wide) || (rw < _viv_image_wide)) - { - rw = _viv_image_wide; - rh = _viv_image_high; - } - } - #endif - - rx = (((_viv_dst_pos_x - 250) * (wide*2)) / 1000) - (rw / 2) - _viv_view_x; - ry = (((_viv_dst_pos_y - 250) * (high*2)) / 1000) - (rh / 2) - _viv_view_y; - - // rh += (-dst_left_offset + dst_right_offset) * wide / 1000; - // rh += (-dst_top_offset + dst_bottom_offset) * high / 1000; - - mem_hdc = CreateCompatibleDC(ps.hdc); - if (mem_hdc) - { - HBITMAP mip_hbitmap; - int mip_wide; - int mip_high; - -debug_printf("PAINT %d %d %d\n",_viv_frame_position,rw,rh); - mip_hbitmap = _viv_get_mipmap(_viv_frames[_viv_frame_position].hbitmap,_viv_image_wide,_viv_image_high,rw,rh,&mip_wide,&mip_high,&_viv_frames[_viv_frame_position].mipmap); - - if (mip_hbitmap) - { - HGDIOBJ last_hbitmap; - - last_hbitmap = SelectObject(mem_hdc,mip_hbitmap); - - if (last_hbitmap) - { - if ((rw == mip_wide) && (rh == mip_high)) - { - if (BitBlt(ps.hdc,rx,ry,rw,rh,mem_hdc,0,0,SRCCOPY)) - { - } - else - { - debug_printf("BitBlt failed %d\n",GetLastError()); - } - } - else - { - int last_stretch_mode; - int did_set_stretch_blt_mode; - int is_halftone; - int is_mag; - - did_set_stretch_blt_mode = 0; - is_halftone = 0; - is_mag = 0; - - if ((rw >= mip_wide) && (rh >= mip_high)) - { - is_mag = 1; - } - - if ((rw < mip_wide) || (rh < mip_high)) - { - if (config_shrink_blit_mode == CONFIG_SHRINK_BLIT_MODE_HALFTONE) - { - is_halftone = 1; - last_stretch_mode = SetStretchBltMode(ps.hdc,HALFTONE); - SetBrushOrgEx(ps.hdc,-rx,-ry,NULL); - } - else - { - last_stretch_mode = SetStretchBltMode(ps.hdc,COLORONCOLOR); - } - - did_set_stretch_blt_mode = 1; - } - else - if ((rw > mip_wide) || (rh > mip_high)) - { - if (config_mag_filter == CONFIG_MAG_FILTER_HALFTONE) - { - is_halftone = 1; - last_stretch_mode = SetStretchBltMode(ps.hdc,HALFTONE); - } - else - { - last_stretch_mode = SetStretchBltMode(ps.hdc,COLORONCOLOR); - } - - did_set_stretch_blt_mode = 1; - } - - { - DWORD region_size; - - region_size = GetRegionData(update_hrgn,0,NULL); - if (region_size) - { - small_pool_t region_data_small_pool; - RGNDATA *region_data; - - small_pool_init(®ion_data_small_pool); - - region_data = small_pool_alloc(®ion_data_small_pool,region_size); - - if (GetRegionData(update_hrgn,region_size,region_data)) - { - RECT *rect_p; - DWORD rect_run; - - - // StretchBlt is REALLY SLOW when there is a complex clipping region. - // only call StretchBlt for a simple rect clipping region. - // - // this only works for halftone - // don't bother breaking down into simple rects if we are magnifying. - - rect_p = (RECT *)region_data->Buffer; - rect_run = region_data->rdh.nCount; - - while(rect_run) - { - if (is_halftone) - { - HRGN clip_hrgn; - - clip_hrgn = CreateRectRgn(rect_p->left,rect_p->top,rect_p->right,rect_p->bottom); - if (clip_hrgn) - { - if (SelectClipRgn(ps.hdc,clip_hrgn) != ERROR) - { - if (StretchBlt(ps.hdc,rx,ry,rw,rh,mem_hdc,0,0,mip_wide,mip_high,SRCCOPY)) - { - } - else - { - debug_printf("StretchBlt failed %d\n",GetLastError()); - } - } - - DeleteObject(clip_hrgn); - } - } - else - { - if (is_mag) - { - int paint_left; - int paint_right; - int paint_wide; - int paint_top; - int paint_bottom; - int paint_high; - - paint_left = rx; - paint_right = rx + rw; - paint_top = ry; - paint_bottom = ry + rh; - - if (paint_left < 0) - { - paint_left = 0; - } - - if (paint_right > wide) - { - paint_right = wide; - } - - if (paint_top < 0) - { - paint_top = 0; - } - - if (paint_bottom > high) - { - paint_bottom = high; - } - - paint_wide = paint_right - paint_left; - paint_high = paint_bottom - paint_top; - - // are we drawing the whole thing? - if ((rect_p->right - rect_p->left >= paint_wide) && (rect_p->bottom - rect_p->top >= paint_high)) - { - // if the clipping region is the full area, just use stretchblt, which is faster. - if (_viv_StretchBltStitch(ps.hdc,rx,ry,rw,rh,mem_hdc,0,0,mip_wide,mip_high,SRCCOPY,rect_p->left,rect_p->top,rect_p->right - rect_p->left,rect_p->bottom - rect_p->top)) - { - } - else - { - debug_printf("StretchBlt failed %d\n",GetLastError()); - } - } - else - { - // use our own stretch that only renders the clipping rect region. - // where-as StretchBlt ignores the clipping region and renders the entire dst region. - _viv_stretch_blt(ps.hdc,rx,ry,rw,rh,mem_hdc,mip_wide,mip_high,rect_p->left,rect_p->top,rect_p->right - rect_p->left,rect_p->bottom - rect_p->top); - } - } - else - { - if (_viv_StretchBltStitch(ps.hdc,rx,ry,rw,rh,mem_hdc,0,0,mip_wide,mip_high,SRCCOPY,rect_p->left,rect_p->top,rect_p->right - rect_p->left,rect_p->bottom - rect_p->top)) - { - } - else - { - debug_printf("StretchBlt failed %d\n",GetLastError()); - } - } - } - - rect_p++; - rect_run--; - } - - if (is_halftone) - { - SelectClipRgn(ps.hdc,NULL); - } - } - - small_pool_kill(®ion_data_small_pool); - } - } - - if (did_set_stretch_blt_mode) - { - SetStretchBltMode(ps.hdc,last_stretch_mode); - } - } - - SelectObject(mem_hdc,last_hbitmap); - } - else - { - debug_printf("SelectObject failed %d\n",GetLastError()); - } - - //ExcludeClipRect(ps.hdc,rx,ry,rx+rw,ry+rh); - } - - DeleteDC(mem_hdc); - } - else - { - debug_printf("CreateCompatibleDC failed %d\n",GetLastError()); - } - } - - { - HBRUSH hbrush; - - hbrush = CreateSolidBrush(_viv_is_fullscreen ? RGB(config_fullscreen_background_color_r,config_fullscreen_background_color_g,config_fullscreen_background_color_b) : RGB(config_windowed_background_color_r,config_windowed_background_color_g,config_windowed_background_color_b)); - - if (hbrush) - { - os_fill_clipped_rect(ps.hdc,rect.left,rect.top,rect.right - rect.left,rect.bottom - rect.top,rx,ry,rw,rh,hbrush); - - DeleteObject(hbrush); - } - } - } - - _viv_is_animation_paint = 0; - - DeleteObject(update_hrgn); - - EndPaint(hwnd,&ps); - } - else - { - debug_printf("BeginPaint failed %d\n",GetLastError()); - } - - return 0; - } - - case WM_ERASEBKGND: - return 1; - - case WM_GETMINMAXINFO: - - { - int wide; - int high; - RECT rect; - BOOL is_menu; - - wide = _viv_toolbar_get_wide(); - high = _viv_get_status_high() + _viv_get_controls_high(); - - is_menu = GetMenu(_viv_hwnd) ? TRUE : FALSE; - - rect.left = 0; - rect.top = 0; - rect.right = wide; - rect.bottom = high; - - AdjustWindowRectEx(&rect,os_get_window_style(hwnd),is_menu,os_get_window_ex_style(hwnd)); - - ((MINMAXINFO *)lParam)->ptMinTrackSize.x = rect.right - rect.left; - ((MINMAXINFO *)lParam)->ptMinTrackSize.y = rect.bottom - rect.top; - } - - break; - } - - return DefWindowProc(hwnd,msg,wParam,lParam); -} - -static int _viv_process_install_command_line_options(wchar_t *cl) -{ - wchar_t *p; - wchar_t buf[STRING_SIZE]; - DWORD install_flags; - DWORD uninstall_flags; - int appdata; - int is_runas; - wchar_t install_path[STRING_SIZE]; - wchar_t install_options[STRING_SIZE]; - wchar_t uninstall_path[STRING_SIZE]; - int startmenu; - wchar_t *cl_start; - int is_admin_install; - int is_standard_user_install; - - startmenu = 0; - install_flags = 0; - uninstall_flags = 0; - appdata = 0; - is_runas = 0; - is_admin_install = 0; - is_standard_user_install = 0; - install_path[0] = 0; - install_options[0] = 0; - uninstall_path[0] = 0; - - p = string_skip_ws(cl); - - // skip exe filename - p = string_get_word(p,buf); - p = string_skip_ws(p); - - cl_start = p; - - // skip first parameter. - for(;;) - { - wchar_t *bufstart; - BOOL was_quote; - - // no more text? - if (!*p) - { - break; - } - - was_quote = FALSE; - if (*p == '"') - { - was_quote = TRUE; - } - - p = string_get_word(p,buf); - p = string_skip_ws(p); - - bufstart = buf; - - // treat switches with a '.' as a filename. - // eg: voidimageviewer.exe -my-image.png - if ((!was_quote) && ((*bufstart == '/') || (*bufstart == '-')) && (!string_is_dot(buf))) - { - bufstart++; - - if (string_icompare_lowercase_ascii(bufstart,"install") == 0) - { - p = string_get_word(p,install_path); - p = string_skip_ws(p); - - uninstall_path[0] = 0; - - is_admin_install = 1; - } - else - if (string_icompare_lowercase_ascii(bufstart,"install-options") == 0) - { - p = string_get_word(p,install_options); - p = string_skip_ws(p); - - is_admin_install = 1; - } - else - if (string_icompare_lowercase_ascii(bufstart,"uninstall") == 0) - { - p = string_get_word(p,uninstall_path); - p = string_skip_ws(p); - - // no uninstall path? - if (!uninstall_path[0]) - { - // caller will need to manually delete voidimageviewer.exe - string_get_exe_path(uninstall_path); - } - - // uninstall all - uninstall_flags = 0xffffffff; - install_flags = 0; - startmenu = -1; - - install_path[0] = 0; - - is_admin_install = 1; - is_standard_user_install = 1; - } - else - if (string_icompare_lowercase_ascii(bufstart,"appdata") == 0) - { - appdata = 1; - is_admin_install = 1; - } - else - if (string_icompare_lowercase_ascii(bufstart,"noappdata") == 0) - { - appdata = -1; - is_admin_install = 1; - } - else - if (string_icompare_lowercase_ascii(bufstart,"startmenu") == 0) - { - startmenu = 1; - is_admin_install = 1; - } - else - if (string_icompare_lowercase_ascii(bufstart,"nostartmenu") == 0) - { - startmenu = -1; - is_admin_install = 1; - } - else - if (string_icompare_lowercase_ascii(bufstart,"isrunas") == 0) - { - is_runas = 1; - } - else - { - int exti; - int is_no; - - is_no = 0; - - if (string_istartwith_lowercase_ascii(bufstart,"no")) - { - bufstart += 2; - is_no = 1; - } - - for(exti=0;exti<_VIV_ASSOCIATION_COUNT;exti++) - { - if (string_icompare_lowercase_ascii(bufstart,_viv_association_extensions[exti]) == 0) - { - if (is_no) - { - uninstall_flags |= 1 << exti; - } - else - { - install_flags |= 1 << exti; - } - - is_standard_user_install = 1; - break; - } - } - } - } - } - - // debug_printf("isrunas %d install_flags %u uninstall_flags %u\n",is_runas,install_flags,uninstall_flags); - - // do associationas as standard user - if (!is_runas) - { - if (install_flags) - { - _viv_install_association(install_flags); - } - - if (uninstall_flags) - { - _viv_uninstall_association(uninstall_flags); - } - } - - if (is_admin_install) - { - if (!os_is_admin()) - { - if (!is_runas) - { - wchar_t exe_filename[STRING_SIZE]; - wchar_t params[STRING_SIZE]; - wchar_t cwd[STRING_SIZE]; - - _viv_get_exe_filename(exe_filename); - GetCurrentDirectory(STRING_SIZE,cwd); - - string_copy_utf8_string(params,(const utf8_t *)"/isrunas "); - string_cat(params,cl_start); - - os_shell_execute(0,exe_filename,1,"runas",params); - - return 1; - } - } - } - - if (appdata > 0) - { - config_appdata = 1; - - config_save_settings(config_appdata); - - // appdata enabled. - config_save_settings(0); - } - else - if (appdata < 0) - { - config_appdata = 0; - - // appdata disabled - config_save_settings(0); - } - - if (startmenu > 0) - { - _viv_install_start_menu_shortcuts(); - } - else - if (startmenu < 0) - { - _viv_uninstall_start_menu_shortcuts(); - } - - if (install_path[0]) - { - wchar_t temp_path[STRING_SIZE]; - - // make sure no other process is running. - _viv_close_existing_process(); - - string_get_exe_path(temp_path); - - os_make_sure_path_exists(install_path); - - _viv_install_copy_file(install_path,temp_path,(const utf8_t *)"voidImageViewer.exe",1); - _viv_install_copy_file(install_path,temp_path,(const utf8_t *)"Uninstall.exe",0); - _viv_install_copy_file(install_path,temp_path,(const utf8_t *)"Changes.txt",0); - - if (install_options[0]) - { - wchar_t new_exe_filename_wbuf[STRING_SIZE]; - - string_path_combine_utf8(new_exe_filename_wbuf,install_path,(const utf8_t *)"voidImageViewer.exe"); - - os_shell_execute(0,new_exe_filename_wbuf,1,NULL,install_options); - } - } - - if (uninstall_path[0]) - { - wchar_t path[STRING_SIZE]; - - // make sure no other process is running. - _viv_close_existing_process(); - - // remove %APPDATA%\voidimageviewer - if (string_get_appdata_voidimageviewer_path(path)) - { - _viv_uninstall_delete_file(path,(const utf8_t *)"voidImageViewer.ini"); - - RemoveDirectory(path); - } - - _viv_uninstall_delete_file(uninstall_path,(const utf8_t *)"Uninstall.exe"); - _viv_uninstall_delete_file(uninstall_path,(const utf8_t *)"Changes.txt"); - _viv_uninstall_delete_file(uninstall_path,(const utf8_t *)"voidImageViewer.ini"); - _viv_uninstall_delete_file(uninstall_path,(const utf8_t *)"voidImageViewer.exe"); - - RemoveDirectory(uninstall_path); - } - - if ((is_admin_install) || (is_standard_user_install)) - { - return 1; - } - - return 0; -} - -static void _viv_process_command_line(wchar_t *cl) -{ - wchar_t *p; - wchar_t buf[STRING_SIZE]; - wchar_t single[STRING_SIZE]; - int file_count; - int start_slideshow; - int start_fullscreen; - int start_window; - int window_x; - int window_y; - int window_wide; - int window_high; - int set_window_rect; - RECT rect; - int start_maximized; - int is_add; - - debug_printf("cl: %S\n",cl); - - start_slideshow = 0; - start_fullscreen = 0; - start_window = 0; - start_maximized = 0; - is_add = 0; - p = cl; - file_count = 0; - single[0] = 0; - set_window_rect = 0; - - GetWindowRect(_viv_hwnd,&rect); - window_x = rect.left; - window_y = rect.top; - window_wide = rect.right - rect.left; - window_high = rect.bottom - rect.top; - - if (config_add_command_line_timeout) - { - if (got_last_process_command_line_tick) - { - if ((GetTickCount() - last_process_command_line_tick) < (DWORD)config_add_command_line_timeout) - { - // don't add if nothing is loaded. - if (*_viv_current_fd->cFileName) - { - is_add = 1; - } - } - } - } - - p = string_skip_ws(p); - - // skip exe filename - p = string_get_word(p,buf); - p = string_skip_ws(p); - - // skip first parameter. - for(;;) - { - wchar_t *bufstart; - BOOL was_quote; - - // no more text? - if (!*p) - { - break; - } - - was_quote = FALSE; - if (*p == '"') - { - was_quote = TRUE; - } - - p = string_get_word(p,buf); - p = string_skip_ws(p); - - bufstart = buf; - - // treat switches with a '.' as a filename. - if ((!was_quote) && ((*bufstart == '/') || (*bufstart == '-')) && (!string_is_dot(buf))) - { - bufstart++; - - if (string_icompare_lowercase_ascii(bufstart,"slideshow") == 0) - { - start_slideshow = 1; - } - else - if (string_icompare_lowercase_ascii(bufstart,"fullscreen") == 0) - { - start_fullscreen = 1; - start_window = 0; - } - else - if (string_icompare_lowercase_ascii(bufstart,"window") == 0) - { - start_fullscreen = 0; - start_window = 1; - } - else - if (string_icompare_lowercase_ascii(bufstart,"maximized") == 0) - { - start_fullscreen = 0; - start_window = 1; - start_maximized = 1; - } - else - if (string_icompare_lowercase_ascii(bufstart,"ontop") == 0) - { - _viv_command(VIV_ID_VIEW_ONTOP_ALWAYS); - } - else - if (string_icompare_lowercase_ascii(bufstart,"shuffle") == 0) - { - config_shuffle = 1; - } - else - if (string_icompare_lowercase_ascii(bufstart,"everything") == 0) - { - p = string_get_word(p,buf); - p = string_skip_ws(p); - - _viv_send_everything_search(0,0,0,buf); - } - else - if (string_icompare_lowercase_ascii(bufstart,"random") == 0) - { - p = string_get_word(p,buf); - p = string_skip_ws(p); - - _viv_send_everything_search(0,0,1,buf); - } - else - if (string_icompare_lowercase_ascii(bufstart,"minimal") == 0) - { - _viv_command(VIV_ID_VIEW_PRESET_1); - } - else - if (string_icompare_lowercase_ascii(bufstart,"compact") == 0) - { - _viv_command(VIV_ID_VIEW_PRESET_2); - } - else - if (string_icompare_lowercase_ascii(bufstart,"x") == 0) - { - p = string_get_word(p,buf); - p = string_skip_ws(p); - - window_x = string_to_int(buf); - set_window_rect = 1; - } - else - if (string_icompare_lowercase_ascii(bufstart,"y") == 0) - { - p = string_get_word(p,buf); - p = string_skip_ws(p); - - window_y = string_to_int(buf); - set_window_rect = 1; - } - else - if (string_icompare_lowercase_ascii(bufstart,"width") == 0) - { - p = string_get_word(p,buf); - p = string_skip_ws(p); - - window_wide = string_to_int(buf); - set_window_rect = 1; - } - else - if (string_icompare_lowercase_ascii(bufstart,"height") == 0) - { - p = string_get_word(p,buf); - p = string_skip_ws(p); - - window_high = string_to_int(buf); - set_window_rect = 1; - } - else - if (string_icompare_lowercase_ascii(bufstart,"rate") == 0) - { - p = string_get_word(p,buf); - p = string_skip_ws(p); - - config_slideshow_rate = string_to_int(buf); - } - else - if (string_icompare_lowercase_ascii(bufstart,"name") == 0) - { - config_nav_sort = CONFIG_NAV_SORT_NAME; - config_nav_sort_ascending = 1; - } - else - if (string_icompare_lowercase_ascii(bufstart,"dm") == 0) - { - config_nav_sort = CONFIG_NAV_SORT_DATE_MODIFIED; - config_nav_sort_ascending = 0; - } - else - if (string_icompare_lowercase_ascii(bufstart,"dc") == 0) - { - config_nav_sort = CONFIG_NAV_SORT_DATE_CREATED; - config_nav_sort_ascending = 0; - } - else - if (string_icompare_lowercase_ascii(bufstart,"path") == 0) - { - config_nav_sort = CONFIG_NAV_SORT_FULL_PATH_AND_FILENAME; - config_nav_sort_ascending = 1; - } - else - if (string_icompare_lowercase_ascii(bufstart,"size") == 0) - { - config_nav_sort = CONFIG_NAV_SORT_SIZE; - config_nav_sort_ascending = 0; - } - else - if (string_icompare_lowercase_ascii(bufstart,"ascending") == 0) - { - config_nav_sort_ascending = 1; - } - else - if (string_icompare_lowercase_ascii(bufstart,"descending") == 0) - { - config_nav_sort_ascending = 0; - } - else - if (string_icompare_lowercase_ascii(bufstart,"isrunas") == 0) - { - // ignore this for non-install commands. - } - else - if (string_icompare_lowercase_ascii(bufstart,"add") == 0) - { - // don't add if nothing is loaded. - if (*_viv_current_fd->cFileName) - { - is_add = 1; - } - } - else - { - _viv_command_line_options(); - } - } - else - { - if (*buf) - { - if (file_count == 0) - { - // new playlist - if (_viv_random) - { - mem_free(_viv_random); - - _viv_random = 0; - } - - if (!is_add) - { - _viv_playlist_clearall(); - } - } - - if (file_count == 1) - { - // add the last single filename. - // we have two modes: - // 1) playlist mode. (navigate the playlist) - // 2) single file mode. (navigate the folder from the single file) - _viv_playlist_add_filename(single); - } - - if (file_count >= 1) - { - // add this file - _viv_playlist_add_filename(buf); - } - - if (file_count == 0) - { - string_copy(single,buf); - } - - file_count++; - } - } - } - - // add the single image filename to the playlist if we are adding. - if (is_add) - { - // if the playlist is empty, add the current item. - if (!_viv_playlist_start) - { - if (*_viv_current_fd->cFileName) - { - _viv_playlist_add_filename(_viv_current_fd->cFileName); - } - } - - if (file_count == 1) - { - _viv_playlist_add_filename(single); - } - } - - debug_printf("file count %d\n",file_count); - - // show the first image. - // don't show anything if we are adding. - // show something if nothing is already shown. - if (!is_add) - { - if (file_count >= 1) - { - const wchar_t *open_filename; - - if (_viv_random) - { - mem_free(_viv_random); - - _viv_random = 0; - } - - open_filename = NULL; - - if (file_count > 1) - { - // treat as a playlist. - if (_viv_playlist_start) - { - open_filename = _viv_playlist_start->fd.cFileName; - } - } - else - if (file_count == 1) - { - open_filename = single; - } - - // open the first image found (if multiple images passed). - // if we only specified a single image, use the single image filename. - if ((open_filename) && (_viv_open_from_filename(open_filename))) - { - // all good. - } - else - { - _viv_file_not_found = 1; - _viv_status_update(); - } - } - } - - if (start_slideshow) - { - _viv_slideshow(); - } - - if (start_fullscreen) - { - if (!_viv_is_fullscreen) - { - _viv_toggle_fullscreen(); - - if (start_maximized) - { - _viv_fullscreen_is_maxed = 1; - } - } - } - else - { - if (start_window) - { - if (_viv_is_fullscreen) - { - _viv_toggle_fullscreen(); - } - } - else - { - if (set_window_rect) - { - SetWindowPos(_viv_hwnd,0,window_x,window_y,window_wide,window_high,SWP_NOZORDER|SWP_NOACTIVATE); - } - } - - if (start_maximized) - { - if (!_viv_is_window_maximized(_viv_hwnd)) - { - ShowWindow(_viv_hwnd,SW_MAXIMIZE); - } - } - } - - // save last processing time - // if we make another immediate call, add items to the playlist, instead of setting the playlist. - last_process_command_line_tick = GetTickCount(); - got_last_process_command_line_tick = 1; -} - -static int _viv_init(int nCmdShow) -{ - RECT rect; - STARTUPINFO si; - int show_maximized; - DWORD window_style; - - os_init(); - localization_init(); // Initialize language system - show_maximized = 0; - - debug_printf("%u\n",sizeof(_viv_key_list_t)); - - _viv_key_list = mem_alloc(sizeof(_viv_key_list_t)); - - _viv_key_list_init(_viv_key_list); - - // setup keys. - { - int i; - - for(i=0;i<_VIV_DEFAULT_KEY_COUNT;i++) - { - viv_key_add(_viv_command_index_from_command_id(_viv_default_keys[i].command_id),_viv_default_keys[i].key_flags); - } - } - - // init _viv_dst_zoom_values - - _viv_dst_zoom_values = mem_alloc(sizeof(float) * _VIV_DST_ZOOM_MAX); - - { - int i; - float f; - - f = 1.0; - - i = _VIV_DST_ZOOM_ONE; - while(i >= 0) - { - _viv_dst_zoom_values[i] = f; - f /= 1.02; - - i--; - } - - f = 1.0; - - i = _VIV_DST_ZOOM_ONE; - while(i < _VIV_DST_ZOOM_MAX) - { - _viv_dst_zoom_values[i] = f; - f *= 1.02; - - i++; - } - } - - debug_printf("viv %d.%d.%d.%d%s %s\n",VERSION_MAJOR,VERSION_MINOR,VERSION_REVISION,VERSION_BUILD,VERSION_TYPE,VERSION_TARGET_MACHINE); - - os_hinstance = GetModuleHandle(0); - - _viv_current_fd = (WIN32_FIND_DATA *)mem_alloc(sizeof(WIN32_FIND_DATA)); - os_zero_memory(_viv_current_fd,sizeof(WIN32_FIND_DATA)); - - _viv_preload_fd = (WIN32_FIND_DATA *)mem_alloc(sizeof(WIN32_FIND_DATA)); - os_zero_memory(_viv_preload_fd,sizeof(WIN32_FIND_DATA)); - - _viv_last_fd = (WIN32_FIND_DATA *)mem_alloc(sizeof(WIN32_FIND_DATA)); - os_zero_memory(_viv_last_fd,sizeof(WIN32_FIND_DATA)); - - _viv_frame_fd = (WIN32_FIND_DATA *)mem_alloc(sizeof(WIN32_FIND_DATA)); - os_zero_memory(_viv_frame_fd,sizeof(WIN32_FIND_DATA)); - - _viv_load_fd = (WIN32_FIND_DATA *)mem_alloc(sizeof(WIN32_FIND_DATA)); - os_zero_memory(_viv_load_fd,sizeof(WIN32_FIND_DATA)); - - debug_printf("CoInitializeEx\n"); - CoInitializeEx(NULL, COINIT_APARTMENTTHREADED|COINIT_DISABLE_OLE1DDE); - - // this resolves ATL window thunking problem when Microsoft Layer for Unicode (MSLU) is used - DefWindowProc(NULL,0,0,0); - - // init common controls - - debug_printf("InitCommonControlsEx\n"); - { - INITCOMMONCONTROLSEX icex; - - icex.dwSize = sizeof(INITCOMMONCONTROLSEX); - icex.dwICC = ICC_STANDARD_CLASSES | ICC_BAR_CLASSES | ICC_WIN95_CLASSES; - InitCommonControlsEx(&icex); - } - - InitializeCriticalSection(&_viv_cs); - - // Initialize GDI+. - if (os_GdiplusStartup) - { - os_GdiplusStartupInput_t gdiplusStartupInput; - int gdiplus_ret; - - gdiplusStartupInput.GdiplusVersion = 1; - gdiplusStartupInput.DebugEventCallback = NULL; - gdiplusStartupInput.SuppressBackgroundThread = FALSE; - gdiplusStartupInput.SuppressExternalCodecs = FALSE; - - gdiplus_ret = os_GdiplusStartup(&os_GdiplusToken,&gdiplusStartupInput,NULL); - } - - // load settings - config_load_settings(); - - // config_maximized will be overwritten when we show are normal window - // so save it now and apply it later. - show_maximized = config_maximized; - - // process install command line options - { - if (_viv_process_install_command_line_options(GetCommandLineW())) - { - _viv_kill(); - - return 0; - } - } - - // mutex - if (!config_multiple_instances) - { - SetLastError(0); - - _viv_mutex = CreateMutexA(NULL,0,"VOIDIMAGEVIEWER"); - - if (GetLastError() == ERROR_ALREADY_EXISTS) - { - HWND hwnd; - - hwnd = FindWindowA("VOIDIMAGEVIEWER",0); - - if (hwnd) - { - COPYDATASTRUCT cds; - wchar_t *command_line; - wchar_t cwd[STRING_SIZE]; - int size; - char *buf; - char *d; - - // allow this process to set focus - SetForegroundWindow(hwnd); - - command_line = GetCommandLineW(); - GetCurrentDirectory(STRING_SIZE,cwd); - - si.cb = sizeof(STARTUPINFO); - GetStartupInfo(&si); - - if (!(si.dwFlags & STARTF_USESHOWWINDOW)) - { - si.wShowWindow = nCmdShow; - } - - // calc size - size = sizeof(DWORD) + (((int)string_get_length(command_line) + 1) * sizeof(wchar_t)) + (((int)string_get_length(cwd) + 1) * sizeof(wchar_t)); - buf = (char *)mem_alloc(size); - - // fill in - d = buf; - *(DWORD *)d = si.wShowWindow; - d += sizeof(DWORD); - string_copy((wchar_t *)d,command_line); - d += ((string_get_length(command_line) + 1) * sizeof(wchar_t)); - string_copy((wchar_t *)d,cwd); - d += ((string_get_length(cwd) + 1) * sizeof(wchar_t)); - - // setup copydata struct - cds.lpData = buf; - cds.cbData = size; - cds.dwData = _VIV_COPYDATA_COMMAND_LINE; - - SendMessage(hwnd,WM_COPYDATA,(WPARAM)0,(LPARAM)&cds); - - mem_free(buf); - } - - _viv_kill(); - - return 0; - } - } - - os_RegisterClassEx( - CS_DBLCLKS | CS_VREDRAW | CS_HREDRAW, - _viv_proc, - (HICON)LoadImage(os_hinstance,MAKEINTRESOURCE(IDI_ICON1),IMAGE_ICON,GetSystemMetrics(SM_CXICON),GetSystemMetrics(SM_CXICON),0), - LoadCursor(NULL,IDC_ARROW), - (HBRUSH)(COLOR_BTNFACE+1), - "VOIDIMAGEVIEWER", - (HICON)LoadImage(os_hinstance,MAKEINTRESOURCE(IDI_ICON1),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0)); - - _viv_hmenu = _viv_create_menu(); - - rect.left = config_x; - rect.top = config_y; - rect.right = config_x + config_wide; - rect.bottom = config_y + config_high; - - // position the window nicely on first use - // auto-fit and center on the monitor from the mouse cursor. - if ((!config_wide) || (!config_high)) - { - RECT monitor_rect; - int default_wide; - int default_high; - - default_wide = 640; - default_high = 480; - - // use full screen to calculate auto-fit size. - os_MonitorRectFromCursor(1,&monitor_rect); - - if (config_auto_fit_wide_div) - { - default_wide = ((monitor_rect.right - monitor_rect.left) * config_auto_fit_wide_mul) / config_auto_fit_wide_div; - } - - if (config_auto_fit_high_div) - { - default_high = ((monitor_rect.bottom - monitor_rect.top) * config_auto_fit_high_mul) / config_auto_fit_high_div; - } - - rect.left = ((monitor_rect.right - monitor_rect.left) / 2) - (default_wide / 2); - rect.top = ((monitor_rect.bottom - monitor_rect.top) / 2) - (default_high / 2); - rect.right = rect.left + default_wide; - rect.bottom = rect.top + default_high; - } - - window_style = WS_CAPTION | WS_THICKFRAME | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; - - _viv_hwnd = os_CreateWindowEx( - 0, - "VOIDIMAGEVIEWER", - localization_get_string(LOCALIZATION_ID_APP_NAME), - window_style, - rect.left,rect.top,rect.right - rect.left,rect.bottom - rect.top, - 0,config_show_menu ? _viv_hmenu : NULL,os_hinstance,NULL); - - if ((!config_show_caption) || (!config_show_thickframe)) - { - _viv_update_frame(); - } - - os_make_rect_completely_visible(_viv_hwnd,&rect); - - SetWindowPos(_viv_hwnd,0,rect.left,rect.top,rect.right - rect.left,rect.bottom - rect.top,SWP_NOZORDER|SWP_NOACTIVATE); - - // allow non-admin/admins to close this window. - if (os_ChangeWindowMessageFilterEx) - { - // MSGFLT_ALLOW = 1 - os_ChangeWindowMessageFilterEx(_viv_hwnd,WM_CLOSE,1,0); - } - - _viv_status_show(config_show_status); - _viv_controls_show(config_show_controls); - - DragAcceptFiles(_viv_hwnd,TRUE); - - _viv_update_title(); - - _viv_update_ontop(); - - si.cb = sizeof(STARTUPINFO); - GetStartupInfo(&si); - - if (!(si.dwFlags & STARTF_USESHOWWINDOW)) - { - si.wShowWindow = nCmdShow; - } - - // default is to shownormal. - // if its anything else, like minimize/maximize to that before we apply the command line. - if (si.wShowWindow != SW_SHOWNORMAL) - { - ShowWindow(_viv_hwnd,si.wShowWindow); - UpdateWindow(_viv_hwnd); - } - - if (show_maximized) - { - ShowWindow(_viv_hwnd,SW_MAXIMIZE); - } - - _viv_process_command_line(GetCommandLineW()); - - // if we didn't show the window above, make sure it - // is shown now. - if (si.wShowWindow == SW_SHOWNORMAL) - { - ShowWindow(_viv_hwnd,SW_SHOW); - UpdateWindow(_viv_hwnd); - } - - return 1; -} - -static void _viv_kill(void) -{ - _viv_show_cursor(); - - // don't load another image.. - if (_viv_load_image_next_fd) - { - mem_free(_viv_load_image_next_fd); - - _viv_load_image_next_fd = 0; - } - - // stop load_image immediately... - if (_viv_load_image_thread) - { - _viv_load_image_terminate = 1; - - // it's critical we wait for load image to finish before we kill the main window. - WaitForSingleObject(_viv_load_image_thread,INFINITE); - - CloseHandle(_viv_load_image_thread); - } - - if (_viv_load_image_filename) - { - mem_free(_viv_load_image_filename); - } - - if (_viv_last_frames) - { - _viv_clear_frames(_viv_last_frames,_viv_last_frame_count); - - _viv_last_frames = NULL; - } - - _viv_clear_preload_frames(); - _viv_clear(); - _viv_process_pending_clear(); - - if (_viv_hwnd) - { - _viv_status_show(0); - _viv_controls_show(0); - // _viv_tooltip_hide(); - - DestroyWindow(_viv_hwnd); - } - - if (_viv_status_temp_text) - { - mem_free(_viv_status_temp_text); - } - - _viv_nav_item_free_all(); - - if (_viv_random) - { - mem_free(_viv_random); - } - - if (_viv_hmenu) - { - DestroyMenu(_viv_hmenu); - } - - if (_viv_about_hfont) - { - DeleteObject(_viv_about_hfont); - } - - if (_viv_mutex) - { - CloseHandle(_viv_mutex); - } - - _viv_playlist_clearall(); - _viv_reply_clear_all(); - - if (os_GdiplusShutdown) - { - os_GdiplusShutdown(os_GdiplusToken); - } - - if (_viv_stobject_hmodule) - { - FreeLibrary(_viv_stobject_hmodule); - } - - CoUninitialize(); - - DeleteCriticalSection(&_viv_cs); - - if (_viv_last_open_file) - { - mem_free(_viv_last_open_file); - } - - if (_viv_last_open_folder) - { - mem_free(_viv_last_open_folder); - } - - mem_free(_viv_load_fd); - mem_free(_viv_frame_fd); - mem_free(_viv_last_fd); - mem_free(_viv_preload_fd); - mem_free(_viv_current_fd); - - mem_free(_viv_dst_zoom_values); - - _viv_key_clear_all(_viv_key_list); - mem_free(_viv_key_list); - - os_kill(); - -#ifdef _DEBUG - mem_debug(); -#endif -} - -static int _viv_main(int nCmdShow) -{ - if (_viv_init(nCmdShow)) - { - for(;;) - { - // Main message loop: - for(;;) - { - MSG msg; - - if (!PeekMessage(&msg,0,0,0,PM_REMOVE)) break; - -// debug_printf("MSG %u %u %u\n",msg.message,msg.wParam,msg.lParam); - - if (msg.message == WM_QUIT) goto exit; - - if (!_viv_is_msg(&msg)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } - - WaitMessage(); - } - - exit: - - _viv_kill(); - } - - return 0; -} - -int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd) -{ - return _viv_main(nShowCmd); -} - -int __cdecl main(int argc,char **argv) -{ - return _viv_main(SW_SHOW); -} - -static int _viv_compare_id(const WIN32_FIND_DATA *a,const WIN32_FIND_DATA *b) -{ - if (a->dwReserved0 < b->dwReserved0) - { - return -1; - } - - if (a->dwReserved0 > b->dwReserved0) - { - return 1; - } - - if (a->dwReserved1 < b->dwReserved1) - { - return -1; - } - - if (a->dwReserved1 > b->dwReserved1) - { - return 1; - } - - return 0; -} - -static int _viv_fd_compare_name(const WIN32_FIND_DATA *a,const WIN32_FIND_DATA *b) -{ - int ret; - const wchar_t *afilename; - const wchar_t *bfilename; - DWORD dwCmpFlags; - - dwCmpFlags = SORT_STRINGSORT|NORM_IGNORECASE; - - if (os_is_windows_7_or_later()) - { - // #define SORT_DIGITSASNUMBERS 0x00000008 // use digits as numbers sort method - dwCmpFlags |= 0x00000008; - } - - afilename = string_get_filename_part(a->cFileName); - bfilename = string_get_filename_part(b->cFileName); - - ret = CompareString(LOCALE_USER_DEFAULT,dwCmpFlags,afilename,string_get_length(afilename),bfilename,string_get_length(bfilename)); - - switch(ret) - { - case CSTR_LESS_THAN: - return -1; - - case CSTR_GREATER_THAN: - return 1; - } - - return _viv_compare_id(a,b); -} - -static int _viv_fd_compare_path_and_name(const WIN32_FIND_DATA *a,const WIN32_FIND_DATA *b) -{ - int ret; - DWORD dwCmpFlags; - - dwCmpFlags = SORT_STRINGSORT|NORM_IGNORECASE; - - if (os_is_windows_7_or_later()) - { - // #define SORT_DIGITSASNUMBERS 0x00000008 // use digits as numbers sort method - dwCmpFlags |= 0x00000008; - } - - ret = CompareString(LOCALE_USER_DEFAULT,dwCmpFlags,a->cFileName,string_get_length(a->cFileName),b->cFileName,string_get_length(b->cFileName)); - - switch(ret) - { - case CSTR_LESS_THAN: - return -1; - - case CSTR_GREATER_THAN: - return 1; - } - - return _viv_compare_id(a,b); -} - -static int _viv_fd_compare(const WIN32_FIND_DATA *a,const WIN32_FIND_DATA *b) -{ - int ret; - - ret = 0; - - switch(config_nav_sort) - { - case CONFIG_NAV_SORT_NAME: - ret = _viv_fd_compare_name(a,b); - break; - - case CONFIG_NAV_SORT_FULL_PATH_AND_FILENAME: - ret = _viv_fd_compare_path_and_name(a,b); - break; - - case CONFIG_NAV_SORT_SIZE: - { - LARGE_INTEGER sizea; - LARGE_INTEGER sizeb; - - sizea.HighPart = a->nFileSizeHigh; - sizea.LowPart = a->nFileSizeLow; - - sizeb.HighPart = b->nFileSizeHigh; - sizeb.LowPart = b->nFileSizeLow; - - if (sizea.QuadPart < sizeb.QuadPart) - { - ret = -1; - } - else - if (sizea.QuadPart > sizeb.QuadPart) - { - ret = 1; - } - else - { - // we want name ascending when we are size descending. - ret = -_viv_fd_compare_name(a,b); - } - - break; - } - - case CONFIG_NAV_SORT_DATE_MODIFIED: - { - LARGE_INTEGER datea; - LARGE_INTEGER dateb; - - datea.HighPart = a->ftLastWriteTime.dwHighDateTime; - datea.LowPart = a->ftLastWriteTime.dwLowDateTime; - - dateb.HighPart = b->ftLastWriteTime.dwHighDateTime; - dateb.LowPart = b->ftLastWriteTime.dwLowDateTime; - - if (datea.QuadPart < dateb.QuadPart) - { - ret = -1; - } - else - if (datea.QuadPart > dateb.QuadPart) - { - ret = 1; - } - else - { - ret = -_viv_fd_compare_name(a,b); - } - - break; - } - - case CONFIG_NAV_SORT_DATE_CREATED: - { - LARGE_INTEGER datea; - LARGE_INTEGER dateb; - - datea.HighPart = a->ftCreationTime.dwHighDateTime; - datea.LowPart = a->ftCreationTime.dwLowDateTime; - - dateb.HighPart = b->ftCreationTime.dwHighDateTime; - dateb.LowPart = b->ftCreationTime.dwLowDateTime; - - if (datea.QuadPart < dateb.QuadPart) - { - ret = -1; - } - else - if (datea.QuadPart > dateb.QuadPart) - { - ret = 1; - } - else - { - ret = -_viv_fd_compare_name(a,b); - } - - break; - } - } - - if (!config_nav_sort_ascending) - { - ret *= -1; - } - - return ret; -} - -static int _viv_next(int prev,int reset_slideshow_timer,int is_preload,int wait_for_current_load) -{ - int ret; - - ret = 1; - -debug_printf("_viv_next %d %d\n",prev,is_preload); - - if (is_preload) - { - if (_viv_random) - { - // preloading not supported.. - return 0; - } - } - else - { - _viv_last_is_prev = prev; - } - -//TODO: review -when enabled, viv fills unresponsive/sluggish. -// when disabled, viv can load multiple images when the 'up' key is released. -//wait_for_current_load = 0; - -// NEVER use the preload, always go to disk to find the next real image. -// users expects the next image. Not the one we preloaded ages ago. -// 99% it will be the preloaded image anyway.. - - if ((!is_preload) && (_viv_load_image_thread) && ((_viv_load_frame_count <= 1) || (_viv_load_image_terminate)) && (wait_for_current_load)) - { - //_viv_open_preload(); - - // still loading. - // wait for current load to finish. - return 0; - } - else - if (_viv_random) - { - _viv_send_random_everything_search(); - } - else - { - _viv_do_initial_shuffle(); - - if (*_viv_current_fd->cFileName) - { - WIN32_FIND_DATA start_fd; - WIN32_FIND_DATA best_fd; - int got_start; - int got_best; - - got_best = 0; - got_start = 0; - - if (_viv_playlist_start) - { - _viv_playlist_t *d; - - d = _viv_playlist_start; - -debug_printf("next %d\n",config_shuffle); - - if (config_shuffle) - { - int index; - - index = _viv_playlist_shuffle_index_from_fd(_viv_current_fd); - - debug_printf("cur %d %d\n",index,_viv_current_fd->dwReserved1); - - if (index != -1) - { - if (prev) - { - index--; - if (index < 0) - { - index = _viv_playlist_count - 1; - } - } - else - { - index++; - if (index >= _viv_playlist_count) - { - index = 0; - } - } - } - else - { - if (prev) - { - index = _viv_playlist_count - 1; - } - else - { - index = 0; - } - } - - os_copy_memory(&best_fd,&_viv_playlist_shuffle_indexes[index]->fd,sizeof(WIN32_FIND_DATA)); - - got_best = 1; - } - else - { - _viv_playlist_t *current_d; - - current_d = _viv_playlist_from_fd(_viv_current_fd); - debug_printf("cur %d\n",current_d); - - while(d) - { - if (d != current_d) - { - int compare_ret; - - compare_ret = _viv_fd_compare(&d->fd,_viv_current_fd); - - if (compare_ret != 0) - { - if (prev) - { - if (compare_ret < 0) - { - if ((!got_best) || (_viv_fd_compare(&d->fd,&best_fd) > 0)) - { - os_copy_memory(&best_fd,&d->fd,sizeof(WIN32_FIND_DATA)); - got_best = 1; - } - } - } - else - { - if (compare_ret > 0) - { - if ((!got_best) || (_viv_fd_compare(&d->fd,&best_fd) < 0)) - { - os_copy_memory(&best_fd,&d->fd,sizeof(WIN32_FIND_DATA)); - got_best = 1; - } - } - } - } - - // compare with start.. - if (prev) - { - if ((!got_start) || (_viv_fd_compare(&d->fd,&start_fd) > 0)) - { - os_copy_memory(&start_fd,&d->fd,sizeof(WIN32_FIND_DATA)); - - got_start = 1; - } - } - else - { - if ((!got_start) || (_viv_fd_compare(&d->fd,&start_fd) < 0)) - { - os_copy_memory(&start_fd,&d->fd,sizeof(WIN32_FIND_DATA)); - got_start = 1; - } - } - } - - d = d->next; - } - debug_printf("gotbest %d %d\n",got_best,got_start); - } - } - else - { - WIN32_FIND_DATA fd; - HANDLE h; - wchar_t search_wbuf[STRING_SIZE]; - wchar_t path_wbuf[STRING_SIZE]; - -debug_printf("FIND next\n"); - - string_get_path_part(path_wbuf,_viv_current_fd->cFileName); - - string_copy(search_wbuf,path_wbuf); - string_cat_utf8(search_wbuf,(const utf8_t *)"\\*.*"); - - h = FindFirstFile(search_wbuf,&fd); - if (h != INVALID_HANDLE_VALUE) - { - for(;;) - { - if (_viv_is_valid_filename(&fd)) - { - int compare_ret; - - fd.dwReserved0 = 0; - fd.dwReserved1 = 0; - - compare_ret = _viv_fd_compare(&fd,_viv_current_fd); - - if (compare_ret != 0) - { - if (prev) - { - if (compare_ret < 0) - { - if ((!got_best) || (_viv_fd_compare(&fd,&best_fd) > 0)) - { - string_path_combine(search_wbuf,path_wbuf,fd.cFileName); - string_copy(fd.cFileName,search_wbuf); - os_copy_memory(&best_fd,&fd,sizeof(WIN32_FIND_DATA)); - got_best = 1; - } - } - } - else - { - if (compare_ret > 0) - { - if ((!got_best) || (_viv_fd_compare(&fd,&best_fd) < 0)) - { - string_path_combine(search_wbuf,path_wbuf,fd.cFileName); - string_copy(fd.cFileName,search_wbuf); - os_copy_memory(&best_fd,&fd,sizeof(WIN32_FIND_DATA)); - got_best = 1; - } - } - } - } - - // compare with start.. - if (prev) - { - if ((!got_start) || (_viv_fd_compare(&fd,&start_fd) > 0)) - { - string_path_combine(search_wbuf,path_wbuf,fd.cFileName); - string_copy(fd.cFileName,search_wbuf); - os_copy_memory(&start_fd,&fd,sizeof(WIN32_FIND_DATA)); - - got_start = 1; - } - } - else - { - if ((!got_start) || (_viv_fd_compare(&fd,&start_fd) < 0)) - { - string_path_combine(search_wbuf,path_wbuf,fd.cFileName); - string_copy(fd.cFileName,search_wbuf); - os_copy_memory(&start_fd,&fd,sizeof(WIN32_FIND_DATA)); - got_start = 1; - } - } - } - - if (!FindNextFile(h,&fd)) break; - } - - FindClose(h); - } - } - - if (got_best) - { - _viv_open(&best_fd,is_preload); - } - else - if (got_start) - { - // don't open the same image again. - debug_printf("%S %S\n",start_fd.cFileName,_viv_current_fd->cFileName); - if (string_compare(start_fd.cFileName,_viv_current_fd->cFileName) != 0) - { - _viv_open(&start_fd,is_preload); - } - } - else - { - // dont blank because we may not have a best or start because we only have one image - // (compare_ret != 0) -// _viv_blank(); - ret = 0; - } - } - else - { - _viv_home(0,is_preload); - } - } - - // reset slideshow timer. - if (reset_slideshow_timer) - { - if (_viv_is_slideshow) - { - KillTimer(_viv_hwnd,VIV_ID_SLIDESHOW_TIMER); - SetTimer(_viv_hwnd,VIV_ID_SLIDESHOW_TIMER,config_slideshow_rate,0); - } - } - - return ret; -} - -static void _viv_home(int end,int is_preload) -{ - if (_viv_random) - { - _viv_send_random_everything_search(); - } - else - { - WIN32_FIND_DATA best_fd; - int got_best; - - got_best = 0; - - _viv_do_initial_shuffle(); - - if (_viv_playlist_start) - { - if (config_shuffle) - { - int index; - - if (end) - { - index = _viv_playlist_count - 1; - } - else - { - index = 0; - } - - os_copy_memory(&best_fd,&_viv_playlist_shuffle_indexes[index]->fd,sizeof(WIN32_FIND_DATA)); - - got_best = 1; - } - else - { - _viv_playlist_t *d; - - d = _viv_playlist_start; - while(d) - { - if (end) - { - if ((!got_best) || (_viv_fd_compare(&d->fd,&best_fd) > 0)) - { - os_copy_memory(&best_fd,&d->fd,sizeof(WIN32_FIND_DATA)); - got_best = 1; - } - } - else - { - if ((!got_best) || (_viv_fd_compare(&d->fd,&best_fd) < 0)) - { - os_copy_memory(&best_fd,&d->fd,sizeof(WIN32_FIND_DATA)); - got_best = 1; - } - } - - d = d->next; - } - } - } - else - { - HANDLE h; - WIN32_FIND_DATA fd; - wchar_t search_wbuf[STRING_SIZE]; - wchar_t path_wbuf[STRING_SIZE]; - - if (*_viv_current_fd->cFileName) - { - string_get_path_part(path_wbuf,_viv_current_fd->cFileName); - } - else - { - GetCurrentDirectory(STRING_SIZE,path_wbuf); - } - - string_copy(search_wbuf,path_wbuf); - string_cat_utf8(search_wbuf,(const utf8_t *)"\\*.*"); - - h = FindFirstFile(search_wbuf,&fd); - - if (h != INVALID_HANDLE_VALUE) - { - for(;;) - { - if (_viv_is_valid_filename(&fd)) - { - fd.dwReserved0 = 0; - fd.dwReserved1 = 0; - - if (end) - { - if ((!got_best) || (_viv_fd_compare(&fd,&best_fd) > 0)) - { - string_path_combine(search_wbuf,path_wbuf,fd.cFileName); - string_copy(fd.cFileName,search_wbuf); - os_copy_memory(&best_fd,&fd,sizeof(WIN32_FIND_DATA)); - got_best = 1; - } - } - else - { - if ((!got_best) || (_viv_fd_compare(&fd,&best_fd) < 0)) - { - string_path_combine(search_wbuf,path_wbuf,fd.cFileName); - string_copy(fd.cFileName,search_wbuf); - os_copy_memory(&best_fd,&fd,sizeof(WIN32_FIND_DATA)); - got_best = 1; - } - } - } - - if (!FindNextFile(h,&fd)) break; - } - - FindClose(h); - } - } - - if (got_best) - { - _viv_open(&best_fd,is_preload); - } - else - { - if (is_preload) - { - } - else - { - _viv_blank(); - } - } - } - - // reset slideshow timer. - if (_viv_is_slideshow) - { - KillTimer(_viv_hwnd,VIV_ID_SLIDESHOW_TIMER); - SetTimer(_viv_hwnd,VIV_ID_SLIDESHOW_TIMER,config_slideshow_rate,0); - } -} - -static int _viv_is_valid_filename(WIN32_FIND_DATA *fd) -{ - if (!(fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) - { - const wchar_t *s; - const wchar_t *e; - - e = 0; - s = fd->cFileName; - - while(*s) - { - if (*s == '.') - { - e = s + 1; - } - - s++; - } - - if (e) - { - int exti; - - for(exti=0;exti<_VIV_ASSOCIATION_COUNT;exti++) - { - if (string_icompare_lowercase_ascii(e,_viv_association_extensions[exti]) == 0) - { - return 1; - } - } - } - } - - return 0; -} - -static int _viv_is_msg(MSG *msg) -{ - switch (msg->message) - { - case WM_XBUTTONDOWN: - case WM_XBUTTONDBLCLK: - case WM_NCXBUTTONDOWN: - case WM_NCXBUTTONDBLCLK: - - switch(config_xbutton_action) - { - case 1: - - switch(HIWORD(msg->wParam)) - { - case XBUTTON1: - _viv_zoom_in(1,1,GET_X_LPARAM(msg->lParam),GET_Y_LPARAM(msg->lParam)); - break; - - case XBUTTON2: - _viv_zoom_in(0,1,GET_X_LPARAM(msg->lParam),GET_Y_LPARAM(msg->lParam)); - break; - } - - break; - - case 2: - - switch(HIWORD(msg->wParam)) - { - case XBUTTON1: - _viv_next(1,1,0,0); - break; - - case XBUTTON2: - _viv_next(0,1,0,0); - break; - } - - break; - - } - - break; - - case WM_SYSKEYDOWN: - case WM_KEYDOWN: - - { - int key_flags; - - key_flags = _viv_get_current_key_mod_flags(); - - if (msg->hwnd == _viv_hwnd) - { - int key_index; - -/* - if (msg->wParam == VK_MENU) - { - _viv_is_alt = 1; - _viv_update_show_cursor(); - _viv_update_src_pixel(0,1); - } -*/ - // cancel action - if ((key_flags == 0) && (msg->wParam == VK_ESCAPE)) - { - if (_viv_doing) - { - _viv_doing_cancel(); - - return 1; - } - - if (_viv_is_fullscreen) - { - _viv_toggle_fullscreen(); - - // also pause slideshow - if (_viv_is_slideshow) - { - _viv_pause(); - } - - return 1; - } - } - - // find the key. - for(key_index=0;key_index<_VIV_COMMAND_COUNT;key_index++) - { - config_key_t *k; - - k = _viv_key_list->start[key_index]; - while(k) - { - if ((k->key & CONFIG_KEYFLAG_MOD_MASK) == key_flags) - { - if ((k->key & CONFIG_KEYFLAG_VK_MASK) == msg->wParam) - { - _viv_command_with_is_key_repeat(_viv_commands[key_index].command_id,(msg->lParam & 0x40000000) ? 1 : 0); - - return 1; - } - } - - k = k->next; - } - } - } - } - - break; - -/* - case WM_KEYUP: - case WM_SYSKEYUP: - - if (msg->wParam == VK_MENU) - { - _viv_is_alt = 0; - _viv_update_show_cursor(); - _viv_update_src_pixel(0,1); - } - break; - */ - } - - return 0; -} - -static void _viv_view_set(int view_x,int view_y,int invalidate) -{ - RECT rect; - int wide; - int high; - int rw; - int rh; - - GetClientRect(_viv_hwnd,&rect); - wide = rect.right - rect.left; - high = rect.bottom - rect.top - _viv_get_status_high() - _viv_get_controls_high(); - - _viv_get_render_size(&rw,&rh); -/* - if (_viv_zoom_pos == 1) - { - if ((rw < _viv_image_wide) || (rw < _viv_image_wide)) - { - rw = _viv_image_wide; - rh = _viv_image_high; - } - } -*/ - - { - int rx; - int ry; - - rx = (wide / 2) - (rw / 2) - view_x; - ry = (high / 2) - (rh / 2) - view_y; - - if (config_keep_centered) - { - if (rw > wide) - { - if (rx > 0) - { - view_x = (wide / 2) - (rw / 2); - } - - if (rx + rw < wide) - { - // rx = wide - rw; - view_x = (wide / 2) - (rw / 2) - (wide - rw); - } - } - else - { - view_x = 0; - } - - if (rh > high) - { - if (ry > 0) - { - view_y = (high / 2) - (rh / 2); - } - - if (ry + rh < high) - { - view_y = (high / 2) - (rh / 2) - (high - rh); - } - } - else - { - view_y = 0; - } - } - else - { - - if (rx + rw - 1 < 0) - { - view_x = (wide / 2) - (rw / 2) + rw - 1; - } - - if (rx > wide-1) - { - view_x = (wide / 2) - (rw / 2) - (wide-1); - } - - if (ry + rh - 1 < 0) - { - view_y = (high / 2) - (rh / 2) + rh - 1; - } - - if (ry > high-1) - { - view_y = (high / 2) - (rh / 2) - (high-1); - } - - } - } - - if (rw) - { - int rx; - - rx = (((_viv_dst_pos_x - 250) * (wide*2)) / 1000) - (rw / 2) - view_x; - - // make sure the multiple is done as __int64 to avoid overflows - _viv_view_ix = (((wide / 2) - rx) * (__int64)_viv_image_wide) / (double)rw; - } - else - { - // don't set to 0, just use last value. -// _viv_view_ix = 0.0; - } - - if (rh) - { - int ry; - - ry = (((_viv_dst_pos_y - 250) * (high*2)) / 1000) - (rh / 2) - view_y; - - // make sure the multiple is done as __int64 to avoid overflows - _viv_view_iy = (((high / 2) - ry) * (__int64)_viv_image_high) / (double)rh; - } - else - { - // don't set to 0, just use last value. -// _viv_view_iy = 0; - } - - if ((_viv_view_x != view_x) || (_viv_view_y != view_y)) - { - _viv_view_x = view_x; - _viv_view_y = view_y; - - if (invalidate) - { - InvalidateRect(_viv_hwnd,0,FALSE); - } - } - -debug_printf("SETVIEW %d %d ix %d iy %d rw %d rh %d wide %d high %d\n",_viv_view_x,_viv_view_y,(int)(_viv_view_ix),(int)(_viv_view_iy),rw,rh,wide,high); - - _viv_toolbar_update_buttons(); -} - -static void _viv_toggle_fullscreen(void) -{ - DWORD style; - int old_rw; - int old_rh; - int zoom_wide_array[_VIV_ZOOM_MAX]; - int zoom_high_array[_VIV_ZOOM_MAX]; - - _viv_get_render_size(&old_rw,&old_rh); - - // precalculate all zoom levels for comparison later to find the zoom offset. - { - int backup_zoom; - - backup_zoom = _viv_zoom_pos; - - for(_viv_zoom_pos=0;_viv_zoom_pos<_VIV_ZOOM_MAX;_viv_zoom_pos++) - { - int rw; - int rh; - - _viv_get_render_size(&rw,&rh); - - zoom_wide_array[_viv_zoom_pos] = rw; - zoom_high_array[_viv_zoom_pos] = rh; - } - - _viv_zoom_pos = backup_zoom; - } - - _viv_prevent_on_size = 1; - -debug_printf("toggle fullscreen %d\n",!_viv_is_fullscreen); - - style = GetWindowLong(_viv_hwnd,GWL_STYLE); - - _viv_1to1 = 0; - - if (_viv_is_fullscreen) - { - // set before restore - // otherwise get_render_size will return the wrong size. - _viv_is_fullscreen = 0; - - if (config_show_caption) - { - style |= WS_CAPTION; - } - else - { - style &= ~(WS_CAPTION); - } - - if (config_show_thickframe) - { - style |= WS_THICKFRAME; - } - else - { - style &= ~WS_THICKFRAME; - } - - if (config_show_menu) - { - SetMenu(_viv_hwnd,_viv_hmenu); - } - else - { - SetMenu(_viv_hwnd,0); - } - - _viv_status_show(config_show_status); - _viv_controls_show(config_show_controls); - - SetWindowLong(_viv_hwnd,GWL_STYLE,style); - - SetWindowPos(_viv_hwnd,HWND_TOP,_viv_fullscreen_rect.left,_viv_fullscreen_rect.top,_viv_fullscreen_rect.right - _viv_fullscreen_rect.left,_viv_fullscreen_rect.bottom - _viv_fullscreen_rect.top,SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS); - - if (_viv_fullscreen_is_maxed) - { - ShowWindow(_viv_hwnd,SW_MAXIMIZE); - } - - _viv_zoom_pos += _viv_fullscreen_zoom_offset; - _viv_zoom_pos = _viv_clamp_zoom_pos(_viv_zoom_pos); - } - else - { - RECT monitor_rect; - - // set fullscreen before we resize. - _viv_is_fullscreen = 1; - - os_MonitorRectFromWindow(_viv_hwnd,1,&monitor_rect); - - SetWindowLong(_viv_hwnd,GWL_STYLE,style & ~(WS_CAPTION|WS_THICKFRAME)); - - _viv_fullscreen_is_maxed = IsZoomed(_viv_hwnd); - if (_viv_fullscreen_is_maxed) - { - ShowWindow(_viv_hwnd,SW_SHOWNORMAL); - } - - GetWindowRect(_viv_hwnd,&_viv_fullscreen_rect); - - SetMenu(_viv_hwnd,0); - _viv_status_show(0); - _viv_controls_show(0); - - SetWindowPos(_viv_hwnd,HWND_TOP,monitor_rect.left,monitor_rect.top,monitor_rect.right - monitor_rect.left,monitor_rect.bottom - monitor_rect.top,SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS); - - _viv_prevent_on_deactivate = 1; - - // create a dummy fullscreen window and destroy it immediately - // this window is created fullscreen correctly, and when our normal window gains focus it will keep the fullscreen setting (no taskbar) - // without this dummy window, sometimes the taskbar will not disappear. - - { - HWND fullscreen_hwnd; - - // Initialize global strings - os_RegisterClassEx( - 0, - _viv_fullscreen_proc, - 0, - LoadCursor(NULL,IDC_ARROW), - (HBRUSH)(COLOR_BTNFACE+1), - "_VIV_FULLSCREEN", - 0); - - fullscreen_hwnd = os_CreateWindowEx( - 0, - "_VIV_FULLSCREEN", - localization_get_string(LOCALIZATION_ID_APP_NAME), - WS_POPUP|WS_VISIBLE, - monitor_rect.left,monitor_rect.top,monitor_rect.right - monitor_rect.left,monitor_rect.bottom - monitor_rect.top, - 0,0,os_hinstance,NULL); - - SetForegroundWindow(fullscreen_hwnd); - - DestroyWindow(fullscreen_hwnd); - } - - // find zoom offset. - { - int zoom_index; - - _viv_fullscreen_zoom_offset = 0; - - if (config_fullscreen_fill_window) - { - for(zoom_index=0;zoom_index<_VIV_ZOOM_MAX;zoom_index++) - { - // debug_printf("%d %d\n",zoom_wide_array[zoom_index] , monitor_rect.right - monitor_rect.left); - - if ((zoom_wide_array[zoom_index] > monitor_rect.right - monitor_rect.left) || (zoom_high_array[zoom_index] > monitor_rect.bottom - monitor_rect.top)) - { - break; - } - - _viv_fullscreen_zoom_offset = zoom_index; - } - - if (_viv_fullscreen_zoom_offset > _viv_zoom_pos) - { - _viv_fullscreen_zoom_offset = _viv_zoom_pos; - } - } - else - if (config_fill_window) - { - int backup_zoom_pos; - - backup_zoom_pos = _viv_zoom_pos; - - for(_viv_zoom_pos=0;_viv_zoom_pos<_VIV_ZOOM_MAX;_viv_zoom_pos++) - { - int rw; - int rh; - - _viv_get_render_size(&rw,&rh); - - // debug_printf("%d %d\n",zoom_wide_array[zoom_index] , monitor_rect.right - monitor_rect.left); - - if ((rw > old_rw) || (rh > old_rh)) - { - break; - } - - _viv_fullscreen_zoom_offset = -_viv_zoom_pos; - } - - _viv_zoom_pos = backup_zoom_pos; - - if (_viv_fullscreen_zoom_offset < -(_VIV_ZOOM_MAX-1-_viv_zoom_pos)) - { - _viv_fullscreen_zoom_offset = -(_VIV_ZOOM_MAX-1-_viv_zoom_pos); - } - } - -// debug_printf("ZOOM OFFSET %d\n",_viv_fullscreen_zoom_offset); - } - - _viv_zoom_pos -= _viv_fullscreen_zoom_offset; - _viv_zoom_pos = _viv_clamp_zoom_pos(_viv_zoom_pos); - - _viv_prevent_on_deactivate = 0; - } - - _viv_prevent_on_size = 0; - - _viv_on_size(); - -// InvalidateRect(_viv_hwnd,0,FALSE); - - // update mouseover - // so we show the cursor corectly in - // _viv_update_show_cursor - { - POINT cursor_pt; - HWND hwnd_mouseover; - int is_mouseover; - - GetCursorPos(&cursor_pt); - is_mouseover = 0; - - hwnd_mouseover = WindowFromPoint(cursor_pt); - if (hwnd_mouseover == _viv_hwnd) - { - RECT client_rect; - - ScreenToClient(_viv_hwnd,&cursor_pt); - - GetClientRect(_viv_hwnd,&client_rect); - - if (PtInRect(&client_rect,cursor_pt)) - { - is_mouseover = 1; - } - } - - _viv_is_mouseover = is_mouseover; - } - - _viv_update_show_cursor(); -} - -static void _viv_slideshow(void) -{ - if (_viv_file_not_found) - { - return; - } - - if (!_viv_is_fullscreen) - { - _viv_toggle_fullscreen(); - } - - if (!_viv_is_slideshow) - { - SetTimer(_viv_hwnd,VIV_ID_SLIDESHOW_TIMER,config_slideshow_rate,0); - - _viv_is_slideshow = 1; - _viv_status_update(); - _viv_toolbar_update_buttons(); - _viv_update_ontop(); - _viv_update_prevent_sleep(); - } -} - -static void _viv_get_render_size(int *prw,int *prh) -{ - RECT rect; - int wide; - int high; - int rw; - int rh; - int fill_window; - int max_zoom_wide; - int max_zoom_high; - - if (!((_viv_image_wide) && (_viv_image_high))) - { - *prw = 0; - *prh = 0; - - return; - } - - GetClientRect(_viv_hwnd,&rect); - wide = rect.right - rect.left; - high = rect.bottom - rect.top - _viv_get_status_high() - _viv_get_controls_high(); - - if (!((wide) && (high))) - { - *prw = 0; - *prh = 0; - - return; - } - - if ((_viv_1to1) || (_viv_doing == _VIV_DOING_1TO1SCROLL)) - { - *prw = _viv_image_wide; - *prh = _viv_image_high; - - return; - } - - if (_viv_is_fullscreen) - { - fill_window = config_fullscreen_fill_window; - } - else - { - fill_window = config_fill_window; - } - - if (config_keep_aspect_ratio) - { - if ((high * _viv_image_wide) / _viv_image_high < wide) - { - // tall image. - // add _viv_image_high - 1 so when we resize the window to 50% it stretches to the screen edges correctly. - rh = high; - rw = ((high * (__int64)_viv_image_wide) + _viv_image_high - 1) / _viv_image_high; - - // make sure we have some width. - if (rw <= 0) - { - rw = 1; - } - } - else - { - // long image. - // add _viv_image_wide - 1 so when we resize the window to 50% it stretches to the screen edges correctly. - rw = wide; - rh = ((wide * (__int64)_viv_image_high) + _viv_image_wide - 1) / _viv_image_wide; - - // make sure we have some height - if (rh <= 0) - { - rh = 1; - } - } - - if (!fill_window) - { - if ((rw > _viv_image_wide) || (rh > _viv_image_high)) - { - rw = _viv_image_wide; - rh = _viv_image_high; - } - } - } - else - { - rw = wide; - rh = high; - - if (!fill_window) - { - if (rw > _viv_image_wide) - { - rw = _viv_image_wide; - } - - if (rh > _viv_image_high) - { - rh = _viv_image_high; - } - } - } - -// debug_printf("GET_RENDER_SIZE wide %d high %d rw %d rh %d fill_window %d\n",wide,high,rw,rh,fill_window); - - if (!config_allow_shrinking) - { - if (config_keep_aspect_ratio) - { - if ((rw < _viv_image_wide) || (rh < _viv_image_high)) - { - rw = _viv_image_wide; - rh = _viv_image_high; - } - } - else - { - if (rw < _viv_image_wide) - { - rw = _viv_image_wide; - } - - if (rh < _viv_image_high) - { - rh = _viv_image_high; - } - } - } - - if (config_keep_aspect_ratio) - { - if (rw > _viv_image_wide) - { - max_zoom_wide = rw * 16; - } - else - { - max_zoom_wide = _viv_image_wide * 16; - } - - if (rh > _viv_image_high) - { - max_zoom_high = rh * 16; - } - else - { - max_zoom_high = _viv_image_high * 16; - } - } - else - { - max_zoom_wide = rw * 16; - max_zoom_high = rh * 16; - } -/* - if (max_zoom_wide < _viv_image_wide) - { - max_zoom_wide = _viv_image_wide; - } - - if (max_zoom_high < _viv_image_high) - { - max_zoom_high = _viv_image_high; - } - */ - if (_viv_zoom_pos) - { - rw = rw + (int)((max_zoom_wide - rw) * _viv_zoom_presets[_viv_zoom_pos]); - rh = rh + (int)((max_zoom_high - rh) * _viv_zoom_presets[_viv_zoom_pos]); - } - - *prw = rw; - *prh = rh; -} - -static void _viv_set_custom_rate(void) -{ - if (DialogBox(os_hinstance,MAKEINTRESOURCE(IDD_CUSTOM_RATE),_viv_hwnd,_viv_custom_rate_proc)) - { - switch(config_slideshow_custom_rate_type) - { - case 0: - config_slideshow_rate = config_slideshow_custom_rate; - break; - - case 1: - config_slideshow_rate = config_slideshow_custom_rate * 1000; - break; - - case 2: - config_slideshow_rate = config_slideshow_custom_rate * 1000 * 60; - break; - } - - if (config_slideshow_rate < 1) - { - config_slideshow_rate = 1; - } - - if (_viv_is_slideshow) - { - KillTimer(_viv_hwnd,VIV_ID_SLIDESHOW_TIMER); - - SetTimer(_viv_hwnd,VIV_ID_SLIDESHOW_TIMER,config_slideshow_rate,0); - } - - _viv_status_update_slideshow_rate(); - } -} - -static void _viv_set_rate(int rate) -{ - config_slideshow_rate = rate; - - if (_viv_is_slideshow) - { - KillTimer(_viv_hwnd,VIV_ID_SLIDESHOW_TIMER); - - SetTimer(_viv_hwnd,VIV_ID_SLIDESHOW_TIMER,config_slideshow_rate,0); - } - - _viv_status_update_slideshow_rate(); -} - -static void _viv_check_menus(HMENU hmenu) -{ - int is_slideshow; - int fill_window; - int rw; - int rh; - int slideshow_rate_id; - UINT is_image_enabled; - - is_slideshow = 0; - - if (_viv_is_fullscreen) - { - if (_viv_is_slideshow) - { - is_slideshow = 1; - _viv_status_update(); - _viv_toolbar_update_buttons(); - _viv_update_ontop(); - } - - fill_window = config_fullscreen_fill_window; - } - else - { - fill_window = config_fill_window; - } - - _viv_get_render_size(&rw,&rh); - - is_image_enabled = ((*_viv_current_fd->cFileName) && (!_viv_file_not_found) && (!_viv_load_failed)) ? MF_ENABLED : MF_DISABLED; - - EnableMenuItem(hmenu,VIV_ID_FILE_CLOSE,is_image_enabled); - EnableMenuItem(hmenu,VIV_ID_EDIT_COPY,is_image_enabled); - EnableMenuItem(hmenu,VIV_ID_EDIT_COPY_FILENAME,is_image_enabled); - EnableMenuItem(hmenu,VIV_ID_EDIT_COPY_IMAGE,is_image_enabled); - EnableMenuItem(hmenu,VIV_ID_EDIT_COPY_TO,is_image_enabled); - EnableMenuItem(hmenu,VIV_ID_EDIT_CUT,is_image_enabled); - EnableMenuItem(hmenu,VIV_ID_FILE_DELETE,is_image_enabled); - EnableMenuItem(hmenu,VIV_ID_FILE_EDIT,is_image_enabled); - EnableMenuItem(hmenu,VIV_ID_EDIT_MOVE_TO,is_image_enabled); - EnableMenuItem(hmenu,VIV_ID_FILE_OPEN_FILE_LOCATION,is_image_enabled); - EnableMenuItem(hmenu,VIV_ID_FILE_PREVIEW,is_image_enabled); - EnableMenuItem(hmenu,VIV_ID_FILE_PRINT,is_image_enabled); - EnableMenuItem(hmenu,VIV_ID_FILE_PROPERTIES,is_image_enabled); - EnableMenuItem(hmenu,VIV_ID_FILE_SET_DESKTOP_WALLPAPER,is_image_enabled); - EnableMenuItem(hmenu,VIV_ID_FILE_RENAME,is_image_enabled); - - EnableMenuItem(hmenu,VIV_ID_EDIT_ROTATE_270,is_image_enabled); - EnableMenuItem(hmenu,VIV_ID_EDIT_ROTATE_90,is_image_enabled); -// EnableMenuItem(hmenu,VIV_ID_SLIDESHOW_PAUSE,is_image_enabled); - - CheckMenuItem(hmenu,VIV_ID_VIEW_CAPTION,config_show_caption ? MF_CHECKED : MF_UNCHECKED); - CheckMenuItem(hmenu,VIV_ID_VIEW_THICKFRAME,config_show_thickframe ? MF_CHECKED : MF_UNCHECKED); - CheckMenuItem(hmenu,VIV_ID_VIEW_MENU,config_show_menu ? MF_CHECKED : MF_UNCHECKED); - CheckMenuItem(hmenu,VIV_ID_VIEW_CONTROLS,config_show_controls ? MF_CHECKED : MF_UNCHECKED); - CheckMenuItem(hmenu,VIV_ID_VIEW_STATUS,config_show_status ? MF_CHECKED : MF_UNCHECKED); - CheckMenuItem(hmenu,VIV_ID_VIEW_ALLOW_SHRINKING,config_allow_shrinking ? MF_CHECKED : MF_UNCHECKED); - CheckMenuItem(hmenu,VIV_ID_VIEW_KEEP_ASPECT_RATIO,config_keep_aspect_ratio ? MF_CHECKED : MF_UNCHECKED); - CheckMenuItem(hmenu,VIV_ID_VIEW_FILL_WINDOW,fill_window ? MF_CHECKED : MF_UNCHECKED); - CheckMenuItem(hmenu,VIV_ID_VIEW_1TO1,((rw == _viv_image_wide) && (rh == _viv_image_high)) ? MF_CHECKED : MF_UNCHECKED); - CheckMenuItem(hmenu,VIV_ID_VIEW_FULLSCREEN,_viv_is_fullscreen ? MF_CHECKED : MF_UNCHECKED); - CheckMenuItem(hmenu,VIV_ID_VIEW_SLIDESHOW,is_slideshow ? MF_CHECKED : MF_UNCHECKED); - CheckMenuItem(hmenu,VIV_ID_VIEW_ONTOP_ALWAYS,config_ontop == 1 ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); - CheckMenuItem(hmenu,VIV_ID_VIEW_ONTOP_WHILE_PLAYING_OR_ANIMATING,config_ontop == 2 ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); - CheckMenuItem(hmenu,VIV_ID_VIEW_ONTOP_NEVER,config_ontop == 0 ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); - - CheckMenuItem(hmenu,VIV_ID_SLIDESHOW_PAUSE,_viv_is_slideshow ? MF_CHECKED : MF_UNCHECKED); - - switch(config_slideshow_rate) - { - case 250: slideshow_rate_id = VIV_ID_SLIDESHOW_RATE_250; break; - case 500: slideshow_rate_id = VIV_ID_SLIDESHOW_RATE_500; break; - case 1000: slideshow_rate_id = VIV_ID_SLIDESHOW_RATE_1000; break; - case 2000: slideshow_rate_id = VIV_ID_SLIDESHOW_RATE_2000; break; - case 3000: slideshow_rate_id = VIV_ID_SLIDESHOW_RATE_3000; break; - case 4000: slideshow_rate_id = VIV_ID_SLIDESHOW_RATE_4000; break; - case 5000: slideshow_rate_id = VIV_ID_SLIDESHOW_RATE_5000; break; - case 6000: slideshow_rate_id = VIV_ID_SLIDESHOW_RATE_6000; break; - case 7000: slideshow_rate_id = VIV_ID_SLIDESHOW_RATE_7000; break; - case 8000: slideshow_rate_id = VIV_ID_SLIDESHOW_RATE_8000; break; - case 9000: slideshow_rate_id = VIV_ID_SLIDESHOW_RATE_9000; break; - case 10000: slideshow_rate_id = VIV_ID_SLIDESHOW_RATE_10000; break; - case 20000: slideshow_rate_id = VIV_ID_SLIDESHOW_RATE_20000; break; - case 30000: slideshow_rate_id = VIV_ID_SLIDESHOW_RATE_30000; break; - case 40000: slideshow_rate_id = VIV_ID_SLIDESHOW_RATE_40000; break; - case 50000: slideshow_rate_id = VIV_ID_SLIDESHOW_RATE_50000; break; - case 60000: slideshow_rate_id = VIV_ID_SLIDESHOW_RATE_60000; break; - - default: - slideshow_rate_id = VIV_ID_SLIDESHOW_RATE_CUSTOM; - break; - } - - CheckMenuItem(hmenu,VIV_ID_SLIDESHOW_RATE_250,slideshow_rate_id == VIV_ID_SLIDESHOW_RATE_250 ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); - CheckMenuItem(hmenu,VIV_ID_SLIDESHOW_RATE_500,slideshow_rate_id == VIV_ID_SLIDESHOW_RATE_500 ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); - CheckMenuItem(hmenu,VIV_ID_SLIDESHOW_RATE_1000,slideshow_rate_id == VIV_ID_SLIDESHOW_RATE_1000 ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); - CheckMenuItem(hmenu,VIV_ID_SLIDESHOW_RATE_2000,slideshow_rate_id == VIV_ID_SLIDESHOW_RATE_2000 ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); - CheckMenuItem(hmenu,VIV_ID_SLIDESHOW_RATE_3000,slideshow_rate_id == VIV_ID_SLIDESHOW_RATE_3000 ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); - CheckMenuItem(hmenu,VIV_ID_SLIDESHOW_RATE_4000,slideshow_rate_id == VIV_ID_SLIDESHOW_RATE_4000 ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); - CheckMenuItem(hmenu,VIV_ID_SLIDESHOW_RATE_5000,slideshow_rate_id == VIV_ID_SLIDESHOW_RATE_5000 ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); - CheckMenuItem(hmenu,VIV_ID_SLIDESHOW_RATE_6000,slideshow_rate_id == VIV_ID_SLIDESHOW_RATE_6000 ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); - CheckMenuItem(hmenu,VIV_ID_SLIDESHOW_RATE_7000,slideshow_rate_id == VIV_ID_SLIDESHOW_RATE_7000 ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); - CheckMenuItem(hmenu,VIV_ID_SLIDESHOW_RATE_8000,slideshow_rate_id == VIV_ID_SLIDESHOW_RATE_8000 ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); - CheckMenuItem(hmenu,VIV_ID_SLIDESHOW_RATE_9000,slideshow_rate_id == VIV_ID_SLIDESHOW_RATE_9000 ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); - CheckMenuItem(hmenu,VIV_ID_SLIDESHOW_RATE_10000,slideshow_rate_id == VIV_ID_SLIDESHOW_RATE_10000 ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); - CheckMenuItem(hmenu,VIV_ID_SLIDESHOW_RATE_20000,slideshow_rate_id == VIV_ID_SLIDESHOW_RATE_20000 ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); - CheckMenuItem(hmenu,VIV_ID_SLIDESHOW_RATE_30000,slideshow_rate_id == VIV_ID_SLIDESHOW_RATE_30000 ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); - CheckMenuItem(hmenu,VIV_ID_SLIDESHOW_RATE_40000,slideshow_rate_id == VIV_ID_SLIDESHOW_RATE_40000 ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); - CheckMenuItem(hmenu,VIV_ID_SLIDESHOW_RATE_50000,slideshow_rate_id == VIV_ID_SLIDESHOW_RATE_50000 ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); - CheckMenuItem(hmenu,VIV_ID_SLIDESHOW_RATE_60000,slideshow_rate_id == VIV_ID_SLIDESHOW_RATE_60000 ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); - CheckMenuItem(hmenu,VIV_ID_SLIDESHOW_RATE_CUSTOM,slideshow_rate_id == VIV_ID_SLIDESHOW_RATE_CUSTOM ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); - - CheckMenuItem(hmenu,VIV_ID_ANIMATION_PLAY_PAUSE,_viv_animation_play ? MF_CHECKED : MF_UNCHECKED); - - CheckMenuItem(hmenu,VIV_ID_NAV_SHUFFLE,config_shuffle ? MF_CHECKED : MF_UNCHECKED); - - CheckMenuItem(hmenu,VIV_ID_NAV_SORT_NAME,config_nav_sort == CONFIG_NAV_SORT_NAME ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); - CheckMenuItem(hmenu,VIV_ID_NAV_SORT_FULL_PATH,config_nav_sort == CONFIG_NAV_SORT_FULL_PATH_AND_FILENAME ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); - CheckMenuItem(hmenu,VIV_ID_NAV_SORT_SIZE,config_nav_sort == CONFIG_NAV_SORT_SIZE ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); - CheckMenuItem(hmenu,VIV_ID_NAV_SORT_DATE_MODIFIED,config_nav_sort == CONFIG_NAV_SORT_DATE_MODIFIED ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); - CheckMenuItem(hmenu,VIV_ID_NAV_SORT_DATE_CREATED,config_nav_sort == CONFIG_NAV_SORT_DATE_CREATED ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); - - CheckMenuItem(hmenu,VIV_ID_NAV_SORT_ASCENDING,config_nav_sort_ascending ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); - CheckMenuItem(hmenu,VIV_ID_NAV_SORT_DESCENDING,(!config_nav_sort_ascending) ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); - - CheckMenuItem(hmenu,VIV_ID_VIEW_1TO1,((rw == _viv_image_wide) && (rh == _viv_image_high)) ? MF_CHECKED : MF_UNCHECKED); -} - -static void _viv_delete(int permanently) -{ - if (*_viv_current_fd->cFileName) - { - SHFILEOPSTRUCT fo; - WIN32_FIND_DATA fd; - wchar_t filename_list[STRING_SIZE+1]; - - string_copy_double_null(filename_list,_viv_current_fd->cFileName); - os_copy_memory(&fd,_viv_current_fd,sizeof(WIN32_FIND_DATA)); - - ZeroMemory(&fo,sizeof(SHFILEOPSTRUCT)); - fo.hwnd = _viv_hwnd; - fo.wFunc = FO_DELETE; - fo.pFrom = filename_list; - fo.fFlags = permanently ? 0 : FOF_ALLOWUNDO; - - if (SHFileOperation(&fo) == 0) - { - if (!fo.fAnyOperationsAborted) - { - _viv_playlist_delete(&fd); - - if (!_viv_next(0,1,0,0)) - { - _viv_blank(); - } - } - } - } -} - -static INT_PTR CALLBACK _viv_rename_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) -{ - switch(msg) - { - case WM_INITDIALOG: - { - wchar_t name[STRING_SIZE]; - - os_center_dialog(hwnd); - - os_SetWindowText_localization_id(hwnd,LOCALIZATION_ID_RENAME_CAPTION); - - string_copy(name,string_get_filename_part((wchar_t *)lParam)); - string_remove_extension(name); - - SetDlgItemText(hwnd,IDC_RENAME_OLD_EDIT,(wchar_t *)lParam); - SetDlgItemText(hwnd,IDC_RENAME_EDIT,name); - - return TRUE; - } - - case WM_COMMAND: - - switch(LOWORD(wParam)) - { - case IDOK: - - { - wchar_t old_filename[STRING_SIZE]; - wchar_t new_filename[STRING_SIZE]; - wchar_t path[STRING_SIZE]; - wchar_t new_full_path_and_filename[STRING_SIZE]; - wchar_t *ext; - int dont_end_dialog; - - GetDlgItemText(hwnd,IDC_RENAME_OLD_EDIT,old_filename,STRING_SIZE); - GetDlgItemText(hwnd,IDC_RENAME_EDIT,new_filename,STRING_SIZE); - - string_get_path_part(path,old_filename); - ext = string_get_extension(old_filename); - dont_end_dialog = 0; - - string_path_combine(new_full_path_and_filename,path,new_filename); - if (*ext) - { - string_cat_utf8(new_full_path_and_filename,(const utf8_t *)"."); - string_cat(new_full_path_and_filename,ext); - } - - if (string_compare(old_filename,new_full_path_and_filename) != 0) - { - SHFILEOPSTRUCT fo; - - wchar_t old_filename_list[STRING_SIZE+1]; - wchar_t new_filename_list[STRING_SIZE+1]; - - string_copy_double_null(old_filename_list,old_filename); - string_copy_double_null(new_filename_list,new_full_path_and_filename); - - ZeroMemory(&fo,sizeof(SHFILEOPSTRUCT)); - fo.hwnd = _viv_hwnd; - fo.wFunc = FO_RENAME; - fo.pFrom = old_filename_list; - fo.pTo = new_filename_list; - fo.fFlags = FOF_ALLOWUNDO | FOF_WANTMAPPINGHANDLE; - - // returns ERROR_CANCELLED if user cancelled. - if (SHFileOperation(&fo) == 0) - { - if (fo.fAnyOperationsAborted) - { - // user clicked No to a rename collision - // (not cancelled). - dont_end_dialog = 1; - } - else - { - const wchar_t *file_op_new_name; - - file_op_new_name = new_full_path_and_filename; - - if (fo.hNameMappings) - { - _viv_name_mapping_t *mappings; - - mappings = (_viv_name_mapping_t *)fo.hNameMappings; - - if (mappings->count == 1) - { - // use the resolved name incase there was a rename collision. - file_op_new_name = mappings->mappings[0].pszNewPath; - } - } - - // has the current file changed? slideshow could make this a different filename - if (string_compare(old_filename,_viv_current_fd->cFileName) == 0) - { - // rename - string_copy_with_bufsize(_viv_current_fd->cFileName,MAX_PATH,file_op_new_name); - - _viv_playlist_rename(old_filename,file_op_new_name); - - _viv_update_title(); - } - } - - if (fo.hNameMappings) - { - SHFreeNameMappings(fo.hNameMappings); - } - } - } - - if (!dont_end_dialog) - { - EndDialog(hwnd,1); - } - } - - break; - - - case IDCANCEL: - EndDialog(hwnd,0); - break; - } - - break; - } - - return FALSE; -} - -static void _viv_rename(void) -{ - if (*_viv_current_fd->cFileName) - { - DialogBoxParam(os_hinstance,MAKEINTRESOURCE(IDD_RENAME),_viv_hwnd,_viv_rename_proc,(LPARAM)_viv_current_fd->cFileName); - } -} - -static void _viv_copy(int cut) -{ - if (*_viv_current_fd->cFileName) - { - if (OpenClipboard(_viv_hwnd)) - { - EmptyClipboard(); - - _viv_set_clipboard_image(); - - { - HGLOBAL hmem; - int wlen; - - wlen = string_get_length(_viv_current_fd->cFileName); - - hmem = GlobalAlloc(GMEM_MOVEABLE,(wlen + 1 + 1) * sizeof(wchar_t) + sizeof(DROPFILES)); - if (hmem) - { - DROPFILES *df; - - // build the dropfiles struct - df = (DROPFILES *)GlobalLock(hmem); - if (df) - { - df->pFiles = sizeof(DROPFILES); - df->fWide = 1; - df->fNC = 0; - df->pt.x = 0; - df->pt.y = 0; - - os_copy_memory(df+1,_viv_current_fd->cFileName,wlen * sizeof(wchar_t)); - ((wchar_t *)(df + 1))[wlen] = 0; - ((wchar_t *)(df + 1))[wlen+1] = 0; - - GlobalUnlock(hmem); - } - - // looking at example code,none seem to free hglobal. - // apparently the system now owns the handle - SetClipboardData(CF_HDROP,hmem); - } - } - - { - HGLOBAL hmem; - - hmem = GlobalAlloc(GMEM_MOVEABLE,sizeof(DWORD)); - if (hmem) - { - DWORD *effect; - - // build the dropfiles struct - effect = (DWORD *)GlobalLock(hmem); - if (effect) - { - *effect = cut ? DROPEFFECT_MOVE : (DROPEFFECT_COPY|DROPEFFECT_LINK); - - GlobalUnlock(hmem); - } - - // looking at example code,none seem to free hglobal. - // apparently the system now owns the handle - SetClipboardData(_viv_get_CF_PREFERREDDROPEFFECT(),hmem); - } - } - - CloseClipboard(); - } - } -} - -static void _viv_copy_filename(void) -{ - if (*_viv_current_fd->cFileName) - { - if (OpenClipboard(_viv_hwnd)) - { - EmptyClipboard(); - - { - HGLOBAL hmem; - int wlen; - - wlen = string_get_length(_viv_current_fd->cFileName); - - hmem = GlobalAlloc(GMEM_MOVEABLE,(wlen + 1) * sizeof(wchar_t)); - if (hmem) - { - wchar_t *wstring; - - // build the dropfiles struct - wstring = (wchar_t *)GlobalLock(hmem); - if (wstring) - { - os_copy_memory(wstring,_viv_current_fd->cFileName,wlen*sizeof(wchar_t)); - wstring[wlen] = 0; - - GlobalUnlock(hmem); - } - - // looking at example code,none seem to free hglobal. - // apparently the system now owns the handle - SetClipboardData(CF_UNICODETEXT,hmem); - } - } - - CloseClipboard(); - } - } -} - -static void _viv_set_clipboard_image(void) -{ - if (_viv_frame_count) - { - if (_viv_frames[_viv_frame_position].hbitmap) - { - HDC screen_hdc; - - screen_hdc = GetDC(0); - if (screen_hdc) - { - HDC mem1_hdc; - - mem1_hdc = CreateCompatibleDC(screen_hdc); - if (mem1_hdc) - { - HDC mem2_hdc; - - mem2_hdc = CreateCompatibleDC(screen_hdc); - if (mem2_hdc) - { - HBITMAP mem1_hbitmap; - - mem1_hbitmap = CreateCompatibleBitmap(screen_hdc,_viv_image_wide,_viv_image_high); - if (mem1_hbitmap) - { - HGDIOBJ last_mem1_hbitmap; - HGDIOBJ last_mem2_hbitmap; - - last_mem1_hbitmap = SelectObject(mem1_hdc,mem1_hbitmap); - last_mem2_hbitmap = SelectObject(mem2_hdc,_viv_frames[_viv_frame_position].hbitmap); - - BitBlt(mem1_hdc,0,0,_viv_image_wide,_viv_image_high,mem2_hdc,0,0,SRCCOPY); - - SelectObject(mem2_hdc,last_mem2_hbitmap); - SelectObject(mem1_hdc,last_mem1_hbitmap); - - SetClipboardData(CF_BITMAP,mem1_hbitmap); - } - - DeleteDC(mem2_hdc); - } - - DeleteDC(mem1_hdc); - } - - ReleaseDC(0,screen_hdc); - } - } - } -} - -static void _viv_copy_image(void) -{ - if (*_viv_current_fd->cFileName) - { - if (OpenClipboard(_viv_hwnd)) - { - EmptyClipboard(); - - _viv_set_clipboard_image(); - - CloseClipboard(); - } - } -} - -static int _viv_is_key_state(int control,int shift,int alt) -{ - if (GetKeyState(VK_CONTROL) < 0) - { - if (!control) return 0; - } - else - { - if (control) return 0; - } - - if (GetKeyState(VK_SHIFT) < 0) - { - if (!shift) return 0; - } - else - { - if (shift) return 0; - } - - if (GetKeyState(VK_MENU) < 0) - { - if (!alt) return 0; - } - else - { - if (alt) return 0; - } - - return 1; -} - -static CLIPFORMAT _viv_get_CF_PREFERREDDROPEFFECT(void) -{ - if (!_viv_CF_PREFERREDDROPEFFECT) - { - _viv_CF_PREFERREDDROPEFFECT = RegisterClipboardFormat(CFSTR_PREFERREDDROPEFFECT); - } - - return _viv_CF_PREFERREDDROPEFFECT; -} - -static void _viv_pause(void) -{ -/* - if (_viv_file_not_found) - { - MessageBeep(MB_OK); - return; - } -*/ - if (_viv_is_slideshow) - { - KillTimer(_viv_hwnd,VIV_ID_SLIDESHOW_TIMER); - - _viv_is_slideshow = 0; - } - else - { - SetTimer(_viv_hwnd,VIV_ID_SLIDESHOW_TIMER,config_slideshow_rate,0); - - _viv_is_slideshow = 1; - } - - _viv_status_update(); - _viv_toolbar_update_buttons(); - _viv_update_ontop(); - _viv_update_prevent_sleep(); -} - -static void _viv_increase_rate(int dec) -{ - if (dec) - { - int i; - - for(i=0;i<_VIV_SLIDESHOW_RATE_PRESET_COUNT;i++) - { - if (config_slideshow_rate > _viv_slideshow_rate_presets[_VIV_SLIDESHOW_RATE_PRESET_COUNT-i-1]) - { - _viv_set_rate(_viv_slideshow_rate_presets[_VIV_SLIDESHOW_RATE_PRESET_COUNT-i-1]); - - break; - } - } - } - else - { - int i; - - for(i=0;i<_VIV_SLIDESHOW_RATE_PRESET_COUNT;i++) - { - if (config_slideshow_rate < _viv_slideshow_rate_presets[i]) - { - _viv_set_rate(_viv_slideshow_rate_presets[i]); - - break; - } - } - } - - _viv_status_update_slideshow_rate(); -} - -static void _viv_increase_animation_rate(int dec) -{ - if (dec) - { - if (_viv_animation_rate_pos) - { - _viv_animation_rate_pos--; - } - } - else - { - if (_viv_animation_rate_pos < _VIV_ANIMATION_RATE_MAX-1) - { - _viv_animation_rate_pos++; - } - } - - _viv_status_update_temp_animation_rate(); -} - -static void _viv_reset_animation_rate(void) -{ - _viv_animation_rate_pos = _VIV_ANIMATION_RATE_ONE; - - _viv_status_update_temp_animation_rate(); -} - -static void _viv_file_preview(void) -{ - if (*_viv_current_fd->cFileName) - { - os_shell_execute(_viv_hwnd,_viv_current_fd->cFileName,0,"preview",0); - } -} - -static void _viv_file_print(void) -{ - if (*_viv_current_fd->cFileName) - { - os_shell_execute(_viv_hwnd,_viv_current_fd->cFileName,0,"print",0); - } -} - -static void _viv_file_set_desktop_wallpaper(void) -{ - if (*_viv_current_fd->cFileName) - { - if (!_viv_stobject_hmodule) - { - _viv_stobject_hmodule = LoadLibraryA("stobject.dll"); - } - - if (_viv_stobject_hmodule) - { - os_shell_execute(_viv_hwnd,_viv_current_fd->cFileName,0,"setdesktopwallpaper",0); - } - } -} - -static void _viv_edit_rotate(int counterclockwise) -{ - if (*_viv_current_fd->cFileName) - { - // FIXME: we need to wait for image to load. - if (_viv_frame_loaded_count == _viv_frame_count) - { - // this tends to fail if called too quickly after a previous call - // can't seem to catch the error .. - if (os_shell_execute(_viv_hwnd,_viv_current_fd->cFileName,1,counterclockwise ? "rotate270" : "rotate90",0)) - { - int i; - int temp; - - // rotate images in memory too - - for(i=0;i<_viv_frame_count;i++) - { - HBITMAP new_hbitmap; - - // i do the reverse to reverse the orientation. - new_hbitmap = _viv_orientate_hbitmap(_viv_frames[i].hbitmap,counterclockwise ? 8 : 6); - - if (new_hbitmap) - { - DeleteObject(_viv_frames[i].hbitmap); - - _viv_frames[i].hbitmap = new_hbitmap; - } - - // delete mipmaps - if (_viv_frames[i].mipmap) - { - _viv_mipmap_free(_viv_frames[i].mipmap); - - _viv_frames[i].mipmap = NULL; - } - } - - temp = _viv_image_wide; - _viv_image_wide = _viv_image_high; - _viv_image_high = temp; - - _viv_view_set(_viv_view_x,_viv_view_y,1); - - _viv_update_src_pixel(1,0); - _viv_status_update(); - - InvalidateRect(_viv_hwnd,0,FALSE); - } - } - } -} - -static void _viv_file_edit(void) -{ - if (*_viv_current_fd->cFileName) - { - os_shell_execute(_viv_hwnd,_viv_current_fd->cFileName,0,"edit",0); - } -} - -static void _viv_open_file_location(void) -{ - if (*_viv_current_fd->cFileName) - { - int openpathok; - - openpathok = 0; - - if (os_SHOpenFolderAndSelectItems) - { - wchar_t path_part[STRING_SIZE]; - ITEMIDLIST *folder_idlist; - - string_get_path_part(path_part,_viv_current_fd->cFileName); - - // if path_part_buf.buf is an empty string, os_ILCreateFromPath will - // correctly return the desktop pidl (an empty pidl). - folder_idlist = os_ILCreateFromPath(path_part); - - debug_printf("folder_idlist %p\n",folder_idlist); - if (folder_idlist) - { - ITEMIDLIST *idlist; - - idlist = os_ILCreateFromPath(_viv_current_fd->cFileName); - debug_printf("idlist %S %p\n",_viv_current_fd->cFileName,idlist); - if (idlist) - { - HRESULT hres; - - debug_printf("ENTER os_SHOpenFolderAndSelectItems\n"); - - hres = os_SHOpenFolderAndSelectItems(folder_idlist,1,(LPCITEMIDLIST *)&idlist,0); - - debug_printf("os_SHOpenFolderAndSelectItems %08x\n",hres); - if (SUCCEEDED(hres)) - { - openpathok = 1; - } - else - if (hres == E_ABORT) - { - // aborted, QTBar after 10seconds. - openpathok = 1; - } - - CoTaskMemFree(idlist); - } - - CoTaskMemFree(folder_idlist); - } - } - - if (!openpathok) - { - wchar_t path[STRING_SIZE]; - - string_get_path_part(path,_viv_current_fd->cFileName); - - os_shell_execute(_viv_hwnd,path,0,NULL,NULL); - } - } -} - - -static void _viv_properties(void) -{ - if (*_viv_current_fd->cFileName) - { - os_shell_execute(_viv_hwnd,_viv_current_fd->cFileName,0,"properties",0); - } -} - -static void _viv_doing_cancel(void) -{ - if (_viv_doing) - { - int was_doing; - - was_doing = _viv_doing; - - _viv_doing = _VIV_DOING_NOTHING; - - if (was_doing == _VIV_DOING_MSCROLL) - { - ShowCursor(TRUE); - } - - if (was_doing == _VIV_DOING_1TO1SCROLL) - { -// ShowCursor(TRUE); - _viv_view_set(_viv_doing_x,_viv_doing_y,1); - InvalidateRect(_viv_hwnd,0,FALSE); - } - - ReleaseCapture(); - } -} - -static const char *_viv_get_copydata_string(const char *p,const char *e,wchar_t *buf,int bufsize) -{ - wchar_t *d; - - d = buf; - - while(p + sizeof(wchar_t) <= e) - { - if (!*(wchar_t *)p) - { - p += sizeof(wchar_t); - break; - } - - if (bufsize > 1) - { - *d++ = *(wchar_t *)p; - bufsize--; - } - - p+=sizeof(wchar_t); - } - - if (bufsize > 0) - { - *d = 0; - } - - return p; -} - - -static void _viv_blank(void) -{ - _viv_clear(); - - if (_viv_random) - { - mem_free(_viv_random); - - _viv_random = 0; - } - - _viv_current_fd->cFileName[0] = 0; - - _viv_update_src_pixel(1,0); - _viv_status_update(); - _viv_update_title(); - - // free all dropfiles - _viv_playlist_clearall(); - - _viv_start_first_frame(); - _viv_process_pending_clear(); -} - -static INT_PTR CALLBACK _viv_options_general_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) -{ - switch(msg) - { - case WM_INITDIALOG: - { - int exti; - - os_SetDlgItemText_localization_id(hwnd,IDC_APPDATA,LOCALIZATION_ID_STORE_SETTINGS_APPDATA); - os_SetDlgItemText_localization_id(hwnd,IDC_MULTIPLE_INSTANCES,LOCALIZATION_ID_ALLOW_MULTIPLE_INSTANCES); - os_SetDlgItemText_localization_id(hwnd,IDC_STARTMENU,LOCALIZATION_ID_STARTMENU_SHORTCUTS); - os_SetDlgItemText_localization_id(hwnd,IDC_ASSOCIATIONS_GROUPBOX,LOCALIZATION_ID_ASSOCIATIONS); - os_SetDlgItemText_localization_id(hwnd,IDC_CHECKALL,LOCALIZATION_ID_CHECK_ALL); - os_SetDlgItemText_localization_id(hwnd,IDC_CHECKNONE,LOCALIZATION_ID_CHECK_NONE); - - if (config_appdata) - { - CheckDlgButton(hwnd,IDC_APPDATA,BST_CHECKED); - } - - if (config_multiple_instances) - { - CheckDlgButton(hwnd,IDC_MULTIPLE_INSTANCES,BST_CHECKED); - } - - for(exti=0;exti<_VIV_ASSOCIATION_COUNT;exti++) - { - if (_viv_is_association(_viv_association_extensions[exti])) - { - CheckDlgButton(hwnd,_viv_association_dlg_item_id[exti],BST_CHECKED); - } - } - - if (_viv_is_start_menu_shortcuts()) - { - CheckDlgButton(hwnd,IDC_STARTMENU,BST_CHECKED); - } - - return FALSE; - } - - case WM_COMMAND: - - switch(LOWORD(wParam)) - { - case IDC_STARTMENU: - case IDC_APPDATA: - _viv_options_update_sheild(GetParent(hwnd)); - break; - - case IDC_CHECKALL: - case IDC_CHECKNONE: - { - UINT check; - - check = LOWORD(wParam) == IDC_CHECKALL ? BST_CHECKED : BST_UNCHECKED; - - CheckDlgButton(hwnd,IDC_BMP,check); - CheckDlgButton(hwnd,IDC_GIF,check); - CheckDlgButton(hwnd,IDC_ICO,check); - CheckDlgButton(hwnd,IDC_JPEG,check); - CheckDlgButton(hwnd,IDC_JPG,check); - CheckDlgButton(hwnd,IDC_PNG,check); - CheckDlgButton(hwnd,IDC_TIF,check); - CheckDlgButton(hwnd,IDC_TIFF,check); - CheckDlgButton(hwnd,IDC_WEBP,check); - - break; - } - } - - break; - - } - - return FALSE; -} - -static void _viv_options_key_list_sel_change(HWND hwnd,int previous_key_index) -{ - int index; - _viv_key_list_t *keylist; - int key_count; - - keylist = (_viv_key_list_t *)GetWindowLongPtr(GetDlgItem(hwnd,IDC_COMMANDS_LIST),GWLP_USERDATA); - - index = ListBox_GetCurSel(GetDlgItem(hwnd,IDC_COMMANDS_LIST)); - - ListBox_ResetContent(GetDlgItem(hwnd,IDC_KEYS_LIST)); - SetWindowRedraw(GetDlgItem(hwnd,IDC_KEYS_LIST),FALSE); - - key_count = 0; - - if (index != LB_ERR) - { - int command_index; - config_key_t *key; - - command_index = ListBox_GetItemData(GetDlgItem(hwnd,IDC_COMMANDS_LIST),index); - - key = keylist->start[command_index]; - - while(key) - { - wchar_t key_text[STRING_SIZE]; - int listbox_index; - - _viv_get_key_text(key_text,key->key); - - listbox_index = ListBox_AddString(GetDlgItem(hwnd,IDC_KEYS_LIST),key_text); - - if (listbox_index != LB_ERR) - { - ListBox_SetItemData(GetDlgItem(hwnd,IDC_KEYS_LIST),listbox_index,key->key); - } - - key_count++; - key = key->next; - } - - EnableWindow(GetDlgItem(hwnd,IDC_ADD_KEY_BUTTON),TRUE); - - if (key_count) - { - EnableWindow(GetDlgItem(hwnd,IDC_EDIT_KEY_BUTTON),TRUE); - EnableWindow(GetDlgItem(hwnd,IDC_REMOVE_KEY_BUTTON),TRUE); - - if ((previous_key_index == LB_ERR) || (previous_key_index > key_count - 1)) - { - previous_key_index = key_count - 1; - } - - ListBox_SetCurSel(GetDlgItem(hwnd,IDC_KEYS_LIST),previous_key_index); - } - else - { - EnableWindow(GetDlgItem(hwnd,IDC_EDIT_KEY_BUTTON),FALSE); - EnableWindow(GetDlgItem(hwnd,IDC_REMOVE_KEY_BUTTON),FALSE); - } - } - else - { - EnableWindow(GetDlgItem(hwnd,IDC_ADD_KEY_BUTTON),FALSE); - EnableWindow(GetDlgItem(hwnd,IDC_EDIT_KEY_BUTTON),FALSE); - EnableWindow(GetDlgItem(hwnd,IDC_REMOVE_KEY_BUTTON),FALSE); - } - - SetWindowRedraw(GetDlgItem(hwnd,IDC_KEYS_LIST),TRUE); -} - -static void _viv_options_remove_key(HWND hwnd) -{ - int index; - _viv_key_list_t *keylist; - - keylist = (_viv_key_list_t *)GetWindowLongPtr(GetDlgItem(hwnd,IDC_COMMANDS_LIST),GWLP_USERDATA); - - index = ListBox_GetCurSel(GetDlgItem(hwnd,IDC_COMMANDS_LIST)); - - if (index != LB_ERR) - { - int key_index; - - key_index = ListBox_GetCurSel(GetDlgItem(hwnd,IDC_KEYS_LIST)); - - if (key_index != LB_ERR) - { - int command_index; - WORD keyflags; - - command_index = ListBox_GetItemData(GetDlgItem(hwnd,IDC_COMMANDS_LIST),index); - keyflags = ListBox_GetItemData(GetDlgItem(hwnd,IDC_KEYS_LIST),key_index); - - _viv_key_remove(keylist,command_index,keyflags); - - _viv_options_key_list_sel_change(hwnd,key_index); - } - } -} - -static INT_PTR CALLBACK _viv_edit_key_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) -{ - switch(msg) - { - case WM_INITDIALOG: - { - WNDPROC last_proc; - wchar_t caption_wbuf[STRING_SIZE]; - - string_printf(caption_wbuf,localization_get_string(lParam ? LOCALIZATION_ID_EDIT_KEYBOARD_SHORTCUT_CAPTION : LOCALIZATION_ID_ADD_KEYBOARD_SHORTCUT_CAPTION)); - SetWindowText(hwnd,caption_wbuf); - - os_SetDlgItemText_localization_id(hwnd,IDC_EDIT_KEYBOARD_SHORTCUT_KEY_STATIC,LOCALIZATION_ID_SHORTCUT_KEY); - os_SetDlgItemText_localization_id(hwnd,IDC_EDIT_KEYBOARD_SHORTCUT_KEY_CURRENTLY_USED_BY_STATIC,LOCALIZATION_ID_SHORTCUT_KEY_CURRENTLY_USED_BY); - os_SetDlgItemText_localization_id(hwnd,IDOK,LOCALIZATION_ID_OK_BUTTON); - os_SetDlgItemText_localization_id(hwnd,IDCANCEL,LOCALIZATION_ID_CANCEL_BUTTON); - - os_center_dialog(hwnd); - - last_proc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hwnd,IDC_EDIT_KEY_EDIT),GWLP_WNDPROC,(LONG_PTR)_viv_edit_key_edit_proc); - SetWindowLongPtr(GetDlgItem(hwnd,IDC_EDIT_KEY_EDIT),GWLP_USERDATA,(LONG_PTR)last_proc); - - _viv_edit_key_set_key(GetDlgItem(hwnd,IDC_EDIT_KEY_EDIT),lParam); - _viv_options_edit_key_changed(hwnd); - - return FALSE; - } - - case WM_COMMAND: - - switch(LOWORD(wParam)) - { - case IDOK: - EndDialog(hwnd,GetWindowLongPtr(hwnd,GWLP_USERDATA)); - break; - - case IDCANCEL: - EndDialog(hwnd,0); - break; - } - - break; - } - - return FALSE; -} - -static void _viv_options_edit_key(HWND hwnd,int key_index) -{ - int index; - _viv_key_list_t *keylist; - - keylist = (_viv_key_list_t *)GetWindowLongPtr(GetDlgItem(hwnd,IDC_COMMANDS_LIST),GWLP_USERDATA); - - index = ListBox_GetCurSel(GetDlgItem(hwnd,IDC_COMMANDS_LIST)); - - if (index != LB_ERR) - { - WORD keyflags; - - if (key_index == LB_ERR) - { - keyflags = 0; - } - else - { - keyflags = ListBox_GetItemData(GetDlgItem(hwnd,IDC_KEYS_LIST),key_index); - } - - keyflags = DialogBoxParam(os_hinstance,MAKEINTRESOURCE(IDD_EDIT_KEY),hwnd,_viv_edit_key_proc,keyflags); - - _viv_edit_key_remove_currently_used_by(keylist,keyflags); - - if (keyflags) - { - int command_index; - - command_index = ListBox_GetItemData(GetDlgItem(hwnd,IDC_COMMANDS_LIST),index); - - if (key_index == LB_ERR) - { - // new - _viv_key_add(keylist,command_index,keyflags); - } - else - { - config_key_t *key; - int keyi; - - // edit - key = keylist->start[command_index]; - keyi = 0; - - while(key) - { - if (keyi == key_index) - { - key->key = keyflags; - break; - } - - keyi++; - key = key->next; - } - } - - _viv_options_key_list_sel_change(hwnd,key_index); - } - } -} - -static INT_PTR CALLBACK _viv_options_controls_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) -{ - switch(msg) - { - case WM_INITDIALOG: - { - os_SetDlgItemText_localization_id(hwnd,IDC_LEFT_CLICK_ACTION_STATIC,LOCALIZATION_ID_LEFT_CLICK_ACTION_STATIC); - os_ComboBox_AddString_localization_id(hwnd,IDC_LEFTCLICKACTION_COMBOBOX,LOCALIZATION_ID_OPTIONS_ACTION_SCROLL_COMBOBOXITEM); - os_ComboBox_AddString_localization_id(hwnd,IDC_LEFTCLICKACTION_COMBOBOX,LOCALIZATION_ID_OPTIONS_ACTION_PLAY_PAUSE_SLIDESHOW_COMBOBOXITEM); - os_ComboBox_AddString_localization_id(hwnd,IDC_LEFTCLICKACTION_COMBOBOX,LOCALIZATION_ID_OPTIONS_ACTION_PLAY_PAUSE_ANIMATION_COMBOBOXITEM); - os_ComboBox_AddString_localization_id(hwnd,IDC_LEFTCLICKACTION_COMBOBOX,LOCALIZATION_ID_OPTIONS_ACTION_ZOOM_IN_COMBOBOXITEM); - os_ComboBox_AddString_localization_id(hwnd,IDC_LEFTCLICKACTION_COMBOBOX,LOCALIZATION_ID_OPTIONS_ACTION_NEXT_IMAGE_COMBOBOXITEM); - os_ComboBox_AddString_localization_id(hwnd,IDC_LEFTCLICKACTION_COMBOBOX,LOCALIZATION_ID_OPTIONS_ACTION_ONE_TO_ONE_SCROLL_COMBOBOXITEM); - os_ComboBox_AddString_localization_id(hwnd,IDC_LEFTCLICKACTION_COMBOBOX,LOCALIZATION_ID_OPTIONS_ACTION_SCROLL_MOVE_WINDOW_COMBOBOXITEM); - ComboBox_SetCurSel(GetDlgItem(hwnd,IDC_LEFTCLICKACTION_COMBOBOX),config_left_click_action); - - os_SetDlgItemText_localization_id(hwnd,IDC_RIGHT_CLICK_ACTION_STATIC,LOCALIZATION_ID_RIGHT_CLICK_ACTION_STATIC); - os_ComboBox_AddString_localization_id(hwnd,IDC_RIGHTCLICKACTION_COMBOBOX,LOCALIZATION_ID_OPTIONS_ACTION_CONTEXT_MENU_COMBOBOXITEM); - os_ComboBox_AddString_localization_id(hwnd,IDC_RIGHTCLICKACTION_COMBOBOX,LOCALIZATION_ID_OPTIONS_ACTION_ZOOM_OUT_COMBOBOXITEM); - os_ComboBox_AddString_localization_id(hwnd,IDC_RIGHTCLICKACTION_COMBOBOX,LOCALIZATION_ID_OPTIONS_ACTION_PREVIOUS_IMAGE_COMBOBOXITEM); - ComboBox_SetCurSel(GetDlgItem(hwnd,IDC_RIGHTCLICKACTION_COMBOBOX),config_right_click_action); - - os_SetDlgItemText_localization_id(hwnd,IDC_MOUSE_WHEEL_ACTION_STATIC,LOCALIZATION_ID_MOUSE_WHEEL_ACTION_STATIC); - os_ComboBox_AddString_localization_id(hwnd,IDC_MOUSEWHEELACTION_COMBOBOX,LOCALIZATION_ID_OPTIONS_ACTION_ZOOM_COMBOBOXITEM); - os_ComboBox_AddString_localization_id(hwnd,IDC_MOUSEWHEELACTION_COMBOBOX,LOCALIZATION_ID_OPTIONS_ACTION_NEXT_PREV_COMBOBOXITEM); - os_ComboBox_AddString_localization_id(hwnd,IDC_MOUSEWHEELACTION_COMBOBOX,LOCALIZATION_ID_OPTIONS_ACTION_PREV_NEXT_COMBOBOXITEM); - ComboBox_SetCurSel(GetDlgItem(hwnd,IDC_MOUSEWHEELACTION_COMBOBOX),config_mouse_wheel_action); - - os_SetDlgItemText_localization_id(hwnd,IDC_COMMANDS_STATIC,LOCALIZATION_ID_COMMANDS_STATIC); - os_SetDlgItemText_localization_id(hwnd,IDC_SETTINGS_FOR_SELECTED_COMMAND_STATIC,LOCALIZATION_ID_SETTINGS_FOR_SELECTED_COMMAND); - os_SetDlgItemText_localization_id(hwnd,IDC_ADD_KEY_BUTTON,LOCALIZATION_ID_ADD_KEY_BUTTON); - os_SetDlgItemText_localization_id(hwnd,IDC_EDIT_KEY_BUTTON,LOCALIZATION_ID_EDIT_KEY_BUTTON); - os_SetDlgItemText_localization_id(hwnd,IDC_REMOVE_KEY_BUTTON,LOCALIZATION_ID_REMOVE_KEY_BUTTON); - - { - int i; - _viv_key_list_t *keylist; - - keylist = mem_alloc(sizeof(_viv_key_list_t)); - - _viv_key_list_init(keylist); - - _viv_key_list_copy(keylist,_viv_key_list); - - SetWindowLongPtr(GetDlgItem(hwnd,IDC_COMMANDS_LIST),GWLP_USERDATA,(LONG_PTR)keylist); - - for(i=0;i<_VIV_COMMAND_COUNT;i++) - { - if (!(_viv_commands[i].flags & MF_POPUP)) - { - if (!(_viv_commands[i].flags & MF_SEPARATOR)) - { - if (!(_viv_commands[i].flags & MF_DELETE)) - { - wchar_t command_name_wbuf[STRING_SIZE]; - int index; - - _viv_get_command_name(command_name_wbuf,i); - - index = ListBox_AddString(GetDlgItem(hwnd,IDC_COMMANDS_LIST),command_name_wbuf); - if (index != LB_ERR) - { - ListBox_SetItemData(GetDlgItem(hwnd,IDC_COMMANDS_LIST),index,i); - } - } - } - } - } - } - - ListBox_SetCurSel(GetDlgItem(hwnd,IDC_COMMANDS_LIST),0); - _viv_options_key_list_sel_change(hwnd,0); - - return FALSE; - } - - case WM_COMMAND: - - switch(LOWORD(wParam)) - { - case IDC_COMMANDS_LIST: - if (HIWORD(wParam) == LBN_SELCHANGE) - { - _viv_options_key_list_sel_change(hwnd,0); - } - break; - - case IDC_REMOVE_KEY_BUTTON: - _viv_options_remove_key(hwnd); - break; - - case IDC_EDIT_KEY_BUTTON: - _viv_options_edit_key(hwnd,ListBox_GetCurSel(GetDlgItem(hwnd,IDC_KEYS_LIST))); - break; - - case IDC_ADD_KEY_BUTTON: - _viv_options_edit_key(hwnd,LB_ERR); - break; - } - break; - - case WM_DESTROY: - { - _viv_key_list_t *keylist; - - keylist = (_viv_key_list_t *)GetWindowLongPtr(GetDlgItem(hwnd,IDC_COMMANDS_LIST),GWLP_USERDATA); - - _viv_key_clear_all(keylist); - mem_free(keylist); - - break; - } - } - - return FALSE; -} - -static INT_PTR CALLBACK _viv_options_view_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) -{ - switch(msg) - { - case WM_INITDIALOG: - - os_SetDlgItemText_localization_id(hwnd,IDC_SHRINK_BLIT_MODE_STATIC,LOCALIZATION_ID_SHRINK_BLIT_MODE_STATIC); - os_ComboBox_AddString_localization_id(hwnd,IDC_SHRINK_BLIT_MODE_COMBOBOX,LOCALIZATION_ID_BLIT_MODE_NEAREST_COMBOBOXITEM); - os_ComboBox_AddString_localization_id(hwnd,IDC_SHRINK_BLIT_MODE_COMBOBOX,LOCALIZATION_ID_BLIT_MODE_LINEAR_COMBOBOXITEM); - - if (config_shrink_blit_mode == CONFIG_SHRINK_BLIT_MODE_HALFTONE) - { - ComboBox_SetCurSel(GetDlgItem(hwnd,IDC_SHRINK_BLIT_MODE_COMBOBOX),1); - } - else - { - ComboBox_SetCurSel(GetDlgItem(hwnd,IDC_SHRINK_BLIT_MODE_COMBOBOX),0); - } - - os_SetDlgItemText_localization_id(hwnd,IDC_MAGNIFY_BLIT_MODE_STATIC,LOCALIZATION_ID_MAGNIFY_BLIT_MODE); - os_ComboBox_AddString_localization_id(hwnd,IDC_MAGNIFY_BLIT_MODE_COMBOBOX,LOCALIZATION_ID_BLIT_MODE_NEAREST_COMBOBOXITEM); - os_ComboBox_AddString_localization_id(hwnd,IDC_MAGNIFY_BLIT_MODE_COMBOBOX,LOCALIZATION_ID_BLIT_MODE_LINEAR_COMBOBOXITEM); - - if (config_mag_filter == CONFIG_MAG_FILTER_HALFTONE) - { - ComboBox_SetCurSel(GetDlgItem(hwnd,IDC_MAGNIFY_BLIT_MODE_COMBOBOX),1); - } - else - { - ComboBox_SetCurSel(GetDlgItem(hwnd,IDC_MAGNIFY_BLIT_MODE_COMBOBOX),0); - } - - os_SetDlgItemText_localization_id(hwnd,IDC_TITLE_BAR_FORMAT_STATIC,LOCALIZATION_ID_OPTIONS_TITLE_BAR_FORMAT_STATIC); - os_ComboBox_AddString_localization_id(hwnd,IDC_TITLE_BAR_FORMAT_COMBOBOX,LOCALIZATION_ID_OPTIONS_TITLE_BAR_FORMAT_FULL_PATH_COMBOBOXITEM); - os_ComboBox_AddString_localization_id(hwnd,IDC_TITLE_BAR_FORMAT_COMBOBOX,LOCALIZATION_ID_OPTIONS_TITLE_BAR_FORMAT_FILENAME_ONLY_COMBOBOXITEM); - os_ComboBox_AddString_localization_id(hwnd,IDC_TITLE_BAR_FORMAT_COMBOBOX,LOCALIZATION_ID_OPTIONS_TITLE_BAR_FORMAT_NONE_COMBOBOXITEM); - ComboBox_SetCurSel(GetDlgItem(hwnd,IDC_TITLE_BAR_FORMAT_COMBOBOX),config_title_bar_format); - - CheckDlgButton(hwnd,IDC_AUTO_ZOOM,config_auto_zoom ? BST_CHECKED : BST_UNCHECKED); - - os_SetDlgItemText_localization_id(hwnd,IDC_AUTO_ZOOM,LOCALIZATION_ID_OPTIONS_VIEW_AUTO_SIZE_WINDOW_STATIC); - os_ComboBox_AddString_localization_id(hwnd,IDC_AUTO_SIZE_WINDOW_COMBOBOX,LOCALIZATION_ID_OPTIONS_VIEW_AUTO_SIZE_WINDOW_50_PERCENT_COMBOBOXITEM); - os_ComboBox_AddString_localization_id(hwnd,IDC_AUTO_SIZE_WINDOW_COMBOBOX,LOCALIZATION_ID_OPTIONS_VIEW_AUTO_SIZE_WINDOW_100_PERCENT_COMBOBOXITEM); - os_ComboBox_AddString_localization_id(hwnd,IDC_AUTO_SIZE_WINDOW_COMBOBOX,LOCALIZATION_ID_OPTIONS_VIEW_AUTO_SIZE_WINDOW_200_PERCENT_COMBOBOXITEM); - os_ComboBox_AddString_localization_id(hwnd,IDC_AUTO_SIZE_WINDOW_COMBOBOX,LOCALIZATION_ID_OPTIONS_VIEW_AUTO_SIZE_WINDOW_AUTO_FIT_COMBOBOXITEM); - ComboBox_SetCurSel(GetDlgItem(hwnd,IDC_AUTO_SIZE_WINDOW_COMBOBOX),config_auto_zoom_type); - EnableWindow(GetDlgItem(hwnd,IDC_AUTO_SIZE_WINDOW_COMBOBOX),IsDlgButtonChecked(hwnd,IDC_AUTO_ZOOM) == BST_CHECKED); - - os_SetDlgItemText_localization_id(hwnd,IDC_LOOP_ANIMATIONS_ONCE_STATIC,LOCALIZATION_ID_PLAY_ANIMATIONS_ONCE_STATIC); - CheckDlgButton(hwnd,IDC_LOOP_ANIMATIONS_ONCE_STATIC,config_loop_animations_once ? BST_CHECKED : BST_UNCHECKED); - - os_SetDlgItemText_localization_id(hwnd,IDC_PRELOAD_NEXT_IMAGE_STATIC,LOCALIZATION_ID_PRELOAD_NEXT_IMAGE_STATIC); - CheckDlgButton(hwnd,IDC_PRELOAD_NEXT_IMAGE_STATIC,config_preload_next ? BST_CHECKED : BST_UNCHECKED); - - os_SetDlgItemText_localization_id(hwnd,IDC_CACHE_LAST_IMAGE_STATIC,LOCALIZATION_ID_CACHE_LAST_IMAGE_STATIC); - CheckDlgButton(hwnd,IDC_CACHE_LAST_IMAGE_STATIC,config_cache_last ? BST_CHECKED : BST_UNCHECKED); - - { - int static_wide; - - static_wide = 0; - - os_SetDlgItemText_localization_id(hwnd,IDC_WINDOWEDBACKGROUNDCOLOR_STATIC,LOCALIZATION_ID_WINDOWED_BACKGROUND_COLOR_STATIC); - SetWindowLongPtr(GetDlgItem(hwnd,IDC_WINDOWEDBACKGROUNDCOLOR_BUTTON),GWLP_USERDATA,RGB(config_windowed_background_color_r,config_windowed_background_color_g,config_windowed_background_color_b)); - _viv_update_color_button_bitmap(GetDlgItem(hwnd,IDC_WINDOWEDBACKGROUNDCOLOR_BUTTON)); - static_wide = os_expand_static_wide(hwnd,IDC_WINDOWEDBACKGROUNDCOLOR_STATIC,static_wide); - - os_SetDlgItemText_localization_id(hwnd,IDC_FULLSCREENBACKGROUNDCOLOR_STATIC,LOCALIZATION_ID_FULLSCREEN_BACKGROUND_COLOR_STATIC); - SetWindowLongPtr(GetDlgItem(hwnd,IDC_FULLSCREENBACKGROUNDCOLOR_BUTTON),GWLP_USERDATA,RGB(config_fullscreen_background_color_r,config_fullscreen_background_color_g,config_fullscreen_background_color_b)); - _viv_update_color_button_bitmap(GetDlgItem(hwnd,IDC_FULLSCREENBACKGROUNDCOLOR_BUTTON)); - static_wide = os_expand_static_wide(hwnd,IDC_FULLSCREENBACKGROUNDCOLOR_STATIC,static_wide); - - os_set_dialog_item_x_wide(hwnd,IDC_WINDOWEDBACKGROUNDCOLOR_STATIC,0,static_wide+6); - os_set_dialog_item_x_wide(hwnd,IDC_WINDOWEDBACKGROUNDCOLOR_BUTTON,static_wide+6,75); - os_set_dialog_item_x_wide(hwnd,IDC_FULLSCREENBACKGROUNDCOLOR_STATIC,0,static_wide+6); - os_set_dialog_item_x_wide(hwnd,IDC_FULLSCREENBACKGROUNDCOLOR_BUTTON,static_wide+6,75); - } - - return FALSE; - - case WM_DESTROY: - _viv_delete_color_button_bitmap(GetDlgItem(hwnd,IDC_WINDOWEDBACKGROUNDCOLOR_BUTTON)); - _viv_delete_color_button_bitmap(GetDlgItem(hwnd,IDC_FULLSCREENBACKGROUNDCOLOR_BUTTON)); - break; - - case WM_COMMAND: - - switch(LOWORD(wParam)) - { - case IDC_AUTO_ZOOM: - - EnableWindow(GetDlgItem(hwnd,IDC_AUTO_SIZE_WINDOW_COMBOBOX),IsDlgButtonChecked(hwnd,IDC_AUTO_ZOOM) == BST_CHECKED); - - break; - - case IDC_WINDOWEDBACKGROUNDCOLOR_BUTTON: - case IDC_FULLSCREENBACKGROUNDCOLOR_BUTTON: - - { - COLORREF color; - - color = GetWindowLongPtr(GetDlgItem(hwnd,LOWORD(wParam)),GWLP_USERDATA); - - if (os_choose_color(hwnd,&color)) - { - SetWindowLongPtr(GetDlgItem(hwnd,LOWORD(wParam)),GWLP_USERDATA,color); - _viv_update_color_button_bitmap(GetDlgItem(hwnd,LOWORD(wParam))); - } - } - - break; - } - - break; - } - - return FALSE; -} - -static void _viv_options_treeview_changed(HWND hwnd) -{ - TV_ITEM tvi; - - // get the current index - tvi.hItem = TreeView_GetSelection(GetDlgItem(hwnd,IDC_TREE1)); - if (tvi.hItem) - { - int i; - - tvi.mask = TVIF_PARAM; - - TreeView_GetItem(GetDlgItem(hwnd,IDC_TREE1),&tvi); - - ShowWindow(GetDlgItem(hwnd,_viv_options_tab_ids[tvi.lParam]),SW_SHOW); - ShowWindow(GetDlgItem(hwnd,_viv_options_page_ids[tvi.lParam]),SW_SHOW); - - for(i=0;i<_VIV_OPTIONS_PAGE_COUNT;i++) - { - if (i != tvi.lParam) - { - ShowWindow(GetDlgItem(hwnd,_viv_options_tab_ids[i]),SW_HIDE); - ShowWindow(GetDlgItem(hwnd,_viv_options_page_ids[i]),SW_HIDE); - } - } - - config_options_last_page = tvi.lParam; - } -} - -static void _viv_options_update_sheild(HWND hwnd) -{ -// int exti; - int need_admin; - HWND general_page; - - general_page = GetDlgItem(hwnd,VIV_ID_OPTIONS_GENERAL); - - need_admin = 0; - /* - for(exti=0;exti<_VIV_ASSOCIATION_COUNT;exti++) - { - if (IsDlgButtonChecked(general_page,_viv_association_dlg_item_id[exti]) == BST_CHECKED) - { - if (!_viv_is_association(_viv_association_extensions[exti])) - { - need_admin = 1; - } - } - else - { - if (_viv_is_association(_viv_association_extensions[exti])) - { - need_admin = 1; - } - } - } -*/ - if ((!!config_appdata) != (IsDlgButtonChecked(general_page,IDC_APPDATA) == BST_CHECKED)) - { - need_admin = 1; - } - - if ((IsDlgButtonChecked(general_page,IDC_STARTMENU) == BST_CHECKED) != !!_viv_is_start_menu_shortcuts()) - { - need_admin = 1; - } - - if ((need_admin) && (!os_is_admin())) - { - SendMessage(GetDlgItem(hwnd,IDOK),BCM_SETSHIELD,0,TRUE); - } - else - { - SendMessage(GetDlgItem(hwnd,IDOK),BCM_SETSHIELD,0,FALSE); - } -} - -static INT_PTR CALLBACK _viv_options_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) -{ - switch(msg) - { - case WM_NOTIFY: - - switch(((NMHDR *)lParam)->idFrom) - { - case IDC_TREE1: - - switch(((NMHDR *)lParam)->code) - { - case TVN_SELCHANGEDA: - case TVN_SELCHANGEDW: - - if (IsWindowVisible(hwnd)) - { - _viv_options_treeview_changed(hwnd); - } - - break; - } - - break; - } - - return 0; - - case WM_INITDIALOG: - - // update text. - os_SetWindowText_localization_id(hwnd,LOCALIZATION_ID_OPTIONS_CAPTION); - os_SetDlgItemText_localization_id(hwnd,IDOK,LOCALIZATION_ID_OK_BUTTON); - os_SetDlgItemText_localization_id(hwnd,IDCANCEL,LOCALIZATION_ID_CANCEL_BUTTON); - - os_center_dialog(hwnd); - - { - int i; - - for(i=0;i<_VIV_OPTIONS_PAGE_COUNT;i++) - { - TV_INSERTSTRUCT tvitem; - TCITEM tcitem; - RECT rect; - HWND page_hwnd; - HTREEITEM hitem; - wchar_t text_wbuf[STRING_SIZE]; - - string_copy_utf8_string(text_wbuf,localization_get_string(_viv_options_page_localization_id_array[i])); - - // treeview - tvitem.hInsertAfter = TVI_LAST; - tvitem.hParent = TVI_ROOT; - tvitem.item.mask = TVIF_TEXT | TVIF_PARAM; - tvitem.item.lParam = i; - tvitem.item.pszText = text_wbuf; - - hitem = TreeView_InsertItem(GetDlgItem(hwnd,IDC_TREE1),&tvitem); - - if (i == config_options_last_page) - { - TreeView_Select(GetDlgItem(hwnd,IDC_TREE1),hitem,TVGN_CARET); - } - - // tab - string_copy_utf8_string(text_wbuf,localization_get_string(_viv_options_page_localization_id_array[i])); - - tcitem.mask = TCIF_TEXT; - tcitem.pszText = text_wbuf; - TabCtrl_InsertItem(GetDlgItem(hwnd,_viv_options_tab_ids[i]),0,&tcitem); - - // page - GetClientRect(GetDlgItem(hwnd,IDC_PAGEPLACEHOLDER),&rect); - MapWindowPoints(GetDlgItem(hwnd,IDC_PAGEPLACEHOLDER),hwnd,(LPPOINT)&rect,2); - - page_hwnd = CreateDialog(os_hinstance,MAKEINTRESOURCE(_viv_options_dialog_ids[i]),hwnd,_viv_options_page_procs[i]); - SetWindowLong(page_hwnd,GWL_ID,_viv_options_page_ids[i]); - - if (os_EnableThemeDialogTexture) - { - os_EnableThemeDialogTexture(page_hwnd,ETDT_ENABLETAB); - } - - SetWindowPos(page_hwnd,HWND_TOP,rect.left,rect.top,rect.right - rect.left,rect.bottom - rect.top,SWP_NOSIZE|SWP_NOACTIVATE); - } - } - - _viv_options_treeview_changed(hwnd); - _viv_options_update_sheild(hwnd); - - return TRUE; - - case WM_COMMAND: - - switch(LOWORD(wParam)) - { - case IDOK: - case IDCANCEL: - - if (LOWORD(wParam) == IDOK) - { - HWND general_page; - HWND view_page; - HWND controls_page; - int old_shrink_blit_mode; - int exti; - COLORREF colorref; - wchar_t params[STRING_SIZE]; - - params[0] = 0; - - general_page = GetDlgItem(hwnd,VIV_ID_OPTIONS_GENERAL); - view_page = GetDlgItem(hwnd,VIV_ID_OPTIONS_VIEW); - controls_page = GetDlgItem(hwnd,VIV_ID_OPTIONS_CONTROLS); - config_multiple_instances = 0; - - if (IsDlgButtonChecked(general_page,IDC_APPDATA) == BST_CHECKED) - { - if (!config_appdata) - { - _viv_append_admin_param(params,(const utf8_t *)"appdata"); - config_appdata = 1; - } - } - else - { - if (config_appdata) - { - _viv_append_admin_param(params,(const utf8_t *)"noappdata"); - - config_appdata = 0; - } - } - - if (IsDlgButtonChecked(general_page,IDC_MULTIPLE_INSTANCES) == BST_CHECKED) - { - config_multiple_instances = 1; - } - - if (IsDlgButtonChecked(general_page,IDC_STARTMENU) == BST_CHECKED) - { - if (!_viv_is_start_menu_shortcuts()) - { - _viv_append_admin_param(params,(const utf8_t *)"startmenu"); - } - } - else - { - if (_viv_is_start_menu_shortcuts()) - { - _viv_append_admin_param(params,(const utf8_t *)"nostartmenu"); - } - } - - - for(exti=0;exti<_VIV_ASSOCIATION_COUNT;exti++) - { - if (IsDlgButtonChecked(general_page,_viv_association_dlg_item_id[exti]) == BST_CHECKED) - { - if (!_viv_is_association(_viv_association_extensions[exti])) - { - _viv_install_association_by_extension(_viv_association_extensions[exti],localization_get_string(_viv_association_description_localization_id_array[exti]),_viv_association_icon_locations[exti]); - } - } - else - { - if (_viv_is_association(_viv_association_extensions[exti])) - { - _viv_uninstall_association_by_extension(_viv_association_extensions[exti]); - } - } - } - - old_shrink_blit_mode = config_shrink_blit_mode; - - config_left_click_action = ComboBox_GetCurSel(GetDlgItem(controls_page,IDC_LEFTCLICKACTION_COMBOBOX)); - config_right_click_action = ComboBox_GetCurSel(GetDlgItem(controls_page,IDC_RIGHTCLICKACTION_COMBOBOX)); - config_mouse_wheel_action = ComboBox_GetCurSel(GetDlgItem(controls_page,IDC_MOUSEWHEELACTION_COMBOBOX)); - - if (ComboBox_GetCurSel(GetDlgItem(view_page,IDC_SHRINK_BLIT_MODE_COMBOBOX)) == 1) - { - config_shrink_blit_mode = CONFIG_SHRINK_BLIT_MODE_HALFTONE; - } - else - { - config_shrink_blit_mode = CONFIG_SHRINK_BLIT_MODE_COLORONCOLOR; - } - - colorref = (COLORREF)GetWindowLongPtr(GetDlgItem(view_page,IDC_WINDOWEDBACKGROUNDCOLOR_BUTTON),GWLP_USERDATA); - - if ((GetRValue(colorref) != config_windowed_background_color_r) || (GetGValue(colorref) != config_windowed_background_color_g) || (GetBValue(colorref) != config_windowed_background_color_b)) - { - config_windowed_background_color_r = GetRValue(colorref); - config_windowed_background_color_g = GetGValue(colorref); - config_windowed_background_color_b = GetBValue(colorref); - - InvalidateRect(_viv_hwnd,0,FALSE); - } - - colorref = (COLORREF)GetWindowLongPtr(GetDlgItem(view_page,IDC_FULLSCREENBACKGROUNDCOLOR_BUTTON),GWLP_USERDATA); - - if ((GetRValue(colorref) != config_fullscreen_background_color_r) || (GetGValue(colorref) != config_fullscreen_background_color_g) || (GetBValue(colorref) != config_fullscreen_background_color_b)) - { - config_fullscreen_background_color_r = GetRValue(colorref); - config_fullscreen_background_color_g = GetGValue(colorref); - config_fullscreen_background_color_b = GetBValue(colorref); - - InvalidateRect(_viv_hwnd,0,FALSE); - } - - if (old_shrink_blit_mode != config_shrink_blit_mode) - { - InvalidateRect(_viv_hwnd,0,FALSE); - } - - old_shrink_blit_mode = config_mag_filter; - - if (ComboBox_GetCurSel(GetDlgItem(view_page,IDC_MAGNIFY_BLIT_MODE_COMBOBOX)) == 1) - { - config_mag_filter = CONFIG_SHRINK_BLIT_MODE_HALFTONE; - } - else - { - config_mag_filter = CONFIG_SHRINK_BLIT_MODE_COLORONCOLOR; - } - - if (old_shrink_blit_mode != config_mag_filter) - { - InvalidateRect(_viv_hwnd,0,FALSE); - } - - config_title_bar_format = ComboBox_GetCurSel(GetDlgItem(view_page,IDC_TITLE_BAR_FORMAT_COMBOBOX)); - _viv_update_title(); - - config_auto_zoom = IsDlgButtonChecked(view_page,IDC_AUTO_ZOOM) == BST_CHECKED ? 1 : 0; - config_auto_zoom_type = ComboBox_GetCurSel(GetDlgItem(view_page,IDC_AUTO_SIZE_WINDOW_COMBOBOX)); - config_loop_animations_once = IsDlgButtonChecked(view_page,IDC_LOOP_ANIMATIONS_ONCE_STATIC) == BST_CHECKED ? 1 : 0; - config_preload_next = IsDlgButtonChecked(view_page,IDC_PRELOAD_NEXT_IMAGE_STATIC) == BST_CHECKED ? 1 : 0; - config_cache_last = IsDlgButtonChecked(view_page,IDC_CACHE_LAST_IMAGE_STATIC) == BST_CHECKED ? 1 : 0; - - // copy keys. - _viv_key_list_copy(_viv_key_list,(_viv_key_list_t *)GetWindowLongPtr(GetDlgItem(controls_page,IDC_COMMANDS_LIST),GWLP_USERDATA)); - - // reinit menu. - - { - HMENU new_hmenu; - - new_hmenu = _viv_create_menu(); - - if (GetMenu(_viv_hwnd)) - { - SetMenu(_viv_hwnd,new_hmenu); - } - - if (_viv_hmenu) - { - DestroyMenu(_viv_hmenu); - } - - _viv_hmenu = new_hmenu; - } - - // do admin commands. - if (*params) - { - wchar_t exe_filename[STRING_SIZE]; - - _viv_get_exe_filename(exe_filename); - - os_shell_execute(0,exe_filename,1,NULL,params); - } - - // save settings to disk - config_save_settings(config_appdata); - } - - EndDialog(hwnd,0); - break; - } - - break; - } - - return FALSE; -} - -static void _viv_options(void) -{ - DialogBox(os_hinstance,MAKEINTRESOURCE(IDD_OPTIONS),_viv_hwnd,_viv_options_proc); -} - -// use the default class description, ie: TXT File -static void _viv_install_association_by_extension(const char *association,const char *description,const char *icon_location) -{ - HKEY hkey; - wchar_t class_name[STRING_SIZE]; - wchar_t key[STRING_SIZE]; - wchar_t default_icon[STRING_SIZE]; - wchar_t dot_association[STRING_SIZE]; - LONG reg_ret; - - string_copy_utf8_string(dot_association,(const utf8_t *)"."); - string_cat_utf8(dot_association,association); - - // make sure we uninstall old associations first. - _viv_uninstall_association_by_extension(association); - - string_copy_utf8_string(class_name,"voidImageViewer"); - string_cat(class_name,dot_association); - - string_copy_utf8_string(default_icon,"SOFTWARE\\Classes\\voidImageViewer"); - string_cat(default_icon,dot_association); - string_cat_utf8(default_icon,"\\DefaultIcon"); - - if (RegCreateKeyExW(HKEY_CURRENT_USER,default_icon,0,0,0,KEY_QUERY_VALUE|KEY_SET_VALUE,0,&hkey,0) == ERROR_SUCCESS) - { - if (icon_location) - { - wchar_t icon_location_wbuf[STRING_SIZE]; - - string_copy_utf8_string(icon_location_wbuf,icon_location); - - _viv_set_registry_string(hkey,0,icon_location_wbuf); - } - else - { - wchar_t filename[STRING_SIZE]; - wchar_t command[STRING_SIZE]; - - _viv_get_exe_filename(filename); - - string_copy(command,filename); - - string_cat_utf8(command,(const utf8_t *)",0"); - - _viv_set_registry_string(hkey,0,command); - } - - RegCloseKey(hkey); - } - - string_copy_utf8_string(key,"SOFTWARE\\Classes\\"); - string_cat(key,class_name); - - if (RegCreateKeyExW(HKEY_CURRENT_USER,key,0,0,0,KEY_QUERY_VALUE|KEY_SET_VALUE,0,&hkey,0) == ERROR_SUCCESS) - { - wchar_t description_wbuf[STRING_SIZE]; - - string_copy_utf8_string(description_wbuf,description); - - _viv_set_registry_string(hkey,0,description_wbuf); - - RegCloseKey(hkey); - } - - string_copy_utf8_string(key,"SOFTWARE\\Classes\\"); - string_cat(key,class_name); - string_cat_utf8(key,"\\shell\\open\\command"); - - if (RegCreateKeyExW(HKEY_CURRENT_USER,key,0,0,0,KEY_QUERY_VALUE|KEY_SET_VALUE,0,&hkey,0) == ERROR_SUCCESS) - { - wchar_t filename[STRING_SIZE]; - wchar_t command[STRING_SIZE]; - - _viv_get_exe_filename(filename); - - string_copy_utf8_string(command,(const utf8_t *)"\""); - string_cat(command,filename); - string_cat_utf8(command,(const utf8_t *)"\" \"%1\""); - - _viv_set_registry_string(hkey,0,command); - - RegCloseKey(hkey); - } - - string_copy_utf8_string(key,"SOFTWARE\\Classes\\"); - string_cat(key,dot_association); - - reg_ret = RegCreateKeyExW(HKEY_CURRENT_USER,key,0,0,0,KEY_QUERY_VALUE|KEY_SET_VALUE,0,&hkey,0); - if (reg_ret == ERROR_SUCCESS) - { - wchar_t wbuf[STRING_SIZE]; - - if (!_viv_get_registry_string(hkey,(const utf8_t *)"voidImageViewer.Backup",wbuf,STRING_SIZE)) - { - if (!_viv_get_registry_string(hkey,0,wbuf,STRING_SIZE)) - { - *wbuf = 0; - } - - _viv_set_registry_string(hkey,(const utf8_t *)"voidImageViewer.Backup",wbuf); - } - - _viv_set_registry_string(hkey,0,class_name); - - RegCloseKey(hkey); - } - else - { - debug_printf("RegCreateKeyExW failed %u\n",reg_ret); - } -} - -static void _viv_uninstall_association_by_extension(const char *association) -{ - long reg_ret; - HKEY hkey; - wchar_t key[STRING_SIZE]; - - string_copy_utf8_string(key,(const utf8_t *)"SOFTWARE\\Classes\\."); - string_cat_utf8(key,association); - - // debug_printf("query %S\n",key); - - if (RegCreateKeyExW(HKEY_CURRENT_USER,key,0,0,0,KEY_QUERY_VALUE|KEY_SET_VALUE,0,&hkey,0) == ERROR_SUCCESS) - { - wchar_t wbuf[STRING_SIZE]; - - if (_viv_get_registry_string(hkey,(const utf8_t *)"voidImageViewer.Backup",wbuf,STRING_SIZE)) - { - _viv_set_registry_string(hkey,0,wbuf); - - // debug_printf("Delete voidImageViewer.Backup\n"); - - reg_ret = RegDeleteValueA(hkey,"voidImageViewer.Backup"); - if (reg_ret == ERROR_SUCCESS) - { - // debug_printf("Delete voidImageViewer.Backup OK\n"); - } - else - { - debug_printf("RegDeleteValueA failed %u\n",reg_ret); - } - } - - RegCloseKey(hkey); - } - - string_copy_utf8_string(key,(const utf8_t *)"SOFTWARE\\Classes\\voidImageViewer."); - string_cat_utf8(key,association); - - RegDeleteKey(HKEY_CURRENT_USER,key); -} - -static int _viv_is_association(const char *association) -{ - int ret; - HKEY hkey; - wchar_t class_name[STRING_SIZE]; - wchar_t key[STRING_SIZE]; - - string_copy_utf8_string(class_name,(const utf8_t *)"voidImageViewer."); - string_cat_utf8(class_name,association); - - ret = 0; - - string_copy_utf8_string(key,"SOFTWARE\\Classes\\."); - string_cat_utf8(key,association); - -//debug_printf("key %S\n",key); - - if (RegOpenKeyExW(HKEY_CURRENT_USER,key,0,KEY_QUERY_VALUE,&hkey) == ERROR_SUCCESS) - { - wchar_t wbuf[STRING_SIZE]; - -//debug_printf("key OK\n",key); - - if (_viv_get_registry_string(hkey,0,wbuf,STRING_SIZE)) - { -//debug_printf("value cmp %S %S\n",wbuf,class_name); - if (string_compare(wbuf,class_name) == 0) - { - ret++; - } - } - - RegCloseKey(hkey); - } - - string_copy_utf8_string(key,"SOFTWARE\\Classes\\"); - string_cat(key,class_name); - string_cat_utf8(key,(const utf8_t *)"\\shell\\open\\command"); - -//debug_printf("key %S\n",key); - - if (RegOpenKeyExW(HKEY_CURRENT_USER,key,0,KEY_QUERY_VALUE,&hkey) == ERROR_SUCCESS) - { - wchar_t wbuf[STRING_SIZE]; - - if (_viv_get_registry_string(hkey,0,wbuf,STRING_SIZE)) - { - wchar_t filename[STRING_SIZE]; - wchar_t command[STRING_SIZE]; - -//debug_printf("key OK\n",key); - - _viv_get_exe_filename(filename); - - string_copy_utf8_string(command,(const utf8_t *)"\""); - string_cat(command,filename); - string_cat_utf8(command,(const utf8_t *)"\" \"%1\""); - -//debug_printf("value cmp %S %S\n",wbuf,command); - - if (string_compare(wbuf,command) == 0) - { - ret++; - } - } - - RegCloseKey(hkey); - } - - return ret == 2; -} - -static int _viv_get_registry_string(HKEY hkey,const utf8_t *value,wchar_t *wbuf,int size_in_wchars) -{ - wchar_t value_wbuf[STRING_SIZE]; - wchar_t *value_wp; - DWORD cbData; - DWORD type; - - if (value) - { - string_copy_utf8_string(value_wbuf,value); - value_wp = value_wbuf; - } - else - { - value_wp = 0; - } - - cbData = size_in_wchars * sizeof(wchar_t); - - if (RegQueryValueExW(hkey,value_wp,0,&type,(BYTE *)wbuf,&cbData) == ERROR_SUCCESS) - { - if ((type == REG_SZ) || (type == REG_EXPAND_SZ)) - { - return 1; - } - } - - return 0; -} - -static int _viv_set_registry_string(HKEY hkey,const utf8_t *value,const wchar_t *wbuf) -{ - wchar_t value_wbuf[STRING_SIZE]; - wchar_t *value_wp; - LONG reg_ret; - - if (value) - { - string_copy_utf8_string(value_wbuf,value); - value_wp = value_wbuf; - } - else - { - value_wp = 0; - } - - reg_ret = RegSetValueExW(hkey,value_wp,0,REG_SZ,(BYTE *)wbuf,(string_get_length(wbuf) + 1) * sizeof(wchar_t)); - if (reg_ret == ERROR_SUCCESS) - { - return 1; - } - else - { - debug_printf("failed to set reg value %u %s %S",reg_ret,value,wbuf); - } - - return 0; -} - -VOID NTAPI _viv_timer_queue_timer_callback(PVOID param,BOOLEAN TimerOrWaitFired) -{ - if (!_viv_is_animation_timer_event) - { - _viv_is_animation_timer_event = 1; - - PostMessage(_viv_hwnd,WM_TIMER,VIV_ID_ANIMATION_TIMER,0); - } -} - -static void _viv_timer_start(void) -{ - if (!_viv_is_animation_timer) - { - _viv_is_animation_timer = 1; - - _viv_animation_timer_tick_start = os_get_tick_count(); - _viv_timer_tick = 0; - - if ((os_CreateTimerQueueTimer) && (os_DeleteTimerQueueTimer)) - { - _viv_is_timer_queue_timer = 0; - - if (os_CreateTimerQueueTimer(&_viv_timer_queue_timer_handle,NULL,_viv_timer_queue_timer_callback,NULL,1,1,0)) - { - _viv_is_timer_queue_timer = 1; - } - } - else - { - SetTimer(_viv_hwnd,VIV_ID_ANIMATION_TIMER,USER_TIMER_MINIMUM,0); - } - - _viv_update_prevent_sleep(); - } -} - -static void _viv_mousemove(void) -{ - POINT pt; - - GetCursorPos(&pt); - -// debug_printf("MOUSEMOVE %d %d, last %d %d\n",pt.x,pt.y,_viv_mousemove_x,_viv_mousemove_y); - - if ((pt.x != _viv_mousemove_x) || (pt.y != _viv_mousemove_y)) - { - _viv_show_cursor(); - - if (!_viv_should_show_cursor()) - { - _viv_start_hide_cursor_timer(); - } - } - - _viv_mousemove_x = pt.x; - _viv_mousemove_y = pt.y; -} - -static void _viv_update_src_pixel(int force,int update_statusbar) -{ -// if ((config_pixel_info) || ((_viv_is_alt) && (_viv_is_tracking_mouse))) - if (config_pixel_info) - { - POINT src_pixel_pt; - POINT client_pt; - RECT client_rect; - POINT pt; - - GetCursorPos(&pt); - - client_pt.x = pt.x; - client_pt.y = pt.y; - ScreenToClient(_viv_hwnd,&client_pt); - GetClientRect(_viv_hwnd,&client_rect); - - if (_viv_get_src_pixel_pos(client_pt.x,client_pt.y,&src_pixel_pt)) - { - - } - else - { - src_pixel_pt.x = -1; - src_pixel_pt.y = -1; - } - - if ((force) || (src_pixel_pt.x != _viv_src_pixel_x) || (src_pixel_pt.y != _viv_src_pixel_y)) - { - COLORREF src_pixel_rgb; - - _viv_src_pixel_x = src_pixel_pt.x; - _viv_src_pixel_y = src_pixel_pt.y; - - if ((_viv_src_pixel_x >= 0) && (_viv_src_pixel_y >= 0)) - { - _viv_get_src_pixel_rgb(_viv_src_pixel_x,_viv_src_pixel_y,&src_pixel_rgb); - } - - _viv_src_pixel_r = GetRValue(src_pixel_rgb); - _viv_src_pixel_g = GetGValue(src_pixel_rgb); - _viv_src_pixel_b = GetBValue(src_pixel_rgb); - - if (update_statusbar) - { - _viv_status_update(); - } - -/* - if ((src_pixel_pt.x != -1) && (src_pixel_pt.y != -1)) - { - _viv_tooltip_update(); - } - else - { - _viv_tooltip_hide(); - }*/ - } - } - else - { - _viv_src_pixel_x = -1; - _viv_src_pixel_y = -1; - } - -/* - if ((_viv_is_alt) && (_viv_is_tracking_mouse)) - { - _viv_tooltip_update_track_position(); - } - else - { - _viv_tooltip_hide(); - } - */ -} - -static void _viv_animation_pause(void) -{ - _viv_animation_play = !_viv_animation_play; -} - -static void _viv_frame_step(void) -{ - _viv_frame_looped = 0; - - if (_viv_animation_play) - { - _viv_animation_play = 0; - } - - if (_viv_frame_count > 1) - { - if ((_viv_frame_loaded_count == _viv_frame_count) || (_viv_frame_position + 1 < _viv_frame_loaded_count)) - { - _viv_frame_position++; - if (_viv_frame_position == _viv_frame_count) - { - _viv_frame_position = 0; - } - - _viv_animation_timer_tick_start = os_get_tick_count(); - _viv_timer_tick = 0; - - _viv_update_src_pixel(1,0); - _viv_status_update(); - - InvalidateRect(_viv_hwnd,NULL,FALSE); - UpdateWindow(_viv_hwnd); - } - } -} - -static void _viv_frame_prev(void) -{ - _viv_frame_looped = 0; - - if (_viv_animation_play) - { - _viv_animation_play = 0; - } - - if (_viv_frame_count > 1) - { - if (_viv_frame_position > 0) - { - _viv_frame_position--; - } - else - { - _viv_frame_position = _viv_frame_loaded_count - 1; - } - - _viv_animation_timer_tick_start = os_get_tick_count(); - _viv_timer_tick = 0; - - _viv_update_src_pixel(1,0); - _viv_status_update(); - - InvalidateRect(_viv_hwnd,NULL,FALSE); - UpdateWindow(_viv_hwnd); - } -} - -static void _viv_view_1to1(void) -{ - if (_viv_1to1) - { - if (_viv_have_old_zoom) - { - _viv_1to1 = 0; - _viv_zoom_pos = _viv_old_zoom_pos; - _viv_view_set(_viv_view_x,_viv_view_y,1); - InvalidateRect(_viv_hwnd,0,FALSE); - - return; - } - } - - _viv_have_old_zoom = 1; - _viv_old_zoom_pos = _viv_zoom_pos; - - _viv_1to1 = 1; - _viv_zoom_pos = 0; - _viv_view_set(_viv_view_x,_viv_view_y,1); - InvalidateRect(_viv_hwnd,0,FALSE); -} - -static void _viv_playlist_add_current_if_empty(void) -{ - // add current? - if (!_viv_playlist_start) - { - if (*_viv_current_fd->cFileName) - { - _viv_playlist_add(_viv_current_fd); - } - } -} - -static void _viv_playlist_clearall(void) -{ - _viv_playlist_t *d; - - d = _viv_playlist_start; - while(d) - { - _viv_playlist_t *next_d; - - next_d = d->next; - - mem_free(d); - - d = next_d; - } - - if (_viv_playlist_shuffle_indexes) - { - mem_free(_viv_playlist_shuffle_indexes); - - _viv_playlist_shuffle_indexes = 0; - _viv_playlist_shuffle_allocated = 0; - } - - _viv_playlist_start = 0; - _viv_playlist_last = 0; - _viv_playlist_count = 0; - _viv_playlist_id.QuadPart = 0; -} - -static void _viv_playlist_delete(const WIN32_FIND_DATA *fd) -{ - if (_viv_playlist_shuffle_indexes) - { - int index; - - index = _viv_playlist_shuffle_index_from_fd(fd); - if (index != -1) - { - _viv_playlist_t *d; - - d = _viv_playlist_shuffle_indexes[index]; - - os_move_memory(_viv_playlist_shuffle_indexes + index,_viv_playlist_shuffle_indexes + index + 1,_viv_playlist_count - (index + 1)); - - if (_viv_playlist_start == d) - { - _viv_playlist_start = d->next; - } - else - { - d->prev->next = d->next; - } - - if (_viv_playlist_last == d) - { - _viv_playlist_last = d->prev; - } - else - { - d->next->prev = d->prev; - } - - mem_free(d); - - _viv_playlist_count--; - } - } - else - { - _viv_playlist_t *d; - - d = _viv_playlist_from_fd(fd); - if (d) - { - if (_viv_playlist_start == d) - { - _viv_playlist_start = d->next; - } - else - { - d->prev->next = d->next; - } - - if (_viv_playlist_last == d) - { - _viv_playlist_last = d->prev; - } - else - { - d->next->prev = d->prev; - } - - mem_free(d); - - _viv_playlist_count--; - } - } -} - -static void _viv_playlist_rename(const wchar_t *old_filename,const wchar_t *new_filename) -{ - _viv_playlist_t *d; - - d = _viv_playlist_start; - while(d) - { - if (string_compare(d->fd.cFileName,old_filename) == 0) - { - string_copy(d->fd.cFileName,new_filename); - - break; - } - - d = d->next; - } -} - -static _viv_playlist_t *_viv_playlist_add(const WIN32_FIND_DATA *fd) -{ - _viv_playlist_t *d; - - d = (_viv_playlist_t *)mem_alloc(sizeof(_viv_playlist_t)); - - os_copy_memory(&d->fd,fd,sizeof(WIN32_FIND_DATA)); - d->fd.dwReserved0 = _viv_playlist_id.HighPart; - d->fd.dwReserved1 = _viv_playlist_id.LowPart; - _viv_playlist_id.QuadPart = _viv_playlist_id.QuadPart + 1; - - if (_viv_playlist_start) - { - _viv_playlist_last->next = d; - d->prev = _viv_playlist_last; - } - else - { - _viv_playlist_start = d; - d->prev = 0; - } - - _viv_playlist_last = d; - d->next = 0; - - if (_viv_playlist_shuffle_indexes) - { - // make sure shuffle list has enough room... - if (_viv_playlist_count + 1 > _viv_playlist_shuffle_allocated) - { - _viv_playlist_t **new_indexes; - - _viv_playlist_shuffle_allocated *= 2; - - if (!_viv_playlist_shuffle_allocated) - { - _viv_playlist_shuffle_allocated = _VIV_DEFAULT_SHUFFLE_ALLOCATED; - } - - new_indexes = mem_alloc(_viv_playlist_shuffle_allocated * sizeof(_viv_playlist_t *)); - - os_copy_memory(new_indexes,_viv_playlist_shuffle_indexes,_viv_playlist_count * sizeof(_viv_playlist_t *)); - - mem_free(_viv_playlist_shuffle_indexes); - - _viv_playlist_shuffle_indexes = new_indexes; - } - - // place in shuffle list in a random position. - { - int index; - - index = ((rand() * RAND_MAX) + rand()) % (_viv_playlist_count + 1); - - if (_viv_playlist_count != index) - { - _viv_playlist_shuffle_indexes[_viv_playlist_count] = _viv_playlist_shuffle_indexes[index]; - } - - _viv_playlist_shuffle_indexes[index] = d; - } - } - - _viv_playlist_count++; - - return d; -} - -static void _viv_playlist_add_path(const wchar_t *full_path_and_filename) -{ - WIN32_FIND_DATA fd; - wchar_t buf[STRING_SIZE]; - HANDLE h; - - string_copy(buf,full_path_and_filename); - string_cat_utf8(buf,(const utf8_t *)"\\*.*"); - - h = FindFirstFile(buf,&fd); - if (h != INVALID_HANDLE_VALUE) - { - for(;;) - { - if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - { - if (!((string_compare_ascii(fd.cFileName,".") == 0) || (string_compare_ascii(fd.cFileName,"..") == 0))) - { - string_copy(buf,full_path_and_filename); - string_cat_path_separator(buf); - string_cat(buf,fd.cFileName); - - _viv_playlist_add_path(buf); - } - } - else - { - if (_viv_is_valid_filename(&fd)) - { - string_copy(buf,full_path_and_filename); - string_cat_path_separator(buf); - string_cat(buf,fd.cFileName); - - string_copy(fd.cFileName,buf); - - _viv_playlist_add(&fd); - } - } - - if (!FindNextFile(h,&fd)) break; - } - - FindClose(h); - } -} - -static void _viv_playlist_add_filename(const wchar_t *filename) -{ - WIN32_FIND_DATA fd; - wchar_t full_path_and_filename[STRING_SIZE]; - wchar_t cwd[STRING_SIZE]; - - GetCurrentDirectory(STRING_SIZE,cwd); - - string_path_combine(full_path_and_filename,cwd,filename); - - if ((os_GetFileAttributesExW) && (os_GetFileAttributesExW(full_path_and_filename,GetFileExInfoStandard,&fd))) - { - if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - { - _viv_playlist_add_path(full_path_and_filename); - } - else - { - string_copy(fd.cFileName,full_path_and_filename); - - if (_viv_is_valid_filename(&fd)) - { - _viv_playlist_add(&fd); - } - } - } -} - -static void _viv_timer_stop(void) -{ - if (_viv_is_animation_timer) - { - _viv_is_animation_timer = 0; - - if ((os_CreateTimerQueueTimer) && (os_DeleteTimerQueueTimer)) - { - if (_viv_is_timer_queue_timer) - { - os_DeleteTimerQueueTimer(NULL,_viv_timer_queue_timer_handle,NULL); - - _viv_is_timer_queue_timer = 0; - } - } - else - { - KillTimer(_viv_hwnd,VIV_ID_ANIMATION_TIMER); - } - - _viv_update_prevent_sleep(); - } -} - -static int _viv_is_window_maximized(HWND hwnd) -{ - // are we minimized with the WPF_RESTORETOMAXIMIZED flag set? - if (IsIconic(hwnd)) - { - WINDOWPLACEMENT wp; - - // IsZoomed does not work when the window is minimized. - // its ok to use GetWindowPlacement here as we do not touch the normal rect. - wp.length = sizeof(WINDOWPLACEMENT); - GetWindowPlacement(hwnd,&wp); - - if (wp.flags & WPF_RESTORETOMAXIMIZED) - { - return 1; - } - } - - if (IsZoomed(hwnd)) - { - return 1; - } - - return 0; -} - -static INT_PTR CALLBACK _viv_custom_rate_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) -{ - switch(msg) - { - case WM_INITDIALOG: - - { - int static_wide; - RECT rect; - int wide; - - os_center_dialog(hwnd); - GetClientRect(hwnd,&rect); - wide = rect.right - rect.left - 12 - 12; - - os_SetWindowText_localization_id(hwnd,LOCALIZATION_ID_SET_CUSTOM_RATE_CAPTION); - - os_SetDlgItemText_localization_id(hwnd,IDOK,LOCALIZATION_ID_OK_BUTTON); - os_SetDlgItemText_localization_id(hwnd,IDCANCEL,LOCALIZATION_ID_CANCEL_BUTTON); - - SetDlgItemInt(hwnd,IDC_CUSTOM_RATE_EDIT,config_slideshow_custom_rate,FALSE); - - os_SetDlgItemText_localization_id(hwnd,IDC_CUSTOM_RATE_STATIC,LOCALIZATION_ID_CUSTOM_RATE_STATIC); - static_wide = os_get_static_wide(hwnd,IDC_CUSTOM_RATE_STATIC); - os_set_dialog_item_x_wide(hwnd,IDC_CUSTOM_RATE_STATIC,12,static_wide+6); - - { - int edit_combo_wide; - - edit_combo_wide = (wide - (static_wide+6) - 6) / 2; - - os_set_dialog_item_x_wide(hwnd,IDC_CUSTOM_RATE_EDIT,12 + static_wide+6,edit_combo_wide); - os_set_dialog_item_x_wide(hwnd,IDC_CUSTOM_RATE_TYPE_COMBOBOX,12 + static_wide+6 + edit_combo_wide + 6,edit_combo_wide); - } - - os_ComboBox_AddString_localization_id(hwnd,IDC_CUSTOM_RATE_TYPE_COMBOBOX,LOCALIZATION_ID_CUSTOM_RATE_MILLISECONDS); - os_ComboBox_AddString_localization_id(hwnd,IDC_CUSTOM_RATE_TYPE_COMBOBOX,LOCALIZATION_ID_CUSTOM_RATE_SECONDS); - os_ComboBox_AddString_localization_id(hwnd,IDC_CUSTOM_RATE_TYPE_COMBOBOX,LOCALIZATION_ID_CUSTOM_RATE_MINUTES); - - ComboBox_SetCurSel(GetDlgItem(hwnd,IDC_CUSTOM_RATE_TYPE_COMBOBOX),config_slideshow_custom_rate_type); - } - - return TRUE; - - case WM_COMMAND: - - switch(LOWORD(wParam)) - { - case IDOK: - config_slideshow_custom_rate_type = ComboBox_GetCurSel(GetDlgItem(hwnd,IDC_CUSTOM_RATE_TYPE_COMBOBOX)); - config_slideshow_custom_rate = GetDlgItemInt(hwnd,IDC_CUSTOM_RATE_EDIT,NULL,FALSE); - EndDialog(hwnd,1); - break; - - case IDCANCEL: - EndDialog(hwnd,0); - break; - } - - break; - } - - return FALSE; -} - -static INT_PTR CALLBACK _viv_about_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) -{ - switch(msg) - { - case WM_CTLCOLOREDIT: - case WM_CTLCOLORSTATIC: - if (((HWND)lParam == GetDlgItem(hwnd,IDC_ABOUTBACK)) || ((HWND)lParam == GetDlgItem(hwnd,IDC_ABOUTTITLE))) - { - SetTextColor((HDC)wParam,RGB(255,255,255)); - SetBkColor((HDC)wParam,RGB(0,0,0)); - return (LRESULT)GetStockObject(BLACK_BRUSH); - } - else - { - SetTextColor((HDC)wParam,RGB(0,0,0)); - SetBkColor((HDC)wParam,RGB(255,255,255)); - return (LRESULT)GetStockObject(WHITE_BRUSH); - } - break; - - case WM_PAINT: - { - RECT rect; - PAINTSTRUCT ps; - GetClientRect(hwnd,&rect); - BeginPaint(hwnd,&ps); - rect.bottom -= (48 * os_logical_high) / 96; - FillRect(ps.hdc,&rect,(HBRUSH)GetStockObject(WHITE_BRUSH)); - rect.top = rect.bottom; - rect.bottom++; - FillRect(ps.hdc,&rect,(HBRUSH)(COLOR_BTNSHADOW + 1)); - rect.top = rect.bottom; - rect.bottom++; - FillRect(ps.hdc,&rect,(HBRUSH)(COLOR_BTNHIGHLIGHT + 1)); - rect.top = rect.bottom; - rect.bottom+=(46 * os_logical_high) / 96; - FillRect(ps.hdc,&rect,(HBRUSH)(COLOR_BTNFACE + 1)); - EndPaint(hwnd,&ps); - break; - } - - case WM_INITDIALOG: - { - HFONT hfont; - LOGFONT lf; - wchar_t version_wbuf[STRING_SIZE]; - - os_center_dialog(hwnd); - - string_copy_utf8_string(version_wbuf,localization_get_string(LOCALIZATION_ID_ABOUT_CAPTION)); - SetWindowText(hwnd,version_wbuf); - os_SetDlgItemText_localization_id(hwnd,IDC_ABOUTTITLE,LOCALIZATION_ID_APP_NAME); - os_SetDlgItemText_localization_id(hwnd,IDC_ABOUTVOIDIMAGEVIEWER,LOCALIZATION_ID_APP_NAME); - string_printf(version_wbuf,"%d.%d.%d.%d%s %s",VERSION_MAJOR,VERSION_MINOR,VERSION_REVISION,VERSION_BUILD,VERSION_TYPE,VERSION_TARGET_MACHINE); - SetDlgItemText(hwnd,IDC_ABOUTVERSION,version_wbuf); - string_printf(version_wbuf,localization_get_string(LOCALIZATION_ID_ABOUT_COPYRIGHT_FORMAT),VERSION_YEAR); - SetDlgItemText(hwnd,IDC_ABOUTCOPYRIGHT,version_wbuf); - os_SetDlgItemText_localization_id(hwnd,IDC_ABOUTEMAIL,LOCALIZATION_ID_ABOUT_EMAIL); - os_SetDlgItemText_localization_id(hwnd,IDC_ABOUTWEBSITE,LOCALIZATION_ID_ABOUT_WEBSITE); - os_SetDlgItemText_localization_id(hwnd,IDOK,LOCALIZATION_ID_OK_BUTTON); - os_SetDlgItemText_localization_id(hwnd,IDCANCEL,LOCALIZATION_ID_CANCEL_BUTTON); - - if (!_viv_about_hfont) - { - hfont = (HFONT)SendMessage(GetDlgItem(hwnd,IDC_ABOUTTITLE),WM_GETFONT,0,0); - GetObject(hfont,sizeof(LOGFONT),&lf); - - lf.lfHeight = 32; - _viv_about_hfont = CreateFontIndirect(&lf); - } - - SendMessage(GetDlgItem(hwnd,IDC_ABOUTTITLE),WM_SETFONT,(WPARAM)_viv_about_hfont,0); - - return TRUE; - } - - case WM_DESTROY: - break; - - case WM_COMMAND: - - switch(LOWORD(wParam)) - { - case IDOK: - case IDCANCEL: - EndDialog(hwnd,0); - break; - } - - break; - } - - return FALSE; -} - -static void _viv_update_frame(void) -{ - if (!_viv_is_fullscreen) - { - DWORD oldstyle; - DWORD newstyle; - RECT windowrect; - RECT clientrect; - RECT newrect; - RECT oldrect; - int was_maximized; - - was_maximized = 0; - - // get out of maximized state. - if (_viv_is_window_maximized(_viv_hwnd)) - { - ShowWindow(_viv_hwnd,SW_RESTORE); - was_maximized = 1; - } - - oldstyle = GetWindowLong(_viv_hwnd,GWL_STYLE); - newstyle = oldstyle; - - GetClientRect(_viv_hwnd,&clientrect); - debug_printf("clientrect %d %d %d %d\n",clientrect.left,clientrect.top,clientrect.right,clientrect.bottom); - - CopyRect(&oldrect,&clientrect); - AdjustWindowRect(&oldrect,oldstyle,GetMenu(_viv_hwnd) ? TRUE : FALSE); - - oldrect.bottom += _viv_get_status_high() + _viv_get_controls_high(); - - debug_printf("oldrect %d %d %d %d %d\n",oldrect.left,oldrect.top,oldrect.right,oldrect.bottom,GetMenu(_viv_hwnd) ? TRUE : FALSE); - - if (config_show_caption) - { - newstyle |= WS_CAPTION | WS_SYSMENU; - } - else - { - newstyle &= ~(WS_CAPTION | WS_SYSMENU); - } - - if (config_show_thickframe) - { - newstyle |= WS_THICKFRAME; - } - else - { - newstyle &= ~WS_THICKFRAME; - } - - if (config_show_menu) - { - if (GetMenu(_viv_hwnd) != _viv_hmenu) - { - SetMenu(_viv_hwnd,_viv_hmenu); - } - } - else - { - if (GetMenu(_viv_hwnd) != 0) - { - SetMenu(_viv_hwnd,0); - } - } - - _viv_status_show(config_show_status); - _viv_controls_show(config_show_controls); - - CopyRect(&newrect,&clientrect); - AdjustWindowRect(&newrect,newstyle,config_show_menu ? TRUE : FALSE); - - newrect.bottom += _viv_get_status_high() + _viv_get_controls_high(); - - debug_printf("newrect %d %d %d %d %d\n",newrect.left,newrect.top,newrect.right,newrect.bottom,config_show_menu ? TRUE : FALSE); - - GetWindowRect(_viv_hwnd,&windowrect); - - windowrect.left += newrect.left - oldrect.left; - windowrect.top += newrect.top - oldrect.top; - windowrect.right += newrect.right - oldrect.right; - windowrect.bottom += newrect.bottom - oldrect.bottom; - - SetWindowLong(_viv_hwnd,GWL_STYLE,newstyle); - - SetWindowPos(_viv_hwnd,HWND_TOP,windowrect.left,windowrect.top,windowrect.right - windowrect.left,windowrect.bottom - windowrect.top,SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS); - - // if there is no catpion or thick frame we should not allow maximize - // avoid our resize borders when maximized. - if ((was_maximized) && (config_show_caption) && (config_show_thickframe)) - { - ShowWindow(_viv_hwnd,SW_MAXIMIZE); - } - } -} - -static void _viv_update_ontop(void) -{ - int is_top_most; - - is_top_most = 0; - - switch(config_ontop) - { - case 1: - is_top_most = 1; - break; - - case 2: - is_top_most = (_viv_is_slideshow) || ((_viv_frame_count > 1) && (_viv_animation_play)); - break; - } - - SetWindowPos(_viv_hwnd,is_top_most ? HWND_TOPMOST : HWND_NOTOPMOST,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE); -} - -static void _viv_update_prevent_sleep(void) -{ - BYTE _is_prevent_sleep; - - _is_prevent_sleep = 0; - - if (config_prevent_sleep) - { - if ((_viv_is_slideshow) || (_viv_is_animation_timer)) - { - _is_prevent_sleep = 1; - } - } - - // _is_prevent_sleep changed? - if (!!_viv_is_prevent_sleep != !!_is_prevent_sleep) - { - if (os_SetThreadExecutionState) - { - os_SetThreadExecutionState(_is_prevent_sleep ? (ES_CONTINUOUS | ES_DISPLAY_REQUIRED | ES_SYSTEM_REQUIRED) : ES_CONTINUOUS); - } - - _viv_is_prevent_sleep = _is_prevent_sleep; - } -} - -static void _viv_dst_pos_set(int x,int y) -{ - if (x < 0) - { - x = 0; - } - - if (y < 0) - { - y = 0; - } - - if (x > 1000) - { - x = 1000; - } - - if (y > 1000) - { - y = 1000; - } - - if ((x != _viv_dst_pos_x) || (y != _viv_dst_pos_y)) - { - _viv_dst_pos_x = x; - _viv_dst_pos_y = y; - - InvalidateRect(_viv_hwnd,NULL,FALSE); - } - - _viv_status_update_temp_pos_zoom(); -} - -static void _viv_dst_zoom_set(int x,int y) -{ - if (x < 0) - { - x = 0; - } - else - if (x > _VIV_DST_ZOOM_MAX - 1) - { - x = _VIV_DST_ZOOM_MAX - 1; - } - - if (y < 0) - { - y = 0; - } - else - if (y > _VIV_DST_ZOOM_MAX - 1) - { - y = _VIV_DST_ZOOM_MAX - 1; - } - - if ((x != _viv_dst_zoom_x_pos) || (y != _viv_dst_zoom_y_pos)) - { - _viv_dst_zoom_x_pos = x; - _viv_dst_zoom_y_pos = y; - - InvalidateRect(_viv_hwnd,NULL,FALSE); - } - - _viv_status_update_temp_pos_zoom(); - /* - { - RECT rect; - int wide; - int high; - int rw; - int rh; - double new_view_x; - double new_view_y; - - - GetClientRect(_viv_hwnd,&rect); - wide = rect.right - rect.left; - high = rect.bottom - rect.top; - _viv_get_render_size(&rw,&rh); - - new_view_x = (int)(((_viv_view_ix * rw) / _viv_image_wide) + 0.5) + (((_viv_dst_pos_x - 250) * (wide*2)) / 1000) - (wide / 2) - (rw / 2); - new_view_y = (int)(((_viv_view_iy * rh) / _viv_image_high) + 0.5) + (((_viv_dst_pos_y - 250) * (high*2)) / 1000) - (high / 2) - (rh / 2); - -debug_printf("RESTORE VIEW x %d y %d ix %d iy %d rw %d rh %d wide %d high %d\n",(int)(new_view_x),(int)(new_view_y),(int)_viv_view_ix,(int)_viv_view_iy,rw,rh,wide,high) ; -// _viv_view_set((int)(_viv_view_ix * (double)rw),(int)(_viv_view_iy * (double)rh),1); - _viv_view_set((int)new_view_x,(int)new_view_y,1); - } - */ -} - -static void _viv_frame_skip(int size) -{ - if (_viv_frame_count > 1) - { - if (size > 0) - { - while(size > 0) - { - if ((_viv_frame_loaded_count == _viv_frame_count) || (_viv_frame_position + 1 < _viv_frame_loaded_count)) - { - _viv_frame_position++; - if (_viv_frame_position == _viv_frame_count) - { - _viv_frame_position = 0; - } - - _viv_animation_timer_tick_start = os_get_tick_count(); - _viv_timer_tick = 0; - } - - size -= _viv_frames[_viv_frame_position].delay; - } - } - else - if (size < 0) - { - while(size < 0) - { - _viv_frame_position--; - if (_viv_frame_position < 0) - { - _viv_frame_position = _viv_frame_loaded_count - 1; - } - - _viv_animation_timer_tick_start = os_get_tick_count(); - _viv_timer_tick = 0; - - size += _viv_frames[_viv_frame_position].delay; - } - } - - _viv_update_src_pixel(1,0); - _viv_status_update(); - - InvalidateRect(_viv_hwnd,NULL,FALSE); - UpdateWindow(_viv_hwnd); - } -} - -static int _viv_webp_info_proc(_viv_webp_t *viv_webp,DWORD frame_count,DWORD wide,DWORD high,int has_alpha) -{ - int ret; - - ret = 0; - - viv_webp->wide = wide; - viv_webp->high = high; - viv_webp->has_alpha = has_alpha; - viv_webp->frame_count = frame_count; - - viv_webp->screen_hdc = GetDC(NULL); - if (viv_webp->screen_hdc) - { - viv_webp->mem_hdc = CreateCompatibleDC(viv_webp->screen_hdc); - - if (viv_webp->mem_hdc) - { - ret = 1; - } - } - - return ret; -} - -static int _viv_webp_frame_proc(_viv_webp_t *viv_webp,BYTE *pixels,int delay) -{ - // always load first frame.. - if ((viv_webp->frame_index) && (_viv_load_image_terminate)) - { - return 0; - } - - if (viv_webp->has_alpha) - { - BYTE *p; - DWORD run; - - run = viv_webp->wide * viv_webp->high; - p = pixels; - - while(run) - { - int a; - - a = p[3]; - - if (a != 255) - { - while(run) - { - int r; - int g; - int b; - int a; - - r = p[0]; - g = p[1]; - b = p[2]; - a = p[3]; - - b = config_windowed_background_color_b + ((b - config_windowed_background_color_b) * a) / 255; - g = config_windowed_background_color_g + ((g - config_windowed_background_color_g) * a) / 255; - r = config_windowed_background_color_r + ((r - config_windowed_background_color_r) * a) / 255; - - p[0] = r; - p[1] = g; - p[2] = b; - p[3] = 255; - - p += 4; - run--; - } - - break; - } - - p += 4; - run--; - } - } - - /* - { - int x; - int y; - - for(y=0;y BGR - - { - const BYTE *p; - BYTE *d; - DWORD high_run; - - high_run = viv_webp->high; - p = pixels; - d = pixels; - - while(high_run) - { - BYTE *wd; - DWORD wide_run; - - wide_run = viv_webp->wide; - wd = d; - - while(wide_run) - { - int a; - int r; - int g; - int b; - - r = p[0]; - g = p[1]; - b = p[2]; - a = p[3]; - - p += 4; - - wd[0] = b; - wd[1] = g; - wd[2] = r; - wd += 3; - - wide_run--; - } - - d += (((viv_webp->wide * 3) + 3) / 4) * 4; - - high_run--; - } - } - - - { - BITMAPINFO bmi; - HBITMAP hbitmap; - - // Create compatible bitmap - ZeroMemory(&bmi, sizeof(BITMAPINFO)); - bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bmi.bmiHeader.biWidth = viv_webp->wide; - bmi.bmiHeader.biHeight = -(int)viv_webp->high; // Negative height to indicate top-down bitmap - bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biBitCount = 24; - bmi.bmiHeader.biCompression = BI_RGB; - - hbitmap = CreateCompatibleBitmap(viv_webp->screen_hdc,viv_webp->wide,viv_webp->high); - - // Set RGB data to the bitmap - if (hbitmap) - { - int mip_wide; - int mip_high; - - SetDIBits(viv_webp->mem_hdc,hbitmap,0,viv_webp->high,pixels,&bmi,DIB_RGB_COLORS); - - if (viv_webp->orientation > 1) - { - HBITMAP new_hbitmap; - - new_hbitmap = _viv_orientate_hbitmap(hbitmap,viv_webp->orientation); - if (new_hbitmap) - { - DeleteObject(hbitmap); - hbitmap = new_hbitmap; - } - } - - if (viv_webp->frame_index == 0) - { - _viv_reply_load_image_first_frame_t first_frame; - - first_frame.wide = viv_webp->wide; - first_frame.high = viv_webp->high; - first_frame.frame.hbitmap = hbitmap; - first_frame.frame.mipmap = NULL; - first_frame.frame.delay = 0; - first_frame.frame_count = viv_webp->frame_count; - - if (viv_webp->frame_count > 1) - { - first_frame.frame.delay = delay; - } - - // preload first mipmap - _viv_get_mipmap(hbitmap,first_frame.wide,first_frame.high,_viv_load_render_wide/2,_viv_load_render_high/2,&mip_wide,&mip_high,&first_frame.frame.mipmap); - - _viv_reply_add(_VIV_REPLY_LOAD_IMAGE_FIRST_FRAME,sizeof(_viv_reply_load_image_first_frame_t),&first_frame); - } - else - { - _viv_frame_t frame; - - frame.hbitmap = hbitmap; - frame.mipmap = NULL; - frame.delay = delay; - -//printf("DELAY %d\n",delay) ; - - _viv_get_mipmap(hbitmap,viv_webp->wide,viv_webp->high,_viv_load_render_wide/2,_viv_load_render_high/2,&mip_wide,&mip_high,&frame.mipmap); - - _viv_reply_add(_VIV_REPLY_LOAD_IMAGE_ADDITIONAL_FRAME,sizeof(_viv_frame_t),&frame); - } - - viv_webp->frame_index++; - } - } - - return 1; -} - -// 14.447 - CreateStreamOnHGlobal - this is too slow over slow networks -which doesn't matter because the gif wont show the first frame until the entire gif is loaded anyway. -// 14.520 - CreateStreamOnHGlobal -// 15.834 - SHCreateStreamOnFile -// 15.850 - SHCreateStreamOnFile -// 14.914 - _viv stream - 1MB file buffer -// 14.914 - _viv stream -static DWORD WINAPI _viv_load_image_thread_proc(void *param) -{ - _viv_reply_load_image_first_frame_t first_frame; - IStream *stream; - int ret; - DWORD tickstart; - - tickstart = GetTickCount(); - - CoInitializeEx(NULL, COINIT_APARTMENTTHREADED|COINIT_DISABLE_OLE1DDE); - - first_frame.wide = 0; - first_frame.high = 0; - first_frame.frame_count = 0; - first_frame.frame.hbitmap = 0; - first_frame.frame.mipmap = 0; - first_frame.frame.delay = 0; - - ret = 0; - stream = NULL; - - debug_printf("%s %S...\n",_viv_load_is_preload ? "PRELOAD" : "LOAD",_viv_load_image_filename); - - { - HANDLE h; - - h = CreateFile(_viv_load_image_filename,GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE|((os_major_version >= 5) ? FILE_SHARE_DELETE : 0),0,OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,0); - if (h != INVALID_HANDLE_VALUE) - { - DWORD size; - HANDLE global_handle; - - size = GetFileSize(h,0); - - global_handle = GlobalAlloc(GMEM_MOVEABLE,size); - if (global_handle) - { - char *buf; - - buf = (char *)GlobalLock(global_handle); - - if (buf) - { - DWORD numread; - DWORD totreadsize; - char *d; - - d = buf; - totreadsize = size; - - while(totreadsize) - { - DWORD readsize; - -// if (_viv_load_image_terminate) -// { -// totreadsize = 0; -// break; -// } - - readsize = 1 * 1024 * 1024; - - if (readsize > totreadsize) - { - readsize = totreadsize; - } - - if (ReadFile(h,d,readsize,&numread,0)) - { - if (!numread) - { - break; - } - - d += numread; - totreadsize -= numread; - } - else - { - break; - } - } - - GlobalUnlock(global_handle); - - if (totreadsize == 0) - { - HRESULT hresult; - - hresult = CreateStreamOnHGlobal(global_handle,TRUE,&stream); - - if (SUCCEEDED(hresult)) - { - debug_printf("got stream in %f seconds\n",(double)(GetTickCount()-tickstart) * 0.001); - - // the stream owns this handle now. - global_handle = 0; - } - else - { - debug_printf("CreateStreamOnHGlobal %x\n",hresult); - stream = 0; - } - } - } - - if (global_handle) - { - GlobalFree(global_handle); - } - } - - CloseHandle(h); - } - else - { - debug_printf("CreateFile %x\n",GetLastError()); - } - } - - -/* - // webp uses hglobals - { - IStream *my_stream; - - if (SUCCEEDED(SHCreateStreamOnFileEx(_viv_load_image_filename,STGM_READ,FILE_ATTRIBUTE_NORMAL,FALSE,NULL,&my_stream))) - { - // stream owns my_stream now. - stream = my_stream; - } - } -*/ - - if (stream) - { - int orientation; - - debug_printf("stream %d\n",stream); - - if (config_orientation) - { - orientation = os_get_orientation(_viv_load_image_filename); - - debug_printf("orientation %d\n",orientation); - } - else - { - orientation = 0; - } - -// if (!_viv_load_image_terminate) - { - void *image; - int load_ret; - - // not implemented. - load_ret = 1; - - if ((os_GdipLoadImageFromStream) && (os_GdipLoadImageFromStreamICM) && (os_GdipGetImageWidth) && (os_GdipGetImageHeight) && (os_GdipImageGetFrameDimensionsCount) && (os_GdipImageGetFrameDimensionsList) && (os_GdipImageGetFrameCount) && (os_GdipGetPropertyItemSize) && (os_GdipGetPropertyItem) && (os_GdipImageSelectActiveFrame) && (os_GdipGetImageFlags) && (os_GdipDisposeImage) && (os_GdipCreateFromHDC) && (os_GdipSetCompositingMode) && (os_GdipSetCompositingQuality) && (os_GdipSetInterpolationMode) && (os_GdipSetPixelOffsetMode) && (os_GdipSetSmoothingMode) && (os_GdipDrawImageRectI) && (os_GdipDeleteGraphics)) - { - if (config_icm) - { - load_ret = os_GdipLoadImageFromStreamICM(stream,&image); - } - else - { - load_ret = os_GdipLoadImageFromStream(stream,&image); - } - } - - debug_printf("image %p\n",image); - - if (load_ret == 0) - { -// if (!_viv_load_image_terminate) - { - if (os_GdipGetImageWidth(image,&first_frame.wide) == 0) - { - if (os_GdipGetImageHeight(image,&first_frame.high) == 0) - { - UINT count; - int load_wide; - int load_high; - - load_wide = first_frame.wide; - load_high = first_frame.high; - - // apply orientation. - switch (orientation) - { - case 2: // #define PHOTO_ORIENTATION_FLIPHORIZONTAL 2u - break; - - case 5: // #define PHOTO_ORIENTATION_TRANSPOSE 5u - case 6: // #define PHOTO_ORIENTATION_ROTATE270 6u - case 7: // #define PHOTO_ORIENTATION_TRANSVERSE 7u - case 8: // #define PHOTO_ORIENTATION_ROTATE90 8u - { - int temp; - temp = first_frame.wide; - first_frame.wide = first_frame.high; - first_frame.high = temp; - } - break; - } - - //First of all we should get the number of frame dimensions - //Images considered by GDI+ as: - //frames[animation_frame_index][how_many_animation]; - if (os_GdipImageGetFrameDimensionsCount(image,&count) == 0) - { - os_PropertyItem_t *frame_delay; - SIZE_T frame_delay_size; - - frame_delay = NULL; - frame_delay_size = 0; - - //Now we should get the identifiers for the frame dimensions - { - GUID *DimensionIDs; - - DimensionIDs = mem_alloc(sizeof(GUID) * count); - - if (os_GdipImageGetFrameDimensionsList(image,DimensionIDs,count) == 0) - { - //For gif image , we only care about animation set#0 - WCHAR strGuid[39]; - - StringFromGUID2(&DimensionIDs[0], strGuid, 39); - - os_GdipImageGetFrameCount(image,&DimensionIDs[0],&first_frame.frame_count); - - } - - mem_free(DimensionIDs); - } - - // get frame delays. - if (first_frame.frame_count > 1) - { - UINT size; - - // PropertyTagFrameDelay 0x5100 - os_GdipGetPropertyItemSize(image,0x5100,&size); - - debug_printf("frame delay size %d\n",size); - - frame_delay = (os_PropertyItem_t *)mem_alloc(size); - frame_delay_size = size; - - // PropertyTagFrameDelay 0x5100 - os_GdipGetPropertyItem(image,0x5100,size,frame_delay); - } - - // draw frames. - - { - HDC screen_hdc; - - screen_hdc = GetDC(0); - - if (screen_hdc) - { - HDC mem_hdc; - - mem_hdc = CreateCompatibleDC(screen_hdc); - if (mem_hdc) - { - DWORD i; - - for(i=0;i 1) - { - HBITMAP new_hbitmap; - - new_hbitmap = _viv_orientate_hbitmap(hbitmap,orientation); - if (new_hbitmap) - { - DeleteObject(hbitmap); - hbitmap = new_hbitmap; - } - } - - SelectObject(mem_hdc,last_hbitmap); - - if (i) - { - _viv_frame_t frame; - int mip_wide; - int mip_high; - UINT frame_data_value; - - frame.hbitmap = hbitmap; - frame.mipmap = NULL; - - // therube: we are accessing bad data here for some images. - // just use a value of 0 for bad data. - if (!_viv_safe_copy_data(frame_delay,frame_delay_size,&(((UINT *)frame_delay[0].value)[i]),&frame_data_value,sizeof(UINT))) - { - frame_data_value = 0; - } - - frame.delay = frame_data_value * 10; - - if (!frame.delay) - { - frame.delay = 100; - } - - _viv_get_mipmap(hbitmap,first_frame.wide,first_frame.high,_viv_load_render_wide/2,_viv_load_render_high/2,&mip_wide,&mip_high,&frame.mipmap); - - _viv_reply_add(_VIV_REPLY_LOAD_IMAGE_ADDITIONAL_FRAME,sizeof(_viv_frame_t),&frame); - } - else - { - int mip_wide; - int mip_high; - UINT frame_data_value; - - first_frame.frame.hbitmap = hbitmap; - first_frame.frame.mipmap = NULL; - first_frame.frame.delay = 0; - - if (first_frame.frame_count > 1) - { - // therube: we are accessing bad data here for some images. - // just use a value of 0 for bad data. - if (!_viv_safe_copy_data(frame_delay,frame_delay_size,&(((UINT *)frame_delay[0].value)[i]),&frame_data_value,sizeof(UINT))) - { - frame_data_value = 0; - } - - first_frame.frame.delay = frame_data_value * 10; - - if (!first_frame.frame.delay) - { - first_frame.frame.delay = 100; - } - } - - // preload first mipmap - _viv_get_mipmap(hbitmap,first_frame.wide,first_frame.high,_viv_load_render_wide/2,_viv_load_render_high/2,&mip_wide,&mip_high,&first_frame.frame.mipmap); - - _viv_reply_add(_VIV_REPLY_LOAD_IMAGE_FIRST_FRAME,sizeof(_viv_reply_load_image_first_frame_t),&first_frame); - - ret = 1; - } - } - } - - DeleteDC(mem_hdc); - } - - ReleaseDC(0,screen_hdc); - } - } - - if (frame_delay) - { - mem_free(frame_delay); - } - - debug_printf("image loaded\n"); - } - } - } - } - - os_GdipDisposeImage(image); - } - else - { - _viv_webp_t viv_webp; - - debug_printf("GDIPlus failed to load image %S %d\n",_viv_load_image_filename,load_ret); - - viv_webp.screen_hdc = NULL; - viv_webp.mem_hdc = NULL; - viv_webp.frame_index = 0; - viv_webp.last_delay = 0; - viv_webp.orientation = orientation; - - if (webp_load(stream,&viv_webp,_viv_webp_info_proc,_viv_webp_frame_proc)) - { - ret = 1; - } - else - { - debug_printf("libwebp failed to load image %S\n",_viv_load_image_filename); - - // we loaded at least one frame, so treat it as complete. - if (viv_webp.frame_index > 0) - { - ret = 1; - } - } - - if (viv_webp.mem_hdc) - { - DeleteDC(viv_webp.mem_hdc); - } - - if (viv_webp.screen_hdc) - { - ReleaseDC(NULL,viv_webp.screen_hdc); - } - } - } - - stream->lpVtbl->Release(stream); - } - else - { - debug_printf("Failed to create stream from %S\n",_viv_load_image_filename); - } - - _viv_reply_add(ret ? _VIV_REPLY_LOAD_IMAGE_COMPLETE : _VIV_REPLY_LOAD_IMAGE_FAILED,0,0); - - CoUninitialize(); - - debug_printf("loaded in %f seconds\n",(double)(GetTickCount()-tickstart) * 0.001); - - return 0; -} - -static void _viv_reply_free(_viv_reply_t *e) -{ - switch (e->type) - { - case _VIV_REPLY_LOAD_IMAGE_FIRST_FRAME: - - if (((_viv_reply_load_image_first_frame_t *)(e+1))->frame.hbitmap) - { - DeleteObject(((_viv_reply_load_image_first_frame_t *)(e+1))->frame.hbitmap); - } - - if (((_viv_reply_load_image_first_frame_t *)(e+1))->frame.mipmap) - { - _viv_mipmap_free(((_viv_reply_load_image_first_frame_t *)(e+1))->frame.mipmap); - } - - break; - - case _VIV_REPLY_LOAD_IMAGE_ADDITIONAL_FRAME: - - if (((_viv_frame_t *)(e + 1))->hbitmap) - { - DeleteObject(((_viv_frame_t *)(e + 1))->hbitmap); - } - - if (((_viv_frame_t *)(e + 1))->mipmap) - { - _viv_mipmap_free(((_viv_frame_t *)(e + 1))->mipmap); - } - - break; - } - - mem_free(e); -} - -static _viv_reply_t *_viv_reply_add(DWORD type,DWORD size,void *data) -{ - _viv_reply_t *e; - int is_first; - - is_first = 0; - - e = (_viv_reply_t *)mem_alloc(sizeof(_viv_reply_t) + size); - - e->type = type; - e->size = size; - - os_copy_memory(e + 1,data,size); - - EnterCriticalSection(&_viv_cs); - - if (_viv_reply_start) - { - _viv_reply_last->next = e; - } - else - { - _viv_reply_start = e; - is_first = 1; - } - - _viv_reply_last = e; - e->next = 0; - - LeaveCriticalSection(&_viv_cs); - - if (is_first) - { - PostMessage(_viv_hwnd,_VIV_WM_REPLY,0,0); - } - - return e; -} - -static void _viv_reply_clear_all(void) -{ - _viv_reply_t *e; - - EnterCriticalSection(&_viv_cs); - - e = _viv_reply_start; - _viv_reply_start = 0; - _viv_reply_last = 0; - - LeaveCriticalSection(&_viv_cs); - - while(e) - { - _viv_reply_t *next_e; - - next_e = e->next; - - _viv_reply_free(e); - - e = next_e; - } -} - -static void _viv_status_show(int show) -{ - if (show) - { - if (!_viv_status_hwnd) - { - // WS_EX_COMPOSITED stops flickering issues - _viv_status_hwnd = os_CreateWindowEx( - WS_EX_COMPOSITED, - STATUSCLASSNAMEA, - "", - WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_CHILD | SBARS_SIZEGRIP | WS_VISIBLE, - 0,0,0,0, - _viv_hwnd,(HMENU)VIV_ID_STATUS,os_hinstance,NULL); - - _viv_old_status_proc = os_set_window_proc(_viv_status_hwnd,_viv_status_proc); - } - } - else - { - if (_viv_status_hwnd) - { - DestroyWindow(_viv_status_hwnd); - - _viv_status_hwnd = 0; - } - } - - _viv_on_size(); -} - -static void _viv_controls_show(int show) -{ - if (show) - { - if (!_viv_toolbar_hwnd) - { - os_RegisterClassEx( - CS_DBLCLKS, - _viv_rebar_proc, - 0, - LoadCursor(NULL,IDC_ARROW), - (HBRUSH)(COLOR_WINDOW+1), - "_VIV_REBAR", - 0); - - _viv_rebar_hwnd = os_CreateWindowEx( - 0, - "_VIV_REBAR", - "", - WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_CHILD | WS_VISIBLE, - 0,0,0,0, - _viv_hwnd,(HMENU)VIV_ID_TOOLBAR,os_hinstance,NULL); - - _viv_toolbar_hwnd = os_CreateWindowEx( - 0, - TOOLBARCLASSNAMEA, - "", - WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_CHILD | TBSTYLE_TRANSPARENT | TBSTYLE_LIST | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE | CCS_TOP, - 0,0,0,0, - _viv_rebar_hwnd,(HMENU)VIV_ID_TOOLBAR,os_hinstance,NULL); - - SendMessage(_viv_toolbar_hwnd,TB_SETEXTENDEDSTYLE,0,TBSTYLE_EX_MIXEDBUTTONS|TBSTYLE_EX_HIDECLIPPEDBUTTONS|TBSTYLE_EX_DOUBLEBUFFER); - SendMessage(_viv_toolbar_hwnd,TB_BUTTONSTRUCTSIZE,sizeof(TBBUTTON),0); - - _viv_toolbar_image_list = ImageList_Create((16 * os_logical_wide) / 96,(16 * os_logical_high) / 96,ILC_COLOR24|ILC_MASK,0,0); - - ImageList_AddIcon(_viv_toolbar_image_list,LoadIcon(os_hinstance,(LPCTSTR)IDI_PREV)); - ImageList_AddIcon(_viv_toolbar_image_list,LoadIcon(os_hinstance,(LPCTSTR)IDI_PLAY)); - ImageList_AddIcon(_viv_toolbar_image_list,LoadIcon(os_hinstance,(LPCTSTR)IDI_PAUSE)); - ImageList_AddIcon(_viv_toolbar_image_list,LoadIcon(os_hinstance,(LPCTSTR)IDI_NEXT)); - ImageList_AddIcon(_viv_toolbar_image_list,LoadIcon(os_hinstance,(LPCTSTR)IDI_BESTFIT)); - ImageList_AddIcon(_viv_toolbar_image_list,LoadIcon(os_hinstance,(LPCTSTR)IDI_1TO1)); - - SendMessage(_viv_toolbar_hwnd,TB_SETIMAGELIST,0,(LPARAM)_viv_toolbar_image_list); - - { - TBBUTTON buttons[8]; - wchar_t button_text[8][STRING_SIZE]; - int buttoni; - - buttoni = 0; - - buttons[buttoni].iBitmap = 0; - buttons[buttoni].idCommand = VIV_ID_NAV_PREV; - buttons[buttoni].fsState = TBSTATE_ENABLED; - buttons[buttoni].fsStyle = TBSTYLE_BUTTON; - string_copy_utf8_string(button_text[buttoni],localization_get_string(LOCALIZATION_ID_TOOLBAR_PREVIOUS_IMAGE_BUTTON)); - buttons[buttoni].iString = (INT_PTR)button_text[buttoni]; - buttoni++; - - buttons[buttoni].iBitmap = 3; - buttons[buttoni].idCommand = VIV_ID_NAV_NEXT; - buttons[buttoni].fsState = TBSTATE_ENABLED; - buttons[buttoni].fsStyle = TBSTYLE_BUTTON; - string_copy_utf8_string(button_text[buttoni],localization_get_string(LOCALIZATION_ID_TOOLBAR_NEXT_IMAGE_BUTTON)); - buttons[buttoni].iString = (INT_PTR)button_text[buttoni]; - buttoni++; - - buttons[buttoni].iBitmap = 0; - buttons[buttoni].idCommand = 0; - buttons[buttoni].fsState = 0; - buttons[buttoni].fsStyle = TBSTYLE_SEP; - buttons[buttoni].iString = 0; - buttoni++; - - buttons[buttoni].iBitmap = 1; - buttons[buttoni].idCommand = VIV_ID_SLIDESHOW_PLAY_ONLY; - buttons[buttoni].fsState = TBSTATE_ENABLED; - buttons[buttoni].fsStyle = TBSTYLE_BUTTON|TBSTYLE_CHECK|TBSTYLE_GROUP; - string_copy_utf8_string(button_text[buttoni],localization_get_string(LOCALIZATION_ID_TOOLBAR_PLAY_SLIDESHOW_BUTTON)); - buttons[buttoni].iString = (INT_PTR)button_text[buttoni]; - buttoni++; - - buttons[buttoni].iBitmap = 2; - buttons[buttoni].idCommand = VIV_ID_SLIDESHOW_PAUSE_ONLY; - buttons[buttoni].fsState = TBSTATE_ENABLED; - buttons[buttoni].fsStyle = TBSTYLE_BUTTON|TBSTYLE_CHECK|TBSTYLE_GROUP; - string_copy_utf8_string(button_text[buttoni],localization_get_string(LOCALIZATION_ID_TOOLBAR_PAUSE_SLIDESHOW_BUTTON)); - buttons[buttoni].iString = (INT_PTR)button_text[buttoni]; - buttoni++; - - buttons[buttoni].iBitmap = 0; - buttons[buttoni].idCommand = 0; - buttons[buttoni].fsState = 0; - buttons[buttoni].fsStyle = TBSTYLE_SEP; - buttons[buttoni].iString = 0; - buttoni++; - - buttons[buttoni].iBitmap = 4; - buttons[buttoni].idCommand = VIV_ID_VIEW_BESTFIT; - buttons[buttoni].fsState = TBSTATE_ENABLED; - buttons[buttoni].fsStyle = TBSTYLE_BUTTON; - string_copy_utf8_string(button_text[buttoni],localization_get_string(LOCALIZATION_ID_TOOLBAR_BEST_FIT_BUTTON)); - buttons[buttoni].iString = (INT_PTR)button_text[buttoni]; - buttoni++; - - buttons[buttoni].iBitmap = 5; - buttons[buttoni].idCommand = VIV_ID_VIEW_1TO1; - buttons[buttoni].fsState = TBSTATE_ENABLED; - buttons[buttoni].fsStyle = TBSTYLE_BUTTON; - string_copy_utf8_string(button_text[buttoni],localization_get_string(LOCALIZATION_ID_TOOLBAR_ACTUAL_SIZE_BUTTON)); - buttons[buttoni].iString = (INT_PTR)button_text[buttoni]; - buttoni++; - - SendMessage(_viv_toolbar_hwnd,TB_ADDBUTTONS,8,(LPARAM)buttons); - } - - _viv_toolbar_update_buttons(); - ShowWindow(_viv_toolbar_hwnd,SW_SHOW); - } - } - else - { - if (_viv_toolbar_hwnd) - { - DestroyWindow(_viv_toolbar_hwnd); - DestroyWindow(_viv_rebar_hwnd); - - _viv_toolbar_hwnd = 0; - _viv_rebar_hwnd = 0; - } - - if (_viv_toolbar_image_list) - { - ImageList_Destroy(_viv_toolbar_image_list); - - _viv_toolbar_image_list = 0; - } - } - - _viv_on_size(); -} - -static void _viv_status_update(void) -{ - if (_viv_status_hwnd) - { - int part_array[6]; - RECT rect; - wchar_t widebuf[STRING_SIZE]; - wchar_t highbuf[STRING_SIZE]; - wchar_t dimension_buf[STRING_SIZE]; - wchar_t frame_buf[STRING_SIZE]; - wchar_t pixel_pos_buf[STRING_SIZE]; - wchar_t pixel_rgb_buf[STRING_SIZE]; - wchar_t preload_buf[STRING_SIZE]; - HDC hdc; - int dimension_wide; - int frame_wide; - int preload_wide; - int pixel_pos_wide; - int pixel_rgb_wide; - int minwide; - - GetClientRect(_viv_hwnd,&rect); - - *preload_buf = 0; - *pixel_pos_buf = 0; - *pixel_rgb_buf = 0; - - if ((_viv_image_wide) && (_viv_image_high)) - { - string_format_number(widebuf,_viv_image_wide); - string_format_number(highbuf,_viv_image_high); - - string_copy(dimension_buf,widebuf); - string_cat_utf8(dimension_buf,(const utf8_t *)" x "); - string_cat(dimension_buf,highbuf); - } - else - { - string_copy_utf8_string(dimension_buf,(const utf8_t *)""); - } - - if (*_viv_frame_fd->cFileName) - { - LARGE_INTEGER size; - - size.HighPart = _viv_frame_fd->nFileSizeHigh; - size.LowPart = _viv_frame_fd->nFileSizeLow; - - if (size.QuadPart) - { - NUMBERFMT numberfmt; - - if (*dimension_buf) - { - string_cat_utf8(dimension_buf," "); - } - - string_cat_utf8(dimension_buf,"("); - string_format_number(widebuf,(size.QuadPart + 1023) / 1024); - - numberfmt.NumDigits = 0; - numberfmt.LeadingZero = 0; - numberfmt.Grouping = 3; - numberfmt.lpThousandSep = L","; - numberfmt.lpDecimalSep = L"."; - numberfmt.NegativeOrder = 0; - - GetNumberFormat(LOCALE_USER_DEFAULT,0,widebuf,&numberfmt,highbuf,STRING_SIZE); - - string_cat(dimension_buf,highbuf); - string_cat_utf8(dimension_buf," KB)"); - } - } - - if (_viv_frame_count > 1) - { - int frame_pos; - string_format_number(highbuf,_viv_frame_count); - - string_copy_utf8_string(frame_buf,(const utf8_t *)""); - - if (config_frame_minus) - { - frame_pos = _viv_frame_count - (_viv_frame_position); - string_cat_utf8(frame_buf,(const utf8_t *)"- "); - } - else - { - frame_pos = _viv_frame_position + 1; - } - - string_format_number(widebuf,frame_pos); - - string_cat(frame_buf,widebuf); - string_cat_utf8(frame_buf,(const utf8_t *)" / "); - string_cat(frame_buf,highbuf); - } - else - { - string_copy_utf8_string(frame_buf,(const utf8_t *)""); - } - - // this is just noise.. - - if ((_viv_load_is_preload) && (_viv_preload_state == 0) && (!_viv_should_activate_preload_on_load) && (!_viv_load_image_terminate) && (!_viv_preload_frame_loaded_count)) - { - string_copy_utf8_string(preload_buf,localization_get_string(LOCALIZATION_ID_STATUS_BAR_PRELOAD)); - } - - if (config_pixel_info) - { - if ((_viv_src_pixel_x >= 0) && (_viv_src_pixel_y >= 0)) - { - string_printf(pixel_pos_buf,"POS: %d,%d",_viv_src_pixel_x,_viv_src_pixel_y); - string_printf(pixel_rgb_buf,"RGB: %d,%d,%d",_viv_src_pixel_r,_viv_src_pixel_g,_viv_src_pixel_b); - } - } - - dimension_wide = 0; - frame_wide = 0; - preload_wide = 0; - pixel_pos_wide = 0; - pixel_rgb_wide = 0; - minwide = (72 * os_logical_wide) / 96; - - hdc = GetDC(_viv_status_hwnd); - if (hdc) - { - HFONT hfont; - - hfont = (HFONT)SendMessage(_viv_status_hwnd,WM_GETFONT,0,0); - if (hfont) - { - SIZE size; - HGDIOBJ last_font; - - last_font = SelectObject(hdc,hfont); - - if (GetTextExtentPoint32(hdc,dimension_buf,string_get_length(dimension_buf),&size)) - { - dimension_wide = size.cx + GetSystemMetrics(SM_CXEDGE) * 5; - - if (dimension_wide < minwide) - { - dimension_wide = minwide; - } - } - - if (*frame_buf) - { - if (GetTextExtentPoint32(hdc,frame_buf,string_get_length(frame_buf),&size)) - { - frame_wide = size.cx + GetSystemMetrics(SM_CXEDGE) * 5; - - if (frame_wide < minwide) - { - frame_wide = minwide; - } - } - } - - if (*preload_buf) - { - if (GetTextExtentPoint32(hdc,preload_buf,string_get_length(preload_buf),&size)) - { - preload_wide = size.cx + GetSystemMetrics(SM_CXEDGE) * 5; - } - } - - if (*pixel_pos_buf) - { - if (GetTextExtentPoint32(hdc,pixel_pos_buf,string_get_length(pixel_pos_buf),&size)) - { - pixel_pos_wide = size.cx + GetSystemMetrics(SM_CXEDGE) * 5; - } - } - - if (*pixel_rgb_buf) - { - if (GetTextExtentPoint32(hdc,pixel_rgb_buf,string_get_length(pixel_rgb_buf),&size)) - { - pixel_rgb_wide = size.cx + GetSystemMetrics(SM_CXEDGE) * 5; - } - } - - SelectObject(hdc,last_font); - } - - ReleaseDC(_viv_status_hwnd,hdc); - } - - // add size box - dimension_wide += GetSystemMetrics(SM_CXVSCROLL) + GetSystemMetrics(SM_CXBORDER); - - { - int parti; - int part_wide; - - parti = 0; - part_wide = (rect.right - rect.left) - dimension_wide - frame_wide - preload_wide - pixel_pos_wide - pixel_rgb_wide; - - part_array[parti] = part_wide; - if (part_array[parti] < 0) - { - part_array[parti] = 0; - } - parti++; - - if (*preload_buf) - { - part_wide += preload_wide; - part_array[parti] = part_wide; - parti++; - } - - if (pixel_pos_buf) - { - part_wide += pixel_pos_wide; - part_array[parti] = part_wide; - parti++; - } - - if (pixel_rgb_buf) - { - part_wide += pixel_rgb_wide; - part_array[parti] = part_wide; - parti++; - } - - part_wide += frame_wide; - part_array[parti] = part_wide; - parti++; - - part_array[parti] = -1; - parti++; - - SendMessage(_viv_status_hwnd,SB_SETPARTS,parti,(LPARAM)part_array); - } - - { - wchar_t *text; - wchar_t text_buf[STRING_SIZE]; - - text = L""; - - if (_viv_status_temp_text) - { - text = _viv_status_temp_text; - } - else - if ((_viv_load_image_thread) && ((!_viv_load_is_preload) || (_viv_should_activate_preload_on_load))) - { - string_copy_utf8_string(text_buf,localization_get_string(LOCALIZATION_ID_STATUS_BAR_LOADING)); - text = text_buf; - } - else - if (_viv_file_not_found) - { - string_copy_utf8_string(text_buf,localization_get_string(LOCALIZATION_ID_STATUS_BAR_FILE_NOT_FOUND)); - text = text_buf; - } - else - if (_viv_load_failed) - { - string_copy_utf8_string(text_buf,localization_get_string(LOCALIZATION_ID_STATUS_BAR_FAILED_TO_LOAD_IMAGE)); - text = text_buf; - } - else - if (_viv_is_slideshow) - { - string_copy_utf8_string(text_buf,localization_get_string(LOCALIZATION_ID_STATUS_BAR_SLIDESHOW_PLAYING)); - text = text_buf; - } - - _viv_status_set(0,text); - } - - { - int parti; - - parti = 1; - - if (*preload_buf) - { - _viv_status_set(parti,preload_buf); - parti++; - } - - if (pixel_pos_buf) - { - _viv_status_set(parti,pixel_pos_buf); - parti++; - } - - if (pixel_rgb_buf) - { - _viv_status_set(parti,pixel_rgb_buf); - parti++; - } - - _viv_status_set(parti,frame_buf); - parti++; - - _viv_status_set(parti,dimension_buf); - parti++; - } - } -} - -static void _viv_status_set(int part,const wchar_t *text) -{ - wchar_t oldtext[STRING_SIZE]; - - SendMessage(_viv_status_hwnd,SB_GETTEXTW,(WPARAM)part,(LPARAM)oldtext); - - if (string_compare(oldtext,text) != 0) - { - SendMessage(_viv_status_hwnd,SB_SETTEXTW,(WPARAM)part,(LPARAM)text); - } -} - -static int _viv_get_status_high(void) -{ - if (_viv_status_hwnd) - { - RECT rect; - - GetWindowRect(_viv_status_hwnd,&rect); - - return rect.bottom - rect.top; - } - - return 0; -} - -static int _viv_get_controls_high(void) -{ - if (_viv_toolbar_hwnd) - { - return (32 * os_logical_high) / 96; - } - - return 0; -} - -static LRESULT CALLBACK _viv_rebar_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) -{ - switch (msg) - { - case WM_LBUTTONDOWN: - - if (config_toolbar_move_window) - { - _viv_start_move_window(); - - return 0; - } - - break; - - case WM_NOTIFY: - - switch(((NMHDR *)lParam)->idFrom) - { - case VIV_ID_TOOLBAR: - - if (_viv_toolbar_hwnd) - { - switch(((NMHDR *)lParam)->code) - { - case NM_CUSTOMDRAW: - { - switch(((NMTBCUSTOMDRAW *)lParam)->nmcd.dwDrawStage) - { - case CDDS_PREPAINT: - { - RECT rect; - GetClientRect(_viv_toolbar_hwnd,&rect); - FillRect(((NMTBCUSTOMDRAW *)lParam)->nmcd.hdc,&rect,(HBRUSH)(COLOR_BTNFACE+1)); - return CDRF_NOTIFYITEMDRAW; - } - } - - break; - } - } - } - - break; - } - - break; - - - case WM_COMMAND: - return SendMessage(_viv_hwnd,WM_COMMAND,wParam,lParam); - - case WM_PAINT: - { - RECT rect; - int wide; - int high; - PAINTSTRUCT ps; - - GetClientRect(hwnd,&rect); - wide = rect.right - rect.left; - high = rect.bottom - rect.top; - - BeginPaint(hwnd,&ps); - - rect.left = 0; - rect.top = 0; - rect.right = wide; - rect.bottom = 1; - -// FillRect(ps.hdc,&rect,(HBRUSH)(COLOR_WINDOW + 1)); - FillRect(ps.hdc,&rect,(HBRUSH)(COLOR_3DSHADOW + 1)); - - rect.left = 0; - rect.top = 1; - rect.right = wide; - rect.bottom = 2; - -// FillRect(ps.hdc,&rect,(HBRUSH)(COLOR_WINDOW + 1)); - FillRect(ps.hdc,&rect,(HBRUSH)(COLOR_3DHIGHLIGHT + 1)); - - rect.left = 0; - rect.top = 2; - rect.right = wide; - rect.bottom = high; - -// FillRect(ps.hdc,&rect,(HBRUSH)(COLOR_WINDOW + 1)); - FillRect(ps.hdc,&rect,(HBRUSH)(COLOR_BTNFACE + 1)); - - EndPaint(hwnd,&ps); - - return 0; - } - - case WM_ERASEBKGND: - return 1; - } - - return DefWindowProc(hwnd,msg,wParam,lParam); -} - -static LRESULT CALLBACK _viv_status_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) -{ - switch (msg) - { - case WM_LBUTTONDOWN: - - if (config_toolbar_move_window) - { - if (os_statusbar_index_from_x(hwnd,GET_X_LPARAM(lParam)) == 0) - { - _viv_start_move_window(); - - return 0; - } - } - - break; - } - - return CallWindowProc(_viv_old_status_proc,hwnd,msg,wParam,lParam); -} - -static int _viv_toolbar_get_wide(void) -{ - if (_viv_toolbar_hwnd) - { - DWORD count; - DWORD button_index; - int min_x; - int max_x; - int got_x; - - count = (DWORD)SendMessage(_viv_toolbar_hwnd,TB_BUTTONCOUNT,0,0); - got_x = 0; - - for(button_index=0;button_index max_x) - { - max_x = button_rect.right; - } - } - else - { - min_x = button_rect.left; - max_x = button_rect.right; - - got_x = 1; - } - } - } - - if (got_x) - { - return max_x - min_x; - } - -/* -{ - TBMETRICS tbmetrics; - DWORD button_size; - - os_zero_memory(&tbmetrics,sizeof(TBMETRICS)); - - tbmetrics.cbSize = sizeof(TBMETRICS); - tbmetrics.dwMask = TBMF_PAD | TBMF_BARPAD | TBMF_BUTTONSPACING; - - SendMessage(_viv_toolbar_hwnd,TB_GETMETRICS,0,(LPARAM)&tbmetrics); - - debug_printf("TB_GETMETRICS cbSize %u %u %p\n",tbmetrics.cbSize,sizeof(TB_GETMETRICS),&tbmetrics); - debug_printf("TB_GETMETRICS dwMask %u\n",tbmetrics.dwMask); - debug_printf("TB_GETMETRICS cxPad %d\n",tbmetrics.cxPad); - debug_printf("TB_GETMETRICS cyPad %d\n",tbmetrics.cyPad); - debug_printf("TB_GETMETRICS cxBarPad %d\n",tbmetrics.cxBarPad); - debug_printf("TB_GETMETRICS cyBarPad %d\n",tbmetrics.cyBarPad); - debug_printf("TB_GETMETRICS cxButtonSpacing %d\n",tbmetrics.cxButtonSpacing); - debug_printf("TB_GETMETRICS cyButtonSpacing %d\n",tbmetrics.cyButtonSpacing); - - button_size = SendMessage(_viv_toolbar_hwnd,TB_GETBUTTONSIZE,0,0); - debug_printf("TB_GETBUTTONSIZE wide %u\n",LOWORD(button_size)); - debug_printf("TB_GETBUTTONSIZE high %u\n",HIWORD(button_size)); - - if (SendMessage(_viv_toolbar_hwnd,TB_GETMAXSIZE,0,(LPARAM)&size)) - { - debug_printf("TB_GETMAXSIZE wide %u\n",size.cx); - debug_printf("TB_GETMAXSIZE high %u\n",size.cy); - } -}*/ - -/* - SIZE size; - - // doesn't work at all on win9x / older than common controls v6 - if (SendMessage(_viv_toolbar_hwnd,TB_GETMAXSIZE,0,(LPARAM)&size)) - { - return size.cx; - }*/ - } - - return 0; -} - -static void _viv_toolbar_update_buttons(void) -{ - if (_viv_toolbar_hwnd) - { - TBBUTTONINFO tbbinfo; - int rw; - int rh; - - tbbinfo.cbSize = sizeof(TBBUTTONINFO); - tbbinfo.dwMask = TBIF_STATE; - tbbinfo.fsState = _viv_is_slideshow ? (TBSTATE_ENABLED | TBSTATE_CHECKED) : (TBSTATE_ENABLED); - - SendMessage(_viv_toolbar_hwnd,TB_SETBUTTONINFO,VIV_ID_SLIDESHOW_PLAY_ONLY,(LPARAM)&tbbinfo); - - tbbinfo.cbSize = sizeof(TBBUTTONINFO); - tbbinfo.dwMask = TBIF_STATE; - tbbinfo.fsState = _viv_is_slideshow ? (TBSTATE_ENABLED) : (TBSTATE_ENABLED | TBSTATE_CHECKED); - - SendMessage(_viv_toolbar_hwnd,TB_SETBUTTONINFO,VIV_ID_SLIDESHOW_PAUSE_ONLY,(LPARAM)&tbbinfo); - - _viv_get_render_size(&rw,&rh); - - tbbinfo.cbSize = sizeof(TBBUTTONINFO); - tbbinfo.dwMask = TBIF_STATE; - tbbinfo.fsState = ((rw == _viv_image_wide) && (rh == _viv_image_high)) ? (0) : (TBSTATE_ENABLED); - - SendMessage(_viv_toolbar_hwnd,TB_SETBUTTONINFO,VIV_ID_VIEW_1TO1,(LPARAM)&tbbinfo); - - tbbinfo.cbSize = sizeof(TBBUTTONINFO); - tbbinfo.dwMask = TBIF_STATE; - tbbinfo.fsState = ((_viv_zoom_pos == 0) && (!_viv_1to1)) ? (0) : (TBSTATE_ENABLED); - - SendMessage(_viv_toolbar_hwnd,TB_SETBUTTONINFO,VIV_ID_VIEW_BESTFIT,(LPARAM)&tbbinfo); - } -} - -static LRESULT CALLBACK _viv_fullscreen_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) -{ - switch(msg) - { - case WM_PAINT: - { - RECT rect; - PAINTSTRUCT ps; - - GetClientRect(hwnd,&rect); - BeginPaint(hwnd,&ps); - /* - { - HBRUSH hbrush; - - hbrush = CreateSolidBrush(RGB(config_fullscreen_background_color_r,config_fullscreen_background_color_g,config_fullscreen_background_color_b)); - - if (hbrush) - { - FillRect(ps.hdc,&rect,hbrush); - - DeleteObject(hbrush); - } - } - */ - EndPaint(hwnd,&ps); - break; - } - - case WM_ERASEBKGND: - return 1; - } - - return DefWindowProc(hwnd,msg,wParam,lParam); -} - -static void _viv_status_set_temp_text(wchar_t *text) -{ - if (_viv_status_temp_text) - { - KillTimer(_viv_hwnd,VIV_ID_STATUS_TEMP_TEXT_TIMER); - - mem_free(_viv_status_temp_text); - - _viv_status_temp_text = 0; - } - - if (text) - { - _viv_status_temp_text = string_alloc(text); - } - - _viv_status_update(); - - if (_viv_status_temp_text) - { - SetTimer(_viv_hwnd,VIV_ID_STATUS_TEMP_TEXT_TIMER,3000,0); - } -} - -static void _viv_status_update_temp_pos_zoom(void) -{ - wchar_t wbuf[STRING_SIZE]; - double x; - double y; - - x = (double)((_viv_dst_pos_x - 500) / 500.0f); - - if (x < 0) - { - x -= 0.0005; - } - else - { - x += 0.0005; - } - - y = (float)((_viv_dst_pos_y - 500) / 500.0f); - - if (y < 0) - { - y -= 0.0005; - } - else - { - y += 0.0005; - } - - string_printf(wbuf,localization_get_string(LOCALIZATION_ID_STATUS_BAR_POS_ZOOM_FORMAT),x,y,(float)_viv_dst_zoom_values[_viv_dst_zoom_x_pos],(float)_viv_dst_zoom_values[_viv_dst_zoom_y_pos],(_viv_dst_zoom_values[_viv_dst_zoom_x_pos] * (float)_viv_image_wide) / (_viv_dst_zoom_values[_viv_dst_zoom_y_pos] * (float)_viv_image_high)); - - _viv_status_set_temp_text(wbuf); -} - -static void _viv_status_update_temp_animation_rate(void) -{ - wchar_t wbuf[STRING_SIZE]; - - string_printf(wbuf,localization_get_string(LOCALIZATION_ID_STATUS_BAR_ANIMATION_RATE_FORMAT),_viv_animation_rates[_viv_animation_rate_pos]); - - _viv_status_set_temp_text(wbuf); -} - -static void _viv_zoom_in(int out,int have_xy,int x,int y) -{ - POINT pt; - - if (have_xy) - { - pt.x = x; - pt.y = y; - } - else - { - RECT rect; - GetClientRect(_viv_hwnd,&rect); - pt.x = (rect.right - rect.left) / 2; - pt.y = (rect.bottom - rect.top - _viv_get_status_high() - _viv_get_controls_high()) / 2; - } - - ClientToScreen(_viv_hwnd,&pt); - - _viv_do_mousewheel_action(0,MAKEWPARAM(0,out ? -120 : 120),pt.x,pt.y); -} - -static void _viv_status_update_slideshow_rate(void) -{ - wchar_t wbuf[STRING_SIZE]; - const utf8_t *res; - int r; - - if ((config_slideshow_rate / 60000) && ((config_slideshow_rate % 60000) == 0)) - { - r = config_slideshow_rate / 60000; - res = localization_get_string(LOCALIZATION_ID_STATUS_BAR_MINUTES); - } - else - if ((config_slideshow_rate / 1000) && ((config_slideshow_rate % 1000) == 0)) - { - r = config_slideshow_rate / 1000; - res = localization_get_string(LOCALIZATION_ID_STATUS_BAR_SECONDS); - } - else - { - r = config_slideshow_rate; - res = localization_get_string(LOCALIZATION_ID_STATUS_BAR_MILLISECONDS); - } - - string_printf(wbuf,localization_get_string(LOCALIZATION_ID_STATUS_BAR_SLIDESHOW_RATE_FORMAT),r,res); - - _viv_status_set_temp_text(wbuf); -} - -static void _viv_command_line_options(void) -{ - wchar_t *text_wbuf; - wchar_t caption_wbuf[STRING_SIZE]; - - text_wbuf = string_alloc_utf8("Usage:\nvoidImageViewer.exe [/switches] [filename(s)]\n" - "\n" - "Switches:\n" - "/slideshow\tStart a slideshow.\n" - "/fullscreen\tStart fullscreen.\n" - "/maximized\tStart maximized.\n" - "/window\t\tStart windowed.\n" - "/ontop\t\tShow on top of other windows.\n" - "/minimal\t\tBorderless window.\n" - "/compact\t\tBordered window.\n" - "/x /y /width /height \n" - "\t\tSet the Window position and size.\n" - "/rate \tSet the slideshow rate in milliseconds.\n" - "/name\t\tSort by name.\n" - "/path\t\tSort by full path.\n" - "/size\t\tSort by size.\n" - "/dm\t\tSort by date modified.\n" - "/dc\t\tSort by date created.\n" - "/ascending\tSort in ascending order.\n" - "/descending\tSort in descending order.\n" -// "/everything Open files from an Everything search.\n" -// "/random \tOpen random files from an Everything search.\n" - "/shuffle\t\tShuffle playlist.\n" - "/\n" - "\t\tInstall association.\n" - "/no\n" - "\t\tUninstall association.\n" - "/appdata\t\tSave settings in appdata.\n" - "/noappdata\tSave settings in exe path.\n" - "/startmenu\tAdd Start menu shortcuts.\n" - "/nostartmenu\tRemove Start menu shortcuts.\n" - "/install \tInstall to the specified path.\n" - "/install-options <...> Run with the specified options after installation.\n" - "/uninstall \tUninstall from the specified path.\n"); - - string_copy_utf8_string(caption_wbuf,localization_get_string(LOCALIZATION_ID_APP_NAME)); - - // MB_ICONQUESTION avoids the messagebeep. - MessageBox(_viv_hwnd, - text_wbuf, - caption_wbuf,MB_OK|MB_ICONQUESTION); - - mem_free(text_wbuf); -} - -static void _viv_install_association(DWORD flags) -{ - int i; - - for(i=0;i<_VIV_ASSOCIATION_COUNT;i++) - { - if (flags & (1 << i)) - { - _viv_install_association_by_extension(_viv_association_extensions[i],localization_get_string(_viv_association_description_localization_id_array[i]),_viv_association_icon_locations[i]); - } - } -} - -static void _viv_uninstall_association(DWORD flags) -{ - int i; - - for(i=0;i<_VIV_ASSOCIATION_COUNT;i++) - { - if (flags & 1 << i) - { - _viv_uninstall_association_by_extension(_viv_association_extensions[i]); - } - } -} - -static void _viv_view_scroll(int mx,int my) -{ - int old_view_x; - int old_view_y; - - old_view_x = _viv_view_x; - old_view_y = _viv_view_y; - - _viv_view_set(_viv_view_x - mx,_viv_view_y - my,0); - - if (config_scroll_window) - { - // this is not working for stamimail?!? - // probably a RTL issue. - if (ScrollWindowEx(_viv_hwnd,old_view_x - _viv_view_x,old_view_y - _viv_view_y,0,0,0,0,SW_INVALIDATE) == ERROR) - { - debug_printf("scroll error %d\n",GetLastError()); - } - } - else - { - // this fixes the scroll bug for stamimail - InvalidateRect(_viv_hwnd,0,FALSE); - } - -// UpdateWindow(_viv_hwnd); -} - -static void _viv_update_color_button_bitmap(HWND hwnd) -{ - HBITMAP hbitmap; - HDC screen_hdc; - HDC mem_hdc; - HGDIOBJ last_hbitmap; - RECT rect; - HBRUSH hbrush; - COLORREF colorref; - int wide; - int high; - - wide = (64 * os_logical_wide) / 96; - high = (13 * os_logical_high) / 96; - - colorref = (COLORREF)GetWindowLongPtr(hwnd,GWLP_USERDATA); - - screen_hdc = GetDC(0); - mem_hdc = CreateCompatibleDC(screen_hdc); - - hbitmap = CreateCompatibleBitmap(screen_hdc,wide,high); - - last_hbitmap = SelectObject(mem_hdc,hbitmap); - - hbrush = CreateSolidBrush(colorref); - - rect.left = 1; - rect.top = 1; - rect.right = wide-1; - rect.bottom = high-1; - FillRect(mem_hdc,&rect,hbrush); - ExcludeClipRect(mem_hdc,rect.left,rect.top,rect.right,rect.bottom); - - rect.left = 0; - rect.top = 0; - rect.right = wide; - rect.bottom = high; - FillRect(mem_hdc,&rect,(HBRUSH)GetStockObject(BLACK_BRUSH)); - - DeleteObject(hbrush); - - SelectObject(mem_hdc,last_hbitmap); - - DeleteDC(mem_hdc); - ReleaseDC(0,screen_hdc); - - last_hbitmap = (HBITMAP)SendMessage(hwnd,BM_SETIMAGE,IMAGE_BITMAP,(LPARAM)hbitmap); - if (last_hbitmap) - { - DeleteObject(last_hbitmap); - } -} - -static void _viv_delete_color_button_bitmap(HWND hwnd) -{ - HGDIOBJ last_hbitmap; - - last_hbitmap = (HBITMAP)SendMessage(hwnd,BM_SETIMAGE,IMAGE_BITMAP,0); - - if (last_hbitmap) - { - DeleteObject(last_hbitmap); - } -} - -static void _viv_get_command_name(wchar_t *wbuf,int command_index) -{ - wchar_t menu_wbuf[STRING_SIZE]; - - *wbuf = 0; - - _viv_cat_command_menu_path(wbuf,_viv_commands[command_index].menu_id); - - _viv_get_menu_display_name(menu_wbuf,localization_get_string(_viv_commands[command_index].localization_id)); - - string_cat(wbuf,menu_wbuf); -} - -static void _viv_cat_command_menu_path(wchar_t *wbuf,int menu_index) -{ - int command_index; - - if (menu_index == _VIV_MENU_ROOT) - { - return; - } - - command_index = _viv_command_index_from_command_id(menu_index); - - if (command_index != -1) - { - wchar_t menu_wbuf[STRING_SIZE]; - - _viv_get_menu_display_name(menu_wbuf,localization_get_string(_viv_commands[command_index].localization_id)); - - _viv_cat_command_menu_path(wbuf,_viv_commands[command_index].menu_id); - - string_cat(wbuf,menu_wbuf); - string_cat_utf8(wbuf," | "); - } -} - -static int _viv_convert_menu_ini_name_ch(int ch) -{ - if ((ch >= 'A') && (ch <= 'Z')) - { - return ch - 'A' + 'a'; - } - - if ((ch >= 'a') && (ch <= 'z')) - { - return ch; - } - - if ((ch >= '0') && (ch <= '9')) - { - return ch; - } - - if (ch == ' ') - { - return '_'; - } - - return 0; -} + else + if (string_icompare_lowercase_ascii(bufstart,"height") == 0) + { + p = string_get_word(p,buf,STRING_SIZE); + p = string_skip_ws(p); + + window_high = string_to_int(buf); + set_window_rect = 1; + } + else + if (string_icompare_lowercase_ascii(bufstart,"rate") == 0) + { + p = string_get_word(p,buf,STRING_SIZE); + p = string_skip_ws(p); -static utf8_t *_viv_cat_command_menu_ini_name_path(utf8_t *buf,int menu_index) -{ - int command_index; - utf8_t *d; - - if (menu_index == _VIV_MENU_ROOT) - { - return buf; - } - - d = buf; - - command_index = _viv_command_index_from_command_id(menu_index); - - if (command_index != -1) - { - const utf8_t *p; - - d = _viv_cat_command_menu_ini_name_path(d,_viv_commands[command_index].menu_id); - - p = localization_get_en_us_string(_viv_commands[command_index].localization_id); - - while(*p) - { - int ch; - - ch = _viv_convert_menu_ini_name_ch(*p); - - if (ch) + config_slideshow_rate = string_to_int(buf); + } + else + if (string_icompare_lowercase_ascii(bufstart,"name") == 0) { - *d++ = ch; + config_nav_sort = CONFIG_NAV_SORT_NAME; + config_nav_sort_ascending = 1; } - - p++; - } - - *d++ = '_'; - } - - return d; -} - -// make sure this is english only. -int viv_menu_name_to_ini_name(utf8_t *buf,int command_index) -{ - if (!(_viv_commands[command_index].flags & MF_POPUP)) - { - if (!(_viv_commands[command_index].flags & MF_SEPARATOR)) - { - if (!(_viv_commands[command_index].flags & MF_DELETE)) + else + if (string_icompare_lowercase_ascii(bufstart,"dm") == 0) { - utf8_t *d; - const utf8_t *p; - - d = buf; - p = localization_get_en_us_string(_viv_commands[command_index].localization_id); - - d = _viv_cat_command_menu_ini_name_path(d,_viv_commands[command_index].menu_id); - - while(*p) + config_nav_sort = CONFIG_NAV_SORT_DATE_MODIFIED; + config_nav_sort_ascending = 0; + } + else + if (string_icompare_lowercase_ascii(bufstart,"dc") == 0) + { + config_nav_sort = CONFIG_NAV_SORT_DATE_CREATED; + config_nav_sort_ascending = 0; + } + else + if (string_icompare_lowercase_ascii(bufstart,"path") == 0) + { + config_nav_sort = CONFIG_NAV_SORT_FULL_PATH_AND_FILENAME; + config_nav_sort_ascending = 1; + } + else + if (string_icompare_lowercase_ascii(bufstart,"size") == 0) + { + config_nav_sort = CONFIG_NAV_SORT_SIZE; + config_nav_sort_ascending = 0; + } + else + if (string_icompare_lowercase_ascii(bufstart,"ascending") == 0) + { + config_nav_sort_ascending = 1; + } + else + if (string_icompare_lowercase_ascii(bufstart,"descending") == 0) + { + config_nav_sort_ascending = 0; + } + else + if (string_icompare_lowercase_ascii(bufstart,"isrunas") == 0) + { + // ignore this for non-install commands. + } + else + if (string_icompare_lowercase_ascii(bufstart,"add") == 0) + { + // don't add if nothing is loaded. + if (*_viv_current_fd->cFileName) { - int ch; - - ch = _viv_convert_menu_ini_name_ch(*p); - - if (ch) - { - *d++ = ch; - } - - p++; + is_add = 1; } - - *d++ = '_'; - *d++ = 'k'; - *d++ = 'e'; - *d++ = 'y'; - *d++ = 's'; - - *d = 0; - - return 1; } - } - } - - return 0; -} - -static void _viv_get_menu_display_name(wchar_t *buf,const utf8_t *menu_name) -{ - wchar_t *d; - const wchar_t *p; - - string_copy_utf8_string(buf,menu_name); - - d = buf; - p = buf; - - while(*p) - { - if ((*p == '&') && (p[1] == '&')) - { - *d++ = '&'; - p += 2; - continue; - } - else - if (*p == '&') - { + else + { + _viv_command_line_options(); + } } else { - *d++ = *p; - } - - p++; - } - - *d = 0; -} - -static int _viv_command_index_from_command_id(int command_id) -{ - int i; - - for(i=0;i<_VIV_COMMAND_COUNT;i++) - { - if (_viv_commands[i].command_id == command_id) - { - return i; - } - } - - return -1; -} - -static int _viv_vk_to_text(wchar_t *wbuf,int vk) -{ - UINT scan_code; - - scan_code = MapVirtualKeyExW(vk,0,GetKeyboardLayout(GetCurrentThreadId())); - - if (scan_code) - { - LONG lParam; - - lParam = scan_code << 16; - - switch (vk) - { - case VK_CONTROL: - case VK_SHIFT: - case VK_MENU: - case VK_LWIN: - case VK_RWIN: - // dont care - lParam |= (1 << 25); - break; - - case VK_HOME: - case VK_END: - case VK_PRIOR: - case VK_NEXT: - case VK_INSERT: - case VK_DELETE: - case VK_NUMLOCK: - case VK_UP: - case VK_DOWN: - case VK_LEFT: - case VK_RIGHT: - case VK_DIVIDE: - // extended - lParam |= (1 << 24); - break; - } - - if (GetKeyNameText(lParam,wbuf,STRING_SIZE)) - { - return 1; - } - } - - return 0; -} - -static void _viv_cat_key_mod(wchar_t *wbuf,int vk,const utf8_t *default_keytext) -{ - wchar_t keytext[STRING_SIZE]; - - if (!_viv_vk_to_text(keytext,vk)) - { - string_copy_utf8_string(keytext,default_keytext); - } - - string_cat(wbuf,keytext); - string_cat_utf8(wbuf,(const utf8_t *)"+"); -} - -static void _viv_get_key_text(wchar_t *wbuf,DWORD keyflags) -{ - wchar_t keytext[STRING_SIZE]; - - *wbuf = 0; - - if (keyflags & CONFIG_KEYFLAG_CTRL) - { - _viv_cat_key_mod(wbuf,VK_CONTROL,"Ctrl"); - } - - if (keyflags & CONFIG_KEYFLAG_ALT) - { - _viv_cat_key_mod(wbuf,VK_MENU,"Alt"); - } - - if (keyflags & CONFIG_KEYFLAG_SHIFT) - { - _viv_cat_key_mod(wbuf,VK_SHIFT,"Shift"); - } - - if (_viv_vk_to_text(keytext,keyflags & CONFIG_KEYFLAG_VK_MASK)) - { - string_cat(wbuf,keytext); - } -} - -static HMENU _viv_create_menu(void) -{ - HMENU hmenu; - - hmenu = CreateMenu(); - - { - int i; - HMENU menus[_VIV_MENU_COUNT]; - - for(i=1;i<_VIV_MENU_COUNT;i++) - { - menus[i] = 0; - } - menus[0] = hmenu; - - for(i=0;i<_VIV_COMMAND_COUNT;i++) - { - if (!(_viv_commands[i].flags & MF_OWNERDRAW)) + if (*buf) { - if (_viv_commands[i].flags & MF_SEPARATOR) - { - AppendMenu(menus[_viv_commands[i].menu_id],_viv_commands[i].flags & (~MF_DELETE),_viv_commands[i].command_id,L""); - } - else + if (file_count == 0) { - wchar_t text_wbuf[STRING_SIZE]; - - string_copy_utf8_string(text_wbuf,localization_get_string(_viv_commands[i].localization_id)); - - if (_viv_commands[i].flags & MF_POPUP) - { - if (!menus[_viv_commands[i].command_id]) - { - menus[_viv_commands[i].command_id] = CreatePopupMenu(); - } - - AppendMenu(menus[_viv_commands[i].menu_id],_viv_commands[i].flags & (~MF_DELETE),(UINT_PTR)menus[_viv_commands[i].command_id],text_wbuf); - } - else + // new playlist + if (_viv_random) { - int key_command_index; - wchar_t key_text[STRING_SIZE]; - - key_command_index = i; - - switch (_viv_commands[i].command_id) - { - case VIV_ID_FILE_DELETE: - key_command_index = _viv_command_index_from_command_id(VIV_ID_FILE_DELETE_RECYCLE); - break; - } - - if (key_command_index >= 0) - { - if (_viv_key_list->start[key_command_index]) - { - _viv_get_key_text(key_text,_viv_key_list->start[key_command_index]->key); - - string_cat_utf8(text_wbuf,(const utf8_t *)"\t"); - string_cat(text_wbuf,key_text); - } - } + mem_free(_viv_random); - AppendMenu(menus[_viv_commands[i].menu_id],_viv_commands[i].flags & (~MF_DELETE),_viv_commands[i].command_id,text_wbuf); + _viv_random = 0; + } + + if (!is_add) + { + _viv_playlist_clearall(); } } - } - } - } - - return hmenu; -} - -static void _viv_key_add(_viv_key_list_t *key_list,int command_index,DWORD keyflags) -{ - config_key_t *key; - - key = mem_alloc(sizeof(config_key_t)); - - key->key = keyflags; - - if (key_list->start[command_index]) - { - key_list->last[command_index]->next = key; - } - else - { - key_list->start[command_index] = key; - } - - key->next = 0; - key_list->last[command_index] = key; -} - -static void _viv_key_clear(_viv_key_list_t *key_list,int command_index) -{ - config_key_t *key; - - key = key_list->start[command_index]; - - while(key) - { - config_key_t *next_key; - - next_key = key->next; - - mem_free(key); - - key = next_key; - } - - key_list->start[command_index] = 0; - key_list->last[command_index] = 0; -} - -static void _viv_key_list_copy(_viv_key_list_t *dst,const _viv_key_list_t *src) -{ - int i; - - _viv_key_clear_all(dst); - - for(i=0;i<_VIV_COMMAND_COUNT;i++) - { - config_key_t *key; + + if (file_count == 1) + { + // add the last single filename. + // we have two modes: + // 1) playlist mode. (navigate the playlist) + // 2) single file mode. (navigate the folder from the single file) + _viv_playlist_add_filename(single); + } - key = src->start[i]; - - while(key) - { - _viv_key_add(dst,i,key->key); + if (file_count >= 1) + { + // add this file + _viv_playlist_add_filename(buf); + } - key = key->next; + if (file_count == 0) + { + string_copy(single,buf); + } + + file_count++; + } } } -} - -static void _viv_key_clear_all(_viv_key_list_t *list) -{ - // free keys - int i; - - for(i=0;i<_VIV_COMMAND_COUNT;i++) - { - _viv_key_clear(list,i); - } -} - -static void _viv_key_list_init(_viv_key_list_t *list) -{ - // free keys - int i; - - for(i=0;i<_VIV_COMMAND_COUNT;i++) - { - list->start[i] = 0; - list->last[i] = 0; - } -} -static LRESULT CALLBACK _viv_edit_key_edit_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) -{ - WNDPROC last_proc; - - last_proc = (WNDPROC)GetWindowLongPtr(hwnd,GWLP_USERDATA); - - switch(msg) + // add the single image filename to the playlist if we are adding. + if (is_add) { - case WM_GETDLGCODE: - return DLGC_WANTALLKEYS; - - case WM_SYSKEYDOWN: - case WM_KEYDOWN: + // if the playlist is empty, add the current item. + if (!_viv_playlist_start) { - int key_flags; - int vk; - - key_flags = _viv_get_current_key_mod_flags(); - vk = wParam; - - switch(vk) + if (*_viv_current_fd->cFileName) { - case VK_CONTROL: - case VK_SHIFT: - case VK_MENU: - case VK_LWIN: - case VK_RWIN: - return 0; - - //FIXME: - // case VK_PROCESSKEY: - // // restore IME hacked key. - // vk = ImmGetVirtualKey(msg->hwnd); - // break; + _viv_playlist_add_filename(_viv_current_fd->cFileName); } - - _viv_edit_key_set_key(hwnd,key_flags | vk); - _viv_options_edit_key_changed(GetParent(hwnd)); - - return 0; } - } - - if ((msg == WM_LBUTTONDOWN) || (msg == WM_RBUTTONDOWN)) - { - SetFocus(hwnd); - - return 0; - } - - // ignore mouse messages. - if ((msg >= WM_MOUSEFIRST) && (msg <= WM_MOUSELAST)) - { - return 0; - } - - // ignore keyboard messages. - if ((msg >= WM_KEYFIRST) && (msg <= WM_KEYLAST)) - { - return 0; - } - - return CallWindowProc(last_proc,hwnd,msg,wParam,lParam); -} - -static int _viv_get_current_key_mod_flags(void) -{ - int key_flags; - - key_flags = 0; - - if (GetKeyState(VK_CONTROL) < 0) - { - key_flags |= CONFIG_KEYFLAG_CTRL; - } - - if (GetKeyState(VK_SHIFT) < 0) - { - key_flags |= CONFIG_KEYFLAG_SHIFT; - } - if (GetKeyState(VK_MENU) < 0) - { - key_flags |= CONFIG_KEYFLAG_ALT; + if (file_count == 1) + { + _viv_playlist_add_filename(single); + } } - return key_flags; -} + debug_printf("file count %d\n",file_count); -static void _viv_options_edit_key_changed(HWND hwnd) -{ - int keyflags; - int command_index; - - keyflags = GetWindowLongPtr(hwnd,GWLP_USERDATA); - - ListBox_ResetContent(GetDlgItem(hwnd,IDC_EDIT_KEY_CURRENTLY_USED_BY_LIST)); - SetWindowRedraw(GetDlgItem(hwnd,IDC_EDIT_KEY_CURRENTLY_USED_BY_LIST),FALSE); - - for(command_index=0;command_index<_VIV_COMMAND_COUNT;command_index++) + // show the first image. + // don't show anything if we are adding. + // show something if nothing is already shown. + if (!is_add) { - config_key_t *key; - - key = _viv_key_list->start[command_index]; - - while(key) + if (file_count >= 1) { - if (key->key == keyflags) + const wchar_t *open_filename; + + if (_viv_random) { - wchar_t command_wbuf[STRING_SIZE]; - - _viv_get_command_name(command_wbuf,command_index); + mem_free(_viv_random); - ListBox_AddString(GetDlgItem(hwnd,IDC_EDIT_KEY_CURRENTLY_USED_BY_LIST),command_wbuf); + _viv_random = 0; } - - key = key->next; - } - } - - ListBox_SetCurSel(GetDlgItem(hwnd,IDC_EDIT_KEY_CURRENTLY_USED_BY_LIST),0); - - SetWindowRedraw(GetDlgItem(hwnd,IDC_EDIT_KEY_CURRENTLY_USED_BY_LIST),TRUE); -} - -static void _viv_edit_key_set_key(HWND hwnd,DWORD key_flags) -{ - wchar_t keytext_wbuf[STRING_SIZE]; - - if (key_flags) - { - _viv_get_key_text(keytext_wbuf,key_flags); - } - else - { - keytext_wbuf[0] = 0; - SetWindowLongPtr(GetParent(hwnd),GWLP_USERDATA,0); - } - - SetWindowLongPtr(GetParent(hwnd),GWLP_USERDATA,key_flags); - - SetWindowText(hwnd,keytext_wbuf); - - os_edit_move_caret_to_end(hwnd); -} - -static void _viv_key_remove(_viv_key_list_t *keylist,int command_index,DWORD keyflags) -{ - config_key_t *key; - - key = keylist->start[command_index]; - - keylist->start[command_index] = 0; - keylist->last[command_index] = 0; - - while(key) - { - config_key_t *next_key; - - next_key = key->next; - - if (key->key == keyflags) - { - mem_free(key); - } - else - { - if (keylist->start[command_index]) + + open_filename = NULL; + + if (file_count > 1) { - keylist->last[command_index]->next = key; + // treat as a playlist. + if (_viv_playlist_start) + { + open_filename = _viv_playlist_start->fd.cFileName; + } } else + if (file_count == 1) { - keylist->start[command_index] = key; + open_filename = single; } - keylist->last[command_index] = key; - key->next = 0; - } - - key = next_key; - } -} - -static void _viv_edit_key_remove_currently_used_by(_viv_key_list_t *keylist,DWORD keyflags) -{ - int command_index; - - for(command_index=0;command_index<_VIV_COMMAND_COUNT;command_index++) - { - _viv_key_remove(keylist,command_index,keyflags); - } -} - -//FIXME: we should timeout -//FIXME: we should check for the process name voidImageViewer.exe rather than the window class name. -be careful when uninstalling as the non-admin process will be waiting for the admin process to exit. -static void _viv_close_existing_process(void) -{ - for(;;) - { - HWND hwnd; - - hwnd = FindWindowA("VOIDIMAGEVIEWER",0); - if (hwnd) - { - DWORD process_id; - HANDLE process_handle; - - GetWindowThreadProcessId(hwnd,&process_id); - - process_handle = OpenProcess(SYNCHRONIZE,FALSE,process_id); - - SendMessage(hwnd,WM_CLOSE,0,0); - - if (process_handle) + // open the first image found (if multiple images passed). + // if we only specified a single image, use the single image filename. + if ((open_filename) && (_viv_open_from_filename(open_filename,VIV_OPEN_FORWARDED))) { - WaitForSingleObject(process_handle,INFINITE); - - CloseHandle(process_handle); + // all good. } - } - else - { - // no window open - break; - } - } -} - -static void _viv_uninstall_delete_file(const wchar_t *path,const utf8_t *filename) -{ - wchar_t full_path_and_filename[STRING_SIZE]; - - string_path_combine_utf8(full_path_and_filename,path,filename); - - DeleteFile(full_path_and_filename); -} - -static int _viv_is_start_menu_shortcuts(void) -{ - wchar_t special_folder_path_wbuf[STRING_SIZE]; - wchar_t path_wbuf[STRING_SIZE]; - int ret; - - ret = 0; - - // delete old english shortcuts - // delete shortcuts - if (os_get_special_folder_path(special_folder_path_wbuf,CSIDL_COMMON_PROGRAMS)) - { - string_path_combine_utf8(path_wbuf,special_folder_path_wbuf,(const utf8_t *)"void Image Viewer"); - - // make sure this directory exists! - if (GetFileAttributesW(path_wbuf) != INVALID_FILE_ATTRIBUTES) - { - // at least one item exists, ret = 2 - ret = 1; - } - } - - return ret; -} - -static void _viv_install_start_menu_shortcuts(void) -{ - wchar_t special_folder_path_wbuf[STRING_SIZE]; - - // always uninstall and reinstall - // this allows us to switch between english and another language. - _viv_uninstall_start_menu_shortcuts(); - - // create shortcuts - if (os_get_special_folder_path(special_folder_path_wbuf,CSIDL_COMMON_PROGRAMS)) - { - wchar_t path_wbuf[STRING_SIZE]; - wchar_t exe_filename_wbuf[STRING_SIZE]; - wchar_t exe_path_wbuf[STRING_SIZE]; - wchar_t uninstall_filename_wbuf[STRING_SIZE]; - wchar_t lnk_wbuf[STRING_SIZE]; - - string_path_combine_utf8(path_wbuf,special_folder_path_wbuf,(const utf8_t *)"void Image Viewer"); - - // make sure this directory exists! - os_make_sure_path_exists(path_wbuf); - - // void image viewer.lnk - _viv_get_exe_filename(exe_filename_wbuf); - string_path_combine_utf8(lnk_wbuf,path_wbuf,"void Image Viewer.lnk"); - os_create_shell_link(exe_filename_wbuf,lnk_wbuf); - - // uninstall - string_get_path_part(exe_path_wbuf,exe_filename_wbuf); - string_path_combine_utf8(uninstall_filename_wbuf,exe_path_wbuf,(const utf8_t *)"Uninstall.exe"); - - string_path_combine_utf8(lnk_wbuf,path_wbuf,"Uninstall.lnk"); - os_create_shell_link(uninstall_filename_wbuf,lnk_wbuf); - } -} - -static void _viv_uninstall_start_menu_shortcuts(void) -{ - wchar_t special_folder_path_wbuf[STRING_SIZE]; - wchar_t path_wbuf[STRING_SIZE]; - - // delete old english shortcuts - // delete shortcuts - if (os_get_special_folder_path(special_folder_path_wbuf,CSIDL_COMMON_PROGRAMS)) - { - wchar_t lnk_wbuf[STRING_SIZE]; - - string_path_combine_utf8(path_wbuf,special_folder_path_wbuf,(const utf8_t *)"void Image Viewer"); - - // localized. - string_path_combine_utf8(lnk_wbuf,path_wbuf,"void Image Viewer.lnk"); - DeleteFile(lnk_wbuf); - - string_path_combine_utf8(lnk_wbuf,path_wbuf,"Uninstall.lnk"); - DeleteFile(lnk_wbuf); - - RemoveDirectory(path_wbuf); - } -} - -static void _viv_append_admin_param(wchar_t *wbuf,const utf8_t *param) -{ - string_cat_utf8(wbuf,(const utf8_t *)" /"); - string_cat_utf8(wbuf,param); -} - -static void _viv_install_copy_file(const wchar_t *install_path,const wchar_t *temp_path,const utf8_t *filename,int critical) -{ - wchar_t dst_wbuf[STRING_SIZE]; - wchar_t src_wbuf[STRING_SIZE]; - - string_path_combine_utf8(dst_wbuf,install_path,filename); - string_path_combine_utf8(src_wbuf,temp_path,filename); + else + { + _viv_file_not_found = 1; + _viv_status_update(); + } + } + } - if (!CopyFile(src_wbuf,dst_wbuf,FALSE)) + if (start_slideshow) { - if (critical) - { - debug_fatal("Error %d: unable to copy %S to %S",GetLastError(),src_wbuf,dst_wbuf); - } - } -} - -static void _viv_shuffle_playlist(void) -{ - if (_viv_playlist_count) + _viv_slideshow(); + } + + if (start_fullscreen) { + if (!_viv_is_fullscreen) { - LARGE_INTEGER counter; - - QueryPerformanceCounter(&counter); + _viv_toggle_fullscreen(); - srand(counter.LowPart); + if (start_maximized) + { + _viv_fullscreen_is_maxed = 1; + } } - - _viv_playlist_shuffle_allocated = _VIV_DEFAULT_SHUFFLE_ALLOCATED; - - while(_viv_playlist_shuffle_allocated < _viv_playlist_count) + } + else + { + if (start_window) { - _viv_playlist_shuffle_allocated *= 2; + if (_viv_is_fullscreen) + { + _viv_toggle_fullscreen(); + } } - - // allocate indexes. - _viv_playlist_shuffle_indexes = mem_alloc(_viv_playlist_shuffle_allocated * sizeof(_viv_playlist_t *)); - - // fill in indexes + else { - _viv_playlist_t **d; - _viv_playlist_t *p; - - d = _viv_playlist_shuffle_indexes; - p = _viv_playlist_start; - - while(p) + if (set_window_rect) { - *d++ = p; - - p = p->next; + SetWindowPos(_viv_hwnd,0,window_x,window_y,window_wide,window_high,SWP_NOZORDER|SWP_NOACTIVATE); } } - - // shuffle + + if (start_maximized) { - int i; - - for(i=0;i<_viv_playlist_count-1;i++) + if (!_viv_is_window_maximized(_viv_hwnd)) { - int j; - _viv_playlist_t *tmp; - - j = i + rand() % (_viv_playlist_count - i); - - tmp = _viv_playlist_shuffle_indexes[i]; - _viv_playlist_shuffle_indexes[i] = _viv_playlist_shuffle_indexes[j]; - _viv_playlist_shuffle_indexes[j] = tmp; + ShowWindow(_viv_hwnd,SW_MAXIMIZE); } } } + + // save last processing time + // if we make another immediate call, add items to the playlist, instead of setting the playlist. + last_process_command_line_tick = GetTickCount(); + got_last_process_command_line_tick = 1; } -static void _viv_jumpto_on_size(HWND hwnd) +static int _viv_init(int nCmdShow) { RECT rect; - int wide; - int high; - int edit_high; - int button_wide; - int button_high; - int y; - int edge; - int list_high; - - GetClientRect(hwnd,&rect); - wide = rect.right - rect.left; - high = rect.bottom - rect.top; - - GetWindowRect(GetDlgItem(hwnd,IDC_JUMPTO_EDIT),&rect); - edit_high = rect.bottom - rect.top; - - GetWindowRect(GetDlgItem(hwnd,IDOK),&rect); - button_wide = rect.right - rect.left; - button_high = rect.bottom - rect.top; - - edge = (12 * os_logical_high) / 96; - y = edge; - - SetWindowPos(GetDlgItem(hwnd,IDC_JUMPTO_EDIT),0,edge,y,wide-edge-edge,edit_high,SWP_NOACTIVATE|SWP_NOZORDER); - - y += edit_high + (6 * os_logical_high) / 96; - - high -= button_high + edge; - - list_high = (high - y) - edge; - if (list_high < 0) - { - list_high = 0; - } - - SetWindowPos(GetDlgItem(hwnd,IDC_JUMPTO_LIST),0,edge,y,wide-edge-edge,list_high,SWP_NOACTIVATE|SWP_NOZORDER); - - y += list_high + edge; - - SetWindowPos(GetDlgItem(hwnd,IDOK),0,wide - edge - button_wide - edge - button_wide,y,button_wide,button_high,SWP_NOACTIVATE|SWP_NOZORDER); - SetWindowPos(GetDlgItem(hwnd,IDCANCEL),0,wide - edge - button_wide,y,button_wide,button_high,SWP_NOACTIVATE|SWP_NOZORDER); -} - -static void _viv_jumpto_on_search(HWND hwnd) -{ - wchar_t search_wbuf[STRING_SIZE]; - int is_path_search; + STARTUPINFO si; + int show_maximized; + DWORD window_style; - GetDlgItemText(hwnd,IDC_JUMPTO_EDIT,search_wbuf,STRING_SIZE); + os_init(); + localization_init(); // Initialize language system + show_maximized = 0; - SendDlgItemMessage(hwnd,IDC_JUMPTO_LIST,WM_SETREDRAW,FALSE,0); + debug_printf("%u\n",sizeof(_viv_key_list_t)); - ListBox_ResetContent(GetDlgItem(hwnd,IDC_JUMPTO_LIST)); + _viv_key_list = mem_alloc(sizeof(_viv_key_list_t)); - is_path_search = 0; + _viv_key_list_init(_viv_key_list); + // setup keys. { - const wchar_t *p; + int i; - p = search_wbuf; - - while(*p) + for(i=0;i<_VIV_DEFAULT_KEY_COUNT;i++) { - if ((*p == '\\') || (*p == '/') || (*p == ':')) - { - is_path_search = 1; - break; - } - - p++; + viv_key_add(_viv_command_index_from_command_id(_viv_default_keys[i].command_id),_viv_default_keys[i].key_flags); } } + // init the zoom ladder: a geometric 1.01x per step. the ladder is long + // enough that the 16x size cap is reachable even for photos much larger + // than the window. { int i; + double f; + + f = 1.0; - for(i=0;i<_viv_nav_item_count;i++) + for(i=0;i<_VIV_ZOOM_MAX;i++) { - const wchar_t *name; - const wchar_t *search_name; + _viv_zoom_scales[i] = (float)f; - name = string_get_filename_part(_viv_nav_items[i]->fd.cFileName); - - if (is_path_search) - { - search_name = _viv_nav_items[i]->fd.cFileName; - } - else - { - search_name = name; - } - - if ((!(*search_wbuf)) || (StrStrI(search_name,search_wbuf))) - { - int lb_index; - - lb_index = ListBox_AddString(GetDlgItem(hwnd,IDC_JUMPTO_LIST),string_get_filename_part(name)); - - ListBox_SetItemData(GetDlgItem(hwnd,IDC_JUMPTO_LIST),lb_index,i); - } + f *= 1.01; } } - ListBox_SetCurSel(GetDlgItem(hwnd,IDC_JUMPTO_LIST),0); + debug_printf("viv %s%s (build %d) %s\n",VERSION_STRING,VERSION_TYPE,VERSION_BUILD,VERSION_TARGET_MACHINE); - SendDlgItemMessage(hwnd,IDC_JUMPTO_LIST,WM_SETREDRAW,TRUE,0); -} + os_hinstance = GetModuleHandle(0); + + _viv_current_fd = (WIN32_FIND_DATA *)mem_alloc(sizeof(WIN32_FIND_DATA)); + os_zero_memory(_viv_current_fd,sizeof(WIN32_FIND_DATA)); -static void _viv_jumpto_open_sel(HWND hwnd) -{ - int lb_index; + _viv_preload_fd = (WIN32_FIND_DATA *)mem_alloc(sizeof(WIN32_FIND_DATA)); + os_zero_memory(_viv_preload_fd,sizeof(WIN32_FIND_DATA)); + + _viv_last_fd = (WIN32_FIND_DATA *)mem_alloc(sizeof(WIN32_FIND_DATA)); + os_zero_memory(_viv_last_fd,sizeof(WIN32_FIND_DATA)); + + _viv_frame_fd = (WIN32_FIND_DATA *)mem_alloc(sizeof(WIN32_FIND_DATA)); + os_zero_memory(_viv_frame_fd,sizeof(WIN32_FIND_DATA)); + + _viv_load_fd = (WIN32_FIND_DATA *)mem_alloc(sizeof(WIN32_FIND_DATA)); + os_zero_memory(_viv_load_fd,sizeof(WIN32_FIND_DATA)); + + debug_printf("CoInitializeEx\n"); + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED|COINIT_DISABLE_OLE1DDE); + + // this resolves ATL window thunking problem when Microsoft Layer for Unicode (MSLU) is used + DefWindowProc(NULL,0,0,0); + + // init common controls - lb_index = ListBox_GetCurSel(GetDlgItem(hwnd,IDC_JUMPTO_LIST)); + debug_printf("InitCommonControlsEx\n"); + { + INITCOMMONCONTROLSEX icex; + + icex.dwSize = sizeof(INITCOMMONCONTROLSEX); + icex.dwICC = ICC_STANDARD_CLASSES | ICC_BAR_CLASSES | ICC_WIN95_CLASSES; + InitCommonControlsEx(&icex); + } - if (lb_index != LB_ERR) - { - int index; + InitializeCriticalSection(&_viv_cs); + + // Initialize GDI+. + if (os_GdiplusStartup) + { + os_GdiplusStartupInput_t gdiplusStartupInput; + int gdiplus_ret; - index = ListBox_GetItemData(GetDlgItem(hwnd,IDC_JUMPTO_LIST),lb_index); + gdiplusStartupInput.GdiplusVersion = 1; + gdiplusStartupInput.DebugEventCallback = NULL; + gdiplusStartupInput.SuppressBackgroundThread = FALSE; + gdiplusStartupInput.SuppressExternalCodecs = FALSE; + + gdiplus_ret = os_GdiplusStartup(&os_GdiplusToken,&gdiplusStartupInput,NULL); + } + + // load settings + config_load_settings(); + + // apply the language setting (config can override the system language). + _viv_apply_config_language(); + + // set the menu theme (light/dark) before any menu or window is created, + // so the dark mode applies from the very first draw. + os_dark_set_app_mode(config_dark_mode); + + // config_maximized will be overwritten when we show are normal window + // so save it now and apply it later. + show_maximized = config_maximized; - if ((index >= 0) && (index < _viv_nav_item_count)) + // process install command line options + { + if (_viv_process_install_command_line_options(GetCommandLineW())) { - _viv_open(&_viv_nav_items[index]->fd,0); + _viv_kill(); + + return 0; } } -} - -static LRESULT CALLBACK _viv_jumpto_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) -{ - switch(msg) - { - case WM_INITDIALOG: - { - int cur_index; - - cur_index = LB_ERR; + // mutex + if (!config_multiple_instances) + { + SetLastError(0); - os_SetWindowText_localization_id(hwnd,LOCALIZATION_ID_JUMP_TO_TITLE); - os_SetDlgItemText_localization_id(hwnd,IDOK,LOCALIZATION_ID_OK_BUTTON); - os_SetDlgItemText_localization_id(hwnd,IDCANCEL,LOCALIZATION_ID_CANCEL_BUTTON); - - os_center_dialog(hwnd); - - _viv_nav_item_free_all(); - - if (_viv_playlist_start) - { - _viv_playlist_t *d; - - d = _viv_playlist_start; - while(d) - { - _viv_nav_item_add(&d->fd); - - d = d->next; - } - } - else - if (*_viv_current_fd->cFileName) - { - WIN32_FIND_DATA fd; - HANDLE h; - wchar_t search_wbuf[STRING_SIZE]; - wchar_t path_wbuf[STRING_SIZE]; + _viv_mutex = CreateMutexA(NULL,0,"VOIDIMAGEVIEWER"); + + if (GetLastError() == ERROR_ALREADY_EXISTS) + { + HWND hwnd; - string_get_path_part(path_wbuf,_viv_current_fd->cFileName); - - string_copy(search_wbuf,path_wbuf); - string_cat_utf8(search_wbuf,(const utf8_t *)"\\*.*"); + hwnd = FindWindowA("VOIDIMAGEVIEWER",0); + + if (hwnd) + { + COPYDATASTRUCT cds; + wchar_t *command_line; + wchar_t cwd[STRING_SIZE]; + int size; + char *buf; + char *d; - h = FindFirstFile(search_wbuf,&fd); - - if (h != INVALID_HANDLE_VALUE) - { - for(;;) - { - if (_viv_is_valid_filename(&fd)) - { - string_path_combine(search_wbuf,path_wbuf,fd.cFileName); - string_copy_with_bufsize(fd.cFileName,MAX_PATH,search_wbuf); - - _viv_nav_item_add(&fd); - } - - if (!FindNextFile(h,&fd)) break; - } + // allow this process to set focus + SetForegroundWindow(hwnd); - FindClose(h); - } - } - - if (_viv_nav_item_count) - { - _viv_nav_item_t **d; - _viv_nav_item_t *navitem; - - _viv_nav_items = (_viv_nav_item_t **)mem_alloc(_viv_nav_item_count * sizeof(_viv_nav_item_t *)); - d = _viv_nav_items; - - navitem = __viv_nav_item_start; - while(navitem) - { - *d++ = navitem; - - navitem = navitem->next; - } - } + command_line = GetCommandLineW(); + GetCurrentDirectory(STRING_SIZE,cwd); - // sort by name - os_qsort(_viv_nav_items,_viv_nav_item_count,_viv_nav_compare); + si.cb = sizeof(STARTUPINFO); + GetStartupInfo(&si); - // find current. + if (!(si.dwFlags & STARTF_USESHOWWINDOW)) { - _viv_nav_item_t **p; - SIZE_T run; - int index; - - p = _viv_nav_items; - run = _viv_nav_item_count; - index = 0; - - while(run) - { - if (string_compare((*p)->fd.cFileName,_viv_current_fd->cFileName) == 0) - { - cur_index = index; - } - - index++; - p++; - run--; - } + si.wShowWindow = nCmdShow; } - _viv_jumpto_on_size(hwnd); - _viv_jumpto_on_search(hwnd); + // calc size + size = (int)safe_size_add(safe_size_add(sizeof(DWORD),safe_size_mul_sizeof_wchar(safe_size_add_one(string_get_length(command_line)))),safe_size_mul_sizeof_wchar(safe_size_add_one(string_get_length(cwd)))); + buf = (char *)mem_alloc(size); - if (cur_index != LB_ERR) - { - ListBox_SetCurSel(GetDlgItem(hwnd,IDC_JUMPTO_LIST),cur_index); - - _viv_center_listbox_item(GetDlgItem(hwnd,IDC_JUMPTO_LIST),cur_index); - } - } - - return TRUE; - - case WM_COMMAND: - - switch(LOWORD(wParam)) - { - case IDC_JUMPTO_EDIT: - if (HIWORD(wParam) == EN_CHANGE) - { - _viv_jumpto_on_search(hwnd); - break; - } - break; + // fill in + d = buf; + *(DWORD *)d = si.wShowWindow; + d += sizeof(DWORD); + string_copy((wchar_t *)d,command_line); + d += ((string_get_length(command_line) + 1) * sizeof(wchar_t)); + string_copy((wchar_t *)d,cwd); + d += ((string_get_length(cwd) + 1) * sizeof(wchar_t)); - case IDC_JUMPTO_LIST: - if (HIWORD(wParam) == LBN_DBLCLK) - { - _viv_jumpto_open_sel(hwnd); - _viv_jump_ret = 1; - break; - } - break; - - case IDOK: - _viv_jumpto_open_sel(hwnd); - _viv_jump_ret = 1; - break; + // setup copydata struct + cds.lpData = buf; + cds.cbData = size; + cds.dwData = _VIV_COPYDATA_COMMAND_LINE; - case IDCANCEL: - _viv_jump_ret = 1; - break; + SendMessage(hwnd,WM_COPYDATA,(WPARAM)0,(LPARAM)&cds); + + mem_free(buf); } - - break; - - case WM_SIZE: - _viv_jumpto_on_size(hwnd); - break; - case WM_CLOSE: - _viv_jump_ret = 1; - return TRUE; - - case WM_DESTROY: - _viv_nav_item_free_all(); - break; + _viv_kill(); + + return 0; + } } - return FALSE; -} - -static void _viv_show_jumpto(void) -{ - HWND dialog_hwnd; + os_RegisterClassEx( + CS_DBLCLKS | CS_VREDRAW | CS_HREDRAW, + _viv_proc, + (HICON)LoadImage(os_hinstance,MAKEINTRESOURCE(IDI_ICON1),IMAGE_ICON,GetSystemMetrics(SM_CXICON),GetSystemMetrics(SM_CXICON),0), + LoadCursor(NULL,IDC_ARROW), + (HBRUSH)(COLOR_BTNFACE+1), + "VOIDIMAGEVIEWER", + (HICON)LoadImage(os_hinstance,MAKEINTRESOURCE(IDI_ICON1),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0)); - _viv_jump_ret = 0; + _viv_hmenu = _viv_create_menu(); - dialog_hwnd = CreateDialog(os_hinstance,MAKEINTRESOURCE(IDD_JUMPTO),_viv_hwnd,_viv_jumpto_proc); + rect.left = config_x; + rect.top = config_y; + rect.right = config_x + config_wide; + rect.bottom = config_y + config_high; - if (dialog_hwnd) + // position the window nicely on first use + // auto-fit and center on the monitor from the mouse cursor. + if ((!config_wide) || (!config_high)) { - ShowWindow(dialog_hwnd,SW_SHOW); - EnableWindow(_viv_hwnd,FALSE); - - while(!_viv_jump_ret) + RECT monitor_rect; + int default_wide; + int default_high; + + default_wide = 640; + default_high = 480; + + // use full screen to calculate auto-fit size. + os_MonitorRectFromCursor(1,&monitor_rect); + + if (config_auto_fit_wide_div) { - MSG msg; - - if (!GetMessageW(&msg,NULL,0,0)) - { - break; - } - - if ((msg.hwnd == dialog_hwnd) || (IsChild(dialog_hwnd,msg.hwnd))) - { - switch (msg.message) - { - case WM_MOUSEWHEEL: - - SendMessage(GetDlgItem(dialog_hwnd,IDC_JUMPTO_LIST),WM_MOUSEWHEEL,msg.wParam,msg.lParam); - continue; - - case WM_SYSKEYDOWN: - case WM_KEYDOWN: - - if (msg.hwnd == GetDlgItem(dialog_hwnd,IDC_JUMPTO_EDIT)) - { - int key_flags; - int vk; - - key_flags = _viv_get_current_key_mod_flags(); - vk = msg.wParam; - - switch(vk) - { - case VK_UP: - case VK_DOWN: - case VK_NEXT: - case VK_PRIOR: - - /* - - { - int count; - int index; - - // msg->hwnd = GetDlgItem(dialog_hwnd,IDC_JUMPTO_LIST); - - index = -1; - count = ListBox_GetCount(GetDlgItem(dialog_hwnd,IDC_JUMPTO_LIST)); - - if (count) - { - switch (msg.wParam) - { - case VK_DOWN: - case VK_NEXT: - index = 0; - break; - - default: - index = count - 1; - break; - } - } - - if (index != -1) - { - ListBox_SetCurSel(GetDlgItem(dialog_hwnd,IDC_JUMPTO_LIST),index); - } - - SetFocus(GetDlgItem(dialog_hwnd,IDC_JUMPTO_LIST)); - } - */ - - SendMessage(GetDlgItem(dialog_hwnd,IDC_JUMPTO_LIST),msg.message,msg.wParam,msg.lParam); + default_wide = ((monitor_rect.right - monitor_rect.left) * config_auto_fit_wide_mul) / config_auto_fit_wide_div; + } - //SetFocus(GetDlgItem(dialog_hwnd,IDC_JUMPTO_LIST)); - - continue; - } - } - - break; - - } - } - - if (!IsDialogMessageW(dialog_hwnd,&msg)) - { - TranslateMessage(&msg); - DispatchMessageW(&msg); - } + if (config_auto_fit_high_div) + { + default_high = ((monitor_rect.bottom - monitor_rect.top) * config_auto_fit_high_mul) / config_auto_fit_high_div; } - EnableWindow(_viv_hwnd,TRUE); - DestroyWindow(dialog_hwnd); + rect.left = ((monitor_rect.right - monitor_rect.left) / 2) - (default_wide / 2); + rect.top = ((monitor_rect.bottom - monitor_rect.top) / 2) - (default_high / 2); + rect.right = rect.left + default_wide; + rect.bottom = rect.top + default_high; } -} + + window_style = WS_CAPTION | WS_THICKFRAME | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; -static void _viv_nav_item_free_all(void) -{ - if (_viv_nav_items) + _viv_hwnd = os_CreateWindowEx( + 0, + "VOIDIMAGEVIEWER", + localization_get_string(LOCALIZATION_ID_APP_NAME), + window_style, + rect.left,rect.top,rect.right - rect.left,rect.bottom - rect.top, + 0,NULL,os_hinstance,NULL); + + if ((!config_show_caption) || (!config_show_thickframe)) { - int i; + _viv_update_frame(); + } - for(i=0;i<_viv_nav_item_count;i++) - { - mem_free(_viv_nav_items[i]); - } + os_make_rect_completely_visible(_viv_hwnd,&rect); - mem_free(_viv_nav_items); + SetWindowPos(_viv_hwnd,0,rect.left,rect.top,rect.right - rect.left,rect.bottom - rect.top,SWP_NOZORDER|SWP_NOACTIVATE); + + // rc.17: the init-time dpi globals came from GetDC(0) - the primary + // monitor. a launch that restores the window onto another monitor + // would otherwise build every strip at the primary's scale + // (wm_dpichanged only fires on a change, and a create-time send is + // undocumented): one explicit sync after the window exists, before + // the first strip is built from the globals. + os_window_update_dpi(_viv_hwnd); + + // the top bar is a client side child now: show it before the first + // layout sweep (the frame menu is gone for good). + _viv_menubar_show(config_show_menu); - __viv_nav_item_start = 0; - _viv_nav_item_last = 0; - _viv_nav_items = 0; - _viv_nav_item_count = 0; + // allow non-admin/admins to close this window. + if (os_ChangeWindowMessageFilterEx) + { + // MSGFLT_ALLOW = 1 + os_ChangeWindowMessageFilterEx(_viv_hwnd,WM_CLOSE,1,0); + + // theme change broadcasts come from unelevated system processes: + // allow them through the uipi filter so an elevated viewer still + // follows the windows theme live. + os_ChangeWindowMessageFilterEx(_viv_hwnd,WM_SETTINGCHANGE,1,0); + os_ChangeWindowMessageFilterEx(_viv_hwnd,WM_THEMECHANGED,1,0); } -} - -static void _viv_nav_item_add(WIN32_FIND_DATA *fd) -{ - _viv_nav_item_t *navitem; + + _viv_status_show(config_show_status); + _viv_controls_show(config_show_controls); + _viv_zoomui_update(); - navitem = mem_alloc(sizeof(_viv_nav_item_t)); + // apply the dark chrome (title bar, status bar, zoom controls) to the + // freshly created window. + _viv_apply_dark_mode(0); + + DragAcceptFiles(_viv_hwnd,TRUE); + + _viv_update_title(); + + _viv_update_ontop(); - os_copy_memory(&navitem->fd,fd,sizeof(WIN32_FIND_DATA)); + si.cb = sizeof(STARTUPINFO); + GetStartupInfo(&si); - if (__viv_nav_item_start) + if (!(si.dwFlags & STARTF_USESHOWWINDOW)) { - _viv_nav_item_last->next = navitem; + si.wShowWindow = nCmdShow; } - else + + // default is to shownormal. + // if its anything else, like minimize/maximize to that before we apply the command line. + if (si.wShowWindow != SW_SHOWNORMAL) { - __viv_nav_item_start = navitem; + ShowWindow(_viv_hwnd,si.wShowWindow); + UpdateWindow(_viv_hwnd); } - navitem->next = 0; - _viv_nav_item_last = navitem; - _viv_nav_item_count++; -} - -static int _viv_nav_compare(const _viv_nav_item_t *a,const _viv_nav_item_t *b) -{ - return _viv_fd_compare_name(&a->fd,&b->fd); -} - -static INT_PTR CALLBACK _viv_search_everything_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) -{ - switch(msg) + if (show_maximized) { - case WM_INITDIALOG: - - os_center_dialog(hwnd); - - SetWindowLongPtr(hwnd,GWLP_USERDATA,lParam); - - os_SetWindowText_localization_id(hwnd,lParam ? LOCALIZATION_ID_EVERYTHING_ADD_EVERYTHING_SEARCH_CAPTION : LOCALIZATION_ID_EVERYTHING_LOAD_EVERYTHING_SEARCH_CAPTION); - os_SetDlgItemText_localization_id(hwnd,IDC_SEARCH_EVERYTHING_RANDOM_CHECKBOX,LOCALIZATION_ID_RANDOMIZE); - - return TRUE; - - case WM_COMMAND: - - switch(LOWORD(wParam)) - { - case IDOK: - { - wchar_t search_wbuf[STRING_SIZE]; - - GetDlgItemText(hwnd,IDC_EVERYTHING_EDIT,search_wbuf,STRING_SIZE); - - if (_viv_send_everything_search(hwnd,GetWindowLongPtr(hwnd,GWLP_USERDATA),IsDlgButtonChecked(hwnd,IDC_SEARCH_EVERYTHING_RANDOM_CHECKBOX) == BST_CHECKED,search_wbuf)) - { - EndDialog(hwnd,0); - } - - break; - } - - case IDCANCEL: - EndDialog(hwnd,0); - break; - } - - break; + ShowWindow(_viv_hwnd,SW_MAXIMIZE); } - return FALSE; -} - -static void _viv_search_everything(int add) -{ - DialogBoxParam(os_hinstance,MAKEINTRESOURCE(IDD_EVERYTHING),_viv_hwnd,_viv_search_everything_proc,add); -} - -static int _viv_send_everything_search(HWND hwnd,int add,int randomize,const wchar_t *search) -{ - if (randomize) - { - // add is ignored in this case. - _viv_random = string_alloc(search); - - _viv_random_tot_results = 0xffffffff; - - _viv_playlist_clearall(); + _viv_process_command_line(GetCommandLineW()); - { - LARGE_INTEGER counter; - - QueryPerformanceCounter(&counter); - - srand(counter.LowPart); - } - - _viv_home(0,0); - - return 1; - } - else + // if we didn't show the window above, make sure it + // is shown now. + if (si.wShowWindow == SW_SHOWNORMAL) { - HWND everything_hwnd; - - if (_viv_random) - { - mem_free(_viv_random); - - _viv_random = 0; - } - - everything_hwnd = FindWindowA(EVERYTHING_IPC_WNDCLASSA,0); - - if (everything_hwnd) - { - EVERYTHING_IPC_QUERY2 *q; - COPYDATASTRUCT cds; - DWORD size; - wchar_t new_search[STRING_SIZE]; - - string_copy_utf8_string(new_search,"ext:bmp;gif;ico;jpeg;jpg;png;tif;tiff;webp <"); - string_cat(new_search,search); - string_cat_utf8(new_search,">"); - - size = (DWORD)(sizeof(EVERYTHING_IPC_QUERY2) + (string_get_length(new_search) + 1) * sizeof(wchar_t)); - - _viv_everything_request_flags = EVERYTHING_IPC_QUERY2_REQUEST_FULL_PATH_AND_NAME; - - if (SendMessage(everything_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_IS_FILE_INFO_INDEXED,EVERYTHING_IPC_FILE_INFO_FILE_SIZE)) - { - _viv_everything_request_flags |= EVERYTHING_IPC_QUERY2_REQUEST_SIZE | EVERYTHING_IPC_QUERY2_REQUEST_DATE_MODIFIED; - } - - if (SendMessage(everything_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_IS_FILE_INFO_INDEXED,EVERYTHING_IPC_FILE_INFO_DATE_MODIFIED)) - { - _viv_everything_request_flags |= EVERYTHING_IPC_QUERY2_REQUEST_DATE_MODIFIED; - } - - if (SendMessage(everything_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_IS_FILE_INFO_INDEXED,EVERYTHING_IPC_FILE_INFO_DATE_CREATED)) - { - _viv_everything_request_flags |= EVERYTHING_IPC_QUERY2_REQUEST_DATE_CREATED; - } - - q = mem_alloc(size); - - q->reply_hwnd = (DWORD)_viv_hwnd; - q->reply_copydata_message = add ? _VIV_COPYDATA_ADD_EVERYTHING_SEARCH : _VIV_COPYDATA_OPEN_EVERYTHING_SEARCH; - q->search_flags = 0; - q->offset = 0; - q->max_results = EVERYTHING_IPC_ALLRESULTS; - q->request_flags = _viv_everything_request_flags; - - q->sort_type = EVERYTHING_IPC_SORT_NAME_ASCENDING; - os_copy_memory(q+1,new_search,(string_get_length(new_search) + 1) * sizeof(wchar_t)); - - cds.dwData = EVERYTHING_IPC_COPYDATA_QUERY2; - cds.cbData = size; - cds.lpData = q; - - SendMessage(everything_hwnd,WM_COPYDATA,(WPARAM)_viv_hwnd,(LPARAM)&cds); - - mem_free(q); - - return 1; - } - else - { - wchar_t *text_wbuf; - wchar_t caption_wbuf[STRING_SIZE]; - - text_wbuf = string_alloc_utf8(localization_get_string(LOCALIZATION_ID_EVERYTHING_NOT_AVAILABLE_MESSAGE)); - - string_copy_utf8_string(caption_wbuf,localization_get_string(LOCALIZATION_ID_APP_NAME)); - - // MB_ICONQUESTION avoids the messagebeep. - MessageBox(hwnd,text_wbuf,caption_wbuf,MB_OK|MB_ICONERROR); - - mem_free(text_wbuf); - - return 0; - } + ShowWindow(_viv_hwnd,SW_SHOW); + UpdateWindow(_viv_hwnd); } + + return 1; } -static void _viv_add_current_path_to_playlist(void) +void _viv_kill(void) { - WIN32_FIND_DATA fd; - HANDLE h; - wchar_t search_wbuf[STRING_SIZE]; - wchar_t path_wbuf[STRING_SIZE]; - - string_get_path_part(path_wbuf,_viv_current_fd->cFileName); - - string_copy(search_wbuf,path_wbuf); - string_cat_utf8(search_wbuf,(const utf8_t *)"\\*.*"); + _viv_show_cursor(); - h = FindFirstFile(search_wbuf,&fd); - if (h != INVALID_HANDLE_VALUE) + // don't load another image.. + if (_viv_load_image_next_fd) { - for(;;) - { - if (_viv_is_valid_filename(&fd)) - { - _viv_playlist_t *d; - - string_path_combine(search_wbuf,path_wbuf,fd.cFileName); - string_copy(fd.cFileName,search_wbuf); - - d = _viv_playlist_add(&fd); - - if (string_compare(fd.cFileName,_viv_current_fd->cFileName) == 0) - { - // copy back the FD ID. - // so when we get the next image we get the next image from the current image instead of the home image. - _viv_current_fd->dwReserved0 = d->fd.dwReserved0; - _viv_current_fd->dwReserved1 = d->fd.dwReserved1; - } - } - - if (!FindNextFile(h,&fd)) break; - } - - FindClose(h); + mem_free(_viv_load_image_next_fd); + + _viv_load_image_next_fd = 0; } -} - -static int _viv_playlist_shuffle_index_from_fd(const WIN32_FIND_DATA *fd) -{ - int index; - - if (_viv_playlist_shuffle_indexes) + + // stop load_image immediately... + if (_viv_load_image_thread) { - for(index=0;index < _viv_playlist_count;index++) - { - if (_viv_playlist_shuffle_indexes[index]->fd.dwReserved0 == fd->dwReserved0) - { - if (_viv_playlist_shuffle_indexes[index]->fd.dwReserved1 == fd->dwReserved1) - { - return index; - } - } + _viv_load_image_terminate = 1; + + // it's critical we wait for load image to finish before we kill the main window. + // the wait is bounded: a decoder wedged mid-decode must not make exit + // impossible. (the terminate flag is checked between decode steps, so + // the timeout below only fires on a truly stuck decoder.) + if (WaitForSingleObject(_viv_load_image_thread,10000) != WAIT_OBJECT_0) + { + // stop the thread where it stands. it is no longer safe for the + // rest of the teardown to share memory with it. the process is + // exiting: anything the thread leaked is reclaimed by the OS. + TerminateThread(_viv_load_image_thread,1); + + WaitForSingleObject(_viv_load_image_thread,1000); } + + CloseHandle(_viv_load_image_thread); } - return -1; -} - -static _viv_playlist_t *_viv_playlist_from_fd(const WIN32_FIND_DATA *fd) -{ - _viv_playlist_t *d; + if (_viv_load_image_filename) + { + mem_free(_viv_load_image_filename); + } - d = _viv_playlist_start; - while(d) + if (_viv_last_frames) { - if (d->fd.dwReserved0 == fd->dwReserved0) - { - if (d->fd.dwReserved1 == fd->dwReserved1) - { - return d; - } - } + _viv_clear_frames(_viv_last_frames,_viv_last_frame_count); - d = d->next; + _viv_last_frames = NULL; } - return 0; -} + _viv_clear_preload_frames(); + _viv_clear(); + _viv_process_pending_clear(); -static void _viv_do_initial_shuffle(void) -{ - // if we don't have a playlist, but we have a current image, add the current path to the playlist and shuffle it. - if (config_shuffle) + if (_viv_hwnd) { - if ((!_viv_playlist_start) && (*_viv_current_fd->cFileName)) - { - _viv_add_current_path_to_playlist(); - - // shuffle_playlist - _viv_shuffle_playlist(); - } - else - if ((_viv_playlist_start) && (!_viv_playlist_shuffle_indexes)) - { - // shuffle_playlist - _viv_shuffle_playlist(); - } - } -} - -static void _viv_update_1to1_scroll(int x,int y) -{ - int cursor_x; - int cursor_y; - int rx; - int ry; - int rw; - int rh; - int old_rw; - int old_rh; - int old_cursor_px; - int old_cursor_py; - int wide; - int high; - RECT rect; - POINT pt; - __int64 new_cursor_x; - __int64 new_cursor_y; - int zoom_backup; - int backup_1to1; - - GetClientRect(_viv_hwnd,&rect); + _viv_status_show(0); + _viv_controls_show(0); + // _viv_tooltip_hide(); - wide = rect.right - rect.left; - high = rect.bottom - rect.top - _viv_get_status_high() - _viv_get_controls_high(); - - pt.x = x ; - pt.y = y; - - cursor_x = pt.x; - cursor_y = pt.y; - - zoom_backup = _viv_zoom_pos; - backup_1to1 = _viv_1to1; - _viv_zoom_pos = 0; - _viv_1to1 = 0; - _viv_doing = _VIV_DOING_NOTHING; - _viv_get_render_size(&old_rw,&old_rh); - _viv_doing = _VIV_DOING_1TO1SCROLL; - _viv_zoom_pos = zoom_backup; - _viv_1to1 = backup_1to1; - - rx = (wide / 2) - (old_rw / 2); - ry = (high / 2) - (old_rh / 2); + DestroyWindow(_viv_hwnd); + } - old_cursor_px = (cursor_x - rx); - old_cursor_py = (cursor_y - ry); - - _viv_get_render_size(&rw,&rh); - - if (old_rw) + if (_viv_status_temp_text) { - new_cursor_x = ((__int64)old_cursor_px * (__int64)rw) / (__int64)old_rw; + mem_free(_viv_status_temp_text); } - else + + _viv_nav_item_free_all(); + + if (_viv_random) { - new_cursor_x = 0; + mem_free(_viv_random); } - if (old_rh) + if (_viv_hmenu) { - new_cursor_y = ((__int64)old_cursor_py * (__int64)rh) / (__int64)old_rh; + DestroyMenu(_viv_hmenu); } - else + + if (_viv_about_hfont) { - new_cursor_y = 0; + DeleteObject(_viv_about_hfont); } - _viv_view_set((wide / 2) - (rw / 2) - cursor_x + new_cursor_x,(high / 2) - (rh / 2) - cursor_y + new_cursor_y,1); + if (_viv_mutex) + { + CloseHandle(_viv_mutex); + } - InvalidateRect(_viv_hwnd,0,FALSE); -} + _viv_playlist_clearall(); + _viv_reply_clear_all(); -// #define PHOTO_ORIENTATION_NORMAL 1u -// #define PHOTO_ORIENTATION_FLIPHORIZONTAL 2u -// #define PHOTO_ORIENTATION_ROTATE180 3u -// #define PHOTO_ORIENTATION_FLIPVERTICAL 4u -// #define PHOTO_ORIENTATION_TRANSPOSE 5u -// #define PHOTO_ORIENTATION_ROTATE270 6u -// #define PHOTO_ORIENTATION_TRANSVERSE 7u -// #define PHOTO_ORIENTATION_ROTATE90 8u -static HBITMAP _viv_orientate_hbitmap(HBITMAP hbitmap,int orientation) -{ - BITMAP bitmap; - HBITMAP ret_hbitmap; - - ret_hbitmap = 0; - - if (GetObject(hbitmap,sizeof(BITMAP),&bitmap)) + if (os_GdiplusShutdown) { - HDC screen_hdc; - - screen_hdc = GetDC(0); - if (screen_hdc) - { - HDC mem_hdc; - - mem_hdc = CreateCompatibleDC(screen_hdc); - if (mem_hdc) - { - int ret_wide; - int ret_high; - - ret_wide = bitmap.bmWidth; - ret_high = bitmap.bmHeight; - - switch(orientation) - { - case 5: // #define PHOTO_ORIENTATION_TRANSPOSE 5u - case 6: // #define PHOTO_ORIENTATION_ROTATE270 6u - case 7: // #define PHOTO_ORIENTATION_TRANSVERSE 7u - case 8: // #define PHOTO_ORIENTATION_ROTATE90 8u - - ret_wide = bitmap.bmHeight; - ret_high = bitmap.bmWidth; - - break; - } - - ret_hbitmap = CreateCompatibleBitmap(screen_hdc,ret_wide,ret_high); - if (ret_hbitmap) - { - int ret; - DWORD *old_pixels; - DWORD *new_pixels; - BITMAPINFOHEADER bi; - - ret = 0; - - os_zero_memory(&bi,sizeof(BITMAPINFOHEADER)); - bi.biSize = sizeof(BITMAPINFOHEADER); - bi.biWidth = bitmap.bmWidth; - bi.biHeight = -bitmap.bmHeight; - bi.biPlanes = 1; - bi.biBitCount = 32; - bi.biCompression = BI_RGB; - - old_pixels = mem_alloc(bitmap.bmWidth * bitmap.bmHeight * sizeof(DWORD)); - new_pixels = mem_alloc(ret_wide * ret_high * sizeof(DWORD)); - - if (GetDIBits(mem_hdc,hbitmap,0,bitmap.bmHeight,old_pixels,(BITMAPINFO *)&bi,DIB_RGB_COLORS)) - { - int y; - - switch(orientation) - { - case 2: // #define PHOTO_ORIENTATION_FLIPHORIZONTAL 2u - - for(y=0;y"); - - size = (DWORD)(sizeof(EVERYTHING_IPC_QUERY2) + (string_get_length(new_search) + 1) * sizeof(wchar_t)); - - _viv_everything_request_flags = EVERYTHING_IPC_QUERY2_REQUEST_FULL_PATH_AND_NAME; - - if (SendMessage(everything_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_IS_FILE_INFO_INDEXED,EVERYTHING_IPC_FILE_INFO_FILE_SIZE)) - { - _viv_everything_request_flags |= EVERYTHING_IPC_QUERY2_REQUEST_SIZE | EVERYTHING_IPC_QUERY2_REQUEST_DATE_MODIFIED; - } - - if (SendMessage(everything_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_IS_FILE_INFO_INDEXED,EVERYTHING_IPC_FILE_INFO_DATE_MODIFIED)) - { - _viv_everything_request_flags |= EVERYTHING_IPC_QUERY2_REQUEST_DATE_MODIFIED; - } - - if (SendMessage(everything_hwnd,EVERYTHING_WM_IPC,EVERYTHING_IPC_IS_FILE_INFO_INDEXED,EVERYTHING_IPC_FILE_INFO_DATE_CREATED)) - { - _viv_everything_request_flags |= EVERYTHING_IPC_QUERY2_REQUEST_DATE_CREATED; - } + DeleteObject(_viv_background_hbrush); - q = mem_alloc(size); - - q->reply_hwnd = (DWORD)_viv_hwnd; - q->reply_copydata_message = _VIV_COPYDATA_RANDOM_EVERYTHING_SEARCH; - q->search_flags = 0; - q->offset = ((rand() * RAND_MAX) + rand()) % _viv_random_tot_results; - q->max_results = 1; - q->request_flags = _viv_everything_request_flags; - - debug_printf("rand index %d\n",q->offset); - - q->sort_type = EVERYTHING_IPC_SORT_NAME_ASCENDING; - os_copy_memory(q+1,new_search,(string_get_length(new_search) + 1) * sizeof(wchar_t)); - - cds.dwData = EVERYTHING_IPC_COPYDATA_QUERY2; - cds.cbData = size; - cds.lpData = q; - - SendMessage(everything_hwnd,WM_COPYDATA,(WPARAM)_viv_hwnd,(LPARAM)&cds); - - mem_free(q); + _viv_background_hbrush = 0; } -} - -// x,y in screen coords -static void _viv_do_mousewheel_action(int action,int delta,int x,int y) -{ - if (action == 0) + + if (_viv_dialog_dark_hbrush) { - int cursor_x; - int cursor_y; - int rx; - int ry; - int rw; - int rh; - int old_rw; - int old_rh; - int old_cursor_px; - int old_cursor_py; - int wide; - int high; - RECT rect; - POINT pt; - __int64 new_cursor_x; - __int64 new_cursor_y; - int old_zoom_pos; - - old_zoom_pos = _viv_zoom_pos; - - GetClientRect(_viv_hwnd,&rect); - wide = rect.right - rect.left; - high = rect.bottom - rect.top - _viv_get_status_high() - _viv_get_controls_high(); + DeleteObject(_viv_dialog_dark_hbrush); - pt.x = x; - pt.y = y; - - ScreenToClient(_viv_hwnd,&pt); - - cursor_x = pt.x; - cursor_y = pt.y; + _viv_dialog_dark_hbrush = 0; + } - _viv_get_render_size(&rw,&rh); + { + int i; -/* - if (_viv_zoom_pos == 1) + for(i=0;i<2;i++) { - if ((rw < _viv_image_wide) || (rw < _viv_image_wide)) + if (_viv_about_light_hbrushes[i]) { - rw = _viv_image_wide; - rh = _viv_image_high; + DeleteObject(_viv_about_light_hbrushes[i]); + + _viv_about_light_hbrushes[i] = 0; } } - */ - rx = (wide / 2) - (rw / 2) - _viv_view_x; - ry = (high / 2) - (rh / 2) - _viv_view_y; - - old_cursor_px = (cursor_x - rx); - old_cursor_py = (cursor_y - ry); - old_rw = rw; - old_rh = rh; -/* - if (old_cursor_px < 0) - { - old_cursor_px = 0; - } - - if (old_cursor_px > 20 * rw) - { - old_cursor_px = 20 * rw; - } - if (old_cursor_py < 0) - { - old_cursor_py = 0; - } - - if (old_cursor_py > 20 * rh) - { - old_cursor_py = 20 * rh; - } - */ - if (_viv_1to1) - { - _viv_1to1 = 0; - - if (delta > 0) - { - for(_viv_zoom_pos = 0;_viv_zoom_pos<_VIV_ZOOM_MAX;_viv_zoom_pos++) - { - _viv_get_render_size(&rw,&rh); - - if (rw > old_rw) - { - break; - } - } - } - else - { - for(_viv_zoom_pos = _VIV_ZOOM_MAX-1;_viv_zoom_pos>=0;_viv_zoom_pos--) - { - _viv_get_render_size(&rw,&rh); - - if (rw < old_rw) - { - break; - } - } - } - } - else +for(i=0;i<4;i++) { - if (delta > 0) - { - _viv_zoom_pos++; - } - else + if (_viv_dark_chrome_hbrushes[i]) { - _viv_zoom_pos--; + DeleteObject(_viv_dark_chrome_hbrushes[i]); + + _viv_dark_chrome_hbrushes[i] = 0; } } + } + + if (_viv_backdrop_solid_hbrush) + { + DeleteObject(_viv_backdrop_solid_hbrush); + + _viv_backdrop_solid_hbrush = 0; + _viv_backdrop_solid_color = 0; + } + + if (_viv_backdrop_checker_hbrush) + { + DeleteObject(_viv_backdrop_checker_hbrush); - if (_viv_zoom_pos < 0) _viv_zoom_pos = 0; - if (_viv_zoom_pos > _VIV_ZOOM_MAX-1) _viv_zoom_pos = _VIV_ZOOM_MAX-1; + _viv_backdrop_checker_hbrush = 0; + } + + if (_viv_backdrop_checker_hbitmap) + { + DeleteObject(_viv_backdrop_checker_hbitmap); - if (_viv_zoom_pos != old_zoom_pos) + _viv_backdrop_checker_hbitmap = 0; + _viv_backdrop_checker_cell = 0; + } + + _viv_paint_kill(); + + _viv_key_clear_all(_viv_key_list); + mem_free(_viv_key_list); + + // the remake domains: the settings window dies with the owner, the + // menubar drops its cached hover and press brushes. + _viv_settings_kill(); + _viv_menubar_kill(); + + zoomui_kill(); + + os_kill(); + +#ifdef _DEBUG + mem_debug(); +#endif +} + +static int _viv_main(int nCmdShow) +{ + if (_viv_init(nCmdShow)) + { +#ifdef VIVP_SELF_SHOT + vivp_selfshot_init(); +#endif + for(;;) { - _viv_get_render_size(&rw,&rh); - /* - if (_viv_zoom_pos == 1) + // Main message loop: + for(;;) { - if ((rw < _viv_image_wide) || (rw < _viv_image_wide)) + MSG msg; + + if (!PeekMessage(&msg,0,0,0,PM_REMOVE)) break; + +// debug_printf("MSG %u %u %u\n",msg.message,msg.wParam,msg.lParam); + + if (msg.message == WM_QUIT) goto exit; + + if (!_viv_is_msg(&msg)) { - rw = _viv_image_wide; - rh = _viv_image_high; + TranslateMessage(&msg); + DispatchMessage(&msg); } } - */ - // - // new_cursor_x = - // rx = (wide / 2) - (rw / 2) - - //debug_printf("%d %d\n",(wide / 2) - (rw / 2),(high / 2) - (rh / 2)); - //debug_printf("%d %d\n",old_cursor_px,(old_cursor_px * 100) / old_rw); - - //debug_printf("old %d %d new %d %d\n",old_cursor_px,old_cursor_py,(wide / 2) - (rw / 2) - cursor_x + ((old_cursor_px * rw) / old_rw),(high / 2) - (rh / 2) - cursor_y + ((old_cursor_py * rh) / old_rh)) ; - //debug_printf("wide / 2 = %d, rw/2=%d, old_cursor_px * rw=%d\n",wide/2,rw/2,old_cursor_px * rw) ; - - if (old_rw) - { - new_cursor_x = ((__int64)old_cursor_px * (__int64)rw) / (__int64)old_rw; - } - else - { - new_cursor_x = 0; - } - - if (old_rh) - { - new_cursor_y = ((__int64)old_cursor_py * (__int64)rh) / (__int64)old_rh; - } - else - { - new_cursor_y = 0; - } - - _viv_view_set((wide / 2) - (rw / 2) - cursor_x + new_cursor_x,(high / 2) - (rh / 2) - cursor_y + new_cursor_y,1); - InvalidateRect(_viv_hwnd,0,FALSE); - } - } - else - if (action == 1) - { - if (delta > 0) - { - _viv_next(1,1,0,0); - } - else - if (delta < 0) - { - _viv_next(0,1,0,0); - } - } - else - if (action == 2) - { - if (delta > 0) - { - _viv_next(0,1,0,0); - } - else - if (delta < 0) - { - _viv_next(1,1,0,0); + WaitMessage(); } + + exit: + + _viv_kill(); } -} -void viv_key_add(int command_index,DWORD keyflags) -{ - _viv_key_add(_viv_key_list,command_index,keyflags); + return 0; } -void viv_key_clear_all(int command_index) +int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd) { - _viv_key_clear(_viv_key_list,command_index); + return _viv_main(nShowCmd); } -config_key_t *viv_key_get_start(int command_index) +int __cdecl main(int argc,char **argv) { - return _viv_key_list->start[command_index]; + return _viv_main(SW_SHOW); } -int viv_get_command_count(void) -{ - return _VIV_COMMAND_COUNT; -} -static HBITMAP _viv_get_mipmap(HBITMAP hbitmap,int image_wide,int image_high,int render_wide,int render_high,int *pmip_wide,int *pmip_high,_viv_mipmap_t **out_mip) + + + + + + +static int _viv_is_msg(MSG *msg) { - int mip_wide; - int mip_high; - _viv_mipmap_t **pmip; - int depth; - HBITMAP best_hbitmap; - int best_wide; - int best_high; - -// debug_printf("GETMIP %d x %d => %d x %d\n",image_wide,image_high,render_wide,render_high); - - mip_wide = (image_wide + 1) / 2; - mip_high = (image_high + 1) / 2; - - if (mip_wide < 1) - { - mip_wide = 1; - } - - if (mip_high < 1) - { - mip_high = 1; - } - - if ((mip_wide == 1) && (mip_high == 1)) + switch (msg->message) { - *pmip_wide = image_wide; - *pmip_high = image_high; + case WM_XBUTTONDOWN: + case WM_XBUTTONDBLCLK: + case WM_NCXBUTTONDOWN: + case WM_NCXBUTTONDBLCLK: -// debug_printf("MIP %d: %d %d\n",1,image_wide,image_high); + switch(config_xbutton_action) + { + case 1: + + switch(HIWORD(msg->wParam)) + { + case XBUTTON1: + _viv_zoom_in(1,1,GET_X_LPARAM(msg->lParam),GET_Y_LPARAM(msg->lParam)); + break; - return hbitmap; - } - - if ((render_wide >= mip_wide) || (render_high >= mip_wide)) - { -// debug_printf("MIP 0: %d %d\n",mip_wide,mip_high); - *pmip_wide = image_wide; - *pmip_high = image_high; + case XBUTTON2: + _viv_zoom_in(0,1,GET_X_LPARAM(msg->lParam),GET_Y_LPARAM(msg->lParam)); + break; + } + + break; -// debug_printf("MIP %d: %d %d\n",1,image_wide,image_high); + case 2: + + switch(HIWORD(msg->wParam)) + { + case XBUTTON1: + _viv_next(1,1,0,0); + break; - return hbitmap; - } - - best_hbitmap = hbitmap; - best_wide = image_wide; - best_high = image_high; - - pmip = out_mip; - - depth = 1; - - for(;;) - { - if (!*pmip) - { - HDC screen_hdc; - HDC mem_hdc; - HDC mem2_hdc; - HGDIOBJ last_hbitmap; - HGDIOBJ last2_hbitmap; - int last_stretch_mode; - - debug_printf("GETMIPMAP %d: %d %d\n",depth,mip_wide,mip_high); + case XBUTTON2: + _viv_next(0,1,0,0); + break; + } + + break; + + } - // create mipmap.. - *pmip = mem_alloc(sizeof(_viv_mipmap_t)); + break; + + case WM_SYSKEYDOWN: + case WM_KEYDOWN: - screen_hdc = GetDC(0); - if (screen_hdc) { - mem_hdc = CreateCompatibleDC(screen_hdc); - if (mem_hdc) + int key_flags; + + key_flags = _viv_get_current_key_mod_flags(); + + if (msg->hwnd == _viv_hwnd) { - mem2_hdc = CreateCompatibleDC(screen_hdc); - if (mem2_hdc) + int key_index; + + // key presses are overlay activity (idle fade timer). + zoomui_activity(); + +/* + if (msg->wParam == VK_MENU) { - (*pmip)->mipmap = NULL; - (*pmip)->hbitmap = CreateCompatibleBitmap(screen_hdc,mip_wide,mip_high); - - last_hbitmap = SelectObject(mem_hdc,(*pmip)->hbitmap); - last2_hbitmap = SelectObject(mem2_hdc,best_hbitmap); - - last_stretch_mode = SetStretchBltMode(mem_hdc,HALFTONE); + _viv_is_alt = 1; + _viv_update_show_cursor(); + _viv_update_src_pixel(0,1); + } +*/ + // cancel action + if ((key_flags == 0) && (msg->wParam == VK_ESCAPE)) + { + if (_viv_doing) + { + _viv_doing_cancel(); - // for crazy large images -https://github.com/voidtools/voidImageViewer/issues/45 - // use stitching, since we are using HALFTONE here, we will end up with sharp tile edges - // but's its better than showing a black image. - if (_viv_StretchBltStitch(mem_hdc,0,0,mip_wide,mip_high,mem2_hdc,0,0,best_wide,best_high,SRCCOPY,0,0,mip_wide,mip_high)) + return 1; + } + + if (_viv_is_fullscreen) { - // OK + _viv_toggle_fullscreen(); + + // also pause slideshow + if (_viv_is_slideshow) + { + _viv_pause(); + } + + return 1; } - else + } + + // find the key. + for(key_index=0;key_index<_VIV_COMMAND_COUNT;key_index++) + { + config_key_t *k; + + k = _viv_key_list->start[key_index]; + while(k) { - debug_printf("get_mipmap %d %d failed %u\n",mip_wide,mip_high,GetLastError()); + if ((k->key & CONFIG_KEYFLAG_MOD_MASK) == key_flags) + { + if ((k->key & CONFIG_KEYFLAG_VK_MASK) == msg->wParam) + { + _viv_command_with_is_key_repeat(_viv_commands[key_index].command_id,(msg->lParam & 0x40000000) ? 1 : 0); + + return 1; + } + } + + k = k->next; } + } + } + } + + break; + +/* + case WM_KEYUP: + case WM_SYSKEYUP: + + if (msg->wParam == VK_MENU) + { + _viv_is_alt = 0; + _viv_update_show_cursor(); + _viv_update_src_pixel(0,1); + } + break; + */ + } + + return 0; +} + + + + + + + + + + + + + + +// the dialog font: the system message font at the dialog window own +// dpi, one handle per dialog (the template face only sized the dlu +// grid at creation; the message font is the family the menu bar and +// the status bar draw, so the locale text renders with real glyphs +// instead of the fallback the hard coded segoe ui forced). the handle +// belongs to the dialog that adopted it: the options container and +// its create dialog pages coexist and jumpto is a create dialog too, +// so no broadcast (a settings change, a theme flip) may delete a +// face some open dialog is still drawing with - the font dies with +// the dialog, at the ncdestroy after its children are gone, and a +// re-apply replaces the old face only inside the same message. + + + + + + + + + + + +// the backdrop shown under transparent pixels. + + + + + +// dark dialog support: the common dialogs (options and its pages, about, +// rename, edit key, custom rate and the everything search) get the dark +// chrome when the dark ui is active. the app mode is already dark app wide +// (the comctl controls draw dark), so what is missing is the dialog title +// bar, the control visual style, the control color replies and the +// background fill. + + + +// the property that marks the controls this module flipped to owner +// drawn (the flip is undone when the ui goes back to light). + + + + + + + + +// the property that caches the button theme handle on a dark dialog: +// uxtheme handles are not free, and the notify path used to pay an open +// and a close pair on every single paint. the handle opens lazily on the +// first dark paint (a dialog born in the light ui opens it when the theme +// flips), rides in the window data, and closes when the dialog goes away +// or the visual style changes. + + + + + + + + + + + + + + + - SetStretchBltMode(mem_hdc,last_stretch_mode); - - SelectObject(mem_hdc,last_hbitmap); - SelectObject(mem2_hdc,last2_hbitmap); - DeleteDC(mem2_hdc); - } - - DeleteDC(mem_hdc); - } - - ReleaseDC(0,screen_hdc); - } - } - best_wide = mip_wide; - best_high = mip_high; - best_hbitmap = (*pmip)->hbitmap; - - mip_wide = (image_wide + 1) / (2<= 'A') && (ca <= 'Z')) { - mip_high = 1; + ca = ca + 'a' - 'A'; } - if ((mip_wide == 1) && (mip_high == 1)) + if ((cb >= 'A') && (cb <= 'Z')) { - *pmip_wide = best_wide; - *pmip_high = best_high; - -// debug_printf("MIP %d: %d %d\n",depth,best_wide,best_high); - - return best_hbitmap; + cb = cb + 'a' - 'A'; } - if ((render_wide >= mip_wide) || (render_high >= mip_wide)) + if (ca != cb) { - *pmip_wide = best_wide; - *pmip_high = best_high; - -// debug_printf("MIP %d: %d %d\n",depth,best_wide,best_high); - - return best_hbitmap; + return 1; } - pmip = &(*pmip)->mipmap; - depth++; + a++; + b++; } -} - -static void _viv_preload_next(void) -{ - if (config_preload_next) + + if (*a != *b) { - //UpdateWindow(_viv_hwnd); - - _viv_next(_viv_last_is_prev,0,1,0); + return 1; } + + return 0; } -static void _viv_start_first_frame(void) -{ - // draw first frame and start timer. - _viv_frame_position = 0; - _viv_frame_looped = 0; - _viv_animation_timer_tick_start = os_get_tick_count(); - _viv_timer_tick = 0; - - if (_viv_frame_count > 1) - { - _viv_timer_start(); - } - _viv_update_src_pixel(1,0); - _viv_status_update(); - - if (_viv_doing == _VIV_DOING_1TO1SCROLL) - { - POINT pt; - GetCursorPos(&pt); - ScreenToClient(_viv_hwnd,&pt); - - _viv_update_1to1_scroll(pt.x,pt.y); - } - // show cursor. - _viv_update_show_cursor(); -//debug_printf("---\n",_viv_load_image_next_fd); -//debug_printf("_viv_load_image_next_fd %p\n",_viv_load_image_next_fd); -//debug_printf("---\n",_viv_load_image_next_fd); -/* - if (_viv_load_image_next_fd) +CLIPFORMAT _viv_get_CF_PREFERREDDROPEFFECT(void) +{ + if (!_viv_CF_PREFERREDDROPEFFECT) { - // load priority paint.. - // we will paint on the 'next next' image we load.. - _viv_low_priority_paint = 1; - return; + _viv_CF_PREFERREDDROPEFFECT = RegisterClipboardFormat(CFSTR_PREFERREDDROPEFFECT); } - _viv_low_priority_paint = 0; - InvalidateRect(_viv_hwnd,NULL,FALSE); - - // building mipmaps as needed hangs the UI. - // this makes rendering lag while holding down right. - // avoid painting when user is holding down right.. - // - // because we build the mipmap for the first image in the load thread this is now instant.. - // ok it's still awful, let the next load refresh.. -// if (_viv_load_image_next_fd) - { -// UpdateWindow(_viv_hwnd); - }*/ - - if (!_viv_is_fullscreen) - { - if (config_auto_zoom) - { - switch(config_auto_zoom_type) - { - case 0: - case 1: - case 2: - case 3: - // don't scroll any regions when sizing. - InvalidateRect(_viv_hwnd,NULL,FALSE); - _viv_command(VIV_ID_VIEW_WINDOW_SIZE_50 + config_auto_zoom_type); - break; - } - } - } + return _viv_CF_PREFERREDDROPEFFECT; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - InvalidateRect(_viv_hwnd,NULL,FALSE); - UpdateWindow(_viv_hwnd); -} -// the preload has completed and we -// want to set it as the current image. -static void _viv_activate_preload(void) -{ -debug_printf("activate preload\n"); - _viv_clear(); - - _viv_frames = _viv_preload_frames; - _viv_preload_frames = NULL; - - _viv_frame_loaded_count = _viv_preload_frame_loaded_count; - _viv_preload_frame_loaded_count = 0; - - _viv_frame_count = _viv_preload_frame_count; - _viv_preload_frame_count = 0; - - _viv_image_wide = _viv_preload_image_wide; - _viv_preload_image_wide = 0; - - _viv_image_high = _viv_preload_image_high; - _viv_preload_image_high = 0; - _viv_start_first_frame(); - _viv_process_pending_clear(); - - os_copy_memory(_viv_frame_fd,_viv_preload_fd,sizeof(WIN32_FIND_DATA)); - _viv_clear_preload_frames(); - - *_viv_preload_fd->cFileName = 0; -} -// copy the current image to the last image. -static void viv_copy_current_image_to_last_image(void) -{ - if (_viv_last_frames) - { - _viv_clear_frames(_viv_last_frames,_viv_last_frame_count); - - _viv_last_frames = NULL; - _viv_last_frame_count = 0; - } -debug_printf("*** Cache LAST : %S\n",_viv_frame_fd->cFileName); - // only copy if the whole image was loaded. - // Otherwise we need to reload the whole image again.. - if (config_cache_last) - { - if (_viv_frame_count == _viv_frame_loaded_count) - { - os_copy_memory(_viv_last_fd,_viv_frame_fd,sizeof(WIN32_FIND_DATA)); - - _viv_last_image_wide = _viv_image_wide; // last image width - _viv_last_image_high = _viv_image_high ; // last image width - _viv_last_frame_count = _viv_frame_count; // last image frame count, 1 for static image, > 1 for animation (all frames are loaded) - _viv_last_frames = _viv_frames; - - _viv_image_wide = 0; - _viv_image_high = 0; - _viv_frame_count = 0; - _viv_frames = NULL; - _viv_frame_fd->cFileName[0] = 0; - } - } -} -static void _viv_activate_last(void) -{ - WIN32_FIND_DATA old_fd; - int old_image_wide; - int old_image_high; - int old_frame_count; - _viv_frame_t *old_frames; - -debug_printf("activate last\n"); - old_frames = NULL; - // save current image so we can store it in last image later. - // we can't do it now because we are setting the last image to the current image. - if (config_cache_last) - { - if (_viv_frame_count == _viv_frame_loaded_count) - { -debug_printf("*** Cache LAST2 : %S\n",_viv_frame_fd->cFileName); - - os_copy_memory(&old_fd,_viv_frame_fd,sizeof(WIN32_FIND_DATA)); - - old_image_wide = _viv_image_wide; // last image width - old_image_high = _viv_image_high ; // last image width - old_frame_count = _viv_frame_count; // last image frame count, 1 for static image, > 1 for animation (all frames are loaded) - old_frames = _viv_frames; - - _viv_image_wide = 0; - _viv_image_high = 0; - _viv_frame_count = 0; - _viv_frames = NULL; - _viv_frame_fd->cFileName[0] = 0; - } - } - - os_copy_memory(_viv_current_fd,_viv_last_fd,sizeof(WIN32_FIND_DATA)); - - _viv_update_title(); - _viv_status_update(); - - _viv_clear(); - - _viv_frames = _viv_last_frames; - os_copy_memory(_viv_frame_fd,_viv_last_fd,sizeof(WIN32_FIND_DATA)); - _viv_last_frames = NULL; - - _viv_frame_loaded_count = _viv_last_frame_count; - _viv_frame_count = _viv_last_frame_count; - _viv_last_frame_count = 0; - - _viv_image_wide = _viv_last_image_wide; - _viv_last_image_wide = 0; - - _viv_image_high = _viv_last_image_high; - _viv_last_image_high = 0; - _viv_start_first_frame(); - _viv_process_pending_clear(); - - if (old_frames) - { - os_copy_memory(_viv_last_fd,&old_fd,sizeof(WIN32_FIND_DATA)); - - _viv_last_image_wide = old_image_wide; - _viv_last_image_high = old_image_high; - _viv_last_frame_count = old_frame_count; - _viv_last_frames = old_frames; - } -} -static void _viv_clear_last(void) -{ - if (_viv_last_frames) - { - _viv_clear_frames(_viv_last_frames,_viv_last_frame_count); - - _viv_last_frames = NULL; - _viv_last_frame_count = 0; - } -} -static void _viv_refresh(void) -{ - WIN32_FIND_DATA fd; - - os_copy_memory(&fd,_viv_current_fd,sizeof(WIN32_FIND_DATA)); - // clear last cache - _viv_clear_last(); - // clear preload. - _viv_clear_loading_preload(); - _viv_clear_preload(); - _viv_clear(); - _viv_start_first_frame(); - _viv_process_pending_clear(); - _viv_open(&fd,0); -} -static void _viv_show_cursor(void) -{ - if (_viv_is_hide_cursor_timer) - { - KillTimer(_viv_hwnd,VIV_ID_HIDE_CURSOR_TIMER); - - _viv_is_hide_cursor_timer = 0; - } - if (!_viv_is_cursor_shown) - { - ShowCursor(TRUE); - - _viv_is_cursor_shown = 1; - } -} -static void _viv_hide_cursor(void) -{ - if (_viv_is_hide_cursor_timer) - { - KillTimer(_viv_hwnd,VIV_ID_HIDE_CURSOR_TIMER); - - _viv_is_hide_cursor_timer = 0; - } - if (_viv_is_cursor_shown) - { - ShowCursor(FALSE); - - _viv_is_cursor_shown = 0; - } -} -static int _viv_should_show_cursor(void) -{ - if (!_viv_in_popup_menu) - { - if ((*_viv_current_fd->cFileName) && (!_viv_file_not_found) && (!_viv_load_failed)) - { - if (GetForegroundWindow() == _viv_hwnd) - { - if (_viv_is_mouseover) - { - if (!GetCapture()) - { - if ((_viv_is_fullscreen) || (config_windowed_hide_cursor)) - { - // if (!((_viv_is_alt) && (_viv_is_tracking_mouse))) - { - return 0; - } - } - } - } - } - } - } - - return 1; -} -static void _viv_update_show_cursor(void) -{ - if (_viv_should_show_cursor()) - { - _viv_show_cursor(); - } - else - { - _viv_start_hide_cursor_timer(); - } -} -static void _viv_start_hide_cursor_timer(void) -{ - if (!_viv_is_hide_cursor_timer) - { - SetTimer(_viv_hwnd,VIV_ID_HIDE_CURSOR_TIMER,_VIV_HIDE_CURSOR_DELAY,0); - - _viv_is_hide_cursor_timer = 1; - } -} -static void _viv_get_exe_filename(wchar_t filename[STRING_SIZE]) -{ - filename[0] = 0; - - GetModuleFileName(0,filename,STRING_SIZE); - - // make sure the drive letter is uppercase. - // launching from .png == d: - // launching from .exe == D: - if ((*filename >= 'a') && (*filename <= 'z')) - { - if (filename[1] == ':') - { - *filename = *filename - 'a' + 'A'; - } - } -} -// 0 = scroll, 1 = play/pause slideshow, 2 = play/pause animation, 3=zoom in, 4=next, 5=1:1 scroll, 6=move-window -static void _viv_do_left_click_action(int action) -{ - POINT cursor_pt; - - GetCursorPos(&cursor_pt); - - ScreenToClient(_viv_hwnd,&cursor_pt); - switch(action) - { - case 0: // scroll - - if (_viv_doing == _VIV_DOING_NOTHING) - { - - - if (!_viv_is_fullscreen) - { - if (!config_show_caption) - { - _viv_start_move_window(); - - return; - } - } - - _viv_doing = _VIV_DOING_SCROLL; - _viv_doing_x = cursor_pt.x; - _viv_doing_y = cursor_pt.y; - SetCapture(_viv_hwnd); - } - break; - case 1: // play/pause slideshow - _viv_pause(); - break; - case 2: // play/pause animation - _viv_animation_pause(); - break; - case 3: // zoom in - _viv_zoom_in(0,1,cursor_pt.x,cursor_pt.y); - break; - case 4: // next - _viv_next(0,1,0,0); - break; - - case 5: // 1:1 scroll - - if (_viv_doing == _VIV_DOING_NOTHING) - { - if (!_viv_is_fullscreen) - { - if (!config_show_caption) - { - _viv_start_move_window(); - - return; - } - } - - _viv_doing = _VIV_DOING_1TO1SCROLL; - // really need to see where the cursor is.. -// ShowCursor(FALSE); - SetCapture(_viv_hwnd); - - _viv_update_1to1_scroll(cursor_pt.x,cursor_pt.y); - } - - break; - case 6: // move-window - - { - RECT rect; - int wide; - int high; - int rw; - int rh; - - GetClientRect(_viv_hwnd,&rect); - wide = rect.right - rect.left; - high = rect.bottom - rect.top - _viv_get_status_high() - _viv_get_controls_high(); - _viv_get_render_size(&rw,&rh); -//debug_printf("MOVEWINDOW %d %d\n",rw,wide); - - if ((rw > wide) || (rh > high)) - { - // scroll - _viv_do_left_click_action(0); - - return; - } - } - - if (_viv_doing == _VIV_DOING_NOTHING) - { - if (!_viv_is_fullscreen) - { - _viv_start_move_window(); - - return; - } - } - break; - } -} -static void _viv_start_move_window(void) -{ - POINT cursor_pt; - - GetCursorPos(&cursor_pt); - - SendMessage(_viv_hwnd,WM_NCLBUTTONDOWN,(WPARAM)HTCAPTION,MAKELPARAM(cursor_pt.x,cursor_pt.y)); -} -static int _viv_ceil(double x) -{ - int xi = (int)x; - - return (x > (double)xi) ? xi + 1 : xi; -} -static void _viv_center_listbox_item(HWND listbox_hwnd,int item_index) -{ - int item_high; - - item_high = ListBox_GetItemHeight(listbox_hwnd,item_index); - - if (item_high > 0) - { - RECT client_rect; - int visible_count; - - GetClientRect(listbox_hwnd,&client_rect); - visible_count = (client_rect.bottom - client_rect.top) / item_high; - - if (visible_count > 0) - { - int new_top; - int item_count; - - item_count = ListBox_GetCount(listbox_hwnd); - new_top = item_index - (visible_count / 2); - - if (new_top < 0) - { - new_top = 0; - } - if (new_top > item_count - visible_count) - { - new_top = item_count - visible_count; - } - - if (new_top < 0) - { - new_top = 0; - } - ListBox_SetTopIndex(listbox_hwnd,new_top); - } - } -} -// stretch a src-HDC with a selected bitmap to a distination-HDC. -// only stretch the specified clipping region (hopefully small from a scroll) -// this is way faster than StretchBlt as StretchBlt stretches the entire image, ignoring the clipping region. -static void _viv_stretch_blt(HDC dst_hdc,int dst_x,int dst_y,int dst_wide,int dst_high,HDC src_hdc,int src_wide,int src_high,int clip_x,int clip_y,int clip_wide,int clip_high) -{ - // clamp clip rectangle inside dst region - if (clip_x < dst_x) - { - clip_wide -= (dst_x - clip_x); - clip_x = dst_x; - } - - if (clip_y < dst_y) - { - clip_high -= (dst_y - clip_y); - clip_y = dst_y; - } - - if (clip_x + clip_wide > dst_x + dst_wide) - { - clip_wide = (dst_x + dst_wide) - clip_x; - } - - if (clip_y + clip_high > dst_y + dst_high) - { - clip_high = (dst_y + dst_high) - clip_y; - } - // something to do? - if ((dst_wide > 0) && (dst_high > 0) && (clip_wide > 0) && (clip_high > 0)) - { - int src_clip_x; - int src_clip_y; - int src_clip_wide; - int src_clip_high; - HDC dst_mem_hdc; - - src_clip_x = ((clip_x - dst_x) * (__int64)src_wide) / dst_wide; - src_clip_y = ((clip_y - dst_y) * (__int64)src_high) / dst_high; - src_clip_wide = (((clip_wide - 1 + clip_x - dst_x) * (__int64)src_wide) / dst_wide) + 1 - src_clip_x; - src_clip_high = (((clip_high - 1 + clip_y - dst_y) * (__int64)src_high) / dst_high) + 1 - src_clip_y; - - //debug_printf("%d %d %d %d - %d %d %d %d\n",src_clip_x,src_clip_y,src_clip_wide,src_clip_high,clip_x,clip_y,clip_wide,clip_high); - - dst_mem_hdc = CreateCompatibleDC(dst_hdc); - if (dst_mem_hdc) - { - HBITMAP dst_hbitmap; - dst_hbitmap = CreateCompatibleBitmap(dst_hdc,clip_wide,clip_high); - if (dst_hbitmap) - { - HGDIOBJ last_dst_hbitmap; - last_dst_hbitmap = SelectObject(dst_mem_hdc,dst_hbitmap); - - // debug_printf("STRETCH %d %d %d %d - %d %d clip %d %d\n",dst_x-clip_x,dst_y-clip_y,dst_wide,dst_high,src_wide,src_high,clip_wide,clip_high); -// StretchBlt(dst_hdc,dst_x,dst_y,dst_wide,dst_high,src_hdc,0,0,src_wide,src_high,SRCCOPY); - - SetStretchBltMode(dst_mem_hdc,GetStretchBltMode(dst_hdc)); - - if (_viv_StretchBltStitch(dst_mem_hdc,dst_x-clip_x,dst_y-clip_y,dst_wide,dst_high,src_hdc,0,0,src_wide,src_high,SRCCOPY,0,0,clip_wide,clip_high)) - { - } - else - { - debug_printf("StretchBlt %d %d %d %d %d %d failed %u",dst_x-clip_x,dst_y-clip_y,dst_wide,dst_high,src_wide,src_high,GetLastError()); - } - - if (BitBlt(dst_hdc,clip_x,clip_y,clip_wide,clip_high,dst_mem_hdc,0,0,SRCCOPY)) - { - - } - else - { - debug_printf("BitBlt %d %d %d %d failed %u",clip_x,clip_y,clip_wide,clip_high,GetLastError()); - } - SelectObject(dst_mem_hdc,last_dst_hbitmap); - - // Cleanup - DeleteObject(dst_hbitmap); - } - DeleteDC(dst_mem_hdc); - } - } -} -// stitch multiple 1024x1024 stretches together. -// required to render images over 32768x32768 -// only works if using COLORONCOLOR -static BOOL _viv_StretchBltStitch(HDC hdcDest,int xDest,int yDest,int wDest,int hDest,HDC hdcSrc,int xSrc,int ySrc,int wSrc,int hSrc,DWORD rop,int clip_x,int clip_y,int clip_wide,int clip_high) -{ -debug_printf("STRETCHBLT1024 %d %d %d %d SRC %d %d %d %d\n",xDest,yDest,wDest,hDest,xSrc,ySrc,wSrc,hSrc); - if ((wDest < 32768) && (hDest < 32768) && (wSrc < 32768) && (hSrc < 32768)) - { - return StretchBlt(hdcDest,xDest,yDest,wDest,hDest,hdcSrc,xSrc,ySrc,wSrc,hSrc,rop); - } - else - if ((wDest>0) && (hDest>0) && (wSrc>0) && (hSrc>0)) - { - int src_y; - int src_yrun; - int dst_y; - int clip_right; - int clip_bottom; - - dst_y = yDest; - src_y = ySrc; - src_yrun = hSrc; - clip_right = clip_x + clip_wide; - clip_bottom = clip_y + clip_high; - - while(src_yrun) - { - int src_high; - int dst_y2; - - if (dst_y >= clip_bottom) - { - break; - } - - src_high = src_yrun > _VIV_STRETCH_BLT_STITCH_SIZE ? _VIV_STRETCH_BLT_STITCH_SIZE : src_yrun; - dst_y2 = (((src_y + src_high) * (__int64)hDest) / hSrc) + yDest; - if (dst_y2 >= clip_y) - { - int src_x; - int src_xrun; - int dst_x; - int dst_high; - dst_x = xDest; - dst_high = dst_y2 - dst_y; - - src_x = xSrc; - src_xrun = wSrc; - - while(src_xrun) - { - int dst_x2; - int dst_wide; - int src_wide; - - src_wide = src_xrun > _VIV_STRETCH_BLT_STITCH_SIZE ? _VIV_STRETCH_BLT_STITCH_SIZE : src_xrun; - - dst_x2 = (((src_x + src_wide) * (__int64)wDest) / wSrc) + xDest; - - dst_wide = dst_x2 - dst_x; - - if (dst_x >= clip_right) - { - break; - } - if (dst_x2 > clip_x) - { - debug_printf("DST %d %d %d %d SRC %d %d %d %d CLIP %d %d\n",dst_x,dst_y,dst_wide,dst_high,src_x,src_y,src_wide,src_high,dst_x2,clip_x); - if (!StretchBlt(hdcDest,dst_x,dst_y,dst_wide,dst_high,hdcSrc,src_x,src_y,src_wide,src_high,rop)) - { - return FALSE; - } - } - - dst_x = dst_x2; - src_x += src_wide; - src_xrun -= src_wide; - } - } - - dst_y = dst_y2; - src_y += src_high; - src_yrun -= src_high; - } - } - - return TRUE; -} -// get the source pixel coordinate. -// doesn't use mipmaps. -static BOOL _viv_get_src_pixel_pos(int client_x,int client_y,POINT *out_pixel_pt) -{ - RECT client_rect; - int wide; - int high; - int rx; - int ry; - int rw; - int rh; - - GetClientRect(_viv_hwnd,&client_rect); - wide = client_rect.right - client_rect.left; - high = client_rect.bottom - client_rect.top - _viv_get_status_high() - _viv_get_controls_high(); - if (_viv_frame_count) - { - _viv_get_render_size(&rw,&rh); - rw = (int)(rw * _viv_dst_zoom_values[_viv_dst_zoom_x_pos]); - rh = (int)(rh * _viv_dst_zoom_values[_viv_dst_zoom_y_pos]); - rx = (((_viv_dst_pos_x - 250) * (wide*2)) / 1000) - (rw / 2) - _viv_view_x; - ry = (((_viv_dst_pos_y - 250) * (high*2)) / 1000) - (rh / 2) - _viv_view_y; - - if ((rw) && (rh)) - { - if ((client_x >= rx) && (client_y >= ry) && (client_x < rx + rw) && (client_y < ry + rh)) - { - out_pixel_pt->x = ((client_x - rx) * (__int64)_viv_image_wide) / rw; - out_pixel_pt->y = ((client_y - ry) * (__int64)_viv_image_high) / rh; - - return TRUE; - } - } - } - - return FALSE; -} -// get the source pixel color from the specified position. -// doesn't use mipmaps. -static void _viv_get_src_pixel_rgb(int src_x,int src_y,COLORREF *out_colorref) -{ - RECT client_rect; - int wide; - int high; - int rx; - int ry; - int rw; - int rh; - - GetClientRect(_viv_hwnd,&client_rect); - wide = client_rect.right - client_rect.left; - high = client_rect.bottom - client_rect.top - _viv_get_status_high() - _viv_get_controls_high(); - if (_viv_frame_count) - { - HDC screen_hdc; - - screen_hdc = GetDC(0); - - if (screen_hdc) - { - HDC mem_hdc; - - _viv_get_render_size(&rw,&rh); - rw = (int)(rw * _viv_dst_zoom_values[_viv_dst_zoom_x_pos]); - rh = (int)(rh * _viv_dst_zoom_values[_viv_dst_zoom_y_pos]); - rx = (((_viv_dst_pos_x - 250) * (wide*2)) / 1000) - (rw / 2) - _viv_view_x; - ry = (((_viv_dst_pos_y - 250) * (high*2)) / 1000) - (rh / 2) - _viv_view_y; - - mem_hdc = CreateCompatibleDC(screen_hdc); - if (mem_hdc) - { - HGDIOBJ last_hbitmap; - - last_hbitmap = SelectObject(mem_hdc,_viv_frames[_viv_frame_position].hbitmap); - - if (last_hbitmap) - { - *out_colorref = GetPixel(mem_hdc,src_x,src_y); - - SelectObject(mem_hdc,last_hbitmap); - } - - DeleteDC(mem_hdc); - } - - ReleaseDC(0,screen_hdc); - } - } -} -static int _viv_clamp_zoom_pos(int zoom_pos) -{ - if (zoom_pos > _VIV_ZOOM_MAX-1) - { - return _VIV_ZOOM_MAX-1; - } - if (zoom_pos < 0) - { - return 0; - } - - return zoom_pos; -} -static void _viv_open_preload(void) -{ - os_copy_memory(_viv_current_fd,_viv_preload_fd,sizeof(WIN32_FIND_DATA)); - - _viv_update_title(); - - if (_viv_preload_state == 0) - { - // loading... - // do we have the first frame? - if (_viv_preload_frame_loaded_count) - { - // save current image to last image. - viv_copy_current_image_to_last_image(); - // switch now.. - _viv_load_is_preload = 0; - _viv_activate_preload(); - _viv_status_update(); - } - else - { - // still loading... - // wait... - if (!_viv_should_activate_preload_on_load) - { - _viv_should_activate_preload_on_load = 1; - - // show loading... - _viv_status_update(); - } - - debug_printf("STILL LOADING...\n"); - } - } - else - if (_viv_preload_state == 1) - { - // save current image to last image. - viv_copy_current_image_to_last_image(); - // loaded - // preload next below.. - _viv_load_is_preload = 0; - _viv_status_update(); - - _viv_activate_preload(); - - _viv_preload_next(); - } - else - { - // save current image to last image. - viv_copy_current_image_to_last_image(); - - // failed. - // preload next below.. - _viv_load_failed = 1; - _viv_load_is_preload = 0; - _viv_status_update(); - - _viv_clear(); - - _viv_start_first_frame(); - - _viv_process_pending_clear(); - - _viv_preload_next(); - } -} + + + + + + + + + /* static void _viv_get_tooltip(void) @@ -15235,6 +2301,14 @@ static void _viv_tooltip_update(void) _viv_get_tooltip(); + // the pixel probe tooltip joins the theme (the comctl tooltip paints + // whatever colors it is told here). + if (_viv_tooltip_hwnd) + { + SendMessage(_viv_tooltip_hwnd,TTM_SETTIPBKCOLOR,viv_theme_color(VIV_TK_FACE),0); + SendMessage(_viv_tooltip_hwnd,TTM_SETTIPTEXTCOLOR,viv_theme_color(VIV_TK_TEXT),0); + } + string_printf(pixel_info_buf,"%d,%d: %d,%d,%d",_viv_src_pixel_x,_viv_src_pixel_y,_viv_src_pixel_r,_viv_src_pixel_g,_viv_src_pixel_b); if (_viv_tooltip_hwnd) @@ -15284,40 +2358,7 @@ static void _viv_tooltip_update_track_position(void) } */ -static int _viv_safe_copy_data(const void *base,SIZE_T src_size,const void *src,void *dst,SIZE_T dst_size) -{ - const BYTE *p; - BYTE *d; - SIZE_T run; - SIZE_T end; - - if (((const BYTE *)src) < ((const BYTE *)base)) - { - return 0; - } - - end = safe_size_add(((const BYTE *)src) - ((const BYTE *)base),dst_size); - - if (end == SIZE_MAX) - { - return 0; - } - - if (end > src_size) - { - return 0; - } - - p = (const BYTE *)src; - d = (BYTE *)dst; - run = dst_size; - - while(run) - { - *d++ = *p; - p++; - run--; - } - - return 1; -} + + + + diff --git a/src/viv.h b/src/viv.h index 16daba6a..266e7268 100644 --- a/src/viv.h +++ b/src/viv.h @@ -21,6 +21,13 @@ // // VoidImageViewer +// include guard: upstream relied on each translation unit including this +// exactly once; the R70 split layers viv_state.h and the domain headers +// on top of it, so a plain guard is now required (double inclusion +// redefines the command-id enum). +#ifndef VIV_H +#define VIV_H + #ifdef __cplusplus extern "C" { #endif @@ -46,11 +53,45 @@ extern "C" { #define COBJMACROS // c object interface please #define CINTERFACE // c interface only -#define VIV_UINT64_MAX 0xFFFFFFFFFFFFFFFFUI64 +#define VIV_UINT64_MAX 0xFFFFFFFFFFFFFFFFULL #define VIV_DWORD_MAX 0xffffffff +// single image pixel budget: a corrupted or hostile header can +// claim dimensions that decode to gigabytes of rgba (a 428 kb png +// can ask for 20000 x 20000). the loaders refuse the file before +// any allocation happens so a huge canvas fails like any other +// unloadable file instead of dying inside the allocator. +// +// the ceiling is pointer-width dependent (1.0.04): 32-bit builds +// keep the 100 mp ceiling (a 100 mp rgba frame is already 400 mb +// against a 2 gb address space once gdi copies, mipmaps and +// rotation buffers pile up); 64-bit builds (x64 / arm64) can +// afford 400 mp so real panoramic stitches and large flatbed +// scans (15000 x 9000 and up) load normally instead of failing +// like a corrupt file. both ceilings still bound a hostile canvas +// before the decoder runs. +#if defined(_WIN64) +#define VIV_MAX_IMAGE_PIXELS 400000000 +// animated webp keeps the static ceiling on 64-bit builds: the address +// space absorbs the decode canvas, the anim decoder working frame and +// the display bitmap. +#define VIV_MAX_ANIMATION_PIXELS 400000000 +#else +#define VIV_MAX_IMAGE_PIXELS 100000000 +// 32-bit: an animated canvas pays for the decode canvas, the anim +// decoder working frame and the display bitmap (roughly 12 bytes per +// pixel) inside a 2 gb address space, so the animation ceiling is a +// quarter of the static one (25 mp ~= 300 mb of buffers). +#define VIV_MAX_ANIMATION_PIXELS 25000000 +#endif + typedef unsigned char utf8_t; +// __int64 is msvc only: mingw and zig cc spell it long long. +#ifndef _MSC_VER +#define __int64 long long +#endif + typedef unsigned __int64 VIV_UINT64; #include @@ -63,7 +104,7 @@ typedef unsigned __int64 VIV_UINT64; //#include //#include #include // OPENFILENAME -#include // ShellExecute +#include // ShellExecute #include //#include // _beginthreadex #include // DROPFILES @@ -107,23 +148,6 @@ enum VIV_ID_VIEW_WINDOW_SIZE_200, VIV_ID_VIEW_WINDOW_SIZE_AUTO_FIT, - VIV_ID_VIEW_PANSCAN_INCREASE_SIZE, - VIV_ID_VIEW_PANSCAN_DECREASE_SIZE, - VIV_ID_VIEW_PANSCAN_INCREASE_WIDTH, - VIV_ID_VIEW_PANSCAN_DECREASE_WIDTH, - VIV_ID_VIEW_PANSCAN_INCREASE_HEIGHT, - VIV_ID_VIEW_PANSCAN_DECREASE_HEIGHT, - VIV_ID_VIEW_PANSCAN_MOVE_UP, - VIV_ID_VIEW_PANSCAN_MOVE_DOWN, - VIV_ID_VIEW_PANSCAN_MOVE_LEFT, - VIV_ID_VIEW_PANSCAN_MOVE_RIGHT, - VIV_ID_VIEW_PANSCAN_MOVE_UP_LEFT, - VIV_ID_VIEW_PANSCAN_MOVE_UP_RIGHT, - VIV_ID_VIEW_PANSCAN_MOVE_DOWN_LEFT, - VIV_ID_VIEW_PANSCAN_MOVE_DOWN_RIGHT, - VIV_ID_VIEW_PANSCAN_MOVE_CENTER, - VIV_ID_VIEW_PANSCAN_RESET, - VIV_ID_VIEW_ZOOM_IN, VIV_ID_VIEW_ZOOM_OUT, VIV_ID_VIEW_ZOOM_RESET, @@ -187,15 +211,20 @@ enum VIV_ID_HELP_ABOUT, VIV_ID_FILE_EXIT, + VIV_ID_FILE_SAVE_AS, VIV_ID_SLIDESHOW_TIMER, VIV_ID_HIDE_CURSOR_TIMER, VIV_ID_STATUS_TEMP_TEXT_TIMER, VIV_ID_ANIMATION_TIMER, + VIV_ID_DARK_RECHECK_TIMER, + VIV_ID_DARK_DIALOG_ASSERT_TIMER, + VIV_ID_RECENT_SAVE_TIMER, VIV_ID_STATUS, VIV_ID_REBAR, VIV_ID_TOOLBAR, + VIV_ID_MENUBAR, VIV_ID_OPTIONS_GENERAL, VIV_ID_OPTIONS_VIEW, @@ -221,6 +250,38 @@ enum VIV_ID_VIEW_REFRESH, VIV_ID_VIEW_CAPTION, VIV_ID_VIEW_THICKFRAME, + + // touch / zoom controls (appended so existing ids are not shifted) + VIV_ID_VIEW_ZOOM_CONTROLS, + + // backdrop shown under transparent pixels (appended, ids not shifted) + VIV_ID_VIEW_BACKDROP_FOLLOW, + VIV_ID_VIEW_BACKDROP_BLACK, + VIV_ID_VIEW_BACKDROP_WHITE, + VIV_ID_VIEW_BACKDROP_CUSTOM, + VIV_ID_VIEW_BACKDROP_CHECKERBOARD, + VIV_ID_ZOOMUI, + + // zoom overlay auto hide (appended so existing ids are not shifted) + VIV_ID_VIEW_ZOOM_AUTO_HIDE, + + // recent files mru submenu items and the clear command + // (appended so existing ids are not shifted) + VIV_ID_FILE_RECENT_CLEAR, + VIV_ID_FILE_RECENT_0, + VIV_ID_FILE_RECENT_1, + VIV_ID_FILE_RECENT_2, + VIV_ID_FILE_RECENT_3, + VIV_ID_FILE_RECENT_4, + VIV_ID_FILE_RECENT_5, + VIV_ID_FILE_RECENT_6, + VIV_ID_FILE_RECENT_7, + VIV_ID_FILE_RECENT_8, + VIV_ID_FILE_RECENT_9, + + // view menu windowed background color picker + // (appended so existing ids are not shifted) + VIV_ID_VIEW_WINDOWED_BACKGROUND_COLOR, }; #include "version.h" @@ -233,6 +294,12 @@ enum #include "utf8.h" #include "ini.h" #include "config.h" +#include "viv_theme.h" +#include "viv_msgbox.h" +#include "zoomui.h" +#include "viv_toolbar.h" +#include "viv_settings.h" +#include "glyphs.h" #include "webp.h" #include "small_pool.h" #include "safe_size.h" @@ -247,3 +314,5 @@ config_key_t *viv_key_get_start(int command_index); #ifdef __cplusplus } #endif + +#endif // VIV_H diff --git a/src/viv_anim.c b/src/viv_anim.c new file mode 100644 index 00000000..8716456f --- /dev/null +++ b/src/viv_anim.c @@ -0,0 +1,703 @@ +// +// Copyright 2025 voidtools / David Carpenter +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +// VoidImageViewer +// viv_anim.c - webp animation frames, rates and the timer queue. +// Pure physical move from viv.c (R70 split): bodies are unchanged. +#include "viv.h" +#include "viv_state.h" +#include "viv_anim.h" +#include "viv_menubar.h" +#include "viv_chrome.h" +#include "viv_load.h" +#include "viv_render.h" +#include "viv_view.h" +#include "viv_toolbar.h" + +// forward declarations (order preserved from viv.c) +void _viv_clear_frames(_viv_frame_t *frames,int loaded_count); +void _viv_increase_animation_rate(int dec); +void _viv_reset_animation_rate(void); +VOID NTAPI _viv_timer_queue_timer_callback(PVOID param,BOOLEAN TimerOrWaitFired); +static void _viv_timer_start(void); +void _viv_animation_pause(void); +void _viv_frame_step(void); +void _viv_frame_prev(void); +void _viv_timer_stop(void); +void _viv_update_frame(void); +void _viv_frame_skip(int size); +int _viv_webp_info_proc(_viv_webp_t *viv_webp,DWORD frame_count,DWORD wide,DWORD high,int has_alpha); +int _viv_webp_frame_proc(_viv_webp_t *viv_webp,BYTE *pixels,int delay); +static void _viv_status_update_temp_animation_rate(void); +void _viv_start_first_frame(void); +UINT _viv_frame_delay_at(const os_PropertyItem_t *pd,SIZE_T pd_size,DWORD i); + + +static BYTE _viv_is_timer_queue_timer = 0; +static HANDLE _viv_timer_queue_timer_handle; +void _viv_clear_frames(_viv_frame_t *frames,int loaded_count) +{ + int i; + + for(i=0;i 1) + { + if ((_viv_frame_loaded_count == _viv_frame_count) || (_viv_frame_position + 1 < _viv_frame_loaded_count)) + { + _viv_frame_position++; + if (_viv_frame_position == _viv_frame_count) + { + _viv_frame_position = 0; + } + + _viv_animation_timer_tick_start = os_get_tick_count(); + _viv_timer_tick = 0; + + _viv_update_src_pixel(1,0); + _viv_status_update(); + + InvalidateRect(_viv_hwnd,NULL,FALSE); + UpdateWindow(_viv_hwnd); + } + } + + // rc.13: a manual frame step pauses the clock - the play face and + // the on-top window follow it. + _viv_toolbar_update_buttons(); + + _viv_update_ontop(); +} +void _viv_frame_prev(void) +{ + _viv_frame_looped = 0; + + if (_viv_animation_play) + { + _viv_animation_play = 0; + } + + if (_viv_frame_count > 1) + { + if (_viv_frame_position > 0) + { + _viv_frame_position--; + } + else + { + _viv_frame_position = _viv_frame_loaded_count - 1; + } + + _viv_animation_timer_tick_start = os_get_tick_count(); + _viv_timer_tick = 0; + + _viv_update_src_pixel(1,0); + _viv_status_update(); + + InvalidateRect(_viv_hwnd,NULL,FALSE); + UpdateWindow(_viv_hwnd); + } + + // rc.13: a manual frame step pauses the clock - the play face and + // the on-top window follow it. + _viv_toolbar_update_buttons(); + + _viv_update_ontop(); +} +void _viv_timer_stop(void) +{ + if (_viv_is_animation_timer) + { + _viv_is_animation_timer = 0; + + if ((os_CreateTimerQueueTimer) && (os_DeleteTimerQueueTimer)) + { + if (_viv_is_timer_queue_timer) + { + os_DeleteTimerQueueTimer(NULL,_viv_timer_queue_timer_handle,NULL); + + _viv_is_timer_queue_timer = 0; + } + } + else + { + KillTimer(_viv_hwnd,VIV_ID_ANIMATION_TIMER); + } + + _viv_update_prevent_sleep(); + } +} +void _viv_update_frame(void) +{ + if (!_viv_is_fullscreen) + { + DWORD oldstyle; + DWORD newstyle; + RECT windowrect; + RECT clientrect; + RECT newrect; + RECT oldrect; + int was_maximized; + + was_maximized = 0; + + // get out of maximized state. + if (_viv_is_window_maximized(_viv_hwnd)) + { + ShowWindow(_viv_hwnd,SW_RESTORE); + was_maximized = 1; + } + + oldstyle = GetWindowLong(_viv_hwnd,GWL_STYLE); + newstyle = oldstyle; + + GetClientRect(_viv_hwnd,&clientrect); + debug_printf("clientrect %d %d %d %d\n",clientrect.left,clientrect.top,clientrect.right,clientrect.bottom); + + CopyRect(&oldrect,&clientrect); + AdjustWindowRect(&oldrect,oldstyle,FALSE); + + oldrect.bottom += _viv_menubar_high() + _viv_get_status_high() + _viv_get_controls_high(); + + debug_printf("oldrect %d %d %d %d %d\n",oldrect.left,oldrect.top,oldrect.right,oldrect.bottom,GetMenu(_viv_hwnd) ? TRUE : FALSE); + + if (config_show_caption) + { + newstyle |= WS_CAPTION | WS_SYSMENU; + } + else + { + newstyle &= ~(WS_CAPTION | WS_SYSMENU); + } + + if (config_show_thickframe) + { + newstyle |= WS_THICKFRAME; + } + else + { + newstyle &= ~WS_THICKFRAME; + } + + // the top bar is a client side child: showing it grows the + // required client area instead of the frame. + _viv_menubar_show(config_show_menu); + + _viv_status_show(config_show_status); + _viv_controls_show(config_show_controls); + _viv_zoomui_update(); + + CopyRect(&newrect,&clientrect); + AdjustWindowRect(&newrect,newstyle,config_show_menu ? TRUE : FALSE); + + newrect.bottom += _viv_get_status_high() + _viv_get_controls_high(); + + debug_printf("newrect %d %d %d %d %d\n",newrect.left,newrect.top,newrect.right,newrect.bottom,config_show_menu ? TRUE : FALSE); + + GetWindowRect(_viv_hwnd,&windowrect); + + windowrect.left += newrect.left - oldrect.left; + windowrect.top += newrect.top - oldrect.top; + windowrect.right += newrect.right - oldrect.right; + windowrect.bottom += newrect.bottom - oldrect.bottom; + + SetWindowLong(_viv_hwnd,GWL_STYLE,newstyle); + + SetWindowPos(_viv_hwnd,HWND_TOP,windowrect.left,windowrect.top,windowrect.right - windowrect.left,windowrect.bottom - windowrect.top,SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS); + + // if there is no catpion or thick frame we should not allow maximize + // avoid our resize borders when maximized. + if ((was_maximized) && (config_show_caption) && (config_show_thickframe)) + { + ShowWindow(_viv_hwnd,SW_MAXIMIZE); + } + } +} +void _viv_frame_skip(int size) +{ + if (_viv_frame_count > 1) + { + if (size > 0) + { + while(size > 0) + { + if ((_viv_frame_loaded_count == _viv_frame_count) || (_viv_frame_position + 1 < _viv_frame_loaded_count)) + { + _viv_frame_position++; + if (_viv_frame_position == _viv_frame_count) + { + _viv_frame_position = 0; + } + + _viv_animation_timer_tick_start = os_get_tick_count(); + _viv_timer_tick = 0; + } + + // a zero delay frame (a webp chunk with no duration) must still + // make progress, otherwise this loop never terminates. + size -= (_viv_frames[_viv_frame_position].delay > 0) ? _viv_frames[_viv_frame_position].delay : 1; + } + } + else + if (size < 0) + { + while(size < 0) + { + _viv_frame_position--; + if (_viv_frame_position < 0) + { + _viv_frame_position = _viv_frame_loaded_count - 1; + } + + _viv_animation_timer_tick_start = os_get_tick_count(); + _viv_timer_tick = 0; + + size += (_viv_frames[_viv_frame_position].delay > 0) ? _viv_frames[_viv_frame_position].delay : 1; + } + } + + _viv_update_src_pixel(1,0); + _viv_status_update(); + + InvalidateRect(_viv_hwnd,NULL,FALSE); + UpdateWindow(_viv_hwnd); + } +} +int _viv_webp_info_proc(_viv_webp_t *viv_webp,DWORD frame_count,DWORD wide,DWORD high,int has_alpha) +{ + int ret; + + ret = 0; + + viv_webp->wide = wide; + viv_webp->high = high; + viv_webp->has_alpha = has_alpha; + viv_webp->frame_count = frame_count; + + viv_webp->screen_hdc = GetDC(NULL); + if (viv_webp->screen_hdc) + { + viv_webp->mem_hdc = CreateCompatibleDC(viv_webp->screen_hdc); + + if (viv_webp->mem_hdc) + { + ret = 1; + } + } + + return ret; +} +int _viv_webp_frame_proc(_viv_webp_t *viv_webp,BYTE *pixels,int delay) +{ + // always load first frame.. + if ((viv_webp->frame_index) && (_viv_load_image_terminate)) + { + return 0; + } + + // the webp frame is composited into a 24bpp top-down dib: when the + // frame has alpha the backdrop is painted first and the rgba pixels + // are blended over it, exactly like the gdi+ path does for png/gif. + // opaque frames simply overwrite every pixel. + { + BITMAPINFO bmi; + HBITMAP hbitmap; + void *bits; + + ZeroMemory(&bmi, sizeof(BITMAPINFO)); + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = viv_webp->wide; + bmi.bmiHeader.biHeight = -(int)viv_webp->high; // Negative height to indicate top-down bitmap + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 24; + bmi.bmiHeader.biCompression = BI_RGB; + + hbitmap = CreateDIBSection(viv_webp->screen_hdc,&bmi,DIB_RGB_COLORS,&bits,NULL,0); + + // Set RGB data to the bitmap + if (hbitmap) + { + int mip_wide; + int mip_high; + HGDIOBJ last_hbitmap; + const BYTE *p; + BYTE *d; + DWORD high_run; + int stride; + + last_hbitmap = SelectObject(viv_webp->mem_hdc,hbitmap); + + if (viv_webp->has_alpha) + { + // fill the backdrop under the transparent pixels (cached + // brushes, a single FillRect). + _viv_fill_backdrop(viv_webp->mem_hdc,viv_webp->wide,viv_webp->high); + } + + // blend the rgba frame over the dib pixels. the webp scan0 is + // rgba, the dib is bgr with 4 byte aligned rows: the source is + // read ahead of the write cursor so the shared webp canvas + // buffer is left untouched. + stride = ((viv_webp->wide * 3) + 3) / 4 * 4; + p = pixels; + d = (BYTE *)bits; + high_run = viv_webp->high; + + while(high_run) + { + BYTE *wd; + DWORD wide_run; + + wide_run = viv_webp->wide; + wd = d; + + while(wide_run) + { + int r; + int g; + int b; + int a; + + r = p[0]; + g = p[1]; + b = p[2]; + a = p[3]; + + p += 4; + + // alpha 255 fully replaces the backdrop pixel, alpha 0 + // keeps it. + wd[0] = b + ((wd[0] - b) * (255 - a)) / 255; + wd[1] = g + ((wd[1] - g) * (255 - a)) / 255; + wd[2] = r + ((wd[2] - r) * (255 - a)) / 255; + wd += 3; + + wide_run--; + } + + d += stride; + high_run--; + } + + SelectObject(viv_webp->mem_hdc,last_hbitmap); + if (viv_webp->orientation > 1) + { + HBITMAP new_hbitmap; + + new_hbitmap = _viv_orientate_hbitmap(hbitmap,viv_webp->orientation); + if (new_hbitmap) + { + DeleteObject(hbitmap); + hbitmap = new_hbitmap; + } + } + + if (viv_webp->frame_index == 0) + { + _viv_reply_load_image_first_frame_t first_frame; + + first_frame.wide = viv_webp->wide; + first_frame.high = viv_webp->high; + + // apply orientation: transposed orientations (5-8) swap the axes. + // the hbitmap above was already rotated to match, so the reported + // dimensions swap with it. mirrors the gdi+ path. + switch (viv_webp->orientation) + { + case 5: // #define PHOTO_ORIENTATION_TRANSPOSE 5u + case 6: // #define PHOTO_ORIENTATION_ROTATE270 6u + case 7: // #define PHOTO_ORIENTATION_TRANSVERSE 7u + case 8: // #define PHOTO_ORIENTATION_ROTATE90 8u + + { + int temp; + temp = first_frame.wide; + first_frame.wide = first_frame.high; + first_frame.high = temp; + } + break; + } + first_frame.is_low_res = 0; + first_frame.frame.hbitmap = hbitmap; + first_frame.frame.mipmap = NULL; + first_frame.frame.delay = 0; + first_frame.frame_count = viv_webp->frame_count; + + if (viv_webp->frame_count > 1) + { + first_frame.frame.delay = delay; + } + + // preload first mipmap + _viv_get_mipmap(hbitmap,first_frame.wide,first_frame.high,_viv_load_render_wide/2,_viv_load_render_high/2,&mip_wide,&mip_high,&first_frame.frame.mipmap); + + _viv_reply_add(_VIV_REPLY_LOAD_IMAGE_FIRST_FRAME,sizeof(_viv_reply_load_image_first_frame_t),&first_frame); + } + else + { + _viv_frame_t frame; + int frame_wide; + int frame_high; + + frame.hbitmap = hbitmap; + frame.mipmap = NULL; + frame.delay = delay; + +//printf("DELAY %d\n",delay) ; + + frame_wide = viv_webp->wide; + frame_high = viv_webp->high; + + // apply orientation: transposed orientations (5-8) swap the axes + // for the mipmap too (the hbitmap above is already rotated). + switch (viv_webp->orientation) + { + case 5: + case 6: + case 7: + case 8: + + frame_wide = viv_webp->high; + frame_high = viv_webp->wide; + break; + } + + _viv_get_mipmap(hbitmap,frame_wide,frame_high,_viv_load_render_wide/2,_viv_load_render_high/2,&mip_wide,&mip_high,&frame.mipmap); + + _viv_reply_add(_VIV_REPLY_LOAD_IMAGE_ADDITIONAL_FRAME,sizeof(_viv_frame_t),&frame); + } + + viv_webp->frame_index++; + } + } + + return 1; +} +static void _viv_status_update_temp_animation_rate(void) +{ + wchar_t wbuf[STRING_SIZE]; + + string_printf(wbuf,localization_get_string(LOCALIZATION_ID_STATUS_BAR_ANIMATION_RATE_FORMAT),_viv_animation_rates[_viv_animation_rate_pos]); + + _viv_status_set_temp_text(wbuf); +} +void _viv_start_first_frame(void) +{ + // draw first frame and start timer. + _viv_frame_position = 0; + _viv_frame_looped = 0; + _viv_animation_timer_tick_start = os_get_tick_count(); + _viv_timer_tick = 0; + + if (_viv_frame_count > 1) + { + _viv_timer_start(); + } + + _viv_update_src_pixel(1,0); + _viv_status_update(); + + if (_viv_doing == _VIV_DOING_1TO1SCROLL) + { + POINT pt; + GetCursorPos(&pt); + ScreenToClient(_viv_hwnd,&pt); + + _viv_update_1to1_scroll(pt.x,pt.y); + } + + // show cursor. + _viv_update_show_cursor(); + +//debug_printf("---\n",_viv_load_image_next_fd); +//debug_printf("_viv_load_image_next_fd %p\n",_viv_load_image_next_fd); +//debug_printf("---\n",_viv_load_image_next_fd); +/* + if (_viv_load_image_next_fd) + { + // load priority paint.. + // we will paint on the 'next next' image we load.. + _viv_low_priority_paint = 1; + return; + } + + _viv_low_priority_paint = 0; + InvalidateRect(_viv_hwnd,NULL,FALSE); + + // building mipmaps as needed hangs the UI. + // this makes rendering lag while holding down right. + // avoid painting when user is holding down right.. + // + // because we build the mipmap for the first image in the load thread this is now instant.. + // ok it's still awful, let the next load refresh.. +// if (_viv_load_image_next_fd) + { +// UpdateWindow(_viv_hwnd); + }*/ + + if (!_viv_is_fullscreen) + { + if (config_auto_zoom) + { + switch(config_auto_zoom_type) + { + case 0: + case 1: + case 2: + case 3: + // don't scroll any regions when sizing. + InvalidateRect(_viv_hwnd,NULL,FALSE); + _viv_command(VIV_ID_VIEW_WINDOW_SIZE_50 + config_auto_zoom_type); + break; + } + } + } + + InvalidateRect(_viv_hwnd,NULL,FALSE); + UpdateWindow(_viv_hwnd); +} +UINT _viv_frame_delay_at(const os_PropertyItem_t *pd,SIZE_T pd_size,DWORD i) +{ + UINT value; + UINT count; + const BYTE *v; + + value = 0; + + if ((!pd) || (pd_size <= sizeof(os_PropertyItem_t))) + { + return 0; + } + + // gdi+ points value into the property buffer: keep the dereference + // inside the buffer we actually own. + v = (const BYTE *)pd->value; + + if ((v < (const BYTE *)pd) || ((SIZE_T)(v - (const BYTE *)pd) >= pd_size)) + { + return 0; + } + + if (!(count = pd->length / sizeof(UINT))) + { + return 0; + } + + if (!_viv_safe_copy_data(pd,pd_size,&(((const UINT *)v)[i % count]),&value,sizeof(UINT))) + { + value = 0; + } + + return value; +} diff --git a/src/viv_anim.h b/src/viv_anim.h new file mode 100644 index 00000000..870970a7 --- /dev/null +++ b/src/viv_anim.h @@ -0,0 +1,44 @@ +// +// Copyright 2025 voidtools / David Carpenter +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +// VoidImageViewer +// viv_anim.h - webp animation frames, rates and the timer queue. +#ifndef VIV_ANIM_H +#define VIV_ANIM_H + +#include "viv.h" + +// exported to other domains / the viv.c core +void _viv_clear_frames(_viv_frame_t *frames,int loaded_count); +void _viv_increase_animation_rate(int dec); +void _viv_reset_animation_rate(void); +void _viv_animation_pause(void); +void _viv_frame_step(void); +void _viv_frame_prev(void); +void _viv_timer_stop(void); +void _viv_update_frame(void); +void _viv_frame_skip(int size); +int _viv_webp_info_proc(_viv_webp_t *viv_webp,DWORD frame_count,DWORD wide,DWORD high,int has_alpha); +int _viv_webp_frame_proc(_viv_webp_t *viv_webp,BYTE *pixels,int delay); +void _viv_start_first_frame(void); +UINT _viv_frame_delay_at(const os_PropertyItem_t *pd,SIZE_T pd_size,DWORD i); + +#endif diff --git a/src/viv_chrome.c b/src/viv_chrome.c new file mode 100644 index 00000000..280ef827 --- /dev/null +++ b/src/viv_chrome.c @@ -0,0 +1,1989 @@ +// +// Copyright 2025 voidtools / David Carpenter +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +// VoidImageViewer +// viv_chrome.c - window dressing: rebar, toolbar, status bar, fullscreen, cursors. +// the menu bar strip is owned by viv_menubar.c (the remade top bar). +// Pure physical move from viv.c (R70 split): bodies are unchanged. +#include "viv.h" +#include "viv_state.h" +#include "viv_toolbar.h" +#include "viv_chrome.h" +#include "viv_dark.h" +#include "viv_menubar.h" +#include "viv_render.h" +#include "viv_view.h" + +// forward declarations (order preserved from viv.c) +static LRESULT (CALLBACK *_viv_old_status_proc)(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) = NULL; // old status bar proc + +void _viv_update_title(void); +void _viv_on_size(void); +HBRUSH _viv_dark_chrome_brush(int which); +int _viv_paint_begin(HDC hdc,int wide,int high); +void _viv_paint_kill(void); +void _viv_toggle_fullscreen(void); +HFONT _viv_menu_font(void); +void _viv_menu_font_drop(void); +void _viv_apply_dark_mode(int repaint); +int _viv_is_window_maximized(HWND hwnd); +void _viv_update_ontop(void); +void _viv_update_prevent_sleep(void); +void _viv_status_show(int show); +void _viv_controls_show(int show); +void _viv_status_update(void); +static void _viv_status_set(int part,const wchar_t *text); +int _viv_status_draw_item(DRAWITEMSTRUCT *draw_item); +int _viv_get_status_high(void); +int _viv_get_controls_high(void); +static LRESULT CALLBACK _viv_status_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); +static LRESULT CALLBACK _viv_status_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); + + + +static LRESULT CALLBACK _viv_status_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) + +{ + + switch (msg) + + { + + case WM_ERASEBKGND: + + { + + RECT rect; + + + + // the comctl status class paints its own face from the light + + // palette even under the dark theme class (the field report: the + + // flat light slab under the dark canvas). the strip erases with + + // the chrome token - the same face the menu bar, the toolbar + + // and the owner drawn panes ride, in both themes. + + GetClientRect(hwnd,&rect); + + + + FillRect((HDC)wParam,&rect,viv_theme_brush(VIV_TK_CHROME)); + + + + return 1; + + } + + + + case WM_PAINT: + + { + + LRESULT result; + + + + // the control paints the panes, the sunken top edge and the + + // size grip. in the dark ui the edge and the grip are the two + + // bits left light: repaint them with the chrome palette after + + // the native pass, so the bottom band reads as one dark chrome. + + result = CallWindowProc(_viv_old_status_proc,hwnd,msg,wParam,lParam); + + + + if (_viv_is_dark()) + + { + + RECT client_rect; + + RECT rect; + + HDC hdc; + + int wide; + + + + hdc = GetDC(hwnd); + + + + if (hdc) + + { + + GetClientRect(hwnd,&client_rect); + + wide = client_rect.right - client_rect.left; + + + + // the top edge: the same pair the rebar strip draws + + // (shadow over highlight), so the two bands read as one. + + rect.left = 0; + + rect.top = 0; + + rect.right = wide; + + rect.bottom = 1; + + FillRect(hdc,&rect,_viv_dark_chrome_brush(1)); + + + + rect.top = 1; + + rect.bottom = 2; + + FillRect(hdc,&rect,_viv_dark_chrome_brush(2)); + + + + // the size grip: the native one paints light dots. repaint + + // the box with the dark face and dot it ourselves, only when + + // the native one is up (the parent is resizable and not + + // maximized - the control suppresses it otherwise). + + if (((GetWindowLong(_viv_hwnd,GWL_STYLE)) & WS_THICKFRAME) && (!IsZoomed(_viv_hwnd)) && (!_viv_is_fullscreen)) + + { + + RECT grip_rect; + + int grip_wide; + + int grip_high; + + int step; + + int dot_x; + + int dot_y; + + + + grip_wide = GetSystemMetrics(SM_CXVSCROLL); + + grip_high = GetSystemMetrics(SM_CYVSCROLL); + + + + if ((grip_wide > 0) && (grip_high > 0) && (grip_wide < wide) && (grip_high < (client_rect.bottom - client_rect.top))) + + { + + grip_rect.left = client_rect.right - grip_wide; + + grip_rect.top = client_rect.bottom - grip_high; + + grip_rect.right = client_rect.right; + + grip_rect.bottom = client_rect.bottom; + + + + FillRect(hdc,&grip_rect,viv_theme_brush(VIV_TK_CHROME)); + + + + step = (grip_wide < grip_high) ? (grip_wide / 6) : (grip_high / 6); + + + + if (step < 2) + + { + + step = 2; + + } + + + + // the classic triangle of dots anchored at the corner. + + for(dot_x=0;dot_x<3;dot_x++) + + { + + for(dot_y=0;dot_y<(3 - dot_x);dot_y++) + + { + + SetPixel(hdc,grip_rect.right - 2 - (dot_x * step),grip_rect.bottom - 2 - (dot_y * step),viv_theme_color(VIV_TK_TEXT2)); + + } + + } + + } + + } + + + + ReleaseDC(hwnd,hdc); + + } + + } + + + + return result; + + } + + + + case WM_DRAWITEM: + + + + // the owner drawn panes (defensive route: see _viv_status_draw_item). + + if (_viv_status_draw_item((DRAWITEMSTRUCT *)lParam)) + + { + + return 1; + + } + + + + break; + + + + case WM_CTLCOLOREDIT: + + // the zoom pane's in place editor: the strip palette owns the + // colors so the field reads as part of the chrome, not a foreign + // control - the chrome token and text token, the same pair the + // pane paint rides. (the selection highlight stays the system + // color - the edit control offers no custom one; it lives only + // while the editor is open.) + SetBkColor((HDC)wParam,viv_theme_color(VIV_TK_CHROME)); + SetTextColor((HDC)wParam,viv_theme_color(VIV_TK_TEXT)); + + return (LRESULT)viv_theme_brush(VIV_TK_CHROME); + + + + } + + + + return CallWindowProc(_viv_old_status_proc,hwnd,msg,wParam,lParam); + +} + + + +static LRESULT CALLBACK _viv_fullscreen_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); +void _viv_status_set_temp_text(wchar_t *text); +void _viv_status_update_temp_pos_zoom(void); +void _viv_status_update_slideshow_rate(void); +void _viv_zoomui_update(void); +void _viv_show_cursor(void); +void _viv_hide_cursor(void); +int _viv_should_show_cursor(void); +void _viv_update_show_cursor(void); +void _viv_start_hide_cursor_timer(void); + + +//static HWND _viv_tooltip_hwnd = 0; +static RECT _viv_fullscreen_rect; +static int _viv_fullscreen_zoom_offset = 0; +static BYTE _viv_prevent_on_size = 0; // don't process WM_SIZE changes. +static BYTE _viv_is_prevent_sleep = 0; +void _viv_update_title(void) +{ + wchar_t window_title[STRING_SIZE+STRING_SIZE]; + const wchar_t *filename; + + window_title[0] = 0; + filename = L""; + + switch(config_title_bar_format) + { + case 0: // full path + filename = _viv_current_fd->cFileName; + break; + + case 1: // filename only + default: + filename = string_get_filename_part(_viv_current_fd->cFileName); + break; + + case 2: // none + break; + } + + if (*filename) + { + string_cat(window_title,filename); + string_cat_utf8(window_title," - "); + } + + string_cat_utf8(window_title,localization_get_string(LOCALIZATION_ID_APP_NAME)); + + SetWindowTextW(_viv_hwnd,window_title); +} +void _viv_on_size(void) +{ + if (!_viv_prevent_on_size) + { + // keep the zoom level inside the live ladder: a window resize changes + // the best fit size and with it the reachable zoom range. (inside the + // guard: fullscreen toggle intermediates must not re-clamp.) + _viv_zoom_pos = _viv_clamp_zoom_pos(_viv_zoom_pos); + + RECT rect; + int wide; + int high; + + GetClientRect(_viv_hwnd,&rect); + wide = rect.right - rect.left; + high = rect.bottom - rect.top; + + if (!IsIconic(_viv_hwnd)) + { + if (!_viv_is_fullscreen) + { + int is_maximized; + + is_maximized = _viv_is_window_maximized(_viv_hwnd); + + config_maximized = is_maximized; + + if (!is_maximized) + { + RECT window_rect; + + GetWindowRect(_viv_hwnd,&window_rect); + + config_wide = window_rect.right - window_rect.left; + config_high = window_rect.bottom - window_rect.top; + } + } + } + + // the top bar strip: a client side child now (the frame menu is + // gone). it owns the top of the client area; everything below lays + // out against the reduced height. + if (_viv_menubar_high()) + { + _viv_menubar_resize(wide); + + high -= _viv_menubar_high(); + } + + if (_viv_status_hwnd) + { + _viv_status_update(); + + SendMessage(_viv_status_hwnd,WM_SIZE,0,0); + + high -= _viv_get_status_high(); + } + + if (_viv_toolbar_high()) + { + // the strip anchors under the menu bar (the layout owns the y), so + // the height math only asks the strip how tall it is. + _viv_toolbar_layout(wide); + + high -= _viv_toolbar_high(); + } + zoomui_layout(wide,high); + + { + + int rw; + int rh; + double new_view_x; + double new_view_y; + + _viv_get_render_size(&rw,&rh); + + new_view_x = (int)(((_viv_view_ix * rw) / _viv_image_wide) + 0.5) + (((_viv_dst_pos_x - 250) * (wide*2)) / 1000) - (wide / 2) - (rw / 2); + new_view_y = (int)(((_viv_view_iy * rh) / _viv_image_high) + 0.5) + (((_viv_dst_pos_y - 250) * (high*2)) / 1000) - (high / 2) - (rh / 2); + + debug_printf("RESTORE VIEW x %d y %d ix %d iy %d rw %d rh %d wide %d high %d\n",(int)(new_view_x),(int)(new_view_y),(int)_viv_view_ix,(int)_viv_view_iy,rw,rh,wide,high) ; + // _viv_view_set((int)(_viv_view_ix * (double)rw),(int)(_viv_view_iy * (double)rh),1); + _viv_view_set((int)new_view_x,(int)new_view_y,1); + } + + _viv_toolbar_update_buttons(); + } +} +static HBITMAP _viv_paint_hbitmap = 0; +static HGDIOBJ _viv_paint_last_hbitmap = 0; +static int _viv_paint_wide = 0; +static int _viv_paint_high = 0; +HBRUSH _viv_dark_chrome_brush(int which) +{ + // the four chrome faces live in the shared theme cache now: the + // indices map to face, line, muted and frame, so a theme or accent + // flip re-skins every legacy dark surface for free. + static const int tokens[4] = {VIV_TK_CHROME,VIV_TK_CHROME_LINE,VIV_TK_CHROME_MUTED,VIV_TK_FRAME}; + + if ((which < 0) || (which > 3)) + { + return 0; + } + + return viv_theme_brush(tokens[which]); +} +// prepare the paint backbuffer for a client area of wide x high pixels. +// returns 1 when the caller should draw into _viv_paint_hdc instead of the screen dc. +int _viv_paint_begin(HDC hdc,int wide,int high) +{ + if (_viv_paint_hdc) + { + // reuse the existing bitmap when the client size has not changed. + if ((wide == _viv_paint_wide) && (high == _viv_paint_high)) + { + return 1; + } + + // the size changed, discard the old bitmap. + if (_viv_paint_last_hbitmap) + { + SelectObject(_viv_paint_hdc,_viv_paint_last_hbitmap); + _viv_paint_last_hbitmap = 0; + } + + DeleteObject(_viv_paint_hbitmap); + _viv_paint_hbitmap = 0; + + _viv_paint_wide = 0; + _viv_paint_high = 0; + } + else + { + _viv_paint_hdc = CreateCompatibleDC(hdc); + + if (!_viv_paint_hdc) + { + return 0; + } + } + + if ((wide <= 0) || (high <= 0)) + { + return 0; + } + + _viv_paint_hbitmap = CreateCompatibleBitmap(hdc,wide,high); + + if (!_viv_paint_hbitmap) + { + return 0; + } + + _viv_paint_last_hbitmap = SelectObject(_viv_paint_hdc,_viv_paint_hbitmap); + + if (!_viv_paint_last_hbitmap) + { + DeleteObject(_viv_paint_hbitmap); + _viv_paint_hbitmap = 0; + + return 0; + } + + _viv_paint_wide = wide; + _viv_paint_high = high; + + return 1; +} +// free the cached paint backbuffer. +void _viv_paint_kill(void) +{ + if (_viv_paint_hdc) + { + if (_viv_paint_last_hbitmap) + { + SelectObject(_viv_paint_hdc,_viv_paint_last_hbitmap); + _viv_paint_last_hbitmap = 0; + } + + DeleteDC(_viv_paint_hdc); + _viv_paint_hdc = 0; + } + + if (_viv_paint_hbitmap) + { + DeleteObject(_viv_paint_hbitmap); + _viv_paint_hbitmap = 0; + } + + _viv_paint_wide = 0; + _viv_paint_high = 0; +} +void _viv_toggle_fullscreen(void) +{ + DWORD style; + int old_rw; + int old_rh; + int zoom_wide_array[_VIV_ZOOM_MAX]; + int zoom_high_array[_VIV_ZOOM_MAX]; + + _viv_get_render_size(&old_rw,&old_rh); + + // precalculate all zoom levels for comparison later to find the zoom offset. + { + int backup_zoom; + + backup_zoom = _viv_zoom_pos; + + for(_viv_zoom_pos=0;_viv_zoom_pos<_VIV_ZOOM_MAX;_viv_zoom_pos++) + { + int rw; + int rh; + + _viv_get_render_size(&rw,&rh); + + zoom_wide_array[_viv_zoom_pos] = rw; + zoom_high_array[_viv_zoom_pos] = rh; + } + + _viv_zoom_pos = backup_zoom; + } + + _viv_prevent_on_size = 1; + +debug_printf("toggle fullscreen %d\n",!_viv_is_fullscreen); + + style = GetWindowLong(_viv_hwnd,GWL_STYLE); + + _viv_1to1 = 0; + + if (_viv_is_fullscreen) + { + // set before restore + // otherwise get_render_size will return the wrong size. + _viv_is_fullscreen = 0; + + if (config_show_caption) + { + style |= WS_CAPTION; + } + else + { + style &= ~(WS_CAPTION); + } + + if (config_show_thickframe) + { + style |= WS_THICKFRAME; + } + else + { + style &= ~WS_THICKFRAME; + } + + _viv_menubar_show(config_show_menu); + + _viv_status_show(config_show_status); + _viv_controls_show(config_show_controls); + _viv_zoomui_update(); + + SetWindowLong(_viv_hwnd,GWL_STYLE,style); + + SetWindowPos(_viv_hwnd,HWND_TOP,_viv_fullscreen_rect.left,_viv_fullscreen_rect.top,_viv_fullscreen_rect.right - _viv_fullscreen_rect.left,_viv_fullscreen_rect.bottom - _viv_fullscreen_rect.top,SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS); + + if (_viv_fullscreen_is_maxed) + { + ShowWindow(_viv_hwnd,SW_MAXIMIZE); + } + + _viv_zoom_pos += _viv_fullscreen_zoom_offset; + _viv_zoom_pos = _viv_clamp_zoom_pos(_viv_zoom_pos); + } + else + { + RECT monitor_rect; + + // set fullscreen before we resize. + _viv_is_fullscreen = 1; + + os_MonitorRectFromWindow(_viv_hwnd,1,&monitor_rect); + + SetWindowLong(_viv_hwnd,GWL_STYLE,style & ~(WS_CAPTION|WS_THICKFRAME)); + + _viv_fullscreen_is_maxed = IsZoomed(_viv_hwnd); + if (_viv_fullscreen_is_maxed) + { + ShowWindow(_viv_hwnd,SW_SHOWNORMAL); + } + + GetWindowRect(_viv_hwnd,&_viv_fullscreen_rect); + + _viv_menubar_show(0); + _viv_status_show(0); + _viv_controls_show(0); + _viv_zoomui_update(); + + SetWindowPos(_viv_hwnd,HWND_TOP,monitor_rect.left,monitor_rect.top,monitor_rect.right - monitor_rect.left,monitor_rect.bottom - monitor_rect.top,SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS); + + _viv_prevent_on_deactivate = 1; + + // create a dummy fullscreen window and destroy it immediately + // this window is created fullscreen correctly, and when our normal window gains focus it will keep the fullscreen setting (no taskbar) + // without this dummy window, sometimes the taskbar will not disappear. + + { + HWND fullscreen_hwnd; + + // Initialize global strings + os_RegisterClassEx( + 0, + _viv_fullscreen_proc, + 0, + LoadCursor(NULL,IDC_ARROW), + (HBRUSH)(COLOR_BTNFACE+1), + "_VIV_FULLSCREEN", + 0); + + fullscreen_hwnd = os_CreateWindowEx( + 0, + "_VIV_FULLSCREEN", + localization_get_string(LOCALIZATION_ID_APP_NAME), + WS_POPUP|WS_VISIBLE, + monitor_rect.left,monitor_rect.top,monitor_rect.right - monitor_rect.left,monitor_rect.bottom - monitor_rect.top, + 0,0,os_hinstance,NULL); + + SetForegroundWindow(fullscreen_hwnd); + + DestroyWindow(fullscreen_hwnd); + } + + // find zoom offset. + { + int zoom_index; + + _viv_fullscreen_zoom_offset = 0; + + if (config_fullscreen_fill_window) + { + for(zoom_index=0;zoom_index<_VIV_ZOOM_MAX;zoom_index++) + { + // debug_printf("%d %d\n",zoom_wide_array[zoom_index] , monitor_rect.right - monitor_rect.left); + + if ((zoom_wide_array[zoom_index] > monitor_rect.right - monitor_rect.left) || (zoom_high_array[zoom_index] > monitor_rect.bottom - monitor_rect.top)) + { + break; + } + + _viv_fullscreen_zoom_offset = zoom_index; + } + + if (_viv_fullscreen_zoom_offset > _viv_zoom_pos) + { + _viv_fullscreen_zoom_offset = _viv_zoom_pos; + } + } + else + if (config_fill_window) + { + int backup_zoom_pos; + + backup_zoom_pos = _viv_zoom_pos; + + for(_viv_zoom_pos=0;_viv_zoom_pos<_VIV_ZOOM_MAX;_viv_zoom_pos++) + { + int rw; + int rh; + + _viv_get_render_size(&rw,&rh); + + // debug_printf("%d %d\n",zoom_wide_array[zoom_index] , monitor_rect.right - monitor_rect.left); + + if ((rw > old_rw) || (rh > old_rh)) + { + break; + } + + _viv_fullscreen_zoom_offset = -_viv_zoom_pos; + } + + _viv_zoom_pos = backup_zoom_pos; + + if (_viv_fullscreen_zoom_offset < -(_VIV_ZOOM_MAX-1-_viv_zoom_pos)) + { + _viv_fullscreen_zoom_offset = -(_VIV_ZOOM_MAX-1-_viv_zoom_pos); + } + } + +// debug_printf("ZOOM OFFSET %d\n",_viv_fullscreen_zoom_offset); + } + + _viv_zoom_pos -= _viv_fullscreen_zoom_offset; + _viv_zoom_pos = _viv_clamp_zoom_pos(_viv_zoom_pos); + + _viv_prevent_on_deactivate = 0; + } + + _viv_prevent_on_size = 0; + + _viv_on_size(); + +// InvalidateRect(_viv_hwnd,0,FALSE); + + // update mouseover + // so we show the cursor corectly in + // _viv_update_show_cursor + { + POINT cursor_pt; + HWND hwnd_mouseover; + int is_mouseover; + + GetCursorPos(&cursor_pt); + is_mouseover = 0; + + hwnd_mouseover = WindowFromPoint(cursor_pt); + if (hwnd_mouseover == _viv_hwnd) + { + RECT client_rect; + + ScreenToClient(_viv_hwnd,&cursor_pt); + + GetClientRect(_viv_hwnd,&client_rect); + + if (PtInRect(&client_rect,cursor_pt)) + { + is_mouseover = 1; + } + } + + _viv_is_mouseover = is_mouseover; + } + + _viv_update_show_cursor(); +} +static HFONT _viv_menu_font_handle = 0; // the cached menu bar font +static int _viv_menu_font_dpi = 0; // the dpi the menu bar font was created for +// the menu bar font: the system menu font at the window's current dpi, +// cached until the dpi or the theme changes. freed with the process. +HFONT _viv_menu_font(void) +{ + if ((!_viv_menu_font_handle) || (_viv_menu_font_dpi != os_logical_wide)) + { + LOGFONTW lf; + + if (_viv_menu_font_handle) + { + DeleteObject(_viv_menu_font_handle); + + _viv_menu_font_handle = 0; + } + + if (os_menu_font(&lf)) + { + _viv_menu_font_handle = CreateFontIndirectW(&lf); + + _viv_menu_font_dpi = os_logical_wide; + } + } + + return _viv_menu_font_handle; +} +// drop the cached menu font (the dpi or the theme changed: the system +// metrics may have followed). +void _viv_menu_font_drop(void) +{ + if (_viv_menu_font_handle) + { + DeleteObject(_viv_menu_font_handle); + + _viv_menu_font_handle = 0; + } + + _viv_menu_font_dpi = 0; +} +// apply the dark chrome to the main window: frame (title bar), status bar +// and zoom controls. the menu theme was set app wide before the first +// window was created (os_dark_set_app_mode). +void _viv_apply_dark_mode(int repaint) +{ + int dark; + DWORD menu_pid; + + dark = _viv_is_dark(); + + // the token layer re-resolves before anything repaints from it: the + // cached brushes follow the flip (every surface that paints through + // viv_theme_brush rides this, and the auto flip paths used to leave + // the cache on the old palette - the half-skinned ui the field kept + // catching). + viv_theme_refresh(); + + { + HWND menu_hwnd; + + // the #32768 class holds a token brush; the refresh just deleted + // it. an open popup would erase with a dead handle - re-install + // now (every menu open re-installs it again anyway). + menu_hwnd = FindWindowW(L"#32768",0); + + // same-process only: the class name is shared by every menu + // on the desktop (see _viv_menu_popup_theme). + if ((menu_hwnd) && (GetWindowThreadProcessId(menu_hwnd,&menu_pid)) && (menu_pid == GetCurrentProcessId())) + { + SetClassLongPtrW(menu_hwnd,GCLP_HBRBACKGROUND,(LONG_PTR)viv_theme_brush(VIV_TK_FACE)); + } + } + + os_dark_titlebar(_viv_hwnd,dark); + + // windows 11 chrome: rounded corners and a caption color that + // matches the canvas. a silent no-op on windows 10 and older. + os_window_modern_chrome(_viv_hwnd,_viv_windowed_background()); + + // the common controls follow the immersive dark flag per window: + // flag the control windows too so the status bar and the toolbars + // retheme natively (pre windows 10 1903 the flags are no-ops and the + // owner drawn panes / our strip painting carry the dark ui alone). + if (_viv_status_hwnd) + { + os_dark_titlebar(_viv_status_hwnd,dark); + + // the status bar follows the theme both ways: the dark explorer + // class in the dark ui, the light class back on the flip (the bar + // would otherwise keep carrying the dark class in the light ui). + if (dark) + { + os_dark_window_theme(_viv_status_hwnd); + } + else + { + os_light_window_theme(_viv_status_hwnd); + } + + InvalidateRect(_viv_status_hwnd,0,FALSE); + } + + + // the strip repaints through its own latch (the metrics are theme + // independent, so a flip never re-measures). + _viv_toolbar_set_dark(dark); + + // the remade menu bar repaints on the flip: its layout is theme + // independent, so no re-measure and no owner draw toggling. + _viv_menubar_repaint(); + + // the strip metrics are theme independent: the on size sweep right + // below re-lays the strip against the current client width. + _viv_on_size(); + + // the open dialogs re-theme live: the options dialog is usually on + // screen when its own dark mode combo changes the setting. + _viv_dark_dialogs_refresh(); + + // retheme the menu bar: a frame change repaints the non client area + // after the app mode switch (the menus retheme on the next open). + SetWindowPos(_viv_hwnd,0,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_FRAMECHANGED); + + zoomui_set_dark(dark); + + + // every flip repaints the whole window: the per-control + // InvalidateRect calls above cover their own windows, but a flip + // that lands between partial paints left stale light pixels on the + // rebar strip and the client canvas (the field report: the white + // band right of the toolbar until a manual resize or refresh). the + // startup call is free - nothing has painted yet. + InvalidateRect(_viv_hwnd,0,FALSE); + + if (repaint) + { + // forced repaint callers also sweep the children now instead of + // waiting for the message loop. the frame joins the sweep: without + // rdw_frame the official semantics keep the non client area out of + // the immediate update, the pending wm_ncpaint gets consumed without + // painting, the dark gap fill that lives in that message never runs + // and the menu bar keeps the system light strip until a manual resize + // or refresh - the white band the field caught on the flip. + RedrawWindow(_viv_hwnd,0,0,RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN | RDW_FRAME); + } +} +int _viv_is_window_maximized(HWND hwnd) +{ + // are we minimized with the WPF_RESTORETOMAXIMIZED flag set? + if (IsIconic(hwnd)) + { + WINDOWPLACEMENT wp; + + // IsZoomed does not work when the window is minimized. + // its ok to use GetWindowPlacement here as we do not touch the normal rect. + wp.length = sizeof(WINDOWPLACEMENT); + GetWindowPlacement(hwnd,&wp); + + if (wp.flags & WPF_RESTORETOMAXIMIZED) + { + return 1; + } + } + + if (IsZoomed(hwnd)) + { + return 1; + } + + return 0; +} +void _viv_update_ontop(void) +{ + int is_top_most; + + is_top_most = 0; + + switch(config_ontop) + { + case 1: + is_top_most = 1; + break; + + case 2: + is_top_most = (_viv_is_slideshow) || ((_viv_frame_count > 1) && (_viv_animation_play)); + break; + } + + SetWindowPos(_viv_hwnd,is_top_most ? HWND_TOPMOST : HWND_NOTOPMOST,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE); +} +void _viv_update_prevent_sleep(void) +{ + BYTE _is_prevent_sleep; + + _is_prevent_sleep = 0; + + if (config_prevent_sleep) + { + if ((_viv_is_slideshow) || (_viv_is_animation_timer)) + { + _is_prevent_sleep = 1; + } + } + + // _is_prevent_sleep changed? + if (!!_viv_is_prevent_sleep != !!_is_prevent_sleep) + { + if (os_SetThreadExecutionState) + { + os_SetThreadExecutionState(_is_prevent_sleep ? (ES_CONTINUOUS | ES_DISPLAY_REQUIRED | ES_SYSTEM_REQUIRED) : ES_CONTINUOUS); + } + + _viv_is_prevent_sleep = _is_prevent_sleep; + } +} +void _viv_status_show(int show) +{ + if (show) + { + if (!_viv_status_hwnd) + { + // WS_EX_COMPOSITED stops flickering issues + _viv_status_hwnd = os_CreateWindowEx( + WS_EX_COMPOSITED, + STATUSCLASSNAMEA, + "", + WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_CHILD | SBARS_SIZEGRIP | WS_VISIBLE, + 0,0,0,0, + _viv_hwnd,(HMENU)VIV_ID_STATUS,os_hinstance,NULL); + + _viv_old_status_proc = os_set_window_proc(_viv_status_hwnd,_viv_status_proc); + + // the strip rides the menu font (the toolbar and the menu bar + // ride it too): an unpinned bar runs on whatever the common + // control defaults to, which scales but does not match the + // strip basis. the pane paint, the pane width measurement and + // the in-place zoom editor all read the font back through + // wm_getfont, so one pin fixes them together. + SendMessage(_viv_status_hwnd,WM_SETFONT,(WPARAM)_viv_menu_font(),MAKELPARAM(TRUE,0)); + + // a fresh bar starts with empty panes: flush the text store + // (handles can be recycled, so the identity check alone is not + // enough). + os_zero_memory(_viv_status_part_text,sizeof(_viv_status_part_text)); + + // pick up the current dark flags: the bar can be created long + // after the last theme switch. + if (_viv_is_dark()) + { + os_dark_titlebar(_viv_status_hwnd,1); + + os_dark_window_theme(_viv_status_hwnd); + } + } + } + else + { + if (_viv_status_hwnd) + { + DestroyWindow(_viv_status_hwnd); + + _viv_status_hwnd = 0; + + os_zero_memory(_viv_status_part_text,sizeof(_viv_status_part_text)); + } + } + + _viv_on_size(); +} +void _viv_controls_show(int show) +{ + if (show) + { + if (!_viv_toolbar_high()) + { + // the remade strip: one self drawn window, the comctl toolbar, + // its image list and the pinned widths are gone. + _viv_toolbar_create(_viv_hwnd); + } + } + else + { + _viv_toolbar_destroy(); + } + + _viv_on_size(); +} +// the playlist position of the loaded file, for the index pane. the walk +// is cached on the fd pointer, so a steady image costs one compare. +static int _viv_status_nav_index(void) +{ + static const WIN32_FIND_DATA *last_fd; + static int last_index; + _viv_playlist_t *item; + int index; + + if (_viv_playlist_count <= 1) + { + return 0; + } + + if ((last_fd == _viv_frame_fd) && (last_index)) + { + return last_index; + } + + index = 1; + + for(item=_viv_playlist_start;item;item=item->next,index++) + { + if ((&item->fd == _viv_frame_fd) || (string_compare(item->fd.cFileName,_viv_frame_fd->cFileName) == 0)) + { + last_fd = _viv_frame_fd; + last_index = index; + + return index; + } + } + + last_fd = _viv_frame_fd; + last_index = 0; + + return 0; +} + +void _viv_status_update(void) +{ + if (_viv_status_hwnd) + { + int part_array[_VIV_STATUS_PART_MAX]; + RECT rect; + wchar_t widebuf[STRING_SIZE]; + wchar_t highbuf[STRING_SIZE]; + wchar_t dimension_buf[STRING_SIZE]; + wchar_t frame_buf[STRING_SIZE]; + wchar_t pixel_pos_buf[STRING_SIZE]; + wchar_t pixel_rgb_buf[STRING_SIZE]; + wchar_t preload_buf[STRING_SIZE]; + wchar_t zoom_buf[STRING_SIZE]; + wchar_t date_buf[STRING_SIZE]; + HDC hdc; + int dimension_wide; + int frame_wide; + int preload_wide; + int pixel_pos_wide; + int pixel_rgb_wide; + int zoom_wide; + int date_wide; + int minwide; + + GetClientRect(_viv_hwnd,&rect); + + *zoom_buf = 0; + *preload_buf = 0; + *pixel_pos_buf = 0; + *pixel_rgb_buf = 0; + + if ((_viv_image_wide) && (_viv_image_high)) + { + string_format_number(widebuf,_viv_image_wide); + string_format_number(highbuf,_viv_image_high); + + string_copy(dimension_buf,widebuf); + string_cat_utf8(dimension_buf,(const utf8_t *)" x "); + string_cat(dimension_buf,highbuf); + } + else + { + string_copy_utf8_string(dimension_buf,(const utf8_t *)""); + } + + // the zoom pane text. shown whenever an image is loaded. + if ((_viv_image_wide) && (_viv_image_high)) + { + string_printf(zoom_buf,localization_get_string(LOCALIZATION_ID_STATUS_BAR_POS_ZOOM_FORMAT),_viv_zoom_percent()); + } + + if (*_viv_frame_fd->cFileName) + { + LARGE_INTEGER size; + + size.HighPart = _viv_frame_fd->nFileSizeHigh; + size.LowPart = _viv_frame_fd->nFileSizeLow; + + if (size.QuadPart) + { + NUMBERFMT numberfmt; + localization_id_t size_unit_id; + + if (*dimension_buf) + { + string_cat_utf8(dimension_buf," "); + } + + string_cat_utf8(dimension_buf,"("); + + // adaptive size units: a 4 gb scan used to show as a row of comma + // separated kilobytes. pick b / kb / mb / gb by magnitude, with + // one decimal place above a megabyte (integer math only). + if (size.QuadPart < 1024) + { + string_format_number(widebuf,size.QuadPart); + + size_unit_id = LOCALIZATION_ID_STATUS_BAR_SIZE_BYTES_FORMAT; + } + else + if (size.QuadPart < ((LONGLONG)1024 * 1024)) + { + string_format_number(widebuf,(size.QuadPart + 1023) / 1024); + + size_unit_id = LOCALIZATION_ID_STATUS_BAR_SIZE_KB_FORMAT; + } + else + { + VIV_UINT64 divisor; + VIV_UINT64 tenths; + DWORD whole; + DWORD frac; + + divisor = (size.QuadPart < ((LONGLONG)1024 * 1024 * 1024)) ? ((VIV_UINT64)1024 * 1024) : ((VIV_UINT64)1024 * 1024 * 1024); + + size_unit_id = (divisor == ((VIV_UINT64)1024 * 1024)) ? LOCALIZATION_ID_STATUS_BAR_SIZE_MB_FORMAT : LOCALIZATION_ID_STATUS_BAR_SIZE_GB_FORMAT; + + // one decimal place, rounded: (bytes * 10 + divisor / 2) / divisor + tenths = (((VIV_UINT64)size.QuadPart * 10) + (divisor / 2)) / divisor; + whole = (DWORD)(tenths / 10); + frac = (DWORD)(tenths % 10); + + string_format_number(widebuf,whole); + string_cat_utf8(widebuf,(const utf8_t *)"."); + widebuf[string_get_length(widebuf)] = (wchar_t)('0' + frac); + widebuf[string_get_length(widebuf) + 1] = 0; + } + + numberfmt.NumDigits = (size.QuadPart < ((LONGLONG)1024 * 1024)) ? 0 : 1; + numberfmt.LeadingZero = 0; + numberfmt.Grouping = 3; + numberfmt.lpThousandSep = L","; + numberfmt.lpDecimalSep = L"."; + numberfmt.NegativeOrder = 0; + + GetNumberFormat(LOCALE_USER_DEFAULT,0,widebuf,&numberfmt,highbuf,STRING_SIZE); + + string_cat(dimension_buf,highbuf); + string_cat_utf8(dimension_buf,localization_get_string(size_unit_id)); + string_cat_utf8(dimension_buf,")"); + } + } + + if (_viv_frame_count > 1) + { + int frame_pos; + string_format_number(highbuf,_viv_frame_count); + + string_copy_utf8_string(frame_buf,(const utf8_t *)""); + + if (config_frame_minus) + { + frame_pos = _viv_frame_count - (_viv_frame_position); + string_cat_utf8(frame_buf,(const utf8_t *)"- "); + } + else + { + frame_pos = _viv_frame_position + 1; + } + + string_format_number(widebuf,frame_pos); + + string_cat(frame_buf,widebuf); + string_cat_utf8(frame_buf,(const utf8_t *)" / "); + string_cat(frame_buf,highbuf); + } + else + { + string_copy_utf8_string(frame_buf,(const utf8_t *)""); + } + + // this is just noise.. + + if ((_viv_load_is_preload) && (_viv_preload_state == 0) && (!_viv_should_activate_preload_on_load) && (!_viv_load_image_terminate) && (!_viv_preload_frame_loaded_count)) + { + string_copy_utf8_string(preload_buf,localization_get_string(LOCALIZATION_ID_STATUS_BAR_PRELOAD)); + } + + // the file time pane: the local last-modified stamp of the loaded + // file (the remake status row: rgb and the date at the right edge). + *date_buf = 0; + + if (*_viv_frame_fd->cFileName) + { + FILETIME local_filetime; + SYSTEMTIME systemtime; + + if (FileTimeToLocalFileTime(&_viv_frame_fd->ftLastWriteTime,&local_filetime) && + FileTimeToSystemTime(&local_filetime,&systemtime)) + { + wchar_t time_buf[64]; + int date_len; + + // the localized stamp: the system formatters take wide + // formats (the old wide-literal printf went through the + // narrow parser and rendered a lone "0"). + date_buf[0] = 0; + + GetDateFormatW(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&systemtime,0,date_buf,STRING_SIZE - 1); + + date_len = string_get_length(date_buf); + + if ((date_len) && (date_len < STRING_SIZE - 2)) + { + date_buf[date_len] = L' '; + date_buf[date_len + 1] = 0; + } + + GetTimeFormatW(LOCALE_USER_DEFAULT,TIME_NOSECONDS,&systemtime,0,time_buf,64); + + string_cat(date_buf,time_buf); + } + } + + if (config_pixel_info) + { + if ((_viv_src_pixel_x >= 0) && (_viv_src_pixel_y >= 0)) + { + string_printf(pixel_pos_buf,"POS: %d,%d",_viv_src_pixel_x,_viv_src_pixel_y); + string_printf(pixel_rgb_buf,localization_get_string(LOCALIZATION_ID_STATUS_BAR_RGB_FORMAT),_viv_src_pixel_r,_viv_src_pixel_g,_viv_src_pixel_b); + } + } + + date_wide = 0; + dimension_wide = 0; + frame_wide = 0; + preload_wide = 0; + pixel_pos_wide = 0; + pixel_rgb_wide = 0; + zoom_wide = 0; + minwide = (72 * os_logical_wide) / 96; + + hdc = GetDC(_viv_status_hwnd); + if (hdc) + { + HFONT hfont; + + hfont = (HFONT)SendMessage(_viv_status_hwnd,WM_GETFONT,0,0); + if (hfont) + { + SIZE size; + HGDIOBJ last_font; + + last_font = SelectObject(hdc,hfont); + + if (GetTextExtentPoint32(hdc,dimension_buf,string_get_length(dimension_buf),&size)) + { + dimension_wide = size.cx + GetSystemMetrics(SM_CXEDGE) * 5; + + if (dimension_wide < minwide) + { + dimension_wide = minwide; + } + } + + if (*frame_buf) + { + if (GetTextExtentPoint32(hdc,frame_buf,string_get_length(frame_buf),&size)) + { + frame_wide = size.cx + GetSystemMetrics(SM_CXEDGE) * 5; + + if (frame_wide < minwide) + { + frame_wide = minwide; + } + } + } + + if (*preload_buf) + { + if (GetTextExtentPoint32(hdc,preload_buf,string_get_length(preload_buf),&size)) + { + preload_wide = size.cx + GetSystemMetrics(SM_CXEDGE) * 5; + } + } + + if (*pixel_pos_buf) + { + if (GetTextExtentPoint32(hdc,pixel_pos_buf,string_get_length(pixel_pos_buf),&size)) + { + pixel_pos_wide = size.cx + GetSystemMetrics(SM_CXEDGE) * 5; + } + } + + if (*pixel_rgb_buf) + { + if (GetTextExtentPoint32(hdc,pixel_rgb_buf,string_get_length(pixel_rgb_buf),&size)) + { + pixel_rgb_wide = size.cx + GetSystemMetrics(SM_CXEDGE) * 5; + } + } + if (*zoom_buf) + { + if (GetTextExtentPoint32(hdc,zoom_buf,string_get_length(zoom_buf),&size)) + { + zoom_wide = size.cx + GetSystemMetrics(SM_CXEDGE) * 5; + + if (zoom_wide < minwide) + { + zoom_wide = minwide; + } + } + } + + // the stamp measures on its own: a failed load with a + // filename still owns the date pane (it used to hide + // behind the zoom pane's block). + if (*date_buf) + { + if (GetTextExtentPoint32(hdc,date_buf,string_get_length(date_buf),&size)) + { + date_wide = size.cx + GetSystemMetrics(SM_CXEDGE) * 5; + } + } + + SelectObject(hdc,last_font); + } + + ReleaseDC(_viv_status_hwnd,hdc); + } + + // add size box + dimension_wide += GetSystemMetrics(SM_CXVSCROLL) + GetSystemMetrics(SM_CXBORDER); + + { + int parti; + int avail_wide; + int flex_wide; + + parti = 0; + + avail_wide = rect.right - rect.left; + + if (avail_wide < 0) + { + avail_wide = 0; + } + + // the preload pane joins the zoom pane in the left cluster only + // while a preload is actually running, and is capped at a quarter + // of the bar: a long localization must never eat the message pane. + if (preload_wide > (avail_wide / 4)) + { + preload_wide = avail_wide / 4; + } + + // the resolution pane is pinned to the bottom right and is never + // dropped. when a huge image (or a tiny window) makes the panes + // wider than the bar, the optional right panes give way, widest + // last, so the dimension text clips instead of vanishing off the + // edge of the window. + while ((zoom_wide + preload_wide + dimension_wide + frame_wide + pixel_pos_wide + pixel_rgb_wide + date_wide > avail_wide) + && (frame_wide || pixel_rgb_wide || pixel_pos_wide || date_wide)) + { + if (frame_wide) + { + frame_wide = 0; + } + else + if (pixel_rgb_wide) + { + pixel_rgb_wide = 0; + } + else + if (date_wide) + { + date_wide = 0; + } + else + { + pixel_pos_wide = 0; + } + } + + if (zoom_wide + preload_wide + dimension_wide > avail_wide) + { + // last resort: clip the resolution pane itself. it stays + // visible at the bottom right with an ellipsized text. + dimension_wide = avail_wide - zoom_wide - preload_wide; + + if (dimension_wide < 0) + { + dimension_wide = 0; + } + } + + // pane 0: the zoom pane (the in place zoom editor's home). + part_array[parti] = zoom_wide; + parti++; + + // pane 1 (when preloading): the preload indicator, on the left. + if (preload_wide) + { + part_array[parti] = part_array[parti - 1] + preload_wide; + parti++; + } + + // the message pane flexes between the left and right clusters. + flex_wide = avail_wide - zoom_wide - preload_wide - dimension_wide - frame_wide - pixel_pos_wide - pixel_rgb_wide - date_wide; + + if (flex_wide < 0) + { + flex_wide = 0; + } + + part_array[parti] = part_array[parti - 1] + flex_wide; + parti++; + + if (pixel_pos_wide) + { + part_array[parti] = part_array[parti - 1] + pixel_pos_wide; + parti++; + } + + if (pixel_rgb_wide) + { + part_array[parti] = part_array[parti - 1] + pixel_rgb_wide; + parti++; + } + + if (frame_wide) + { + part_array[parti] = part_array[parti - 1] + frame_wide; + parti++; + } + + if (date_wide) + { + part_array[parti] = part_array[parti - 1] + date_wide; + parti++; + } + + // the last pane: the file date, pinned to the bottom right (a + // -1 right edge extends to the window edge). + // the last pane: the resolution, pinned to the bottom right (a + // -1 right edge extends to the window edge). + part_array[parti] = -1; + parti++; + + SendMessage(_viv_status_hwnd,SB_SETPARTS,parti,(LPARAM)part_array); + } + + { + wchar_t *text; + wchar_t text_buf[STRING_SIZE]; + + text = L""; + + if (_viv_status_temp_text) + { + text = _viv_status_temp_text; + } + else + if ((_viv_load_image_thread) && ((!_viv_load_is_preload) || (_viv_should_activate_preload_on_load))) + { + string_copy_utf8_string(text_buf,localization_get_string(LOCALIZATION_ID_STATUS_BAR_LOADING)); + text = text_buf; + } + else + if (_viv_file_not_found) + { + string_copy_utf8_string(text_buf,localization_get_string(LOCALIZATION_ID_STATUS_BAR_FILE_NOT_FOUND)); + text = text_buf; + } + else + if (_viv_load_failed) + { + string_copy_utf8_string(text_buf,localization_get_string(LOCALIZATION_ID_STATUS_BAR_FAILED_TO_LOAD_IMAGE)); + text = text_buf; + } + else + if (_viv_is_slideshow) + { + string_copy_utf8_string(text_buf,localization_get_string(LOCALIZATION_ID_STATUS_BAR_SLIDESHOW_PLAYING)); + text = text_buf; + } + else + if (*_viv_frame_fd->cFileName) + { + int nav_index; + + nav_index = _viv_status_nav_index(); + + if (nav_index > 0) + { + string_printf(text_buf,localization_get_string(LOCALIZATION_ID_STATUS_BAR_POSITION_FORMAT),nav_index,_viv_playlist_count); + string_cat_utf8(text_buf,(const utf8_t *)" "); + string_cat(text_buf,_viv_frame_fd->cFileName); + } + else + { + string_copy(text_buf,_viv_frame_fd->cFileName); + } + + text = text_buf; + } + + // pane 0 is the zoom pane; the preload pane (when active) + // follows it and the message pane takes the rest of the left + // cluster. + _viv_status_set(0,zoom_buf); + + if (preload_wide) + { + _viv_status_set(1,preload_buf); + + _viv_status_set(2,text); + } + else + { + _viv_status_set(1,text); + } + } + + { + int parti; + + // the right cluster starts after the message pane; the widths + // (not the buffers) decide which panes exist so the layout and + // the texts can never drift apart. + parti = preload_wide ? 3 : 2; + + if (pixel_pos_wide) + { + _viv_status_set(parti,pixel_pos_buf); + parti++; + } + + if (pixel_rgb_wide) + { + _viv_status_set(parti,pixel_rgb_buf); + parti++; + } + + if (frame_wide) + { + _viv_status_set(parti,frame_buf); + parti++; + } + + if (date_wide) + { + _viv_status_set(parti,date_buf); + parti++; + } + + _viv_status_set(parti,dimension_buf); + parti++; + } + } +} +static void _viv_status_set(int part,const wchar_t *text) +{ + static HWND part_text_hwnd; + static BYTE part_live[_VIV_STATUS_PART_MAX]; + + if ((part < 0) || (part >= _VIV_STATUS_PART_MAX)) + { + return; + } + + // the store must match the live control: a recreated status bar (or a + // hidden one: updates keep flowing) starts with empty panes, so the + // store flushes whenever the window identity changes - otherwise an + // unchanged text would skip its SB_SETTEXTW and leave the pane blank. + if (part_text_hwnd != _viv_status_hwnd) + { + part_text_hwnd = _viv_status_hwnd; + + os_zero_memory(_viv_status_part_text,sizeof(_viv_status_part_text)); + os_zero_memory(part_live,sizeof(part_live)); + } + + // a pane the control was never told about never draws: the empty-bar + // case showed the light comctl face because no WM_DRAWITEM fired at + // all (the bottom white bar). send once per pane per bar so the owner + // draw fill owns the strip even when every text is empty. + if ((string_compare(_viv_status_part_text[part],text) != 0) || (!part_live[part])) + { + // SBT_OWNERDRAW: the pane text lives in our store; the draw + // reads the pane index from itemID (the official carrier), + // with this lparam as the itemData fallback. + string_copy(_viv_status_part_text[part],text); + + SendMessage(_viv_status_hwnd,SB_SETTEXTW,(WPARAM)(part | SBT_OWNERDRAW),(LPARAM)part); + + part_live[part] = 1; + } +} +// owner draw one status pane: the dark palette for the dark ui, a +// faithful light replica otherwise. the texts come from the pane store; +// an overlong text (a capped resolution pane) ellipsizes instead of +// bleeding into the next pane. +int _viv_status_draw_item(DRAWITEMSTRUCT *draw_item) +{ + HDC hdc; + RECT text_rect; + HFONT hfont; + HGDIOBJ last_font; + COLORREF text_color; + int part; + + if (!draw_item) + { + return 0; + } + + hdc = draw_item->hDC; + + if (!hdc) + { + return 0; + } + + // comctl carries the pane index in itemID - the official carrier + // for status bar draws. the itemData holds whatever lparam the + // pane's SB_SETTEXTW stored (ours: the same index), so it stays the + // compatibility fallback for a draw that did not come from our own + // send. + part = (int)draw_item->itemID; + + if ((part < 0) || (part >= _VIV_STATUS_PART_MAX)) + { + part = (int)draw_item->itemData; + } + + if ((part < 0) || (part >= _VIV_STATUS_PART_MAX)) + { + // an unresolvable pane still owns its pixels: paint the strip + // face so a mystery draw reads as a quiet pane instead of the + // light comctl slab (the rc.11 bottom white bar was exactly a + // draw nobody answered). + FillRect(hdc,&draw_item->rcItem,viv_theme_brush(VIV_TK_CHROME)); + + return 1; + } + + // the strip face and text ride the chrome tokens - the same pair + // the erase, the grip and the toolbar ride, in both themes. + FillRect(hdc,&draw_item->rcItem,viv_theme_brush(VIV_TK_CHROME)); + + text_color = viv_theme_color(VIV_TK_TEXT); + + // draw the text inset like the native panes. + text_rect = draw_item->rcItem; + text_rect.left += GetSystemMetrics(SM_CXEDGE) * 2; + + hfont = (HFONT)SendMessage(_viv_status_hwnd,WM_GETFONT,0,0); + last_font = 0; + + if (hfont) + { + last_font = SelectObject(hdc,hfont); + } + + SetBkMode(hdc,TRANSPARENT); + SetTextColor(hdc,text_color); + + DrawTextW(hdc,_viv_status_part_text[part],-1,&text_rect,DT_LEFT|DT_VCENTER|DT_SINGLELINE|DT_END_ELLIPSIS); + + if (last_font) + { + SelectObject(hdc,last_font); + } + + return 1; +} +int _viv_get_status_high(void) +{ + if (_viv_status_hwnd) + { + RECT rect; + + GetWindowRect(_viv_status_hwnd,&rect); + + return rect.bottom - rect.top; + } + + return 0; +} +// the top chrome stack: the menubar plus the toolbar strip, both client +// side children that own the top of the client area. the image viewport +// starts below them (and above the status bar); the helpers return 0 for +// hidden strips, so fullscreen collapses this to the plain client top. +int _viv_get_view_top(void) +{ + return _viv_menubar_high() + _viv_get_controls_high(); +} + +int _viv_get_controls_high(void) +{ + // the window fit math only wants the strip height; the strip owns + // the touch scaling now. + return _viv_toolbar_high(); +} +static LRESULT CALLBACK _viv_fullscreen_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) +{ + switch(msg) + { + case WM_PAINT: + { + RECT rect; + PAINTSTRUCT ps; + + GetClientRect(hwnd,&rect); + BeginPaint(hwnd,&ps); + /* + { + HBRUSH hbrush; + + hbrush = CreateSolidBrush(RGB(config_fullscreen_background_color_r,config_fullscreen_background_color_g,config_fullscreen_background_color_b)); + + if (hbrush) + { + FillRect(ps.hdc,&rect,hbrush); + + DeleteObject(hbrush); + } + } + */ + EndPaint(hwnd,&ps); + break; + } + + case WM_ERASEBKGND: + return 1; + } + + return DefWindowProc(hwnd,msg,wParam,lParam); +} +void _viv_status_set_temp_text(wchar_t *text) +{ + if (_viv_status_temp_text) + { + KillTimer(_viv_hwnd,VIV_ID_STATUS_TEMP_TEXT_TIMER); + + mem_free(_viv_status_temp_text); + + _viv_status_temp_text = 0; + } + + if (text) + { + _viv_status_temp_text = string_alloc(text); + } + + _viv_status_update(); + + if (_viv_status_temp_text) + { + SetTimer(_viv_hwnd,VIV_ID_STATUS_TEMP_TEXT_TIMER,3000,0); + } +} +void _viv_status_update_temp_pos_zoom(void) +{ + // the zoom percent now lives in its own always visible status bar pane, + // so the old three second temporary text flash is gone: a plain status + // refresh repaints the pane. + _viv_status_update(); +} +void _viv_status_update_slideshow_rate(void) +{ + wchar_t wbuf[STRING_SIZE]; + const utf8_t *res; + int r; + + if ((config_slideshow_rate / 60000) && ((config_slideshow_rate % 60000) == 0)) + { + r = config_slideshow_rate / 60000; + res = localization_get_string(LOCALIZATION_ID_STATUS_BAR_MINUTES); + } + else + if ((config_slideshow_rate / 1000) && ((config_slideshow_rate % 1000) == 0)) + { + r = config_slideshow_rate / 1000; + res = localization_get_string(LOCALIZATION_ID_STATUS_BAR_SECONDS); + } + else + { + r = config_slideshow_rate; + res = localization_get_string(LOCALIZATION_ID_STATUS_BAR_MILLISECONDS); + } + + string_printf(wbuf,localization_get_string(LOCALIZATION_ID_STATUS_BAR_SLIDESHOW_RATE_FORMAT),r,res); + + _viv_status_set_temp_text(wbuf); +} +void _viv_zoomui_update(void) +{ + if (!zoomui_is_created()) + { + zoomui_init(_viv_hwnd); + + // layout the new zoom controls. + _viv_on_size(); + } + + // fullscreen shows the six button overlay bar (auto hiding when + // idle); windowed mode keeps the two button pill. + zoomui_set_fullscreen(_viv_is_fullscreen); + + zoomui_show(config_show_zoom_controls); +} +void _viv_show_cursor(void) +{ + if (_viv_is_hide_cursor_timer) + { + KillTimer(_viv_hwnd,VIV_ID_HIDE_CURSOR_TIMER); + + _viv_is_hide_cursor_timer = 0; + } + + if (!_viv_is_cursor_shown) + { + ShowCursor(TRUE); + + _viv_is_cursor_shown = 1; + } +} +void _viv_hide_cursor(void) +{ + if (_viv_is_hide_cursor_timer) + { + KillTimer(_viv_hwnd,VIV_ID_HIDE_CURSOR_TIMER); + + _viv_is_hide_cursor_timer = 0; + } + + if (_viv_is_cursor_shown) + { + ShowCursor(FALSE); + + _viv_is_cursor_shown = 0; + } +} +int _viv_should_show_cursor(void) +{ + if (!_viv_in_popup_menu) + { + if ((*_viv_current_fd->cFileName) && (!_viv_file_not_found) && (!_viv_load_failed)) + { + if (GetForegroundWindow() == _viv_hwnd) + { + if (_viv_is_mouseover) + { + if (!GetCapture()) + { + if ((_viv_is_fullscreen) || (config_windowed_hide_cursor)) + { + // if (!((_viv_is_alt) && (_viv_is_tracking_mouse))) + { + return 0; + } + } + } + } + } + } + } + + return 1; +} +void _viv_update_show_cursor(void) +{ + if (_viv_should_show_cursor()) + { + _viv_show_cursor(); + } + else + { + _viv_start_hide_cursor_timer(); + } +} +void _viv_start_hide_cursor_timer(void) +{ + if (!_viv_is_hide_cursor_timer) + { + SetTimer(_viv_hwnd,VIV_ID_HIDE_CURSOR_TIMER,_VIV_HIDE_CURSOR_DELAY,0); + + _viv_is_hide_cursor_timer = 1; + } +} diff --git a/src/viv_chrome.h b/src/viv_chrome.h new file mode 100644 index 00000000..e2ac6513 --- /dev/null +++ b/src/viv_chrome.h @@ -0,0 +1,59 @@ +// +// Copyright 2025 voidtools / David Carpenter +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +// VoidImageViewer +// viv_chrome.h - window dressing: rebar, toolbar, status bar, menu bar, fullscreen, cursors. +#ifndef VIV_CHROME_H +#define VIV_CHROME_H + +#include "viv.h" + +// exported to other domains / the viv.c core +void _viv_update_title(void); +void _viv_on_size(void); +HBRUSH _viv_dark_chrome_brush(int which); +int _viv_paint_begin(HDC hdc,int wide,int high); +void _viv_paint_kill(void); +void _viv_toggle_fullscreen(void); +HFONT _viv_menu_font(void); +void _viv_menu_font_drop(void); +void _viv_apply_dark_mode(int repaint); +int _viv_is_window_maximized(HWND hwnd); +void _viv_update_ontop(void); +void _viv_update_prevent_sleep(void); +void _viv_status_show(int show); +void _viv_controls_show(int show); +void _viv_status_update(void); +int _viv_status_draw_item(DRAWITEMSTRUCT *draw_item); +int _viv_get_status_high(void); +int _viv_get_controls_high(void); +int _viv_get_view_top(void); +void _viv_status_set_temp_text(wchar_t *text); +void _viv_status_update_temp_pos_zoom(void); +void _viv_status_update_slideshow_rate(void); +void _viv_zoomui_update(void); +void _viv_show_cursor(void); +void _viv_hide_cursor(void); +int _viv_should_show_cursor(void); +void _viv_update_show_cursor(void); +void _viv_start_hide_cursor_timer(void); + +#endif diff --git a/src/viv_dark.c b/src/viv_dark.c new file mode 100644 index 00000000..46cede47 --- /dev/null +++ b/src/viv_dark.c @@ -0,0 +1,942 @@ +// +// Copyright 2025 voidtools / David Carpenter +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +// VoidImageViewer +// viv_dark.c - dark dialog infrastructure (subclassing, theming, drawing). +// Pure physical move from viv.c (R70 split): bodies are unchanged. +#include "viv.h" +#include "viv_state.h" +#include "viv_dark.h" +#include "viv_chrome.h" +#include "viv_dialogs.h" +#include "viv_render.h" + +// forward declarations (order preserved from viv.c) +HBRUSH _viv_dialog_dark_brush(void); +static int _viv_dialog_dark_combo_item_height(HWND hwnd); +static BOOL CALLBACK _viv_dark_dialog_children(HWND hwnd,LPARAM lParam); +void _viv_dark_dialog(HWND hwnd); +static BOOL CALLBACK _viv_dark_dialogs_enum(HWND hwnd,LPARAM lParam); +void _viv_dark_dialogs_refresh(void); +static INT_PTR _viv_dialog_dark_ctlcolor(HDC hdc); +static int _viv_dialog_dark_erase(HWND hwnd,HDC hdc); +static INT_PTR _viv_dialog_dark_draw_item(HWND hwnd,DRAWITEMSTRUCT *draw_item); +static HANDLE _viv_dialog_dark_theme(HWND hwnd); +static void _viv_dialog_dark_theme_drop(HWND hwnd); +static int _viv_dialog_dark_glyph_state(int type,int check,UINT item_state); +static INT_PTR _viv_dialog_dark_notify(HWND hwnd,NMHDR *header); +INT_PTR _viv_dialog_dark_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); + + +// the dark dialog background brush (lazy created, deleted at kill). +HBRUSH _viv_dialog_dark_brush(void) +{ + if (!_viv_dialog_dark_hbrush) + { + _viv_dialog_dark_hbrush = CreateSolidBrush(viv_theme_color(VIV_TK_FACE)); + } + + return _viv_dialog_dark_hbrush; +} +// give a dialog the dark chrome: a dark title bar and the dark explorer +// control style. call from WM_INITDIALOG. +// the dark explorer style does not cascade from a dialog to its child +// controls: every button, combobox, listbox and edit must opt in +// individually (allow dark mode, then the dark theme class) or it keeps +// drawing with the light visual style on the dark background. this is +// what made the options pages look half themed (dark background, light +// comboboxes and check glyphs). +// the owner drawn combo item height at the control font. +static int _viv_dialog_dark_combo_item_height(HWND hwnd) +{ + HDC hdc; + HFONT font; + HFONT old_font; + TEXTMETRICW tm; + int high; + + high = (16 * os_logical_high) / 96; + + hdc = GetDC(hwnd); + + if (hdc) + { + font = (HFONT)SendMessage(hwnd,WM_GETFONT,0,0); + + old_font = font ? (HFONT)SelectObject(hdc,font) : 0; + + os_zero_memory(&tm,sizeof(tm)); + + if (GetTextMetricsW(hdc,&tm)) + { + high = tm.tmHeight + ((6 * os_logical_high) / 96); + } + + if (old_font) + { + SelectObject(hdc,old_font); + } + + ReleaseDC(hwnd,hdc); + } + + return high; +} +static BOOL CALLBACK _viv_dark_dialog_children(HWND hwnd,LPARAM lParam) +{ + wchar_t class_name[64]; + LONG_PTR style; + int dark; + + (void)lParam; + + dark = _viv_is_dark(); + + // the immersive flag and the theme class have to follow the app theme + // together: the dark classes painted on a light dialog leave black + // fields, black frames and black buttons on the light face (the field + // report: the light options page showed black comboboxes and black + // select-all buttons). + os_allow_dark_mode_for_window(hwnd,dark ? 1 : 0); + + class_name[0] = 0; + + if (GetClassNameW(hwnd,class_name,64)) + { + if (string_compare(class_name,L"ComboBox") == 0) + { + if (dark) + { + // comboboxes have no parts in the darkmode explorer class: the dark + // dialogs kept light frames and arrows on 1903+ builds. the common + // dialog class carries the dark combo parts there, and the owner + // drawn items below carry the field and the list rows everywhere. + os_dark_combobox_theme(hwnd); + } + else + { + // back to the standard light class: the control may carry the + // dark class from an earlier dark state of the same open dialog. + os_light_window_theme(hwnd); + } + } + else + if (string_compare(class_name,L"SysTreeView32") == 0) + { + // the tree never follows the dark explorer class for its item text: + // the theme draws the labels in its own gray, which reads as low + // contrast on the dark face (the field report). pin the face and the + // text color - the same values the options initdialog applies - and + // hand them back to the system on the light flip (0xffffffff is + // clr_default). + SendMessage(hwnd,TVM_SETBKCOLOR,0,dark ? viv_theme_color(VIV_TK_FACE) : (COLORREF)0xFFFFFFFF); + SendMessage(hwnd,TVM_SETTEXTCOLOR,0,dark ? viv_theme_color(VIV_TK_TEXT) : (COLORREF)0xFFFFFFFF); + + if (dark) + { + os_dark_window_theme(hwnd); + } + else + { + os_light_window_theme(hwnd); + } + } + else + { + if (dark) + { + os_dark_window_theme(hwnd); + } + else + { + os_light_window_theme(hwnd); + } + } + + if (dark) + { + if (string_compare(class_name,L"Button") == 0) + { + int type; + + style = GetWindowLongPtr(hwnd,GWL_STYLE); + + type = (int)(style & BS_TYPEMASK); + + // push buttons owner draw on every build: the native dark button + // carries a light bottom edge (the field report called it a chin) + // and paints a hard rectangle that fights the rest of the dark + // chrome, while the flat face below matches the combo fields + // exactly. the glyph controls (checkboxes, radios) never flip: the + // owner draw bit sits in the bs_typemask field, so the flip + // replaces bs_autocheckbox itself and the automatic check state + // machine goes with it - clicks stop toggling, bm_getcheck reads + // zero forever and isdlgbuttonchecked sees a dead control (the + // withdrawn 1.1.09 build flipped them on every machine and the + // field report showed every options checkbox frozen in the dark + // ui; the same dead flip sat latent on the pre 1903 fallback). + // their faces paint through the custom draw path instead (see + // _viv_dialog_dark_notify): the themed button paints its own label + // color and the wm_ctlcolorstatic text never reaches it - the + // field report read black checkbox labels on the dark face (0.78:1 + // against the dialog color) - so the custom draw takes the whole + // face: the dark background, the theme glyph in its checked, mixed, + // hot and disabled states, the light label and the focus frame, + // with the skip traveling through dwlp_msgresult the dialog + // contract requires. the bitmap color swatches keep their own + // painting in every state. + if ((!(style & (BS_BITMAP | BS_ICON))) && ((type == BS_PUSHBUTTON) || (type == BS_DEFPUSHBUTTON))) + { + SetWindowLongPtr(hwnd,GWL_STYLE,(style & ~((LONG_PTR)BS_TYPEMASK)) | BS_OWNERDRAW); + + // the prop carries the original button type (the owner draw bit + // overwrites the type field, so the way back needs it). + SetPropW(hwnd,_VIV_DARK_OWNERDRAW_PROP,(HANDLE)(type + 1)); + + InvalidateRect(hwnd,0,TRUE); + } + } + else + if (string_compare(class_name,L"ComboBox") == 0) + { + // every windows build: even where the dark controls exist the + // explorer class carries no combo parts, so the field and the + // list rows always owner draw through the dialog dark handler. + style = GetWindowLongPtr(hwnd,GWL_STYLE); + + if (!(style & CBS_OWNERDRAWFIXED)) + { + int field_height; + + // the closed field height the control was created with: the + // flip must keep it exactly. an item height rebuilt from the + // font metrics drifts a few pixels at some dpis - the field + // then grows or shrinks against its label row and leaves a + // stray strip under the control (the field report: a chin + // under the dark combos and sizes that no longer matched + // the light ui). + field_height = (int)SendMessage(hwnd,CB_GETITEMHEIGHT,(WPARAM)-1,0); + + if (field_height > 0) + { + SetWindowLongPtr(hwnd,GWL_STYLE,style | CBS_OWNERDRAWFIXED); + + // a runtime flip does not resend the measure item message: set + // the item height directly (the selected field and the list rows) + // at the captured native height. + SendMessage(hwnd,CB_SETITEMHEIGHT,(WPARAM)-1,field_height); + SendMessage(hwnd,CB_SETITEMHEIGHT,(WPARAM)0,field_height); + + // the prop marks the flip and carries the captured height (the + // 0x100 base keeps it apart from the button type codes) for the + // measure item fallback. + SetPropW(hwnd,_VIV_DARK_OWNERDRAW_PROP,(HANDLE)(0x100 + field_height)); + + InvalidateRect(hwnd,0,TRUE); + } + } + } + } + else + { + // the ui went back to light: restore the system painting on the + // controls this module flipped. + if (GetPropW(hwnd,_VIV_DARK_OWNERDRAW_PROP)) + { + style = GetWindowLongPtr(hwnd,GWL_STYLE); + + if ((string_compare(class_name,L"Button") == 0) && (((int)(LONG_PTR)GetPropW(hwnd,_VIV_DARK_OWNERDRAW_PROP)) < 0x100)) + { + LONG_PTR type; + + type = (LONG_PTR)GetPropW(hwnd,_VIV_DARK_OWNERDRAW_PROP) - 1; + + // restore the original button type (the owner draw bit sat in + // the type field). + SetWindowLongPtr(hwnd,GWL_STYLE,(style & ~((LONG_PTR)BS_TYPEMASK)) | type); + } + else + if ((string_compare(class_name,L"ComboBox") == 0) && (((int)(LONG_PTR)GetPropW(hwnd,_VIV_DARK_OWNERDRAW_PROP)) >= 0x100)) + { + SetWindowLongPtr(hwnd,GWL_STYLE,style & ~((LONG_PTR)CBS_OWNERDRAWFIXED)); + } + + RemovePropW(hwnd,_VIV_DARK_OWNERDRAW_PROP); + + InvalidateRect(hwnd,0,TRUE); + } + } + } + + return TRUE; +} +// give a dialog the dark chrome: a dark title bar, the dark explorer +// control style and the same style on every child control. call from +// WM_INITDIALOG (the dialog manager creates the children before it). +void _viv_dark_dialog(HWND hwnd) +{ + // the win11 frame treatment for every dialog: rounded corners and a + // caption color that follows the chrome (a silent no-op earlier). + os_window_modern_chrome(hwnd,viv_theme_color(VIV_TK_CHROME)); + + if (_viv_is_dark()) + { + os_dark_titlebar(hwnd,1); + + os_dark_window_theme(hwnd); + + EnumChildWindows(hwnd,_viv_dark_dialog_children,0); + } + else + { + // the light ui hands the flipped controls back to the system and + // returns the dialog itself to the light chrome: the title bar and + // the control classes may carry the dark state from an earlier flip + // of the same open dialog. + os_dark_titlebar(hwnd,0); + + os_light_window_theme(hwnd); + + EnumChildWindows(hwnd,_viv_dark_dialog_children,0); + } +} +static BOOL CALLBACK _viv_dark_dialogs_enum(HWND hwnd,LPARAM lParam) +{ + wchar_t class_name[16]; + + (void)lParam; + + // the thread enumerator guarantees these windows belong to us: only + // the dialog windows need the refresh. + if ((GetClassNameW(hwnd,class_name,16)) && (string_compare(class_name,L"#32770") == 0)) + { + _viv_dark_dialog(hwnd); + + InvalidateRect(hwnd,0,TRUE); + } + + return TRUE; +} +void _viv_dark_dialogs_refresh(void) +{ + EnumThreadWindows(GetCurrentThreadId(),_viv_dark_dialogs_enum,0); +} +// dark color reply for the dialog control color messages (statics, edits +// and lists). returns the brush, or 0 to keep the default light painting. +static INT_PTR _viv_dialog_dark_ctlcolor(HDC hdc) +{ + if (_viv_is_dark()) + { + SetTextColor(hdc,viv_theme_color(VIV_TK_TEXT)); + SetBkColor(hdc,viv_theme_color(VIV_TK_FACE)); + + return (INT_PTR)_viv_dialog_dark_brush(); + } + + return 0; +} +// erase a dialog background with the dark palette. call from +// WM_ERASEBKGND; returns 1 when the background was painted. +static int _viv_dialog_dark_erase(HWND hwnd,HDC hdc) +{ + if (_viv_is_dark()) + { + RECT rect; + + GetClientRect(hwnd,&rect); + + FillRect(hdc,&rect,_viv_dialog_dark_brush()); + + return 1; + } + + return 0; +} +// shared dark handling for the dialog messages: WM_CTLCOLORSTATIC, +// WM_CTLCOLOREDIT, WM_CTLCOLORLISTBOX and WM_ERASEBKGND. returns the +// dialog proc reply, or -1 when the caller should run its own switch. +// shared dark handling for the dialog messages: WM_CTLCOLORSTATIC, +// WM_CTLCOLOREDIT, WM_CTLCOLORLISTBOX and WM_ERASEBKGND. returns the +// dialog proc reply, or -1 when the caller should run its own switch. +// owner drawn dialog controls: the push buttons and the combo boxes +// paint with the dark palette while the dark ui is active. the glyph +// controls (checkboxes, radios) never flip to owner draw - an owner +// draw flip replaces their automatic check state machine - so their +// faces paint through the custom draw path instead +// (_viv_dialog_dark_notify). the light ui never flips the owner draw +// styles (and unflips them on the way back), so this only runs in the +// dark. +static INT_PTR _viv_dialog_dark_draw_item(HWND hwnd,DRAWITEMSTRUCT *draw_item) +{ + wchar_t text[STRING_SIZE]; + + if (!_viv_is_dark()) + { + return 0; + } + + (void)hwnd; + + switch(draw_item->CtlType) + { + case ODT_BUTTON: + { + UINT style; + RECT rect; + HBRUSH face_brush; + HFONT font; + HFONT old_font; + COLORREF text_color; + int pressed; + + // the original button type rides in the flip property (the owner + // draw bit occupies the type field while it is set). + style = (UINT)((LONG_PTR)GetPropW(draw_item->hwndItem,_VIV_DARK_OWNERDRAW_PROP) - 1); + + // only the push buttons were flipped (the glyph controls paint + // their labels through the custom draw path - an owner draw flip + // would replace their automatic check state machine). + if ((style != BS_PUSHBUTTON) && (style != BS_DEFPUSHBUTTON)) + { + return 0; + } + + // the label text uses the control font. the draw item dc carries no + // defined font, so the owner draw picks it explicitly: the drawn + // text then matches the native rendering face for face (the field + // report read the fonts different between the drawn and the native + // controls). + font = (HFONT)SendMessage(draw_item->hwndItem,WM_GETFONT,0,0); + + old_font = font ? (HFONT)SelectObject(draw_item->hDC,font) : 0; + + text[0] = 0; + GetWindowTextW(draw_item->hwndItem,text,STRING_SIZE); + + CopyRect(&rect,&draw_item->rcItem); + + pressed = (draw_item->itemState & ODS_SELECTED) ? 1 : 0; + + // push buttons: the lifted face with a light frame. + face_brush = _viv_dark_chrome_brush(1); + + FillRect(draw_item->hDC,&rect,face_brush); + FrameRect(draw_item->hDC,&rect,_viv_dark_chrome_brush(2)); + + if (style == BS_DEFPUSHBUTTON) + { + RECT outer; + + CopyRect(&outer,&draw_item->rcItem); + + InflateRect(&outer,-2,-2); + + FrameRect(draw_item->hDC,&outer,_viv_dark_chrome_brush(2)); + } + + if (pressed) + { + OffsetRect(&rect,1,1); + } + + text_color = (draw_item->itemState & ODS_DISABLED) ? viv_theme_color(VIV_TK_TEXTOFF) : viv_theme_color(VIV_TK_TEXT); + + SetBkMode(draw_item->hDC,TRANSPARENT); + SetTextColor(draw_item->hDC,text_color); + + DrawTextW(draw_item->hDC,text,-1,&rect,DT_SINGLELINE | DT_CENTER | DT_VCENTER); + + if (old_font) + { + SelectObject(draw_item->hDC,old_font); + } + + return TRUE; + } + + case ODT_COMBOBOX: + { + RECT rect; + HBRUSH face_brush; + COLORREF text_color; + HFONT font; + HFONT old_font; + int selected; + + text[0] = 0; + + // the row text uses the control font: the draw item dc carries no + // defined font, so the owner draw picks it explicitly (the same + // rule as the buttons - the drawn face matches the native one). + font = (HFONT)SendMessage(draw_item->hwndItem,WM_GETFONT,0,0); + + old_font = font ? (HFONT)SelectObject(draw_item->hDC,font) : 0; + + if (draw_item->itemID == (UINT)-1) + { + // the closed field: the current selection. + int cur; + + cur = (int)SendMessage(draw_item->hwndItem,CB_GETCURSEL,0,0); + + if (cur != -1) + { + SendMessageW(draw_item->hwndItem,CB_GETLBTEXT,cur,(LPARAM)text); + } + } + else + { + SendMessageW(draw_item->hwndItem,CB_GETLBTEXT,draw_item->itemID,(LPARAM)text); + } + + CopyRect(&rect,&draw_item->rcItem); + + // the closed field and the highlighted list rows take the hover + // tone, the plain rows take the dialog face. + selected = (draw_item->itemState & (ODS_SELECTED | ODS_COMBOBOXEDIT)) ? 1 : 0; + + face_brush = selected ? _viv_dark_chrome_brush(1) : _viv_dark_chrome_brush(3); + text_color = (draw_item->itemState & ODS_DISABLED) ? viv_theme_color(VIV_TK_TEXTOFF) : viv_theme_color(VIV_TK_TEXT); + + FillRect(draw_item->hDC,&rect,face_brush); + + SetBkMode(draw_item->hDC,TRANSPARENT); + SetTextColor(draw_item->hDC,text_color); + + DrawTextW(draw_item->hDC,text,-1,&rect,DT_SINGLELINE | DT_LEFT | DT_VCENTER); + + if ((draw_item->itemState & ODS_FOCUS) && (!(draw_item->itemState & ODS_COMBOBOXEDIT))) + { + DrawFocusRect(draw_item->hDC,&rect); + } + + if (old_font) + { + SelectObject(draw_item->hDC,old_font); + } + + return TRUE; + } + } + + return 0; +} +static HANDLE _viv_dialog_dark_theme(HWND hwnd) +{ + HANDLE theme; + + theme = (HANDLE)GetPropW(hwnd,_VIV_DARK_BUTTON_THEME_PROP); + + if (!theme) + { + theme = os_theme_open_button(hwnd); + + if (theme) + { + SetPropW(hwnd,_VIV_DARK_BUTTON_THEME_PROP,theme); + } + } + + return theme; +} +static void _viv_dialog_dark_theme_drop(HWND hwnd) +{ + HANDLE theme; + + theme = (HANDLE)GetPropW(hwnd,_VIV_DARK_BUTTON_THEME_PROP); + + if (theme) + { + os_theme_close(theme); + + RemovePropW(hwnd,_VIV_DARK_BUTTON_THEME_PROP); + } +} +// the theme state for the drawn glyph: the check state rides with the +// control message (bm_getcheck), the disabled, hot and pressed states +// ride with the custom draw item state - the map lands on the exact +// cbs_* / rbs_* state id the native button would have picked for the +// same control. radio has no mixed state; disabled wins over hot and +// pressed the way the visual styles table orders them. +static int _viv_dialog_dark_glyph_state(int type,int check,UINT item_state) +{ + int state; + + if ((type == BS_AUTORADIOBUTTON) || (type == BS_RADIOBUTTON)) + { + state = check ? OS_RBS_CHECKEDNORMAL : OS_RBS_UNCHECKEDNORMAL; + } + else + { + state = (check == BST_INDETERMINATE) ? OS_BS_MIXEDNORMAL : (check ? OS_BS_CHECKEDNORMAL : OS_BS_UNCHECKEDNORMAL); + } + + if (item_state & CDIS_DISABLED) + { + state += 3; + } + else if (item_state & CDIS_HOT) + { + state += 1; + } + else if (item_state & CDIS_SELECTED) + { + state += 2; + } + + return state; +} +// the glyph controls in the dark ui: the themed button paints its own +// label color (the wm_ctlcolorstatic text never reaches it - the field +// report read black checkbox labels at 0.78:1 against the dialog face), +// so the checkboxes and the radios custom draw the whole face here: the +// dark dialog background, the theme glyph in the control's own checked, +// mixed, disabled and hot state, the light label and the focus frame. +// the button styles never change: the automatic check state machine, the +// radio grouping and every isdlgbuttonchecked read keep working in both +// themes (the withdrawn 1.1.09 build flipped the glyph controls to owner +// draw instead, which replaced bs_autocheckbox in the style and left +// every options checkbox dead in the dark ui). +// +// the return value has to travel through dwlp_msgresult: a dialog +// procedure cannot return a notify result directly (the dialog manager +// keeps the message result in the window data, so a plain non-zero +// return hands the control a zero - cdrf_dodefault - and the first +// 1.1.09 redo shipped exactly that: the skip never reached the buttons, +// the system painted its full default face on top of the custom draw, +// the labels read black on black and the two xor focus frames cancelled +// each other). this function returns the cdrf code and the caller +// (_viv_dialog_dark_proc) does the setwindowlongptr + return true pair +// the nm_customdraw documentation prescribes for dialog procedures. +static INT_PTR _viv_dialog_dark_notify(HWND hwnd,NMHDR *header) +{ + wchar_t class_name[64]; + wchar_t text[STRING_SIZE]; + LONG_PTR style; + int type; + + // only the dark ui repaints the faces; the light ui keeps the native + // painting untouched. + if (!_viv_is_dark()) + { + return -1; + } + + // only the button custom draw belongs here: the tree view, the tabs + // and every other common control keep their own notifications flowing + // to the dialog procedures (the options tree switches its pages on + // those). + if (header->code != NM_CUSTOMDRAW) + { + return -1; + } + + class_name[0] = 0; + + if ((!header->hwndFrom) || (!GetClassNameW(header->hwndFrom,class_name,64)) || (string_compare(class_name,L"Button") != 0)) + { + return -1; + } + + style = GetWindowLongPtr(header->hwndFrom,GWL_STYLE); + + type = (int)(style & BS_TYPEMASK); + + // the glyph controls only: the push buttons paint through the owner + // draw flip, the bitmap swatches keep their own painting and the group + // boxes carry no label problem. + if ((type != BS_AUTOCHECKBOX) && (type != BS_AUTORADIOBUTTON) && (type != BS_CHECKBOX) && (type != BS_RADIOBUTTON) && (type != BS_3STATE) && (type != BS_AUTO3STATE)) + { + return -1; + } + + if (((NMCUSTOMDRAW *)header)->dwDrawStage == CDDS_PREPAINT) + { + NMCUSTOMDRAW *custom_draw; + HANDLE theme; + RECT rect; + RECT glyph_rect; + HFONT font; + HFONT old_font; + SIZE digit; + int glyph_wide; + int glyph_high; + int check; + int part; + int state; + + custom_draw = (NMCUSTOMDRAW *)header; + + // the button theme opens once per dialog and stays cached in the + // window data (see _viv_dialog_dark_theme). + theme = _viv_dialog_dark_theme(hwnd); + + part = ((type == BS_AUTORADIOBUTTON) || (type == BS_RADIOBUTTON)) ? OS_BP_RADIOBUTTON : OS_BP_CHECKBOX; + + check = (int)SendMessage(header->hwndFrom,BM_GETCHECK,0,0); + + state = _viv_dialog_dark_glyph_state(type,check,custom_draw->uItemState); + + glyph_wide = 0; + + glyph_high = 0; + + if ((!os_theme_part_size(theme,custom_draw->hdc,part,state,&glyph_wide,&glyph_high)) || (glyph_wide <= 0) || (glyph_high <= 0)) + { + // no usable theme part (the visual styles off): the native + // painting stays - the glyph controls read the system way there, + // exactly as the light ui does. + return CDRF_DODEFAULT; + } + + // the label text uses the control font: the drawn face then matches + // the native rendering (the light and the dark ui read the same). + font = (HFONT)SendMessage(header->hwndFrom,WM_GETFONT,0,0); + + old_font = font ? (HFONT)SelectObject(custom_draw->hdc,font) : 0; + + GetTextExtentPoint32W(custom_draw->hdc,L"0",1,&digit); + + // the skip takes the whole painting, the item background included, + // so the rect takes the dark dialog face first (the parent + // background the native path would have asked for). + FillRect(custom_draw->hdc,&custom_draw->rc,_viv_dialog_dark_brush()); + + // the glyph: the theme part at the left edge, vertically centered + // on the control the way the native layout centers the text. + CopyRect(&glyph_rect,&custom_draw->rc); + + glyph_rect.right = glyph_rect.left + glyph_wide; + + glyph_rect.top = glyph_rect.top + ((glyph_rect.bottom - glyph_rect.top - glyph_high) / 2); + + glyph_rect.bottom = glyph_rect.top + glyph_high; + + os_theme_draw_part(theme,custom_draw->hdc,part,state,&glyph_rect); + + // the label sits right of the glyph: the glyph box plus half a digit + // of gap, vertically centered on the control (the native layout). + CopyRect(&rect,&custom_draw->rc); + + OffsetRect(&rect,glyph_wide + (digit.cx / 2),0); + + text[0] = 0; + + GetWindowTextW(header->hwndFrom,text,STRING_SIZE); + + SetBkMode(custom_draw->hdc,TRANSPARENT); + + SetTextColor(custom_draw->hdc,(style & WS_DISABLED) ? viv_theme_color(VIV_TK_TEXTOFF) : viv_theme_color(VIV_TK_TEXT)); + + DrawTextW(custom_draw->hdc,text,-1,&rect,DT_SINGLELINE | DT_LEFT | DT_VCENTER | DT_END_ELLIPSIS); + + // the focus frame, drawn exactly once: the skip keeps the native + // painting away, so the frame cannot xor against a second frame the + // way the broken return shipped it (two draws cancelled each other + // and the keyboard walk lost its dot in the dark). + if (GetFocus() == header->hwndFrom) + { + RECT focus_rect; + + CopyRect(&focus_rect,&custom_draw->rc); + + InflateRect(&focus_rect,-1,-1); + + DrawFocusRect(custom_draw->hdc,&focus_rect); + } + + if (old_font) + { + SelectObject(custom_draw->hdc,old_font); + } + + // the skip means the whole face is ours now - the background, the + // glyph, the label and the focus frame above. + return CDRF_SKIPDEFAULT; + } + + return CDRF_DODEFAULT; +} +INT_PTR _viv_dialog_dark_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) +{ + switch(msg) + { + case WM_INITDIALOG: + { + // one type system: the message font at this dialog window own + // dpi replaces the template face on the dialog and every child + // control. the break keeps the -1 return so each dialog's own + // initialization still runs: the dark flip measures the final + // font and the localized labels draw with it. + _viv_dialog_apply_font(hwnd); + + break; + } + + case WM_DPICHANGED: + { + // a dialog dragged across monitors re-reads the font at the new + // dpi (the layout grid stays; the type follows). + _viv_dialog_apply_font(hwnd); + + break; + } + + case WM_NCDESTROY: + { + // the dialog dies after its children: the font it adopted + // dies with it, and no live window can still hold the handle + // (the children are gone by the time ncdestroy runs - the + // release is safe by construction). + HFONT font; + + font = (HFONT)GetPropW(hwnd,_VIV_DIALOG_FONT_PROP); + + if (font) + { + RemovePropW(hwnd,_VIV_DIALOG_FONT_PROP); + + DeleteObject(font); + } + + break; + } + + case WM_DRAWITEM: + { + INT_PTR dark_reply; + + // the owner drawn dark controls: the push buttons and the combo + // boxes paint here (the glyph control faces paint through the + // custom draw case above). + dark_reply = _viv_dialog_dark_draw_item(hwnd,(DRAWITEMSTRUCT *)lParam); + + if (dark_reply) + { + return dark_reply; + } + + break; + } + + case WM_MEASUREITEM: + { + if ((((MEASUREITEMSTRUCT *)lParam)->CtlType == ODT_COMBOBOX) && (_viv_is_dark())) + { + HWND combo_hwnd; + int captured_height; + + combo_hwnd = GetDlgItem(hwnd,(int)wParam); + captured_height = combo_hwnd ? (int)(LONG_PTR)GetPropW(combo_hwnd,_VIV_DARK_OWNERDRAW_PROP) : 0; + + if (captured_height > 0x100) + { + // the captured native height keeps the owner drawn rows at the + // exact height the themed control used (no size drift). + ((MEASUREITEMSTRUCT *)lParam)->itemHeight = captured_height - 0x100; + } + else + { + ((MEASUREITEMSTRUCT *)lParam)->itemHeight = _viv_dialog_dark_combo_item_height(combo_hwnd); + } + + return TRUE; + } + + break; + } + case WM_NOTIFY: + { + INT_PTR dark_reply; + + // the glyph controls paint through the custom draw path (the + // filter inside passes every other notification through to the + // dialog's own switch). + dark_reply = _viv_dialog_dark_notify(hwnd,(NMHDR *)lParam); + + if (dark_reply != -1) + { + // a dialog procedure cannot return a notify result directly: + // the dialog manager keeps the message result in the window + // data, so a plain non-zero return hands the control a zero + // (= cdrf_dodefault) - the skip never reached the buttons in + // the first 1.1.09 redo and the system painted its full + // default face on top of the custom draw. the result travels + // through dwlp_msgresult with a true return, the way the + // nm_customdraw documentation prescribes for dialog + // procedures. + SetWindowLongPtr(hwnd,DWLP_MSGRESULT,dark_reply); + + return TRUE; + } + + break; + } + + case WM_CTLCOLORSTATIC: + case WM_CTLCOLOREDIT: + case WM_CTLCOLORLISTBOX: + { + INT_PTR dark_reply; + + dark_reply = _viv_dialog_dark_ctlcolor((HDC)wParam); + + if (dark_reply) + { + return dark_reply; + } + + break; + } + + case WM_DESTROY: + { + // the cached button theme closes with the dialog that opened it + // (the next dialog opens a fresh handle). + _viv_dialog_dark_theme_drop(hwnd); + + break; + } + + case WM_THEMECHANGED: + { + // the uxtheme handles die with the visual style change: the + // cache drops here and the next custom draw reopens it against + // the new style (a stale handle draws garbage or nothing). + _viv_dialog_dark_theme_drop(hwnd); + + break; + } + + case WM_ERASEBKGND: + + if (_viv_dialog_dark_erase(hwnd,(HDC)wParam)) + { + return 1; + } + + break; + } + + (void)lParam; + + return -1; +} diff --git a/src/viv_dark.h b/src/viv_dark.h new file mode 100644 index 00000000..ffe683a4 --- /dev/null +++ b/src/viv_dark.h @@ -0,0 +1,35 @@ +// +// Copyright 2025 voidtools / David Carpenter +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +// VoidImageViewer +// viv_dark.h - dark dialog infrastructure (subclassing, theming, drawing). +#ifndef VIV_DARK_H +#define VIV_DARK_H + +#include "viv.h" + +// exported to other domains / the viv.c core +HBRUSH _viv_dialog_dark_brush(void); +void _viv_dark_dialog(HWND hwnd); +void _viv_dark_dialogs_refresh(void); +INT_PTR _viv_dialog_dark_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); + +#endif diff --git a/src/viv_dialogs.c b/src/viv_dialogs.c new file mode 100644 index 00000000..8cb9c09f --- /dev/null +++ b/src/viv_dialogs.c @@ -0,0 +1,2751 @@ +// +// Copyright 2025 voidtools / David Carpenter +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +// VoidImageViewer +// viv_dialogs.c - modal dialogs: options, jump-to, about, rename, rate. +// the zoom editor lives in place on the status bar pane, not in a box. +// Pure physical move from viv.c (R70 split): bodies are unchanged. +#include "viv.h" +#include "viv_state.h" +#include "viv_dialogs.h" +#include "viv_menubar.h" +#include "viv_chrome.h" +#include "viv_dark.h" +#include "viv_install.h" +#include "viv_load.h" +#include "viv_menu.h" +#include "viv_playlist.h" +#include "viv_recent.h" +#include "viv_render.h" +#include "viv_view.h" + +// forward declarations (order preserved from viv.c) +static HBRUSH _viv_about_light_brush(int which); +static BOOL CALLBACK _viv_dialog_font_child(HWND hwnd,LPARAM lParam); +void _viv_dialog_apply_font(HWND hwnd); +static INT_PTR CALLBACK _viv_rename_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); +void _viv_rename(void); +static INT_PTR CALLBACK _viv_options_general_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); +static void _viv_options_key_list_sel_change(HWND hwnd,int previous_key_index); +static void _viv_options_remove_key(HWND hwnd); +static INT_PTR CALLBACK _viv_edit_key_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); +static void _viv_options_edit_key(HWND hwnd,int key_index); +static INT_PTR CALLBACK _viv_options_controls_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); +static INT_PTR CALLBACK _viv_options_view_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); +static void _viv_options_treeview_changed(HWND hwnd); +static void _viv_options_update_sheild(HWND hwnd); +static LRESULT CALLBACK _viv_options_tab_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); +static INT_PTR CALLBACK _viv_options_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); +void _viv_options(void); +INT_PTR CALLBACK _viv_custom_rate_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); +static INT_PTR _viv_about_colors(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); +INT_PTR CALLBACK _viv_about_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); +void _viv_set_zoom_dialog(void); +static void _viv_zoom_edit_end(HWND hwnd,int apply); +static LRESULT CALLBACK _viv_zoom_edit_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); +void _viv_command_line_options(void); +static void _viv_update_color_button_bitmap(HWND hwnd); +static void _viv_delete_color_button_bitmap(HWND hwnd); +static LRESULT CALLBACK _viv_edit_key_edit_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); +static void _viv_options_edit_key_changed(HWND hwnd); +static void _viv_edit_key_set_key(HWND hwnd,DWORD key_flags); +static void _viv_edit_key_remove_currently_used_by(_viv_key_list_t *keylist,DWORD keyflags); +static void _viv_jumpto_on_size(HWND hwnd); +static void _viv_jumpto_on_search(HWND hwnd); +static void _viv_jumpto_open_sel(HWND hwnd); +static LRESULT CALLBACK _viv_jumpto_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); +void _viv_show_jumpto(void); +static void _viv_center_listbox_item(HWND listbox_hwnd,int item_index); + + +static localization_id_t _viv_options_page_localization_id_array[] = {LOCALIZATION_ID_OPTIONS_GENERAL_DIALOG,LOCALIZATION_ID_OPTIONS_VIEW_DIALOG,LOCALIZATION_ID_OPTIONS_CONTROLS_DIALOG}; +static int _viv_options_tab_ids[] = {IDC_TAB1,IDC_TAB2,IDC_TAB3}; +static int _viv_options_dialog_ids[] = {IDD_GENERAL,IDD_VIEW,IDD_CONTROLS}; +typedef char _viv_options_dialog_ids_count_assert[(sizeof(_viv_options_dialog_ids) / sizeof(int) == _VIV_OPTIONS_PAGE_COUNT) ? 1 : -1]; // the count literal pins the table +static DLGPROC _viv_options_page_procs[] = {_viv_options_general_proc,_viv_options_view_proc,_viv_options_controls_proc}; +static BYTE _viv_jump_ret = 0; +const WORD _viv_association_dlg_item_id[] = +{ + IDC_BMP, + IDC_GIF, + IDC_ICO, + IDC_JPEG, + IDC_JPG, + IDC_PNG, + IDC_TIF, + IDC_TIFF, + IDC_WEBP, + IDC_EMF, + IDC_WMF, +}; +// the about dialog band in the light ui takes the fixed win11 command +// bar palette instead of the system button colors (the band used to +// follow the windows theme of the machine - the fixed face holds one +// look everywhere). 0 = the separator line, 1 = the face. released in +// _viv_kill with the other cached brushes. +static HBRUSH _viv_about_light_brush(int which) +{ + static const COLORREF colors[2] = {RGB(0xEC,0xEC,0xEC),RGB(0xFF,0xFF,0xFF)}; + + if ((which < 0) || (which > 1)) + { + return 0; + } + + if (!_viv_about_light_hbrushes[which]) + { + _viv_about_light_hbrushes[which] = CreateSolidBrush(colors[which]); + } + + return _viv_about_light_hbrushes[which]; +} +static BOOL CALLBACK _viv_dialog_font_child(HWND hwnd,LPARAM lParam) +{ + SendMessage(hwnd,WM_SETFONT,(WPARAM)lParam,MAKELPARAM(TRUE,0)); + + return TRUE; +} +// give a dialog and every child control the message font. the shared +// dialog proc runs this from wm_initdialog before each dialog's own +// case (and again from wm_dpichanged when the window crosses +// monitors): the dark flip captures the native combo field heights +// against the final font, the about title derives its larger face +// from it and the localized labels render with it. +void _viv_dialog_apply_font(HWND hwnd) +{ + LOGFONTW lf; + HFONT font; + HFONT old_font; + + if (!os_dialog_font(&lf,hwnd)) + { + return; + } + + font = CreateFontIndirectW(&lf); + + if (!font) + { + return; + } + + old_font = (HFONT)GetPropW(hwnd,_VIV_DIALOG_FONT_PROP); + + SetPropW(hwnd,_VIV_DIALOG_FONT_PROP,(HANDLE)font); + + // the dialog window itself first: WM_GETFONT on the dialog + // reports the template face until this set. + SendMessage(hwnd,WM_SETFONT,(WPARAM)font,MAKELPARAM(TRUE,0)); + + EnumChildWindows(hwnd,_viv_dialog_font_child,(LPARAM)font); + + // every child took the new face inside this same message: the old + // handle has no user left, so it can die here (a paint can never + // interleave the synchronous broadcast). + if (old_font) + { + DeleteObject(old_font); + } +} +static INT_PTR CALLBACK _viv_rename_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) +{ + { + INT_PTR dark_dialog_reply; + + dark_dialog_reply = _viv_dialog_dark_proc(hwnd,msg,wParam,lParam); + + if (dark_dialog_reply != -1) + { + return dark_dialog_reply; + } + } + + switch(msg) + { + case WM_INITDIALOG: + // dark chrome: title bar and dark explorer control style. + _viv_dark_dialog(hwnd); + + { + wchar_t name[STRING_SIZE]; + + os_center_dialog(hwnd); + + os_SetWindowText_localization_id(hwnd,LOCALIZATION_ID_RENAME_CAPTION); + + string_copy(name,string_get_filename_part((wchar_t *)lParam)); + string_remove_extension(name); + + SetDlgItemText(hwnd,IDC_RENAME_OLD_EDIT,(wchar_t *)lParam); + SetDlgItemText(hwnd,IDC_RENAME_EDIT,name); + + return TRUE; + } + + case WM_COMMAND: + + switch(LOWORD(wParam)) + { + case IDOK: + + { + wchar_t old_filename[STRING_SIZE]; + wchar_t new_filename[STRING_SIZE]; + wchar_t path[STRING_SIZE]; + wchar_t new_full_path_and_filename[STRING_SIZE]; + wchar_t *ext; + int dont_end_dialog; + + GetDlgItemText(hwnd,IDC_RENAME_OLD_EDIT,old_filename,STRING_SIZE); + GetDlgItemText(hwnd,IDC_RENAME_EDIT,new_filename,STRING_SIZE); + + string_get_path_part(path,old_filename); + ext = string_get_extension(old_filename); + dont_end_dialog = 0; + + string_path_combine(new_full_path_and_filename,path,new_filename); + if (*ext) + { + string_cat_utf8(new_full_path_and_filename,(const utf8_t *)"."); + string_cat(new_full_path_and_filename,ext); + } + + if (string_compare(old_filename,new_full_path_and_filename) != 0) + { + SHFILEOPSTRUCT fo; + + wchar_t old_filename_list[STRING_SIZE+1]; + wchar_t new_filename_list[STRING_SIZE+1]; + + string_copy_double_null(old_filename_list,old_filename); + string_copy_double_null(new_filename_list,new_full_path_and_filename); + + ZeroMemory(&fo,sizeof(SHFILEOPSTRUCT)); + fo.hwnd = _viv_hwnd; + fo.wFunc = FO_RENAME; + fo.pFrom = old_filename_list; + fo.pTo = new_filename_list; + fo.fFlags = FOF_ALLOWUNDO | FOF_WANTMAPPINGHANDLE; + + // returns ERROR_CANCELLED if user cancelled. + if (SHFileOperation(&fo) == 0) + { + if (fo.fAnyOperationsAborted) + { + // user clicked No to a rename collision + // (not cancelled). + dont_end_dialog = 1; + } + else + { + const wchar_t *file_op_new_name; + + file_op_new_name = new_full_path_and_filename; + + if (fo.hNameMappings) + { + _viv_name_mapping_t *mappings; + + mappings = (_viv_name_mapping_t *)fo.hNameMappings; + + if (mappings->count == 1) + { + // use the resolved name incase there was a rename collision. + file_op_new_name = mappings->mappings[0].pszNewPath; + } + } + + // has the current file changed? slideshow could make this a different filename + if (string_compare(old_filename,_viv_current_fd->cFileName) == 0) + { + // rename + string_copy_with_bufsize(_viv_current_fd->cFileName,MAX_PATH,file_op_new_name); + + _viv_playlist_rename(old_filename,file_op_new_name); + + // the recent entry follows the rename in place + // (the old name would become a dead row). + _viv_recent_file_rename(old_filename,file_op_new_name); + + _viv_update_title(); + } + } + + if (fo.hNameMappings) + { + SHFreeNameMappings(fo.hNameMappings); + } + } + } + + if (!dont_end_dialog) + { + EndDialog(hwnd,1); + } + } + + break; + + + case IDCANCEL: + EndDialog(hwnd,0); + break; + } + + break; + } + + return FALSE; +} +void _viv_rename(void) +{ + if (*_viv_current_fd->cFileName) + { + DialogBoxParam(os_hinstance,MAKEINTRESOURCE(IDD_RENAME),_viv_hwnd,_viv_rename_proc,(LPARAM)_viv_current_fd->cFileName); + } +} +static INT_PTR CALLBACK _viv_options_general_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) +{ + { + INT_PTR dark_dialog_reply; + + dark_dialog_reply = _viv_dialog_dark_proc(hwnd,msg,wParam,lParam); + + if (dark_dialog_reply != -1) + { + return dark_dialog_reply; + } + } + + switch(msg) + { + case WM_INITDIALOG: + // dark chrome: title bar and dark explorer control style. + _viv_dark_dialog(hwnd); + + { + int exti; + + os_SetDlgItemText_localization_id(hwnd,IDC_APPDATA,LOCALIZATION_ID_STORE_SETTINGS_APPDATA); + os_SetDlgItemText_localization_id(hwnd,IDC_MULTIPLE_INSTANCES,LOCALIZATION_ID_ALLOW_MULTIPLE_INSTANCES); + os_SetDlgItemText_localization_id(hwnd,IDC_STARTMENU,LOCALIZATION_ID_STARTMENU_SHORTCUTS); + os_SetDlgItemText_localization_id(hwnd,IDC_ASSOCIATIONS_GROUPBOX,LOCALIZATION_ID_ASSOCIATIONS); + os_SetDlgItemText_localization_id(hwnd,IDC_CHECKALL,LOCALIZATION_ID_CHECK_ALL); + os_SetDlgItemText_localization_id(hwnd,IDC_CHECKNONE,LOCALIZATION_ID_CHECK_NONE); + + // language selection. entries: auto, english, simplified chinese. + // (language names are always shown in their own language) + os_SetDlgItemText_localization_id(hwnd,IDC_LANGUAGE_STATIC,LOCALIZATION_ID_OPTIONS_LANGUAGE_STATIC); + os_ComboBox_AddString_localization_id(hwnd,IDC_LANGUAGE,LOCALIZATION_ID_LANGUAGE_AUTO); + os_ComboBox_AddString(hwnd,IDC_LANGUAGE,localization_get_language_name(LOCALIZATION_LANGUAGE_ENGLISH)); + os_ComboBox_AddString(hwnd,IDC_LANGUAGE,localization_get_language_name(LOCALIZATION_LANGUAGE_CHINESE_SIMPLIFIED)); + ComboBox_SetCurSel(GetDlgItem(hwnd,IDC_LANGUAGE),config_language); + + // dark mode selection: automatic (follow the windows theme), light or dark. + os_SetDlgItemText_localization_id(hwnd,IDC_DARKMODE_STATIC,LOCALIZATION_ID_OPTIONS_DARK_MODE_STATIC); + os_ComboBox_AddString_localization_id(hwnd,IDC_DARKMODE,LOCALIZATION_ID_DARK_MODE_AUTO); + os_ComboBox_AddString_localization_id(hwnd,IDC_DARKMODE,LOCALIZATION_ID_DARK_MODE_LIGHT); + os_ComboBox_AddString_localization_id(hwnd,IDC_DARKMODE,LOCALIZATION_ID_DARK_MODE_DARK); + // combo order: automatic, light, dark. + ComboBox_SetCurSel(GetDlgItem(hwnd,IDC_DARKMODE),config_dark_mode == 1 ? 2 : (config_dark_mode == 0 ? 1 : 0)); + + if (config_appdata) + { + CheckDlgButton(hwnd,IDC_APPDATA,BST_CHECKED); + } + + if (config_multiple_instances) + { + CheckDlgButton(hwnd,IDC_MULTIPLE_INSTANCES,BST_CHECKED); + } + + for(exti=0;exti<_VIV_ASSOCIATION_COUNT;exti++) + { + if (_viv_is_association(_viv_association_extensions[exti])) + { + CheckDlgButton(hwnd,_viv_association_dlg_item_id[exti],BST_CHECKED); + } + } + + if (_viv_is_start_menu_shortcuts()) + { + CheckDlgButton(hwnd,IDC_STARTMENU,BST_CHECKED); + } + + return FALSE; + } + + case WM_COMMAND: + + switch(LOWORD(wParam)) + { + case IDC_STARTMENU: + case IDC_APPDATA: + _viv_options_update_sheild(GetParent(hwnd)); + break; + + case IDC_CHECKALL: + case IDC_CHECKNONE: + { + UINT check; + + check = LOWORD(wParam) == IDC_CHECKALL ? BST_CHECKED : BST_UNCHECKED; + + CheckDlgButton(hwnd,IDC_BMP,check); + CheckDlgButton(hwnd,IDC_GIF,check); + CheckDlgButton(hwnd,IDC_ICO,check); + CheckDlgButton(hwnd,IDC_JPEG,check); + CheckDlgButton(hwnd,IDC_JPG,check); + CheckDlgButton(hwnd,IDC_PNG,check); + CheckDlgButton(hwnd,IDC_TIF,check); + CheckDlgButton(hwnd,IDC_TIFF,check); + CheckDlgButton(hwnd,IDC_WEBP,check); + CheckDlgButton(hwnd,IDC_EMF,check); + CheckDlgButton(hwnd,IDC_WMF,check); + + break; + } + } + + break; + + } + + return FALSE; +} +static void _viv_options_key_list_sel_change(HWND hwnd,int previous_key_index) +{ + int index; + _viv_key_list_t *keylist; + int key_count; + + keylist = (_viv_key_list_t *)GetWindowLongPtr(GetDlgItem(hwnd,IDC_COMMANDS_LIST),GWLP_USERDATA); + + index = ListBox_GetCurSel(GetDlgItem(hwnd,IDC_COMMANDS_LIST)); + + ListBox_ResetContent(GetDlgItem(hwnd,IDC_KEYS_LIST)); + SetWindowRedraw(GetDlgItem(hwnd,IDC_KEYS_LIST),FALSE); + + key_count = 0; + + if (index != LB_ERR) + { + int command_index; + config_key_t *key; + + command_index = ListBox_GetItemData(GetDlgItem(hwnd,IDC_COMMANDS_LIST),index); + + key = keylist->start[command_index]; + + while(key) + { + wchar_t key_text[STRING_SIZE]; + int listbox_index; + + _viv_get_key_text(key_text,key->key); + + listbox_index = ListBox_AddString(GetDlgItem(hwnd,IDC_KEYS_LIST),key_text); + + if (listbox_index != LB_ERR) + { + ListBox_SetItemData(GetDlgItem(hwnd,IDC_KEYS_LIST),listbox_index,key->key); + } + + key_count++; + key = key->next; + } + + EnableWindow(GetDlgItem(hwnd,IDC_ADD_KEY_BUTTON),TRUE); + + if (key_count) + { + EnableWindow(GetDlgItem(hwnd,IDC_EDIT_KEY_BUTTON),TRUE); + EnableWindow(GetDlgItem(hwnd,IDC_REMOVE_KEY_BUTTON),TRUE); + + if ((previous_key_index == LB_ERR) || (previous_key_index > key_count - 1)) + { + previous_key_index = key_count - 1; + } + + ListBox_SetCurSel(GetDlgItem(hwnd,IDC_KEYS_LIST),previous_key_index); + } + else + { + EnableWindow(GetDlgItem(hwnd,IDC_EDIT_KEY_BUTTON),FALSE); + EnableWindow(GetDlgItem(hwnd,IDC_REMOVE_KEY_BUTTON),FALSE); + } + } + else + { + EnableWindow(GetDlgItem(hwnd,IDC_ADD_KEY_BUTTON),FALSE); + EnableWindow(GetDlgItem(hwnd,IDC_EDIT_KEY_BUTTON),FALSE); + EnableWindow(GetDlgItem(hwnd,IDC_REMOVE_KEY_BUTTON),FALSE); + } + + SetWindowRedraw(GetDlgItem(hwnd,IDC_KEYS_LIST),TRUE); +} +static void _viv_options_remove_key(HWND hwnd) +{ + int index; + _viv_key_list_t *keylist; + + keylist = (_viv_key_list_t *)GetWindowLongPtr(GetDlgItem(hwnd,IDC_COMMANDS_LIST),GWLP_USERDATA); + + index = ListBox_GetCurSel(GetDlgItem(hwnd,IDC_COMMANDS_LIST)); + + if (index != LB_ERR) + { + int key_index; + + key_index = ListBox_GetCurSel(GetDlgItem(hwnd,IDC_KEYS_LIST)); + + if (key_index != LB_ERR) + { + int command_index; + WORD keyflags; + + command_index = ListBox_GetItemData(GetDlgItem(hwnd,IDC_COMMANDS_LIST),index); + keyflags = ListBox_GetItemData(GetDlgItem(hwnd,IDC_KEYS_LIST),key_index); + + _viv_key_remove(keylist,command_index,keyflags); + + _viv_options_key_list_sel_change(hwnd,key_index); + } + } +} +static INT_PTR CALLBACK _viv_edit_key_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) +{ + { + INT_PTR dark_dialog_reply; + + dark_dialog_reply = _viv_dialog_dark_proc(hwnd,msg,wParam,lParam); + + if (dark_dialog_reply != -1) + { + return dark_dialog_reply; + } + } + + switch(msg) + { + case WM_INITDIALOG: + // dark chrome: title bar and dark explorer control style. + _viv_dark_dialog(hwnd); + + { + WNDPROC last_proc; + wchar_t caption_wbuf[STRING_SIZE]; + + string_printf(caption_wbuf,localization_get_string(lParam ? LOCALIZATION_ID_EDIT_KEYBOARD_SHORTCUT_CAPTION : LOCALIZATION_ID_ADD_KEYBOARD_SHORTCUT_CAPTION)); + SetWindowText(hwnd,caption_wbuf); + + os_SetDlgItemText_localization_id(hwnd,IDC_EDIT_KEYBOARD_SHORTCUT_KEY_STATIC,LOCALIZATION_ID_SHORTCUT_KEY); + os_SetDlgItemText_localization_id(hwnd,IDC_EDIT_KEYBOARD_SHORTCUT_KEY_CURRENTLY_USED_BY_STATIC,LOCALIZATION_ID_SHORTCUT_KEY_CURRENTLY_USED_BY); + os_SetDlgItemText_localization_id(hwnd,IDOK,LOCALIZATION_ID_OK_BUTTON); + os_SetDlgItemText_localization_id(hwnd,IDCANCEL,LOCALIZATION_ID_CANCEL_BUTTON); + + os_center_dialog(hwnd); + + last_proc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hwnd,IDC_EDIT_KEY_EDIT),GWLP_WNDPROC,(LONG_PTR)_viv_edit_key_edit_proc); + SetWindowLongPtr(GetDlgItem(hwnd,IDC_EDIT_KEY_EDIT),GWLP_USERDATA,(LONG_PTR)last_proc); + + _viv_edit_key_set_key(GetDlgItem(hwnd,IDC_EDIT_KEY_EDIT),lParam); + _viv_options_edit_key_changed(hwnd); + + return FALSE; + } + + case WM_COMMAND: + + switch(LOWORD(wParam)) + { + case IDOK: + EndDialog(hwnd,GetWindowLongPtr(hwnd,GWLP_USERDATA)); + break; + + case IDCANCEL: + EndDialog(hwnd,0); + break; + } + + break; + } + + return FALSE; +} +static void _viv_options_edit_key(HWND hwnd,int key_index) +{ + int index; + _viv_key_list_t *keylist; + + keylist = (_viv_key_list_t *)GetWindowLongPtr(GetDlgItem(hwnd,IDC_COMMANDS_LIST),GWLP_USERDATA); + + index = ListBox_GetCurSel(GetDlgItem(hwnd,IDC_COMMANDS_LIST)); + + if (index != LB_ERR) + { + WORD keyflags; + + if (key_index == LB_ERR) + { + keyflags = 0; + } + else + { + keyflags = ListBox_GetItemData(GetDlgItem(hwnd,IDC_KEYS_LIST),key_index); + } + + keyflags = DialogBoxParam(os_hinstance,MAKEINTRESOURCE(IDD_EDIT_KEY),hwnd,_viv_edit_key_proc,keyflags); + + _viv_edit_key_remove_currently_used_by(keylist,keyflags); + + if (keyflags) + { + int command_index; + + command_index = ListBox_GetItemData(GetDlgItem(hwnd,IDC_COMMANDS_LIST),index); + + if (key_index == LB_ERR) + { + // new + _viv_key_add(keylist,command_index,keyflags); + } + else + { + config_key_t *key; + int keyi; + + // edit + key = keylist->start[command_index]; + keyi = 0; + + while(key) + { + if (keyi == key_index) + { + key->key = keyflags; + break; + } + + keyi++; + key = key->next; + } + } + + _viv_options_key_list_sel_change(hwnd,key_index); + } + } +} +static INT_PTR CALLBACK _viv_options_controls_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) +{ + { + INT_PTR dark_dialog_reply; + + dark_dialog_reply = _viv_dialog_dark_proc(hwnd,msg,wParam,lParam); + + if (dark_dialog_reply != -1) + { + return dark_dialog_reply; + } + } + + switch(msg) + { + case WM_INITDIALOG: + // dark chrome: title bar and dark explorer control style. + _viv_dark_dialog(hwnd); + + { + os_SetDlgItemText_localization_id(hwnd,IDC_LEFT_CLICK_ACTION_STATIC,LOCALIZATION_ID_LEFT_CLICK_ACTION_STATIC); + os_ComboBox_AddString_localization_id(hwnd,IDC_LEFTCLICKACTION_COMBOBOX,LOCALIZATION_ID_OPTIONS_ACTION_SCROLL_COMBOBOXITEM); + os_ComboBox_AddString_localization_id(hwnd,IDC_LEFTCLICKACTION_COMBOBOX,LOCALIZATION_ID_OPTIONS_ACTION_PLAY_PAUSE_SLIDESHOW_COMBOBOXITEM); + os_ComboBox_AddString_localization_id(hwnd,IDC_LEFTCLICKACTION_COMBOBOX,LOCALIZATION_ID_OPTIONS_ACTION_PLAY_PAUSE_ANIMATION_COMBOBOXITEM); + os_ComboBox_AddString_localization_id(hwnd,IDC_LEFTCLICKACTION_COMBOBOX,LOCALIZATION_ID_OPTIONS_ACTION_ZOOM_IN_COMBOBOXITEM); + os_ComboBox_AddString_localization_id(hwnd,IDC_LEFTCLICKACTION_COMBOBOX,LOCALIZATION_ID_OPTIONS_ACTION_NEXT_IMAGE_COMBOBOXITEM); + os_ComboBox_AddString_localization_id(hwnd,IDC_LEFTCLICKACTION_COMBOBOX,LOCALIZATION_ID_OPTIONS_ACTION_ONE_TO_ONE_SCROLL_COMBOBOXITEM); + os_ComboBox_AddString_localization_id(hwnd,IDC_LEFTCLICKACTION_COMBOBOX,LOCALIZATION_ID_OPTIONS_ACTION_SCROLL_MOVE_WINDOW_COMBOBOXITEM); + ComboBox_SetCurSel(GetDlgItem(hwnd,IDC_LEFTCLICKACTION_COMBOBOX),config_left_click_action); + + os_SetDlgItemText_localization_id(hwnd,IDC_RIGHT_CLICK_ACTION_STATIC,LOCALIZATION_ID_RIGHT_CLICK_ACTION_STATIC); + os_ComboBox_AddString_localization_id(hwnd,IDC_RIGHTCLICKACTION_COMBOBOX,LOCALIZATION_ID_OPTIONS_ACTION_CONTEXT_MENU_COMBOBOXITEM); + os_ComboBox_AddString_localization_id(hwnd,IDC_RIGHTCLICKACTION_COMBOBOX,LOCALIZATION_ID_OPTIONS_ACTION_ZOOM_OUT_COMBOBOXITEM); + os_ComboBox_AddString_localization_id(hwnd,IDC_RIGHTCLICKACTION_COMBOBOX,LOCALIZATION_ID_OPTIONS_ACTION_PREVIOUS_IMAGE_COMBOBOXITEM); + ComboBox_SetCurSel(GetDlgItem(hwnd,IDC_RIGHTCLICKACTION_COMBOBOX),config_right_click_action); + + os_SetDlgItemText_localization_id(hwnd,IDC_MOUSE_WHEEL_ACTION_STATIC,LOCALIZATION_ID_MOUSE_WHEEL_ACTION_STATIC); + os_ComboBox_AddString_localization_id(hwnd,IDC_MOUSEWHEELACTION_COMBOBOX,LOCALIZATION_ID_OPTIONS_ACTION_ZOOM_COMBOBOXITEM); + os_ComboBox_AddString_localization_id(hwnd,IDC_MOUSEWHEELACTION_COMBOBOX,LOCALIZATION_ID_OPTIONS_ACTION_NEXT_PREV_COMBOBOXITEM); + os_ComboBox_AddString_localization_id(hwnd,IDC_MOUSEWHEELACTION_COMBOBOX,LOCALIZATION_ID_OPTIONS_ACTION_PREV_NEXT_COMBOBOXITEM); + ComboBox_SetCurSel(GetDlgItem(hwnd,IDC_MOUSEWHEELACTION_COMBOBOX),config_mouse_wheel_action); + + os_SetDlgItemText_localization_id(hwnd,IDC_COMMANDS_STATIC,LOCALIZATION_ID_COMMANDS_STATIC); + os_SetDlgItemText_localization_id(hwnd,IDC_SETTINGS_FOR_SELECTED_COMMAND_STATIC,LOCALIZATION_ID_SETTINGS_FOR_SELECTED_COMMAND); + os_SetDlgItemText_localization_id(hwnd,IDC_ADD_KEY_BUTTON,LOCALIZATION_ID_ADD_KEY_BUTTON); + os_SetDlgItemText_localization_id(hwnd,IDC_EDIT_KEY_BUTTON,LOCALIZATION_ID_EDIT_KEY_BUTTON); + os_SetDlgItemText_localization_id(hwnd,IDC_REMOVE_KEY_BUTTON,LOCALIZATION_ID_REMOVE_KEY_BUTTON); + + { + int i; + _viv_key_list_t *keylist; + + keylist = mem_alloc(sizeof(_viv_key_list_t)); + + _viv_key_list_init(keylist); + + _viv_key_list_copy(keylist,_viv_key_list); + + SetWindowLongPtr(GetDlgItem(hwnd,IDC_COMMANDS_LIST),GWLP_USERDATA,(LONG_PTR)keylist); + + for(i=0;i<_VIV_COMMAND_COUNT;i++) + { + if (!(_viv_commands[i].flags & MF_POPUP)) + { + if (!(_viv_commands[i].flags & MF_SEPARATOR)) + { + if (!(_viv_commands[i].flags & MF_DELETE)) + { + wchar_t command_name_wbuf[STRING_SIZE]; + int index; + + _viv_get_command_name(command_name_wbuf,i); + + index = ListBox_AddString(GetDlgItem(hwnd,IDC_COMMANDS_LIST),command_name_wbuf); + if (index != LB_ERR) + { + ListBox_SetItemData(GetDlgItem(hwnd,IDC_COMMANDS_LIST),index,i); + } + } + } + } + } + } + + ListBox_SetCurSel(GetDlgItem(hwnd,IDC_COMMANDS_LIST),0); + _viv_options_key_list_sel_change(hwnd,0); + + return FALSE; + } + + case WM_COMMAND: + + switch(LOWORD(wParam)) + { + case IDC_COMMANDS_LIST: + if (HIWORD(wParam) == LBN_SELCHANGE) + { + _viv_options_key_list_sel_change(hwnd,0); + } + break; + + case IDC_REMOVE_KEY_BUTTON: + _viv_options_remove_key(hwnd); + break; + + case IDC_EDIT_KEY_BUTTON: + _viv_options_edit_key(hwnd,ListBox_GetCurSel(GetDlgItem(hwnd,IDC_KEYS_LIST))); + break; + + case IDC_ADD_KEY_BUTTON: + _viv_options_edit_key(hwnd,LB_ERR); + break; + } + break; + + case WM_DESTROY: + { + _viv_key_list_t *keylist; + + keylist = (_viv_key_list_t *)GetWindowLongPtr(GetDlgItem(hwnd,IDC_COMMANDS_LIST),GWLP_USERDATA); + + _viv_key_clear_all(keylist); + mem_free(keylist); + + break; + } + } + + return FALSE; +} +static INT_PTR CALLBACK _viv_options_view_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) +{ + { + INT_PTR dark_dialog_reply; + + dark_dialog_reply = _viv_dialog_dark_proc(hwnd,msg,wParam,lParam); + + if (dark_dialog_reply != -1) + { + return dark_dialog_reply; + } + } + + switch(msg) + { + case WM_INITDIALOG: + // dark chrome: title bar and dark explorer control style. + _viv_dark_dialog(hwnd); + + + os_SetDlgItemText_localization_id(hwnd,IDC_SHRINK_BLIT_MODE_STATIC,LOCALIZATION_ID_SHRINK_BLIT_MODE_STATIC); + os_ComboBox_AddString_localization_id(hwnd,IDC_SHRINK_BLIT_MODE_COMBOBOX,LOCALIZATION_ID_BLIT_MODE_NEAREST_COMBOBOXITEM); + os_ComboBox_AddString_localization_id(hwnd,IDC_SHRINK_BLIT_MODE_COMBOBOX,LOCALIZATION_ID_BLIT_MODE_LINEAR_COMBOBOXITEM); + + if (config_shrink_blit_mode == CONFIG_SHRINK_BLIT_MODE_HALFTONE) + { + ComboBox_SetCurSel(GetDlgItem(hwnd,IDC_SHRINK_BLIT_MODE_COMBOBOX),1); + } + else + { + ComboBox_SetCurSel(GetDlgItem(hwnd,IDC_SHRINK_BLIT_MODE_COMBOBOX),0); + } + + os_SetDlgItemText_localization_id(hwnd,IDC_MAGNIFY_BLIT_MODE_STATIC,LOCALIZATION_ID_MAGNIFY_BLIT_MODE); + os_ComboBox_AddString_localization_id(hwnd,IDC_MAGNIFY_BLIT_MODE_COMBOBOX,LOCALIZATION_ID_BLIT_MODE_NEAREST_COMBOBOXITEM); + os_ComboBox_AddString_localization_id(hwnd,IDC_MAGNIFY_BLIT_MODE_COMBOBOX,LOCALIZATION_ID_BLIT_MODE_LINEAR_COMBOBOXITEM); + + if (config_mag_filter == CONFIG_MAG_FILTER_HALFTONE) + { + ComboBox_SetCurSel(GetDlgItem(hwnd,IDC_MAGNIFY_BLIT_MODE_COMBOBOX),1); + } + else + { + ComboBox_SetCurSel(GetDlgItem(hwnd,IDC_MAGNIFY_BLIT_MODE_COMBOBOX),0); + } + + os_SetDlgItemText_localization_id(hwnd,IDC_TITLE_BAR_FORMAT_STATIC,LOCALIZATION_ID_OPTIONS_TITLE_BAR_FORMAT_STATIC); + os_ComboBox_AddString_localization_id(hwnd,IDC_TITLE_BAR_FORMAT_COMBOBOX,LOCALIZATION_ID_OPTIONS_TITLE_BAR_FORMAT_FULL_PATH_COMBOBOXITEM); + os_ComboBox_AddString_localization_id(hwnd,IDC_TITLE_BAR_FORMAT_COMBOBOX,LOCALIZATION_ID_OPTIONS_TITLE_BAR_FORMAT_FILENAME_ONLY_COMBOBOXITEM); + os_ComboBox_AddString_localization_id(hwnd,IDC_TITLE_BAR_FORMAT_COMBOBOX,LOCALIZATION_ID_OPTIONS_TITLE_BAR_FORMAT_NONE_COMBOBOXITEM); + ComboBox_SetCurSel(GetDlgItem(hwnd,IDC_TITLE_BAR_FORMAT_COMBOBOX),config_title_bar_format); + + CheckDlgButton(hwnd,IDC_AUTO_ZOOM,config_auto_zoom ? BST_CHECKED : BST_UNCHECKED); + + os_SetDlgItemText_localization_id(hwnd,IDC_AUTO_ZOOM,LOCALIZATION_ID_OPTIONS_VIEW_AUTO_SIZE_WINDOW_STATIC); + os_ComboBox_AddString_localization_id(hwnd,IDC_AUTO_SIZE_WINDOW_COMBOBOX,LOCALIZATION_ID_OPTIONS_VIEW_AUTO_SIZE_WINDOW_50_PERCENT_COMBOBOXITEM); + os_ComboBox_AddString_localization_id(hwnd,IDC_AUTO_SIZE_WINDOW_COMBOBOX,LOCALIZATION_ID_OPTIONS_VIEW_AUTO_SIZE_WINDOW_100_PERCENT_COMBOBOXITEM); + os_ComboBox_AddString_localization_id(hwnd,IDC_AUTO_SIZE_WINDOW_COMBOBOX,LOCALIZATION_ID_OPTIONS_VIEW_AUTO_SIZE_WINDOW_200_PERCENT_COMBOBOXITEM); + os_ComboBox_AddString_localization_id(hwnd,IDC_AUTO_SIZE_WINDOW_COMBOBOX,LOCALIZATION_ID_OPTIONS_VIEW_AUTO_SIZE_WINDOW_AUTO_FIT_COMBOBOXITEM); + ComboBox_SetCurSel(GetDlgItem(hwnd,IDC_AUTO_SIZE_WINDOW_COMBOBOX),config_auto_zoom_type); + EnableWindow(GetDlgItem(hwnd,IDC_AUTO_SIZE_WINDOW_COMBOBOX),IsDlgButtonChecked(hwnd,IDC_AUTO_ZOOM) == BST_CHECKED); + + os_SetDlgItemText_localization_id(hwnd,IDC_LOOP_ANIMATIONS_ONCE_STATIC,LOCALIZATION_ID_PLAY_ANIMATIONS_ONCE_STATIC); + CheckDlgButton(hwnd,IDC_LOOP_ANIMATIONS_ONCE_STATIC,config_loop_animations_once ? BST_CHECKED : BST_UNCHECKED); + + os_SetDlgItemText_localization_id(hwnd,IDC_PRELOAD_NEXT_IMAGE_STATIC,LOCALIZATION_ID_PRELOAD_NEXT_IMAGE_STATIC); + CheckDlgButton(hwnd,IDC_PRELOAD_NEXT_IMAGE_STATIC,config_preload_next ? BST_CHECKED : BST_UNCHECKED); + + os_SetDlgItemText_localization_id(hwnd,IDC_CACHE_LAST_IMAGE_STATIC,LOCALIZATION_ID_CACHE_LAST_IMAGE_STATIC); + CheckDlgButton(hwnd,IDC_CACHE_LAST_IMAGE_STATIC,config_cache_last ? BST_CHECKED : BST_UNCHECKED); + + { + int static_wide; + + static_wide = 0; + + os_SetDlgItemText_localization_id(hwnd,IDC_WINDOWEDBACKGROUNDCOLOR_STATIC,LOCALIZATION_ID_WINDOWED_BACKGROUND_COLOR_STATIC); + SetWindowLongPtr(GetDlgItem(hwnd,IDC_WINDOWEDBACKGROUNDCOLOR_BUTTON),GWLP_USERDATA,RGB(config_windowed_background_color_r,config_windowed_background_color_g,config_windowed_background_color_b)); + _viv_update_color_button_bitmap(GetDlgItem(hwnd,IDC_WINDOWEDBACKGROUNDCOLOR_BUTTON)); + static_wide = os_expand_static_wide(hwnd,IDC_WINDOWEDBACKGROUNDCOLOR_STATIC,static_wide); + + os_SetDlgItemText_localization_id(hwnd,IDC_FULLSCREENBACKGROUNDCOLOR_STATIC,LOCALIZATION_ID_FULLSCREEN_BACKGROUND_COLOR_STATIC); + SetWindowLongPtr(GetDlgItem(hwnd,IDC_FULLSCREENBACKGROUNDCOLOR_BUTTON),GWLP_USERDATA,RGB(config_fullscreen_background_color_r,config_fullscreen_background_color_g,config_fullscreen_background_color_b)); + _viv_update_color_button_bitmap(GetDlgItem(hwnd,IDC_FULLSCREENBACKGROUNDCOLOR_BUTTON)); + static_wide = os_expand_static_wide(hwnd,IDC_FULLSCREENBACKGROUNDCOLOR_STATIC,static_wide); + + os_set_dialog_item_x_wide(hwnd,IDC_WINDOWEDBACKGROUNDCOLOR_STATIC,0,static_wide+6); + os_set_dialog_item_x_wide(hwnd,IDC_WINDOWEDBACKGROUNDCOLOR_BUTTON,static_wide+6,75); + os_set_dialog_item_x_wide(hwnd,IDC_FULLSCREENBACKGROUNDCOLOR_STATIC,0,static_wide+6); + os_set_dialog_item_x_wide(hwnd,IDC_FULLSCREENBACKGROUNDCOLOR_BUTTON,static_wide+6,75); + } + + return FALSE; + + case WM_DESTROY: + _viv_delete_color_button_bitmap(GetDlgItem(hwnd,IDC_WINDOWEDBACKGROUNDCOLOR_BUTTON)); + _viv_delete_color_button_bitmap(GetDlgItem(hwnd,IDC_FULLSCREENBACKGROUNDCOLOR_BUTTON)); + break; + + case WM_COMMAND: + + switch(LOWORD(wParam)) + { + case IDC_AUTO_ZOOM: + + EnableWindow(GetDlgItem(hwnd,IDC_AUTO_SIZE_WINDOW_COMBOBOX),IsDlgButtonChecked(hwnd,IDC_AUTO_ZOOM) == BST_CHECKED); + + break; + + case IDC_WINDOWEDBACKGROUNDCOLOR_BUTTON: + case IDC_FULLSCREENBACKGROUNDCOLOR_BUTTON: + + { + COLORREF color; + + color = GetWindowLongPtr(GetDlgItem(hwnd,LOWORD(wParam)),GWLP_USERDATA); + + if (os_choose_color(hwnd,&color)) + { + SetWindowLongPtr(GetDlgItem(hwnd,LOWORD(wParam)),GWLP_USERDATA,color); + _viv_update_color_button_bitmap(GetDlgItem(hwnd,LOWORD(wParam))); + } + } + + break; + } + + break; + } + + return FALSE; +} +static void _viv_options_treeview_changed(HWND hwnd) +{ + TV_ITEM tvi; + + // get the current index + tvi.hItem = TreeView_GetSelection(GetDlgItem(hwnd,IDC_TREE1)); + if (tvi.hItem) + { + int i; + + tvi.mask = TVIF_PARAM; + + TreeView_GetItem(GetDlgItem(hwnd,IDC_TREE1),&tvi); + + ShowWindow(GetDlgItem(hwnd,_viv_options_tab_ids[tvi.lParam]),SW_SHOW); + ShowWindow(GetDlgItem(hwnd,_viv_options_page_ids[tvi.lParam]),SW_SHOW); + + for(i=0;i<_VIV_OPTIONS_PAGE_COUNT;i++) + { + if (i != tvi.lParam) + { + ShowWindow(GetDlgItem(hwnd,_viv_options_tab_ids[i]),SW_HIDE); + ShowWindow(GetDlgItem(hwnd,_viv_options_page_ids[i]),SW_HIDE); + } + } + + config_options_last_page = tvi.lParam; + } +} +static void _viv_options_update_sheild(HWND hwnd) +{ +// int exti; + int need_admin; + HWND general_page; + + general_page = GetDlgItem(hwnd,VIV_ID_OPTIONS_GENERAL); + + need_admin = 0; + /* + for(exti=0;exti<_VIV_ASSOCIATION_COUNT;exti++) + { + if (IsDlgButtonChecked(general_page,_viv_association_dlg_item_id[exti]) == BST_CHECKED) + { + if (!_viv_is_association(_viv_association_extensions[exti])) + { + need_admin = 1; + } + } + else + { + if (_viv_is_association(_viv_association_extensions[exti])) + { + need_admin = 1; + } + } + } +*/ + if ((!!config_appdata) != (IsDlgButtonChecked(general_page,IDC_APPDATA) == BST_CHECKED)) + { + need_admin = 1; + } + + if ((IsDlgButtonChecked(general_page,IDC_STARTMENU) == BST_CHECKED) != !!_viv_is_start_menu_shortcuts()) + { + need_admin = 1; + } + + if ((need_admin) && (!os_is_admin())) + { + SendMessage(GetDlgItem(hwnd,IDOK),BCM_SETSHIELD,0,TRUE); + } + else + { + SendMessage(GetDlgItem(hwnd,IDOK),BCM_SETSHIELD,0,FALSE); + } +} +// the dark options tab: the comctl tab control never follows the dark +// explorer style (no dark variant on any build) and its own WM_PAINT +// covers the whole face - the strip behind the items, the body and the 3d +// edges - in the light style. the old custom draw only reached the items, +// so the strip and the edges stayed light (the white page-title header and +// the white sliver under every page in the field screenshots). the subclass +// takes WM_PAINT over completely in the dark ui: the body face, the strip +// one step above it, and the single page-title item drawn connected to the +// body. the page dialogs paint their own dark faces over the body. +static LRESULT CALLBACK _viv_options_tab_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) +{ + WNDPROC last_proc; + + if (_viv_is_dark()) + { + if (msg == WM_ERASEBKGND) + { + RECT rect; + + GetClientRect(hwnd,&rect); + + FillRect((HDC)wParam,&rect,_viv_dark_chrome_brush(3)); + + return 1; + } + + if (msg == WM_PAINT) + { + PAINTSTRUCT ps; + RECT rect; + RECT item_rect; + wchar_t text[STRING_SIZE]; + TCITEM tcitem; + HFONT font; + HFONT old_font; + + if (BeginPaint(hwnd,&ps)) + { + GetClientRect(hwnd,&rect); + + // the body: the same face the page dialogs erase with. + FillRect(ps.hdc,&rect,_viv_dark_chrome_brush(3)); + + os_zero_memory(&tcitem,sizeof(tcitem)); + tcitem.mask = TCIF_TEXT; + tcitem.pszText = text; + tcitem.cchTextMax = STRING_SIZE; + + text[0] = 0; + + os_zero_memory(&item_rect,sizeof(item_rect)); + + if ((TabCtrl_GetItem(hwnd,0,&tcitem)) && (text[0]) && (TabCtrl_GetItemRect(hwnd,0,&item_rect))) + { + RECT strip_rect; + + CopyRect(&strip_rect,&rect); + + // the strip band behind the item ends one pixel under it: a + // hairline of the strip color separates the header from the + // body. + strip_rect.bottom = item_rect.bottom + 1; + + FillRect(ps.hdc,&strip_rect,_viv_dark_chrome_brush(0)); + + // the single page-title item connects to the body face. + FillRect(ps.hdc,&item_rect,_viv_dark_chrome_brush(3)); + + SetBkMode(ps.hdc,TRANSPARENT); + SetTextColor(ps.hdc,RGB(0xE8,0xE8,0xE8)); + + font = _viv_menu_font(); + old_font = 0; + + if (font) + { + old_font = SelectObject(ps.hdc,font); + } + + DrawTextW(ps.hdc,text,-1,&item_rect,DT_SINGLELINE | DT_CENTER | DT_VCENTER); + + if (old_font) + { + SelectObject(ps.hdc,old_font); + } + } + + EndPaint(hwnd,&ps); + } + + return 0; + } + } + + last_proc = (WNDPROC)GetWindowLongPtr(hwnd,GWLP_USERDATA); + + if (last_proc) + { + return CallWindowProc(last_proc,hwnd,msg,wParam,lParam); + } + + return DefWindowProc(hwnd,msg,wParam,lParam); +} +static INT_PTR CALLBACK _viv_options_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) +{ + { + INT_PTR dark_dialog_reply; + + dark_dialog_reply = _viv_dialog_dark_proc(hwnd,msg,wParam,lParam); + + if (dark_dialog_reply != -1) + { + return dark_dialog_reply; + } + } + + switch(msg) + { + case WM_TIMER: + + // the creation race self heal: re-run the full dialog dark pass (the + // caption, the control classes and the tree colors) with the settled + // state, whatever branch the creation moment took. + if (wParam == VIV_ID_DARK_DIALOG_ASSERT_TIMER) + { + KillTimer(hwnd,VIV_ID_DARK_DIALOG_ASSERT_TIMER); + + _viv_dark_dialog(hwnd); + + InvalidateRect(hwnd,0,TRUE); + } + + break; + + case WM_NOTIFY: + + switch(((NMHDR *)lParam)->idFrom) + { + case IDC_TREE1: + + switch(((NMHDR *)lParam)->code) + { + case TVN_SELCHANGEDA: + case TVN_SELCHANGEDW: + + if (IsWindowVisible(hwnd)) + { + _viv_options_treeview_changed(hwnd); + } + + break; + } + + break; + } + + return 0; + + case WM_INITDIALOG: + // dark chrome: title bar, dark explorer control style and the + // options navigation (tree + tabs). + _viv_dark_dialog(hwnd); + + if (_viv_is_dark()) + { + HWND tree_hwnd; + int tabi; + + tree_hwnd = GetDlgItem(hwnd,IDC_TREE1); + + if (tree_hwnd) + { + os_dark_window_theme(tree_hwnd); + + SendMessage(tree_hwnd,TVM_SETBKCOLOR,0,RGB(0x20,0x20,0x20)); + SendMessage(tree_hwnd,TVM_SETTEXTCOLOR,0,RGB(0xE8,0xE8,0xE8)); + } + + for(tabi=0;tabi<(int)_VIV_OPTIONS_PAGE_COUNT;tabi++) + { + HWND tab_hwnd; + WNDPROC last_proc; + + tab_hwnd = GetDlgItem(hwnd,_viv_options_tab_ids[tabi]); + + os_dark_window_theme(tab_hwnd); + + // the tab body never follows the dark style: subclass the tab so + // the dark body face paints (the items paint in the custom draw + // pass in the dialog proc). + last_proc = (WNDPROC)SetWindowLongPtr(tab_hwnd,GWLP_WNDPROC,(LONG_PTR)_viv_options_tab_proc); + + SetWindowLongPtr(tab_hwnd,GWLP_USERDATA,(LONG_PTR)last_proc); + } + } + + + // the dark init above read the live state: a theme race at the + // creation moment (the registry unsettled, the flip broadcast in + // flight) takes the light branch and the caption keeps the system + // light frame while the per paint cticolor replies already darken + // the body - the mixed dialog the field caught. the one shot assert + // re-runs the full dark pass after the race window closes. + SetTimer(hwnd,VIV_ID_DARK_DIALOG_ASSERT_TIMER,300,0); + + // update text. + os_SetWindowText_localization_id(hwnd,LOCALIZATION_ID_OPTIONS_CAPTION); + os_SetDlgItemText_localization_id(hwnd,IDOK,LOCALIZATION_ID_OK_BUTTON); + os_SetDlgItemText_localization_id(hwnd,IDCANCEL,LOCALIZATION_ID_CANCEL_BUTTON); + + os_center_dialog(hwnd); + + { + int i; + + for(i=0;i<_VIV_OPTIONS_PAGE_COUNT;i++) + { + TV_INSERTSTRUCT tvitem; + TCITEM tcitem; + RECT rect; + HWND page_hwnd; + HTREEITEM hitem; + wchar_t text_wbuf[STRING_SIZE]; + + string_copy_utf8_string(text_wbuf,localization_get_string(_viv_options_page_localization_id_array[i])); + + // treeview + tvitem.hInsertAfter = TVI_LAST; + tvitem.hParent = TVI_ROOT; + tvitem.item.mask = TVIF_TEXT | TVIF_PARAM; + tvitem.item.lParam = i; + tvitem.item.pszText = text_wbuf; + + hitem = TreeView_InsertItem(GetDlgItem(hwnd,IDC_TREE1),&tvitem); + + if (i == config_options_last_page) + { + TreeView_Select(GetDlgItem(hwnd,IDC_TREE1),hitem,TVGN_CARET); + } + + // tab + string_copy_utf8_string(text_wbuf,localization_get_string(_viv_options_page_localization_id_array[i])); + + tcitem.mask = TCIF_TEXT; + tcitem.pszText = text_wbuf; + TabCtrl_InsertItem(GetDlgItem(hwnd,_viv_options_tab_ids[i]),0,&tcitem); + + // page + GetClientRect(GetDlgItem(hwnd,IDC_PAGEPLACEHOLDER),&rect); + MapWindowPoints(GetDlgItem(hwnd,IDC_PAGEPLACEHOLDER),hwnd,(LPPOINT)&rect,2); + + page_hwnd = CreateDialog(os_hinstance,MAKEINTRESOURCE(_viv_options_dialog_ids[i]),hwnd,_viv_options_page_procs[i]); + SetWindowLong(page_hwnd,GWL_ID,_viv_options_page_ids[i]); + + if (os_EnableThemeDialogTexture) + { + // the light tab texture would clash with the dark chrome. + if (!_viv_is_dark()) + { + os_EnableThemeDialogTexture(page_hwnd,ETDT_ENABLETAB); + } + } + + SetWindowPos(page_hwnd,HWND_TOP,rect.left,rect.top,rect.right - rect.left,rect.bottom - rect.top,SWP_NOSIZE|SWP_NOACTIVATE); + } + } + + _viv_options_treeview_changed(hwnd); + _viv_options_update_sheild(hwnd); + + return TRUE; + + case WM_COMMAND: + + switch(LOWORD(wParam)) + { + case IDOK: + case IDCANCEL: + + if (LOWORD(wParam) == IDOK) + { + HWND general_page; + HWND view_page; + HWND controls_page; + int old_shrink_blit_mode; + int exti; + COLORREF colorref; + wchar_t params[STRING_SIZE]; + int language_changed; + + params[0] = 0; + language_changed = 0; + + general_page = GetDlgItem(hwnd,VIV_ID_OPTIONS_GENERAL); + view_page = GetDlgItem(hwnd,VIV_ID_OPTIONS_VIEW); + controls_page = GetDlgItem(hwnd,VIV_ID_OPTIONS_CONTROLS); + config_multiple_instances = 0; + + if (IsDlgButtonChecked(general_page,IDC_APPDATA) == BST_CHECKED) + { + if (!config_appdata) + { + _viv_append_admin_param(params,(const utf8_t *)"appdata"); + config_appdata = 1; + } + } + else + { + if (config_appdata) + { + _viv_append_admin_param(params,(const utf8_t *)"noappdata"); + + config_appdata = 0; + } + } + + if (IsDlgButtonChecked(general_page,IDC_MULTIPLE_INSTANCES) == BST_CHECKED) + { + config_multiple_instances = 1; + } + + // language. + { + int language; + + language = ComboBox_GetCurSel(GetDlgItem(general_page,IDC_LANGUAGE)); + + if (language != config_language) + { + config_language = language; + language_changed = 1; + + if (language == 1) + { + localization_set_language(LOCALIZATION_LANGUAGE_ENGLISH); + } + else + if (language == 2) + { + localization_set_language(LOCALIZATION_LANGUAGE_CHINESE_SIMPLIFIED); + } + else + { + // auto: follow the system language again. + localization_init(); + } + } + } + // dark mode. + { + int dark_mode; + + dark_mode = ComboBox_GetCurSel(GetDlgItem(general_page,IDC_DARKMODE)); + + if (dark_mode < 0) + { + dark_mode = 0; + } + + // combo order: automatic, light, dark. + if (dark_mode == 1) + { + config_dark_mode = 0; + } + else + if (dark_mode == 2) + { + config_dark_mode = 1; + } + else + { + config_dark_mode = 2; + } + + os_dark_set_app_mode(config_dark_mode); + _viv_apply_dark_mode(1); + + // the app mode switch flushes the menu themes and the color + // policy asynchronously: the system sweep can land after this + // apply and repaint the chrome in light (the white band the + // field caught right after the switch). the one shot assert + // re-applies once the sweep has settled. + SetTimer(_viv_hwnd,VIV_ID_DARK_RECHECK_TIMER,400,0); + } + + if (IsDlgButtonChecked(general_page,IDC_STARTMENU) == BST_CHECKED) + { + if (!_viv_is_start_menu_shortcuts()) + { + _viv_append_admin_param(params,(const utf8_t *)"startmenu"); + } + } + else + { + if (_viv_is_start_menu_shortcuts()) + { + _viv_append_admin_param(params,(const utf8_t *)"nostartmenu"); + } + } + + + for(exti=0;exti<_VIV_ASSOCIATION_COUNT;exti++) + { + if (IsDlgButtonChecked(general_page,_viv_association_dlg_item_id[exti]) == BST_CHECKED) + { + if (!_viv_is_association(_viv_association_extensions[exti])) + { + _viv_install_association_by_extension(_viv_association_extensions[exti],localization_get_string(_viv_association_description_localization_id_array[exti]),_viv_association_icon_locations[exti]); + } + } + else + { + if (_viv_is_association(_viv_association_extensions[exti])) + { + _viv_uninstall_association_by_extension(_viv_association_extensions[exti]); + } + } + } + + old_shrink_blit_mode = config_shrink_blit_mode; + + config_left_click_action = ComboBox_GetCurSel(GetDlgItem(controls_page,IDC_LEFTCLICKACTION_COMBOBOX)); + config_right_click_action = ComboBox_GetCurSel(GetDlgItem(controls_page,IDC_RIGHTCLICKACTION_COMBOBOX)); + config_mouse_wheel_action = ComboBox_GetCurSel(GetDlgItem(controls_page,IDC_MOUSEWHEELACTION_COMBOBOX)); + + if (ComboBox_GetCurSel(GetDlgItem(view_page,IDC_SHRINK_BLIT_MODE_COMBOBOX)) == 1) + { + config_shrink_blit_mode = CONFIG_SHRINK_BLIT_MODE_HALFTONE; + } + else + { + config_shrink_blit_mode = CONFIG_SHRINK_BLIT_MODE_COLORONCOLOR; + } + + colorref = (COLORREF)GetWindowLongPtr(GetDlgItem(view_page,IDC_WINDOWEDBACKGROUNDCOLOR_BUTTON),GWLP_USERDATA); + + if ((GetRValue(colorref) != config_windowed_background_color_r) || (GetGValue(colorref) != config_windowed_background_color_g) || (GetBValue(colorref) != config_windowed_background_color_b)) + { + config_windowed_background_color_r = GetRValue(colorref); + config_windowed_background_color_g = GetGValue(colorref); + config_windowed_background_color_b = GetBValue(colorref); + + // the mat, the win11 caption tint and any follow mode + // backdrop all read this color: re-tint the frame, repaint + // the canvas and reload the image so transparency under + // an open file picks the new mat up immediately. + os_window_modern_chrome(_viv_hwnd,_viv_windowed_background()); + + InvalidateRect(_viv_hwnd,0,FALSE); + _viv_refresh(); + } + + colorref = (COLORREF)GetWindowLongPtr(GetDlgItem(view_page,IDC_FULLSCREENBACKGROUNDCOLOR_BUTTON),GWLP_USERDATA); + + if ((GetRValue(colorref) != config_fullscreen_background_color_r) || (GetGValue(colorref) != config_fullscreen_background_color_g) || (GetBValue(colorref) != config_fullscreen_background_color_b)) + { + config_fullscreen_background_color_r = GetRValue(colorref); + config_fullscreen_background_color_g = GetGValue(colorref); + config_fullscreen_background_color_b = GetBValue(colorref); + + InvalidateRect(_viv_hwnd,0,FALSE); + } + + if (old_shrink_blit_mode != config_shrink_blit_mode) + { + InvalidateRect(_viv_hwnd,0,FALSE); + } + + old_shrink_blit_mode = config_mag_filter; + + if (ComboBox_GetCurSel(GetDlgItem(view_page,IDC_MAGNIFY_BLIT_MODE_COMBOBOX)) == 1) + { + config_mag_filter = CONFIG_SHRINK_BLIT_MODE_HALFTONE; + } + else + { + config_mag_filter = CONFIG_SHRINK_BLIT_MODE_COLORONCOLOR; + } + + if (old_shrink_blit_mode != config_mag_filter) + { + InvalidateRect(_viv_hwnd,0,FALSE); + } + + config_title_bar_format = ComboBox_GetCurSel(GetDlgItem(view_page,IDC_TITLE_BAR_FORMAT_COMBOBOX)); + _viv_update_title(); + + config_auto_zoom = IsDlgButtonChecked(view_page,IDC_AUTO_ZOOM) == BST_CHECKED ? 1 : 0; + config_auto_zoom_type = ComboBox_GetCurSel(GetDlgItem(view_page,IDC_AUTO_SIZE_WINDOW_COMBOBOX)); + config_loop_animations_once = IsDlgButtonChecked(view_page,IDC_LOOP_ANIMATIONS_ONCE_STATIC) == BST_CHECKED ? 1 : 0; + config_preload_next = IsDlgButtonChecked(view_page,IDC_PRELOAD_NEXT_IMAGE_STATIC) == BST_CHECKED ? 1 : 0; + config_cache_last = IsDlgButtonChecked(view_page,IDC_CACHE_LAST_IMAGE_STATIC) == BST_CHECKED ? 1 : 0; + + // copy keys. + _viv_key_list_copy(_viv_key_list,(_viv_key_list_t *)GetWindowLongPtr(GetDlgItem(controls_page,IDC_COMMANDS_LIST),GWLP_USERDATA)); + + // reinit menu. + + { + HMENU new_hmenu; + + new_hmenu = _viv_create_menu(); + + if (_viv_hmenu) + { + DestroyMenu(_viv_hmenu); + } + + _viv_hmenu = new_hmenu; + + // the fresh menu: the top bar re-reads the labels and + // re-lays them out at the current font. + _viv_menubar_layout(); + } + + // refresh the visible controls when the language has changed. + if (language_changed) + { + // recreate the toolbar so its texts and tooltips use the new language. + _viv_controls_show(0); + _viv_controls_show(config_show_controls); + + // the recreated toolbar has a fresh (light) tooltip control: + // re-apply the dark chrome to it. + _viv_apply_dark_mode(0); + + // update the floating zoom control tooltips. + zoomui_localize(); + + // relayout and redraw. (the title bar and status bar update here too) + _viv_on_size(); + InvalidateRect(_viv_hwnd,0,FALSE); + } + + // do admin commands. + if (*params) + { + wchar_t exe_filename[STRING_SIZE]; + + _viv_get_exe_filename(exe_filename); + + os_shell_execute(0,exe_filename,1,NULL,params); + } + + // save settings to disk + config_save_settings(config_appdata); + } + + EndDialog(hwnd,0); + break; + } + + break; + } + + return FALSE; +} +void _viv_options(void) +{ + // the remake settings window is the options surface now: the classic + // tabbed dialog stays retired (the template ships but nothing opens it). + _viv_settings_show(); +} +INT_PTR CALLBACK _viv_custom_rate_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) +{ + { + INT_PTR dark_dialog_reply; + + dark_dialog_reply = _viv_dialog_dark_proc(hwnd,msg,wParam,lParam); + + if (dark_dialog_reply != -1) + { + return dark_dialog_reply; + } + } + + switch(msg) + { + case WM_INITDIALOG: + // dark chrome: title bar and dark explorer control style. + _viv_dark_dialog(hwnd); + + + { + int static_wide; + RECT rect; + int wide; + + os_center_dialog(hwnd); + GetClientRect(hwnd,&rect); + wide = rect.right - rect.left - 12 - 12; + + os_SetWindowText_localization_id(hwnd,LOCALIZATION_ID_SET_CUSTOM_RATE_CAPTION); + + os_SetDlgItemText_localization_id(hwnd,IDOK,LOCALIZATION_ID_OK_BUTTON); + os_SetDlgItemText_localization_id(hwnd,IDCANCEL,LOCALIZATION_ID_CANCEL_BUTTON); + + SetDlgItemInt(hwnd,IDC_CUSTOM_RATE_EDIT,config_slideshow_custom_rate,FALSE); + + os_SetDlgItemText_localization_id(hwnd,IDC_CUSTOM_RATE_STATIC,LOCALIZATION_ID_CUSTOM_RATE_STATIC); + static_wide = os_get_static_wide(hwnd,IDC_CUSTOM_RATE_STATIC); + os_set_dialog_item_x_wide(hwnd,IDC_CUSTOM_RATE_STATIC,12,static_wide+6); + + { + int edit_combo_wide; + + edit_combo_wide = (wide - (static_wide+6) - 6) / 2; + + os_set_dialog_item_x_wide(hwnd,IDC_CUSTOM_RATE_EDIT,12 + static_wide+6,edit_combo_wide); + os_set_dialog_item_x_wide(hwnd,IDC_CUSTOM_RATE_TYPE_COMBOBOX,12 + static_wide+6 + edit_combo_wide + 6,edit_combo_wide); + } + + os_ComboBox_AddString_localization_id(hwnd,IDC_CUSTOM_RATE_TYPE_COMBOBOX,LOCALIZATION_ID_CUSTOM_RATE_MILLISECONDS); + os_ComboBox_AddString_localization_id(hwnd,IDC_CUSTOM_RATE_TYPE_COMBOBOX,LOCALIZATION_ID_CUSTOM_RATE_SECONDS); + os_ComboBox_AddString_localization_id(hwnd,IDC_CUSTOM_RATE_TYPE_COMBOBOX,LOCALIZATION_ID_CUSTOM_RATE_MINUTES); + + ComboBox_SetCurSel(GetDlgItem(hwnd,IDC_CUSTOM_RATE_TYPE_COMBOBOX),config_slideshow_custom_rate_type); + } + + return TRUE; + + case WM_COMMAND: + + switch(LOWORD(wParam)) + { + case IDOK: + config_slideshow_custom_rate_type = ComboBox_GetCurSel(GetDlgItem(hwnd,IDC_CUSTOM_RATE_TYPE_COMBOBOX)); + config_slideshow_custom_rate = GetDlgItemInt(hwnd,IDC_CUSTOM_RATE_EDIT,NULL,FALSE); + EndDialog(hwnd,1); + break; + + case IDCANCEL: + EndDialog(hwnd,0); + break; + } + + break; + } + + return FALSE; +} +// the about dialog colors. the banner (aboutback + abouttitle) keeps its +// 1.1.11 face: the black band with the white title in the light ui, the +// shared dark canvas face in the dark. the band chrome (the two separator +// lines and the button strip) answers with the same palettes the wm_paint +// passes painted before the template round moved the geometry into the +// resource template. the rest of the controls answer the light face the +// 1.1.11 ctlcolor case painted and fall through to the shared dark handler +// in the dark ui (the caller runs this before the shared proc so the band +// controls never fall into its flat 0x20 reply). +static INT_PTR _viv_about_colors(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) +{ + if ((msg == WM_CTLCOLORSTATIC) || (msg == WM_CTLCOLOREDIT)) + { + HDC hdc; + HWND control; + + hdc = (HDC)wParam; + control = (HWND)lParam; + + if ((control == GetDlgItem(hwnd,IDC_ABOUTBACK)) || (control == GetDlgItem(hwnd,IDC_ABOUTTITLE))) + { + if (_viv_is_dark()) + { + SetTextColor(hdc,RGB(0xE8,0xE8,0xE8)); + SetBkColor(hdc,RGB(0x20,0x20,0x20)); + + return (INT_PTR)_viv_dialog_dark_brush(); + } + + SetTextColor(hdc,RGB(255,255,255)); + SetBkColor(hdc,RGB(0,0,0)); + + return (LRESULT)GetStockObject(BLACK_BRUSH); + } + + if (control == GetDlgItem(hwnd,IDC_ABOUTLINE1)) + { + if (_viv_is_dark()) + { + SetBkColor(hdc,RGB(0x45,0x45,0x45)); + + return (INT_PTR)_viv_dark_chrome_brush(1); + } + + SetBkColor(hdc,RGB(0xEC,0xEC,0xEC)); + + return (INT_PTR)_viv_about_light_brush(0); + } + + if (control == GetDlgItem(hwnd,IDC_ABOUTLINE2)) + { + if (_viv_is_dark()) + { + SetBkColor(hdc,RGB(0x70,0x70,0x70)); + + return (INT_PTR)_viv_dark_chrome_brush(2); + } + + SetBkColor(hdc,RGB(0xEC,0xEC,0xEC)); + + return (INT_PTR)_viv_about_light_brush(0); + } + + if (control == GetDlgItem(hwnd,IDC_ABOUTBAND)) + { + if (_viv_is_dark()) + { + SetBkColor(hdc,RGB(0x25,0x25,0x25)); + + return (INT_PTR)_viv_dark_chrome_brush(0); + } + + SetBkColor(hdc,RGB(0xFF,0xFF,0xFF)); + + return (INT_PTR)_viv_about_light_brush(1); + } + + // the rest of the controls keep the 1.1.11 light face; the dark ui + // answers them through the shared dark handler - this reply only + // covers the light theme. + if (!_viv_is_dark()) + { + SetTextColor(hdc,RGB(0,0,0)); + SetBkColor(hdc,RGB(255,255,255)); + + return (LRESULT)GetStockObject(WHITE_BRUSH); + } + } + + if (msg == WM_CTLCOLORDLG) + { + // the dialog face: the wm_paint pass used to paint it after the + // default erase; the ctldlg reply now hands the dialog manager the + // same brush for its own erase (the template round owns the + // geometry, the palette travels the official pipeline). + if (_viv_is_dark()) + { + return (INT_PTR)_viv_dialog_dark_brush(); + } + + return (LRESULT)GetStockObject(WHITE_BRUSH); + } + + return -1; +} +INT_PTR CALLBACK _viv_about_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) +{ + { + INT_PTR own_reply; + + // the banner and the band controls answer here (the shared dark + // handler below flattens every static to the 0x20 face and the + // band needs the line and strip colors); the dialog face answers + // here because the shared handler carries no ctldlg case. any + // other message falls through to the shared pair, then to the + // switch below. + own_reply = _viv_about_colors(hwnd,msg,wParam,lParam); + + if (own_reply != -1) + { + return own_reply; + } + } + + { + INT_PTR dark_dialog_reply; + + dark_dialog_reply = _viv_dialog_dark_proc(hwnd,msg,wParam,lParam); + + if (dark_dialog_reply != -1) + { + return dark_dialog_reply; + } + } + + switch(msg) + { + case WM_INITDIALOG: + // dark chrome: title bar and dark explorer control style. + _viv_dark_dialog(hwnd); + + { + HFONT hfont; + HFONT old_hfont; + LOGFONTW lf; + wchar_t version_wbuf[STRING_SIZE]; + + os_center_dialog(hwnd); + + string_copy_utf8_string(version_wbuf,localization_get_string(LOCALIZATION_ID_ABOUT_CAPTION)); + SetWindowText(hwnd,version_wbuf); + os_SetDlgItemText_localization_id(hwnd,IDC_ABOUTTITLE,LOCALIZATION_ID_APP_NAME); + os_SetDlgItemText_localization_id(hwnd,IDC_ABOUTVOIDIMAGEVIEWER,LOCALIZATION_ID_APP_NAME); + string_printf(version_wbuf,"%s%s %s",VERSION_STRING,VERSION_TYPE,VERSION_TARGET_MACHINE); + SetDlgItemText(hwnd,IDC_ABOUTVERSION,version_wbuf); + string_printf(version_wbuf,localization_get_string(LOCALIZATION_ID_ABOUT_COPYRIGHT_FORMAT),VERSION_YEAR); + SetDlgItemText(hwnd,IDC_ABOUTCOPYRIGHT,version_wbuf); + os_SetDlgItemText_localization_id(hwnd,IDC_ABOUTEMAIL,LOCALIZATION_ID_ABOUT_EMAIL); + os_SetDlgItemText_localization_id(hwnd,IDC_ABOUTWEBSITE,LOCALIZATION_ID_ABOUT_WEBSITE); + os_SetDlgItemText_localization_id(hwnd,IDOK,LOCALIZATION_ID_OK_BUTTON); + os_SetDlgItemText_localization_id(hwnd,IDCANCEL,LOCALIZATION_ID_CANCEL_BUTTON); + + // the title face derives from the live dialog font end to + // end: the message font the shared dialog proc applied at this + // dialog window own dpi (wm_getfont reports it here: the apply + // ran before this case), through the wide pipeline so a face + // name survives whole (the unsuffixed forms borrowed the wide + // path from the project unicode define), with the height + // scaled by 8/3 - the ratio the literal 32 encoded at the 96 + // dpi design point (the message font is -12 there and + // -12 * 8 / 3 = -32) - so the family, the weight and the dpi + // scale all travel with the font the dialog actually draws. + hfont = (HFONT)SendMessage(GetDlgItem(hwnd,IDC_ABOUTTITLE),WM_GETFONT,0,0); + + if ((hfont) && (GetObjectW(hfont,sizeof(LOGFONTW),&lf))) + { + lf.lfHeight = (lf.lfHeight * 8) / 3; + + old_hfont = _viv_about_hfont; + + _viv_about_hfont = CreateFontIndirectW(&lf); + + if (_viv_about_hfont) + { + // the face is rebuilt at every open: the old handle dies + // inside this same message after the control took the new + // face (a paint can never interleave the synchronous + // wm_setfont), and a creation failure keeps the previous + // face drawing instead of a null font. + if (old_hfont) + { + DeleteObject(old_hfont); + } + } + else + { + _viv_about_hfont = old_hfont; + } + } + + if (_viv_about_hfont) + { + SendMessage(GetDlgItem(hwnd,IDC_ABOUTTITLE),WM_SETFONT,(WPARAM)_viv_about_hfont,0); + } + + return TRUE; + } + + case WM_DESTROY: + break; + + case WM_COMMAND: + + switch(LOWORD(wParam)) + { + case IDOK: + case IDCANCEL: + EndDialog(hwnd,0); + break; + } + + break; + } + + return FALSE; +} +static HWND _viv_zoom_edit_hwnd = 0; // the open in place zoom editor, or 0. +void _viv_set_zoom_dialog(void) +{ + // the status bar zoom pane click target: type an exact percent in place, + // right on the pane. (the old centered dialog box carried a sunken edit, + // native buttons and a select-all blue block that never met the remade + // chrome, and the click itself had to survive the pane's drag subclass + // first - a down eaten by the move loop, the box left to luck.) + RECT pane_rect; + wchar_t wbuf[STRING_SIZE]; + HFONT hfont; + HWND hwnd; + int wide; + + if (!_viv_image_wide) + { + return; + } + + if (!_viv_status_hwnd) + { + return; + } + + // one editor at a time: a click while one is open commits it, then + // re-opens on the current percent. + if (_viv_zoom_edit_hwnd) + { + _viv_zoom_edit_end(_viv_zoom_edit_hwnd,1); + } + + // pane 0's rect, in status bar client coordinates. + if (!SendMessage(_viv_status_hwnd,SB_GETRECT,0,(LPARAM)&pane_rect)) + { + return; + } + + // the field: the pane width minus breathing room, floor 32 (four digits). + wide = (pane_rect.right - pane_rect.left) - 8; + + if (wide < 32) + { + wide = 32; + } + + hwnd = os_CreateWindowEx( + 0, + "EDIT", + "", + WS_CHILD|WS_VISIBLE|ES_NUMBER|ES_AUTOHSCROLL, + pane_rect.left + 4,pane_rect.top + 1,wide,(pane_rect.bottom - pane_rect.top) - 2, + _viv_status_hwnd,0,os_hinstance,NULL); + + if (!hwnd) + { + return; + } + + _viv_zoom_edit_hwnd = hwnd; + + // the subclass stores the old proc in the userdata (the edit key + // dialog's own editor idiom). + { + WNDPROC old_proc; + + old_proc = (WNDPROC)SetWindowLongPtr(hwnd,GWLP_WNDPROC,(LONG_PTR)_viv_zoom_edit_proc); + + SetWindowLongPtr(hwnd,GWLP_USERDATA,(LONG_PTR)old_proc); + } + + // the pane's own font, so the digits match the strip text. + hfont = (HFONT)SendMessage(_viv_status_hwnd,WM_GETFONT,0,0); + + if (hfont) + { + SendMessage(hwnd,WM_SETFONT,(WPARAM)hfont,0); + } + + // the current percent as plain digits, selected: typing replaces. + string_printf(wbuf,"%d",_viv_zoom_percent()); + SetWindowTextW(hwnd,wbuf); + + SendMessage(hwnd,EM_SETSEL,0,-1); + + SetFocus(hwnd); +} +static void _viv_zoom_edit_end(HWND hwnd,int apply) +{ + wchar_t wbuf[STRING_SIZE]; + RECT rect; + POINT pt; + int percent; + + // the guard stops the re-entries: the kill focus that the destroy + // itself raises, and the status bar teardown cascading into a child + // editor. + if (hwnd != _viv_zoom_edit_hwnd) + { + return; + } + + _viv_zoom_edit_hwnd = 0; + + if (apply) + { + GetWindowTextW(hwnd,wbuf,STRING_SIZE); + + percent = string_to_int(wbuf); + + // the ladder covers 1% .. 1600%: clamp anything above, ignore + // empty or zero input (the old dialog's contract). + if (percent > 1600) + { + percent = 1600; + } + + if (percent >= 1) + { + GetClientRect(_viv_hwnd,&rect); + pt.x = (rect.right - rect.left) / 2; + pt.y = (_viv_get_view_top() + (rect.bottom - rect.top - _viv_get_status_high())) / 2; + + ClientToScreen(_viv_hwnd,&pt); + + _viv_zoom_set_percent(percent,pt.x,pt.y,0); + } + } + + // the keyboard goes home to the main window only while the editor + // still owns it: a kill focus end means the focus already has a new + // home (inside or outside the app) - stealing it back would make the + // app a focus thief. (the kill focus this raises re-enters the guard + // above.) + if (GetFocus() == hwnd) + { + SetFocus(_viv_hwnd); + } + + DestroyWindow(hwnd); +} +static LRESULT CALLBACK _viv_zoom_edit_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) +{ + WNDPROC old_proc; + + old_proc = (WNDPROC)GetWindowLongPtr(hwnd,GWLP_USERDATA); + + switch(msg) + { + case WM_KEYDOWN: + + // enter commits, escape cancels: one short lived field, no + // dialog machinery above it. + if (wParam == VK_RETURN) + { + _viv_zoom_edit_end(hwnd,1); + + return 0; + } + + if (wParam == VK_ESCAPE) + { + _viv_zoom_edit_end(hwnd,0); + + return 0; + } + + break; + + case WM_KILLFOCUS: + + // focus went elsewhere: commit (the field never keeps a half + // typed value). + _viv_zoom_edit_end(hwnd,1); + + return 0; + + case WM_DESTROY: + + _viv_zoom_edit_hwnd = 0; + + break; + } + + return CallWindowProc(old_proc,hwnd,msg,wParam,lParam); +} + +void _viv_command_line_options(void) +{ + wchar_t *text_wbuf; + wchar_t caption_wbuf[STRING_SIZE]; + + text_wbuf = string_alloc_utf8("Usage:\nvoidImageViewer.exe [/switches] [filename(s)]\n" + "\n" + "Switches:\n" + "/slideshow\tStart a slideshow.\n" + "/fullscreen\tStart fullscreen.\n" + "/maximized\tStart maximized.\n" + "/window\t\tStart windowed.\n" + "/ontop\t\tShow on top of other windows.\n" + "/minimal\t\tBorderless window.\n" + "/compact\t\tBordered window.\n" + "/x /y /width /height \n" + "\t\tSet the Window position and size.\n" + "/rate \tSet the slideshow rate in milliseconds.\n" + "/name\t\tSort by name.\n" + "/path\t\tSort by full path.\n" + "/size\t\tSort by size.\n" + "/dm\t\tSort by date modified.\n" + "/dc\t\tSort by date created.\n" + "/ascending\tSort in ascending order.\n" + "/descending\tSort in descending order.\n" +// "/everything Open files from an Everything search.\n" +// "/random \tOpen random files from an Everything search.\n" + "/shuffle\t\tShuffle playlist.\n" + "/\n" + "\t\tInstall association.\n" + "/no\n" + "\t\tUninstall association.\n" + "/appdata\t\tSave settings in appdata.\n" + "/noappdata\tSave settings in exe path.\n" + "/startmenu\tAdd Start menu shortcuts.\n" + "/nostartmenu\tRemove Start menu shortcuts.\n" + "/install \tInstall to the specified path.\n" + "/install-options <...> Run with the specified options after installation.\n" + "/language \tSet the interface language: auto, english or chinese.\n" + "/uninstall \tUninstall from the specified path.\n"); + + string_copy_utf8_string(caption_wbuf,localization_get_string(LOCALIZATION_ID_APP_NAME)); + + // MB_ICONQUESTION avoids the messagebeep. + viv_msgbox(_viv_hwnd,caption_wbuf,text_wbuf,MB_OK|MB_ICONQUESTION); + + mem_free(text_wbuf); +} +static void _viv_update_color_button_bitmap(HWND hwnd) +{ + HBITMAP hbitmap; + HDC screen_hdc; + HDC mem_hdc; + HGDIOBJ last_hbitmap; + RECT rect; + HBRUSH hbrush; + COLORREF colorref; + int wide; + int high; + + wide = (64 * os_logical_wide) / 96; + high = (13 * os_logical_high) / 96; + + colorref = (COLORREF)GetWindowLongPtr(hwnd,GWLP_USERDATA); + + screen_hdc = GetDC(0); + mem_hdc = CreateCompatibleDC(screen_hdc); + + hbitmap = CreateCompatibleBitmap(screen_hdc,wide,high); + + last_hbitmap = SelectObject(mem_hdc,hbitmap); + + hbrush = CreateSolidBrush(colorref); + + rect.left = 1; + rect.top = 1; + rect.right = wide-1; + rect.bottom = high-1; + FillRect(mem_hdc,&rect,hbrush); + ExcludeClipRect(mem_hdc,rect.left,rect.top,rect.right,rect.bottom); + + rect.left = 0; + rect.top = 0; + rect.right = wide; + rect.bottom = high; + FillRect(mem_hdc,&rect,(HBRUSH)GetStockObject(BLACK_BRUSH)); + + DeleteObject(hbrush); + + SelectObject(mem_hdc,last_hbitmap); + + DeleteDC(mem_hdc); + ReleaseDC(0,screen_hdc); + + last_hbitmap = (HBITMAP)SendMessage(hwnd,BM_SETIMAGE,IMAGE_BITMAP,(LPARAM)hbitmap); + if (last_hbitmap) + { + DeleteObject(last_hbitmap); + } +} +static void _viv_delete_color_button_bitmap(HWND hwnd) +{ + HGDIOBJ last_hbitmap; + + last_hbitmap = (HBITMAP)SendMessage(hwnd,BM_SETIMAGE,IMAGE_BITMAP,0); + + if (last_hbitmap) + { + DeleteObject(last_hbitmap); + } +} +static LRESULT CALLBACK _viv_edit_key_edit_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) +{ + WNDPROC last_proc; + + last_proc = (WNDPROC)GetWindowLongPtr(hwnd,GWLP_USERDATA); + + switch(msg) + { + case WM_GETDLGCODE: + return DLGC_WANTALLKEYS; + + case WM_SYSKEYDOWN: + case WM_KEYDOWN: + { + int key_flags; + int vk; + + key_flags = _viv_get_current_key_mod_flags(); + vk = wParam; + + switch(vk) + { + case VK_CONTROL: + case VK_SHIFT: + case VK_MENU: + case VK_LWIN: + case VK_RWIN: + return 0; + + //FIXME: + // case VK_PROCESSKEY: + // // restore IME hacked key. + // vk = ImmGetVirtualKey(msg->hwnd); + // break; + } + + _viv_edit_key_set_key(hwnd,key_flags | vk); + _viv_options_edit_key_changed(GetParent(hwnd)); + + return 0; + } + } + + if ((msg == WM_LBUTTONDOWN) || (msg == WM_RBUTTONDOWN)) + { + SetFocus(hwnd); + + return 0; + } + + // ignore mouse messages. + if ((msg >= WM_MOUSEFIRST) && (msg <= WM_MOUSELAST)) + { + return 0; + } + + // ignore keyboard messages. + if ((msg >= WM_KEYFIRST) && (msg <= WM_KEYLAST)) + { + return 0; + } + + return CallWindowProc(last_proc,hwnd,msg,wParam,lParam); +} +static void _viv_options_edit_key_changed(HWND hwnd) +{ + int keyflags; + int command_index; + + keyflags = GetWindowLongPtr(hwnd,GWLP_USERDATA); + + ListBox_ResetContent(GetDlgItem(hwnd,IDC_EDIT_KEY_CURRENTLY_USED_BY_LIST)); + SetWindowRedraw(GetDlgItem(hwnd,IDC_EDIT_KEY_CURRENTLY_USED_BY_LIST),FALSE); + + for(command_index=0;command_index<_VIV_COMMAND_COUNT;command_index++) + { + config_key_t *key; + + key = _viv_key_list->start[command_index]; + + while(key) + { + if (key->key == keyflags) + { + wchar_t command_wbuf[STRING_SIZE]; + + _viv_get_command_name(command_wbuf,command_index); + + ListBox_AddString(GetDlgItem(hwnd,IDC_EDIT_KEY_CURRENTLY_USED_BY_LIST),command_wbuf); + } + + key = key->next; + } + } + + ListBox_SetCurSel(GetDlgItem(hwnd,IDC_EDIT_KEY_CURRENTLY_USED_BY_LIST),0); + + SetWindowRedraw(GetDlgItem(hwnd,IDC_EDIT_KEY_CURRENTLY_USED_BY_LIST),TRUE); +} +static void _viv_edit_key_set_key(HWND hwnd,DWORD key_flags) +{ + wchar_t keytext_wbuf[STRING_SIZE]; + + if (key_flags) + { + _viv_get_key_text(keytext_wbuf,key_flags); + } + else + { + keytext_wbuf[0] = 0; + SetWindowLongPtr(GetParent(hwnd),GWLP_USERDATA,0); + } + + SetWindowLongPtr(GetParent(hwnd),GWLP_USERDATA,key_flags); + + SetWindowText(hwnd,keytext_wbuf); + + os_edit_move_caret_to_end(hwnd); +} +static void _viv_edit_key_remove_currently_used_by(_viv_key_list_t *keylist,DWORD keyflags) +{ + int command_index; + + for(command_index=0;command_index<_VIV_COMMAND_COUNT;command_index++) + { + _viv_key_remove(keylist,command_index,keyflags); + } +} +static void _viv_jumpto_on_size(HWND hwnd) +{ + RECT rect; + int wide; + int high; + int edit_high; + int button_wide; + int button_high; + int y; + int edge; + int list_high; + + GetClientRect(hwnd,&rect); + wide = rect.right - rect.left; + high = rect.bottom - rect.top; + + GetWindowRect(GetDlgItem(hwnd,IDC_JUMPTO_EDIT),&rect); + edit_high = rect.bottom - rect.top; + + GetWindowRect(GetDlgItem(hwnd,IDOK),&rect); + button_wide = rect.right - rect.left; + button_high = rect.bottom - rect.top; + + edge = (12 * os_logical_high) / 96; + y = edge; + + SetWindowPos(GetDlgItem(hwnd,IDC_JUMPTO_EDIT),0,edge,y,wide-edge-edge,edit_high,SWP_NOACTIVATE|SWP_NOZORDER); + + y += edit_high + (6 * os_logical_high) / 96; + + high -= button_high + edge; + + list_high = (high - y) - edge; + if (list_high < 0) + { + list_high = 0; + } + + SetWindowPos(GetDlgItem(hwnd,IDC_JUMPTO_LIST),0,edge,y,wide-edge-edge,list_high,SWP_NOACTIVATE|SWP_NOZORDER); + + y += list_high + edge; + + SetWindowPos(GetDlgItem(hwnd,IDOK),0,wide - edge - button_wide - edge - button_wide,y,button_wide,button_high,SWP_NOACTIVATE|SWP_NOZORDER); + SetWindowPos(GetDlgItem(hwnd,IDCANCEL),0,wide - edge - button_wide,y,button_wide,button_high,SWP_NOACTIVATE|SWP_NOZORDER); +} +static void _viv_jumpto_on_search(HWND hwnd) +{ + wchar_t search_wbuf[STRING_SIZE]; + int is_path_search; + + GetDlgItemText(hwnd,IDC_JUMPTO_EDIT,search_wbuf,STRING_SIZE); + + SendDlgItemMessage(hwnd,IDC_JUMPTO_LIST,WM_SETREDRAW,FALSE,0); + + ListBox_ResetContent(GetDlgItem(hwnd,IDC_JUMPTO_LIST)); + + is_path_search = 0; + + { + const wchar_t *p; + + p = search_wbuf; + + while(*p) + { + if ((*p == '\\') || (*p == '/') || (*p == ':')) + { + is_path_search = 1; + break; + } + + p++; + } + } + + { + int i; + + for(i=0;i<_viv_nav_item_count;i++) + { + const wchar_t *name; + const wchar_t *search_name; + + name = string_get_filename_part(_viv_nav_items[i]->fd.cFileName); + + if (is_path_search) + { + search_name = _viv_nav_items[i]->fd.cFileName; + } + else + { + search_name = name; + } + + if ((!(*search_wbuf)) || (StrStrI(search_name,search_wbuf))) + { + int lb_index; + + lb_index = ListBox_AddString(GetDlgItem(hwnd,IDC_JUMPTO_LIST),string_get_filename_part(name)); + + ListBox_SetItemData(GetDlgItem(hwnd,IDC_JUMPTO_LIST),lb_index,i); + } + } + } + + ListBox_SetCurSel(GetDlgItem(hwnd,IDC_JUMPTO_LIST),0); + + SendDlgItemMessage(hwnd,IDC_JUMPTO_LIST,WM_SETREDRAW,TRUE,0); +} +static void _viv_jumpto_open_sel(HWND hwnd) +{ + int lb_index; + + lb_index = ListBox_GetCurSel(GetDlgItem(hwnd,IDC_JUMPTO_LIST)); + + if (lb_index != LB_ERR) + { + int index; + + index = ListBox_GetItemData(GetDlgItem(hwnd,IDC_JUMPTO_LIST),lb_index); + + if ((index >= 0) && (index < _viv_nav_item_count)) + { + _viv_open(&_viv_nav_items[index]->fd,0); + } + } +} +static LRESULT CALLBACK _viv_jumpto_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) +{ + { + INT_PTR dark_dialog_reply; + + dark_dialog_reply = _viv_dialog_dark_proc(hwnd,msg,wParam,lParam); + + if (dark_dialog_reply != -1) + { + return dark_dialog_reply; + } + } + + switch(msg) + { + case WM_INITDIALOG: + // dark chrome: title bar and dark explorer control style. + _viv_dark_dialog(hwnd); + + + { + int cur_index; + + cur_index = LB_ERR; + + os_SetWindowText_localization_id(hwnd,LOCALIZATION_ID_JUMP_TO_TITLE); + os_SetDlgItemText_localization_id(hwnd,IDOK,LOCALIZATION_ID_OK_BUTTON); + os_SetDlgItemText_localization_id(hwnd,IDCANCEL,LOCALIZATION_ID_CANCEL_BUTTON); + + os_center_dialog(hwnd); + + _viv_nav_item_free_all(); + + if (_viv_playlist_start) + { + _viv_playlist_t *d; + + d = _viv_playlist_start; + while(d) + { + _viv_nav_item_add(&d->fd); + + d = d->next; + } + } + else + if (*_viv_current_fd->cFileName) + { + WIN32_FIND_DATA fd; + HANDLE h; + wchar_t search_wbuf[STRING_SIZE]; + wchar_t path_wbuf[STRING_SIZE]; + + string_get_path_part(path_wbuf,_viv_current_fd->cFileName); + + string_copy(search_wbuf,path_wbuf); + string_cat_utf8(search_wbuf,(const utf8_t *)"\\*.*"); + + h = FindFirstFile(search_wbuf,&fd); + + if (h != INVALID_HANDLE_VALUE) + { + for(;;) + { + if (_viv_is_valid_filename(&fd)) + { + string_path_combine(search_wbuf,path_wbuf,fd.cFileName); + string_copy_with_bufsize(fd.cFileName,MAX_PATH,search_wbuf); + + _viv_nav_item_add(&fd); + } + + if (!FindNextFile(h,&fd)) break; + } + + FindClose(h); + } + } + + if (_viv_nav_item_count) + { + _viv_nav_item_t **d; + _viv_nav_item_t *navitem; + + _viv_nav_items = (_viv_nav_item_t **)mem_alloc(safe_size_mul_sizeof_pointer((SIZE_T)_viv_nav_item_count)); + d = _viv_nav_items; + + navitem = __viv_nav_item_start; + while(navitem) + { + *d++ = navitem; + + navitem = navitem->next; + } + } + + // sort by name + os_qsort(_viv_nav_items,_viv_nav_item_count,_viv_nav_compare); + + // find current. + { + _viv_nav_item_t **p; + SIZE_T run; + int index; + + p = _viv_nav_items; + run = _viv_nav_item_count; + index = 0; + + while(run) + { + if (string_compare((*p)->fd.cFileName,_viv_current_fd->cFileName) == 0) + { + cur_index = index; + } + + index++; + p++; + run--; + } + } + + _viv_jumpto_on_size(hwnd); + _viv_jumpto_on_search(hwnd); + + if (cur_index != LB_ERR) + { + ListBox_SetCurSel(GetDlgItem(hwnd,IDC_JUMPTO_LIST),cur_index); + + _viv_center_listbox_item(GetDlgItem(hwnd,IDC_JUMPTO_LIST),cur_index); + } + } + + return TRUE; + + case WM_COMMAND: + + switch(LOWORD(wParam)) + { + case IDC_JUMPTO_EDIT: + if (HIWORD(wParam) == EN_CHANGE) + { + _viv_jumpto_on_search(hwnd); + break; + } + break; + + case IDC_JUMPTO_LIST: + if (HIWORD(wParam) == LBN_DBLCLK) + { + _viv_jumpto_open_sel(hwnd); + _viv_jump_ret = 1; + break; + } + break; + + case IDOK: + _viv_jumpto_open_sel(hwnd); + _viv_jump_ret = 1; + break; + + case IDCANCEL: + _viv_jump_ret = 1; + break; + } + + break; + + case WM_SIZE: + _viv_jumpto_on_size(hwnd); + break; + + case WM_CLOSE: + _viv_jump_ret = 1; + return TRUE; + + case WM_DESTROY: + _viv_nav_item_free_all(); + break; + } + + return FALSE; +} +void _viv_show_jumpto(void) +{ + HWND dialog_hwnd; + + _viv_jump_ret = 0; + + dialog_hwnd = CreateDialog(os_hinstance,MAKEINTRESOURCE(IDD_JUMPTO),_viv_hwnd,_viv_jumpto_proc); + + if (dialog_hwnd) + { + ShowWindow(dialog_hwnd,SW_SHOW); + EnableWindow(_viv_hwnd,FALSE); + + while(!_viv_jump_ret) + { + MSG msg; + + if (!GetMessageW(&msg,NULL,0,0)) + { + // the modal pump consumed a WM_QUIT (GetMessage returned 0): + // re-inject it so the main message loop terminates instead of + // blocking in WaitMessage forever. + PostQuitMessage((int)msg.wParam); + break; + } + + if ((msg.hwnd == dialog_hwnd) || (IsChild(dialog_hwnd,msg.hwnd))) + { + switch (msg.message) + { + case WM_MOUSEWHEEL: + + SendMessage(GetDlgItem(dialog_hwnd,IDC_JUMPTO_LIST),WM_MOUSEWHEEL,msg.wParam,msg.lParam); + continue; + + case WM_SYSKEYDOWN: + case WM_KEYDOWN: + + if (msg.hwnd == GetDlgItem(dialog_hwnd,IDC_JUMPTO_EDIT)) + { + int key_flags; + int vk; + + key_flags = _viv_get_current_key_mod_flags(); + vk = msg.wParam; + + switch(vk) + { + case VK_UP: + case VK_DOWN: + case VK_NEXT: + case VK_PRIOR: + + /* + + { + int count; + int index; + + // msg->hwnd = GetDlgItem(dialog_hwnd,IDC_JUMPTO_LIST); + + index = -1; + count = ListBox_GetCount(GetDlgItem(dialog_hwnd,IDC_JUMPTO_LIST)); + + if (count) + { + switch (msg.wParam) + { + case VK_DOWN: + case VK_NEXT: + index = 0; + break; + + default: + index = count - 1; + break; + } + } + + if (index != -1) + { + ListBox_SetCurSel(GetDlgItem(dialog_hwnd,IDC_JUMPTO_LIST),index); + } + + SetFocus(GetDlgItem(dialog_hwnd,IDC_JUMPTO_LIST)); + } + */ + + SendMessage(GetDlgItem(dialog_hwnd,IDC_JUMPTO_LIST),msg.message,msg.wParam,msg.lParam); + + //SetFocus(GetDlgItem(dialog_hwnd,IDC_JUMPTO_LIST)); + + continue; + } + } + + break; + + } + } + + if (!IsDialogMessageW(dialog_hwnd,&msg)) + { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + } + + EnableWindow(_viv_hwnd,TRUE); + DestroyWindow(dialog_hwnd); + } +} +static void _viv_center_listbox_item(HWND listbox_hwnd,int item_index) +{ + int item_high; + + item_high = ListBox_GetItemHeight(listbox_hwnd,item_index); + + if (item_high > 0) + { + RECT client_rect; + int visible_count; + + GetClientRect(listbox_hwnd,&client_rect); + + visible_count = (client_rect.bottom - client_rect.top) / item_high; + + if (visible_count > 0) + { + int new_top; + int item_count; + + item_count = ListBox_GetCount(listbox_hwnd); + + new_top = item_index - (visible_count / 2); + + if (new_top < 0) + { + new_top = 0; + } + + if (new_top > item_count - visible_count) + { + new_top = item_count - visible_count; + } + + if (new_top < 0) + { + new_top = 0; + } + + ListBox_SetTopIndex(listbox_hwnd,new_top); + } + } +} diff --git a/src/viv_dialogs.h b/src/viv_dialogs.h new file mode 100644 index 00000000..036a07f1 --- /dev/null +++ b/src/viv_dialogs.h @@ -0,0 +1,41 @@ +// +// Copyright 2025 voidtools / David Carpenter +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +// VoidImageViewer +// viv_dialogs.h - modal dialogs: options, jump-to, about, rename, zoom, rate. +#ifndef VIV_DIALOGS_H +#define VIV_DIALOGS_H + +#include "viv.h" + +// exported to other domains / the viv.c core +void _viv_dialog_apply_font(HWND hwnd); +void _viv_rename(void); +void _viv_options(void); +INT_PTR CALLBACK _viv_custom_rate_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); +INT_PTR CALLBACK _viv_about_proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); +// opens the in place zoom editor on the status bar pane (the name +// keeps the old dialog's call sites stable). +void _viv_set_zoom_dialog(void); +void _viv_command_line_options(void); +void _viv_show_jumpto(void); + +#endif diff --git a/src/viv_install.c b/src/viv_install.c new file mode 100644 index 00000000..ca98f5ee --- /dev/null +++ b/src/viv_install.c @@ -0,0 +1,1045 @@ +// +// Copyright 2025 voidtools / David Carpenter +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +// VoidImageViewer +// viv_install.c - install/uninstall, associations, registry, shortcuts, elevation. +// Pure physical move from viv.c (R70 split): bodies are unchanged. +#include "viv.h" +#include "viv_state.h" +#include "viv_install.h" + +// forward declarations (order preserved from viv.c) +int _viv_process_install_command_line_options(wchar_t *cl); +void _viv_install_association_by_extension(const char *association,const char *description,const char *icon_location); +void _viv_uninstall_association_by_extension(const char *association); +int _viv_is_association(const char *association); +static int _viv_get_registry_string(HKEY hkey,const utf8_t *value,wchar_t *wbuf,int size_in_wchars); +static int _viv_set_registry_string(HKEY hkey,const utf8_t *value,const wchar_t *wbuf); +static void _viv_install_association(DWORD flags); +static void _viv_uninstall_association(DWORD flags); +static int _viv_is_voidimageviewer_process(DWORD process_id); +static void _viv_close_existing_process(void); +static void _viv_uninstall_delete_file(const wchar_t *path,const utf8_t *filename); +int _viv_is_start_menu_shortcuts(void); +static void _viv_install_start_menu_shortcuts(void); +static void _viv_uninstall_start_menu_shortcuts(void); +void _viv_append_admin_param(wchar_t *wbuf,const utf8_t *param); +static void _viv_install_add_remove_programs(const wchar_t *install_path); +static void _viv_uninstall_add_remove_programs(void); +static void _viv_install_copy_file(const wchar_t *install_path,const wchar_t *temp_path,const utf8_t *filename,int critical); +void _viv_get_exe_filename(wchar_t filename[STRING_SIZE]); + + +int _viv_process_install_command_line_options(wchar_t *cl) +{ + wchar_t *p; + wchar_t buf[STRING_SIZE]; + DWORD install_flags; + DWORD uninstall_flags; + int appdata; + int is_runas; + wchar_t install_path[STRING_SIZE]; + wchar_t install_options[STRING_SIZE]; + wchar_t uninstall_path[STRING_SIZE]; + int startmenu; + int language; + int language_set; + wchar_t *cl_start; + int is_admin_install; + int is_standard_user_install; + + startmenu = 0; + install_flags = 0; + uninstall_flags = 0; + appdata = 0; + is_runas = 0; + is_admin_install = 0; + is_standard_user_install = 0; + language = config_language; + language_set = 0; + install_path[0] = 0; + install_options[0] = 0; + uninstall_path[0] = 0; + + p = string_skip_ws(cl); + + // skip exe filename + p = string_get_word(p,buf,STRING_SIZE); + p = string_skip_ws(p); + + cl_start = p; + + // skip first parameter. + for(;;) + { + wchar_t *bufstart; + BOOL was_quote; + + // no more text? + if (!*p) + { + break; + } + + was_quote = FALSE; + if (*p == '"') + { + was_quote = TRUE; + } + + p = string_get_word(p,buf,STRING_SIZE); + p = string_skip_ws(p); + + bufstart = buf; + + // treat switches with a '.' as a filename. + // eg: voidimageviewer.exe -my-image.png + if ((!was_quote) && ((*bufstart == '/') || (*bufstart == '-')) && (!string_is_dot(buf))) + { + bufstart++; + + if (string_icompare_lowercase_ascii(bufstart,"install") == 0) + { + p = string_get_word(p,install_path,STRING_SIZE); + p = string_skip_ws(p); + + uninstall_path[0] = 0; + + is_admin_install = 1; + } + else + if (string_icompare_lowercase_ascii(bufstart,"install-options") == 0) + { + p = string_get_word(p,install_options,STRING_SIZE); + p = string_skip_ws(p); + + is_admin_install = 1; + } + else + if (string_icompare_lowercase_ascii(bufstart,"uninstall") == 0) + { + p = string_get_word(p,uninstall_path,STRING_SIZE); + p = string_skip_ws(p); + + // no uninstall path? + if (!uninstall_path[0]) + { + // caller will need to manually delete voidimageviewer.exe + string_get_exe_path(uninstall_path); + } + + // uninstall all + uninstall_flags = 0xffffffff; + install_flags = 0; + startmenu = -1; + + install_path[0] = 0; + + is_admin_install = 1; + is_standard_user_install = 1; + } + else + if (string_icompare_lowercase_ascii(bufstart,"appdata") == 0) + { + appdata = 1; + is_admin_install = 1; + } + else + if (string_icompare_lowercase_ascii(bufstart,"noappdata") == 0) + { + appdata = -1; + is_admin_install = 1; + } + else + if (string_icompare_lowercase_ascii(bufstart,"startmenu") == 0) + { + startmenu = 1; + is_admin_install = 1; + } + else + if (string_icompare_lowercase_ascii(bufstart,"nostartmenu") == 0) + { + startmenu = -1; + is_admin_install = 1; + } + else + if (string_icompare_lowercase_ascii(bufstart,"language") == 0) + { + wchar_t language_wbuf[STRING_SIZE]; + + p = string_get_word(p,language_wbuf,STRING_SIZE); + p = string_skip_ws(p); + + // map the language name to a config_language value. + // 0 = auto (system), 1 = english, 2 = simplified chinese. + // this does not require admin rights, the setting is stored in the ini. + + if (string_icompare_lowercase_ascii(language_wbuf,"english") == 0) + { + language = 1; + language_set = 1; + } + else + if (string_icompare_lowercase_ascii(language_wbuf,"chinese") == 0) + { + language = 2; + language_set = 1; + } + else + if (string_icompare_lowercase_ascii(language_wbuf,"auto") == 0) + { + language = 0; + language_set = 1; + } + } + else + if (string_icompare_lowercase_ascii(bufstart,"isrunas") == 0) + { + is_runas = 1; + } + else + { + int exti; + int is_no; + + is_no = 0; + + if (string_istartwith_lowercase_ascii(bufstart,"no")) + { + bufstart += 2; + is_no = 1; + } + + for(exti=0;exti<_VIV_ASSOCIATION_COUNT;exti++) + { + if (string_icompare_lowercase_ascii(bufstart,_viv_association_extensions[exti]) == 0) + { + if (is_no) + { + uninstall_flags |= 1 << exti; + } + else + { + install_flags |= 1 << exti; + } + + is_standard_user_install = 1; + break; + } + } + } + } + } + + // debug_printf("isrunas %d install_flags %u uninstall_flags %u\n",is_runas,install_flags,uninstall_flags); + + // do associationas as standard user + if (!is_runas) + { + if (install_flags) + { + _viv_install_association(install_flags); + } + + if (uninstall_flags) + { + _viv_uninstall_association(uninstall_flags); + } + } + + if (is_admin_install) + { + if (!os_is_admin()) + { + if (!is_runas) + { + wchar_t exe_filename[STRING_SIZE]; + wchar_t params[STRING_SIZE]; + wchar_t cwd[STRING_SIZE]; + + _viv_get_exe_filename(exe_filename); + GetCurrentDirectory(STRING_SIZE,cwd); + + string_copy_utf8_string(params,(const utf8_t *)"/isrunas "); + string_cat(params,cl_start); + + os_shell_execute(0,exe_filename,1,"runas",params); + + return 1; + } + } + } + + if (language_set) + { + config_language = language; + + // save the language selection to the current settings location. + // (before the appdata handling below so that its saves include the new language) + config_save_settings(config_appdata); + } + + if (appdata > 0) + { + config_appdata = 1; + + config_save_settings(config_appdata); + + // appdata enabled. + config_save_settings(0); + } + else + if (appdata < 0) + { + config_appdata = 0; + + // appdata disabled + config_save_settings(0); + } + + if (startmenu > 0) + { + _viv_install_start_menu_shortcuts(); + } + else + if (startmenu < 0) + { + _viv_uninstall_start_menu_shortcuts(); + } + + if (install_path[0]) + { + wchar_t temp_path[STRING_SIZE]; + + // make sure no other process is running. + _viv_close_existing_process(); + + string_get_exe_path(temp_path); + + os_make_sure_path_exists(install_path); + + _viv_install_copy_file(install_path,temp_path,(const utf8_t *)"voidImageViewer.exe",1); + _viv_install_copy_file(install_path,temp_path,(const utf8_t *)"Uninstall.exe",0); + _viv_install_copy_file(install_path,temp_path,(const utf8_t *)"Changes.txt",0); + + // register in add/remove programs so the app shows up in + // programs and features. + _viv_install_add_remove_programs(install_path); + + if (install_options[0]) + { + wchar_t new_exe_filename_wbuf[STRING_SIZE]; + + string_path_combine_utf8(new_exe_filename_wbuf,install_path,(const utf8_t *)"voidImageViewer.exe"); + + os_shell_execute(0,new_exe_filename_wbuf,1,NULL,install_options); + } + } + + if (uninstall_path[0]) + { + wchar_t path[STRING_SIZE]; + + // make sure no other process is running. + _viv_close_existing_process(); + + // remove our add/remove programs entry (from both hives). + _viv_uninstall_add_remove_programs(); + + // remove %APPDATA%\voidimageviewer + if (string_get_appdata_voidimageviewer_path(path)) + { + _viv_uninstall_delete_file(path,(const utf8_t *)"voidImageViewer.ini"); + + RemoveDirectory(path); + } + + _viv_uninstall_delete_file(uninstall_path,(const utf8_t *)"Uninstall.exe"); + _viv_uninstall_delete_file(uninstall_path,(const utf8_t *)"Changes.txt"); + _viv_uninstall_delete_file(uninstall_path,(const utf8_t *)"voidImageViewer.ini"); + _viv_uninstall_delete_file(uninstall_path,(const utf8_t *)"voidImageViewer.exe"); + + RemoveDirectory(uninstall_path); + } + + if ((is_admin_install) || (is_standard_user_install)) + { + return 1; + } + + return 0; +} +// use the default class description, ie: TXT File +void _viv_install_association_by_extension(const char *association,const char *description,const char *icon_location) +{ + HKEY hkey; + wchar_t class_name[STRING_SIZE]; + wchar_t key[STRING_SIZE]; + wchar_t default_icon[STRING_SIZE]; + wchar_t dot_association[STRING_SIZE]; + LONG reg_ret; + + string_copy_utf8_string(dot_association,(const utf8_t *)"."); + string_cat_utf8(dot_association,association); + + // make sure we uninstall old associations first. + _viv_uninstall_association_by_extension(association); + + string_copy_utf8_string(class_name,"voidImageViewer"); + string_cat(class_name,dot_association); + + string_copy_utf8_string(default_icon,"SOFTWARE\\Classes\\voidImageViewer"); + string_cat(default_icon,dot_association); + string_cat_utf8(default_icon,"\\DefaultIcon"); + + if (RegCreateKeyExW(HKEY_CURRENT_USER,default_icon,0,0,0,KEY_QUERY_VALUE|KEY_SET_VALUE,0,&hkey,0) == ERROR_SUCCESS) + { + if (icon_location) + { + wchar_t icon_location_wbuf[STRING_SIZE]; + + string_copy_utf8_string(icon_location_wbuf,icon_location); + + _viv_set_registry_string(hkey,0,icon_location_wbuf); + } + else + { + wchar_t filename[STRING_SIZE]; + wchar_t command[STRING_SIZE]; + + _viv_get_exe_filename(filename); + + string_copy(command,filename); + + string_cat_utf8(command,(const utf8_t *)",0"); + + _viv_set_registry_string(hkey,0,command); + } + + RegCloseKey(hkey); + } + + string_copy_utf8_string(key,"SOFTWARE\\Classes\\"); + string_cat(key,class_name); + + if (RegCreateKeyExW(HKEY_CURRENT_USER,key,0,0,0,KEY_QUERY_VALUE|KEY_SET_VALUE,0,&hkey,0) == ERROR_SUCCESS) + { + wchar_t description_wbuf[STRING_SIZE]; + + string_copy_utf8_string(description_wbuf,description); + + _viv_set_registry_string(hkey,0,description_wbuf); + + RegCloseKey(hkey); + } + + string_copy_utf8_string(key,"SOFTWARE\\Classes\\"); + string_cat(key,class_name); + string_cat_utf8(key,"\\shell\\open\\command"); + + if (RegCreateKeyExW(HKEY_CURRENT_USER,key,0,0,0,KEY_QUERY_VALUE|KEY_SET_VALUE,0,&hkey,0) == ERROR_SUCCESS) + { + wchar_t filename[STRING_SIZE]; + wchar_t command[STRING_SIZE]; + + _viv_get_exe_filename(filename); + + string_copy_utf8_string(command,(const utf8_t *)"\""); + string_cat(command,filename); + string_cat_utf8(command,(const utf8_t *)"\" \"%1\""); + + _viv_set_registry_string(hkey,0,command); + + RegCloseKey(hkey); + } + + string_copy_utf8_string(key,"SOFTWARE\\Classes\\"); + string_cat(key,dot_association); + + reg_ret = RegCreateKeyExW(HKEY_CURRENT_USER,key,0,0,0,KEY_QUERY_VALUE|KEY_SET_VALUE,0,&hkey,0); + if (reg_ret == ERROR_SUCCESS) + { + wchar_t wbuf[STRING_SIZE]; + + if (!_viv_get_registry_string(hkey,(const utf8_t *)"voidImageViewer.Backup",wbuf,STRING_SIZE)) + { + if (!_viv_get_registry_string(hkey,0,wbuf,STRING_SIZE)) + { + *wbuf = 0; + } + + _viv_set_registry_string(hkey,(const utf8_t *)"voidImageViewer.Backup",wbuf); + } + + _viv_set_registry_string(hkey,0,class_name); + + RegCloseKey(hkey); + } + else + { + debug_printf("RegCreateKeyExW failed %u\n",reg_ret); + } +} +void _viv_uninstall_association_by_extension(const char *association) +{ + long reg_ret; + HKEY hkey; + wchar_t key[STRING_SIZE]; + + string_copy_utf8_string(key,(const utf8_t *)"SOFTWARE\\Classes\\."); + string_cat_utf8(key,association); + + // debug_printf("query %S\n",key); + + if (RegCreateKeyExW(HKEY_CURRENT_USER,key,0,0,0,KEY_QUERY_VALUE|KEY_SET_VALUE,0,&hkey,0) == ERROR_SUCCESS) + { + wchar_t wbuf[STRING_SIZE]; + + if (_viv_get_registry_string(hkey,(const utf8_t *)"voidImageViewer.Backup",wbuf,STRING_SIZE)) + { + _viv_set_registry_string(hkey,0,wbuf); + + // debug_printf("Delete voidImageViewer.Backup\n"); + + reg_ret = RegDeleteValueA(hkey,"voidImageViewer.Backup"); + if (reg_ret == ERROR_SUCCESS) + { + // debug_printf("Delete voidImageViewer.Backup OK\n"); + } + else + { + debug_printf("RegDeleteValueA failed %u\n",reg_ret); + } + } + + RegCloseKey(hkey); + } + + string_copy_utf8_string(key,(const utf8_t *)"SOFTWARE\\Classes\\voidImageViewer."); + string_cat_utf8(key,association); + + RegDeleteKey(HKEY_CURRENT_USER,key); +} +int _viv_is_association(const char *association) +{ + int ret; + HKEY hkey; + wchar_t class_name[STRING_SIZE]; + wchar_t key[STRING_SIZE]; + + string_copy_utf8_string(class_name,(const utf8_t *)"voidImageViewer."); + string_cat_utf8(class_name,association); + + ret = 0; + + string_copy_utf8_string(key,"SOFTWARE\\Classes\\."); + string_cat_utf8(key,association); + +//debug_printf("key %S\n",key); + + if (RegOpenKeyExW(HKEY_CURRENT_USER,key,0,KEY_QUERY_VALUE,&hkey) == ERROR_SUCCESS) + { + wchar_t wbuf[STRING_SIZE]; + +//debug_printf("key OK\n",key); + + if (_viv_get_registry_string(hkey,0,wbuf,STRING_SIZE)) + { +//debug_printf("value cmp %S %S\n",wbuf,class_name); + if (string_compare(wbuf,class_name) == 0) + { + ret++; + } + } + + RegCloseKey(hkey); + } + + string_copy_utf8_string(key,"SOFTWARE\\Classes\\"); + string_cat(key,class_name); + string_cat_utf8(key,(const utf8_t *)"\\shell\\open\\command"); + +//debug_printf("key %S\n",key); + + if (RegOpenKeyExW(HKEY_CURRENT_USER,key,0,KEY_QUERY_VALUE,&hkey) == ERROR_SUCCESS) + { + wchar_t wbuf[STRING_SIZE]; + + if (_viv_get_registry_string(hkey,0,wbuf,STRING_SIZE)) + { + wchar_t filename[STRING_SIZE]; + wchar_t command[STRING_SIZE]; + +//debug_printf("key OK\n",key); + + _viv_get_exe_filename(filename); + + string_copy_utf8_string(command,(const utf8_t *)"\""); + string_cat(command,filename); + string_cat_utf8(command,(const utf8_t *)"\" \"%1\""); + +//debug_printf("value cmp %S %S\n",wbuf,command); + + if (string_compare(wbuf,command) == 0) + { + ret++; + } + } + + RegCloseKey(hkey); + } + + return ret == 2; +} +static int _viv_get_registry_string(HKEY hkey,const utf8_t *value,wchar_t *wbuf,int size_in_wchars) +{ + wchar_t value_wbuf[STRING_SIZE]; + wchar_t *value_wp; + DWORD cbData; + DWORD type; + + if (value) + { + string_copy_utf8_string(value_wbuf,value); + value_wp = value_wbuf; + } + else + { + value_wp = 0; + } + + cbData = size_in_wchars * sizeof(wchar_t); + + if (RegQueryValueExW(hkey,value_wp,0,&type,(BYTE *)wbuf,&cbData) == ERROR_SUCCESS) + { + if ((type == REG_SZ) || (type == REG_EXPAND_SZ)) + { + return 1; + } + } + + return 0; +} +static int _viv_set_registry_string(HKEY hkey,const utf8_t *value,const wchar_t *wbuf) +{ + wchar_t value_wbuf[STRING_SIZE]; + wchar_t *value_wp; + LONG reg_ret; + + if (value) + { + string_copy_utf8_string(value_wbuf,value); + value_wp = value_wbuf; + } + else + { + value_wp = 0; + } + + reg_ret = RegSetValueExW(hkey,value_wp,0,REG_SZ,(BYTE *)wbuf,(string_get_length(wbuf) + 1) * sizeof(wchar_t)); + if (reg_ret == ERROR_SUCCESS) + { + return 1; + } + else + { + debug_printf("failed to set reg value %u %s %S",reg_ret,value,wbuf); + } + + return 0; +} +static void _viv_install_association(DWORD flags) +{ + int i; + + for(i=0;i<_VIV_ASSOCIATION_COUNT;i++) + { + if (flags & (1 << i)) + { + _viv_install_association_by_extension(_viv_association_extensions[i],localization_get_string(_viv_association_description_localization_id_array[i]),_viv_association_icon_locations[i]); + } + } +} +static void _viv_uninstall_association(DWORD flags) +{ + int i; + + for(i=0;i<_VIV_ASSOCIATION_COUNT;i++) + { + if (flags & 1 << i) + { + _viv_uninstall_association_by_extension(_viv_association_extensions[i]); + } + } +} +// close every running instance before (un)install. the original loop +// waited forever: a hung instance would block install, uninstall and +// exit forever. (this resolves the upstream FIXME: bounded waits, with +// a last resort terminate.) +// FIXME: we should check for the process name voidImageViewer.exe rather than the +// window class name. -be careful when uninstalling as the non-admin process will be +// waiting for the admin process to exit. +// QueryFullProcessImageNameW (Vista+) is resolved lazily right here: +// the install/uninstall path runs before os_init so the central +// runtime table is not populated yet, and the headers gate the +// declaration behind a newer _WIN32_WINNT than the project targets. +static BOOL (WINAPI *_viv_query_full_process_image_name)(HANDLE,DWORD,wchar_t *,DWORD *); +static int _viv_is_voidimageviewer_process(DWORD process_id) +{ + HANDLE process_handle; + int ret; + + // conservative default: if the image name can not be queried we + // assume the window is ours. in an uninstall context closing a + // real instance is preferred over leaving a locked file behind. + ret = 1; + + process_handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION,FALSE,process_id); + + if (process_handle) + { + wchar_t image_name[STRING_SIZE]; + DWORD image_name_length; + + if (!_viv_query_full_process_image_name) + { + _viv_query_full_process_image_name = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"),"QueryFullProcessImageNameW"); + } + + image_name_length = STRING_SIZE; + + if ((_viv_query_full_process_image_name) && (_viv_query_full_process_image_name(process_handle,0,image_name,&image_name_length))) + { + const wchar_t *basename; + const wchar_t *wanted; + + // the name past the last separator is the image file name. + basename = image_name + image_name_length; + while ((basename > image_name) && (basename[-1] != L'\\') && (basename[-1] != L':')) + { + basename--; + } + + // case insensitive compare against voidImageViewer.exe. + wanted = L"voidImageViewer.exe"; + + while ((*basename) && (*wanted)) + { + wchar_t c1; + wchar_t c2; + + c1 = *basename; + c2 = *wanted; + + if ((c1 >= L'A') && (c1 <= L'Z')) + { + c1 += (L'a' - L'A'); + } + + if ((c2 >= L'A') && (c2 <= L'Z')) + { + c2 += (L'a' - L'A'); + } + + if (c1 != c2) + { + break; + } + + basename++; + wanted++; + } + + if ((*basename) || (*wanted)) + { + // the image is not voidImageViewer.exe: not our window. + ret = 0; + } + } + + CloseHandle(process_handle); + } + + return ret; +} +static void _viv_close_existing_process(void) +{ + int attempts; + + // close at most 16 instances; a window that survives a close attempt + // stops the loop early, so the cap only guards a pathological + // instance spawning loop, not a normal machine. + for(attempts = 0;attempts < 16;attempts++) + { + HWND hwnd; + DWORD process_id; + HANDLE process_handle; + + hwnd = FindWindowA("VOIDIMAGEVIEWER",0); + + if (!hwnd) + { + // no window open + break; + } + + // ask the instance to close. SMTO_ABORTIFHUNG gives up on an + // unresponsive window instead of blocking us forever. + SendMessageTimeoutA(hwnd,WM_CLOSE,0,0,SMTO_ABORTIFHUNG,5000,0); + + process_id = 0; + GetWindowThreadProcessId(hwnd,&process_id); + + // the window class is a weak identity: any program can register + // the same class name and the uninstaller would then close a + // window it does not own. verify the process image name first. + if ((process_id) && (!_viv_is_voidimageviewer_process(process_id))) + { + // the window belongs to another program: leave it alone and + // stop looking (findwindow would return the same window). + break; + } + + process_handle = 0; + + if (process_id) + { + // PROCESS_TERMINATE is for the last resort kill below. opening + // may fail (NULL) for an elevated instance from a non elevated + // uninstaller: we then skip the wait and the window check below + // stops the loop instead of spinning. + process_handle = OpenProcess(SYNCHRONIZE|PROCESS_TERMINATE,FALSE,process_id); + } + + if (process_handle) + { + if (WaitForSingleObject(process_handle,5000) == WAIT_TIMEOUT) + { + // the instance did not exit in time: force it. + TerminateProcess(process_handle,1); + + WaitForSingleObject(process_handle,5000); + } + + CloseHandle(process_handle); + } + + // if the window survived the close (and the possible kill), + // repeating the same failing attempt can not succeed: stop + // instead of stalling setup. + if (hwnd == FindWindowA("VOIDIMAGEVIEWER",0)) + { + break; + } + } +} +static void _viv_uninstall_delete_file(const wchar_t *path,const utf8_t *filename) +{ + wchar_t full_path_and_filename[STRING_SIZE]; + + string_path_combine_utf8(full_path_and_filename,path,filename); + + DeleteFile(full_path_and_filename); +} +int _viv_is_start_menu_shortcuts(void) +{ + wchar_t special_folder_path_wbuf[STRING_SIZE]; + wchar_t path_wbuf[STRING_SIZE]; + int ret; + + ret = 0; + + // delete old english shortcuts + // delete shortcuts + if (os_get_special_folder_path(special_folder_path_wbuf,CSIDL_COMMON_PROGRAMS)) + { + string_path_combine_utf8(path_wbuf,special_folder_path_wbuf,(const utf8_t *)"void Image Viewer"); + + // make sure this directory exists! + if (GetFileAttributesW(path_wbuf) != INVALID_FILE_ATTRIBUTES) + { + // at least one item exists, ret = 2 + ret = 1; + } + } + + return ret; +} +static void _viv_install_start_menu_shortcuts(void) +{ + wchar_t special_folder_path_wbuf[STRING_SIZE]; + + // always uninstall and reinstall + // this allows us to switch between english and another language. + _viv_uninstall_start_menu_shortcuts(); + + // create shortcuts + if (os_get_special_folder_path(special_folder_path_wbuf,CSIDL_COMMON_PROGRAMS)) + { + wchar_t path_wbuf[STRING_SIZE]; + wchar_t exe_filename_wbuf[STRING_SIZE]; + wchar_t exe_path_wbuf[STRING_SIZE]; + wchar_t uninstall_filename_wbuf[STRING_SIZE]; + wchar_t lnk_wbuf[STRING_SIZE]; + + string_path_combine_utf8(path_wbuf,special_folder_path_wbuf,(const utf8_t *)"void Image Viewer"); + + // make sure this directory exists! + os_make_sure_path_exists(path_wbuf); + + // void image viewer.lnk + _viv_get_exe_filename(exe_filename_wbuf); + string_path_combine_utf8(lnk_wbuf,path_wbuf,"void Image Viewer.lnk"); + os_create_shell_link(exe_filename_wbuf,lnk_wbuf); + + // uninstall + string_get_path_part(exe_path_wbuf,exe_filename_wbuf); + string_path_combine_utf8(uninstall_filename_wbuf,exe_path_wbuf,(const utf8_t *)"Uninstall.exe"); + + string_path_combine_utf8(lnk_wbuf,path_wbuf,"Uninstall.lnk"); + os_create_shell_link(uninstall_filename_wbuf,lnk_wbuf); + } +} +static void _viv_uninstall_start_menu_shortcuts(void) +{ + wchar_t special_folder_path_wbuf[STRING_SIZE]; + wchar_t path_wbuf[STRING_SIZE]; + + // delete old english shortcuts + // delete shortcuts + if (os_get_special_folder_path(special_folder_path_wbuf,CSIDL_COMMON_PROGRAMS)) + { + wchar_t lnk_wbuf[STRING_SIZE]; + + string_path_combine_utf8(path_wbuf,special_folder_path_wbuf,(const utf8_t *)"void Image Viewer"); + + // localized. + string_path_combine_utf8(lnk_wbuf,path_wbuf,"void Image Viewer.lnk"); + DeleteFile(lnk_wbuf); + + string_path_combine_utf8(lnk_wbuf,path_wbuf,"Uninstall.lnk"); + DeleteFile(lnk_wbuf); + + RemoveDirectory(path_wbuf); + } +} +void _viv_append_admin_param(wchar_t *wbuf,const utf8_t *param) +{ + string_cat_utf8(wbuf,(const utf8_t *)" /"); + string_cat_utf8(wbuf,param); +} +// register voidImageViewer in add/remove programs (programs and +// features). the setup runs the exe with /install so the exe owns this +// key: hklm for admin installs (what the setup's .onInit reads back), +// hkcu otherwise. the uninstall string is quoted so windows can run it +// with spaces in the path. +static void _viv_install_add_remove_programs(const wchar_t *install_path) +{ + HKEY hkey; + HKEY root; + + root = os_is_admin() ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; + + // write the 64-bit view explicitly: a 32-bit build used to land in + // wow6432node, which the nsis uninstall probe (setregview 64) never + // reads. the flag is ignored by 64-bit builds and on 32-bit windows. + if (RegCreateKeyExW(root,L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\voidImageViewer",0,0,0,KEY_QUERY_VALUE|KEY_SET_VALUE|KEY_WOW64_64KEY,0,&hkey,0) == ERROR_SUCCESS) + { + wchar_t uninstall_wbuf[STRING_SIZE]; + wchar_t icon_wbuf[STRING_SIZE]; + wchar_t version_wbuf[STRING_SIZE]; + DWORD no_modify_repair; + + uninstall_wbuf[0] = L'"'; + // string_cat budgets against the whole STRING_SIZE and ignores + // the quote we already placed: reserve the suffix so a long + // install path can never truncate it mid-way. + string_copy_with_bufsize(uninstall_wbuf + 1,STRING_SIZE - 1 - 16,install_path); + string_cat_utf8(uninstall_wbuf,(const utf8_t *)"\\Uninstall.exe\""); + + string_copy(icon_wbuf,install_path); + string_cat_utf8(icon_wbuf,(const utf8_t *)"\\voidImageViewer.exe,0"); + + // the release identity straight from version.h - must match the tag + string_printf(version_wbuf,"%s%s",VERSION_STRING,VERSION_TYPE); + + no_modify_repair = 1; + + RegSetValueExW(hkey,L"DisplayName",0,REG_SZ,(BYTE *)L"void Image Viewer",sizeof(L"void Image Viewer")); + RegSetValueExW(hkey,L"DisplayVersion",0,REG_SZ,(BYTE *)version_wbuf,(string_get_length(version_wbuf) + 1) * sizeof(wchar_t)); + RegSetValueExW(hkey,L"Publisher",0,REG_SZ,(BYTE *)L"voidtools",sizeof(L"voidtools")); + RegSetValueExW(hkey,L"InstallLocation",0,REG_SZ,(BYTE *)install_path,(string_get_length(install_path) + 1) * sizeof(wchar_t)); + RegSetValueExW(hkey,L"DisplayIcon",0,REG_SZ,(BYTE *)icon_wbuf,(string_get_length(icon_wbuf) + 1) * sizeof(wchar_t)); + RegSetValueExW(hkey,L"UninstallString",0,REG_SZ,(BYTE *)uninstall_wbuf,(string_get_length(uninstall_wbuf) + 1) * sizeof(wchar_t)); + RegSetValueExW(hkey,L"NoModify",0,REG_DWORD,(BYTE *)&no_modify_repair,sizeof(DWORD)); + RegSetValueExW(hkey,L"NoRepair",0,REG_DWORD,(BYTE *)&no_modify_repair,sizeof(DWORD)); + + RegCloseKey(hkey); + } +} +// remove the add/remove programs entry from both hives: the admin +// install writes hklm, a standard user install writes hkcu. +static void _viv_uninstall_add_remove_programs(void) +{ + // regdeletekeyw cannot reach the alternate registry view (msdn), so + // the 64-bit view the install writes needs regdeletekeyexw - resolved + // lazily inside os_reg_delete_key_ex because this path runs before + // os_init. the plain regdeletekeyw sweep after it removes the + // wow6432node copy older 32-bit builds left behind (idempotent, and a + // no-op on 64-bit builds where both calls hit the same view). + os_reg_delete_key_ex(HKEY_LOCAL_MACHINE,L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\voidImageViewer",KEY_WOW64_64KEY); + os_reg_delete_key_ex(HKEY_CURRENT_USER,L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\voidImageViewer",KEY_WOW64_64KEY); + RegDeleteKeyW(HKEY_LOCAL_MACHINE,L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\voidImageViewer"); + RegDeleteKeyW(HKEY_CURRENT_USER,L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\voidImageViewer"); +} +static void _viv_install_copy_file(const wchar_t *install_path,const wchar_t *temp_path,const utf8_t *filename,int critical) +{ + wchar_t dst_wbuf[STRING_SIZE]; + wchar_t src_wbuf[STRING_SIZE]; + + string_path_combine_utf8(dst_wbuf,install_path,filename); + string_path_combine_utf8(src_wbuf,temp_path,filename); + + if (!CopyFile(src_wbuf,dst_wbuf,FALSE)) + { + if (critical) + { + debug_fatal("Error %d: unable to copy %S to %S",GetLastError(),src_wbuf,dst_wbuf); + } + } +} +void _viv_get_exe_filename(wchar_t filename[STRING_SIZE]) +{ + filename[0] = 0; + + GetModuleFileName(0,filename,STRING_SIZE); + + // make sure the drive letter is uppercase. + // launching from .png == d: + // launching from .exe == D: + if ((*filename >= 'a') && (*filename <= 'z')) + { + if (filename[1] == ':') + { + *filename = *filename - 'a' + 'A'; + } + } +} diff --git a/src/viv_install.h b/src/viv_install.h new file mode 100644 index 00000000..c127a0a3 --- /dev/null +++ b/src/viv_install.h @@ -0,0 +1,38 @@ +// +// Copyright 2025 voidtools / David Carpenter +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +// VoidImageViewer +// viv_install.h - install/uninstall, associations, registry, shortcuts, elevation. +#ifndef VIV_INSTALL_H +#define VIV_INSTALL_H + +#include "viv.h" + +// exported to other domains / the viv.c core +int _viv_process_install_command_line_options(wchar_t *cl); +void _viv_install_association_by_extension(const char *association,const char *description,const char *icon_location); +void _viv_uninstall_association_by_extension(const char *association); +int _viv_is_association(const char *association); +int _viv_is_start_menu_shortcuts(void); +void _viv_append_admin_param(wchar_t *wbuf,const utf8_t *param); +void _viv_get_exe_filename(wchar_t filename[STRING_SIZE]); + +#endif diff --git a/src/viv_load.c b/src/viv_load.c new file mode 100644 index 00000000..85a0964d --- /dev/null +++ b/src/viv_load.c @@ -0,0 +1,1884 @@ +// +// Copyright 2025 voidtools / David Carpenter +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +// VoidImageViewer +// viv_load.c - image loading, decode thread, clipboard images, preload. +// Pure physical move from viv.c (R70 split): bodies are unchanged. +#include "viv.h" +#include "viv_state.h" +#include "viv_load.h" +#include "viv_anim.h" +#include "viv_chrome.h" +#include "viv_playlist.h" +#include "viv_recent.h" +#include "viv_render.h" +#include "viv_view.h" + +// forward declarations (order preserved from viv.c) +void _viv_clear(void); +void _viv_process_pending_clear(void); +void _viv_clear_loading_preload(void); +void _viv_clear_preload_frames(void); +void _viv_clear_preload(void); +BOOL _viv_open_from_filename(const wchar_t *filename,int recent_policy); +void _viv_open(WIN32_FIND_DATA *fd,int is_preload); +void _viv_set_clipboard_image(void); +static void _viv_show_clipboard_image(HBITMAP hbitmap,int wide,int high); +void _viv_paste_clipboard_image(void); +static int _viv_get_extension_format(const wchar_t *filename); +void _viv_save_image_as(void); +void _viv_doing_cancel(void); +void _viv_blank(void); +static DWORD WINAPI _viv_load_image_thread_proc(void *param); +void _viv_reply_free(_viv_reply_t *e); +_viv_reply_t *_viv_reply_add(DWORD type,DWORD size,void *data); +void _viv_reply_clear_all(void); +void _viv_preload_next(void); +void _viv_activate_preload(void); +void viv_copy_current_image_to_last_image(void); +static void _viv_activate_last(void); +void _viv_clear_last(void); +void _viv_refresh(void); +void _viv_open_preload(void); +static int _viv_pixel_budget_refused(SIZE_T pixels); +int _viv_safe_copy_data(const void *base,SIZE_T src_size,const void *src,void *dst,SIZE_T dst_size); + + +static GUID _viv_FrameDimensionTime = {0x6aedbd6d,0x3fb5,0x418a,{0x83,0xa6,0x7f,0x45,0x22,0x9d,0xc8,0x72}}; +static BYTE _viv_preload_is_prev = 0; // preload next or previous? +static _viv_frame_t *_viv_pending_clear_frames = NULL; +static int _viv_pending_clear_frame_loaded_count = 0; +static int _viv_last_image_wide = 0; // last image width +static int _viv_last_image_high = 0; // last image height +// clearing is really slow. +// delay this until after the new image is shown. +// we add the clear to a queue which is cleared with _viv_process_pending_clear. +// _viv_process_pending_clear should be called after the new frame is shown. +void _viv_clear(void) +{ + _viv_pending_clear_frames = _viv_frames; + _viv_pending_clear_frame_loaded_count = _viv_frame_loaded_count; + _viv_frames = NULL; + _viv_frame_fd->cFileName[0] = 0; + + _viv_timer_stop(); + + _viv_frame_position = 0; + _viv_frame_looped = 0; + _viv_is_slideshow_timeup = 0; + _viv_frame_count = 0; + _viv_frame_loaded_count = 0; + _viv_zoom_pos = 0; + _viv_view_x = 0; + _viv_view_y = 0; + _viv_view_ix = 0.0; + _viv_view_iy = 0.0; + _viv_1to1 = 0; + _viv_have_old_zoom = 0; + _viv_image_is_low_res = 0; + _viv_image_wide = 0; + _viv_image_high = 0; + _viv_animation_play = 1; +} +void _viv_process_pending_clear(void) +{ + if (_viv_pending_clear_frames) + { + _viv_clear_frames(_viv_pending_clear_frames,_viv_pending_clear_frame_loaded_count); + + _viv_pending_clear_frames = NULL; + } + + _viv_pending_clear_frame_loaded_count = 0; +} +void _viv_clear_loading_preload(void) +{ + if (_viv_load_image_thread) + { + if (_viv_load_is_preload) + { + _viv_load_image_terminate = 1; + } + } +} +void _viv_clear_preload_frames(void) +{ + if (_viv_preload_frames) + { + _viv_clear_frames(_viv_preload_frames,_viv_preload_frame_loaded_count); + + _viv_preload_frames = NULL; + } + + _viv_preload_frame_count = 0; + _viv_preload_frame_loaded_count = 0; + _viv_preload_image_wide = 0; + _viv_preload_image_high = 0; +} +void _viv_clear_preload(void) +{ + _viv_clear_preload_frames(); + + _viv_preload_fd->cFileName[0] = 0; +} +BOOL _viv_open_from_filename(const wchar_t *filename,int recent_policy) +{ + BOOL ret; + WIN32_FIND_DATA fd; + HANDLE h; + wchar_t full_path_and_filename[STRING_SIZE]; + wchar_t cwd[STRING_SIZE]; + + ret = FALSE; + GetCurrentDirectory(STRING_SIZE,cwd); + string_path_combine(full_path_and_filename,cwd,filename); + +debug_printf("open filename: %S\n",full_path_and_filename); + + if ((os_GetFileAttributesExW) && (os_GetFileAttributesExW(full_path_and_filename,GetFileExInfoStandard,&fd))) + { + fd.dwReserved0 = 0; + fd.dwReserved1 = 0; + + ret = TRUE; + + if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + // add subfolders and subsubfolders... + _viv_playlist_add_path(full_path_and_filename); + + _viv_home(0,0); + } + else + { + string_copy_with_bufsize(fd.cFileName,MAX_PATH,full_path_and_filename); + + // the recent-list policy is declared by the caller, never guessed + // here: a user command (the open dialog, the drag-drop, the recent + // click) feeds the list unconditionally - the standard mru + // contract, a re-open of the displayed file re-tops it. the + // forwarded open (the single-instance re-entry the rotate verb's + // refresh and the recheck double-click ride) feeds it only when + // the file is not the one already on screen: a same-file forward + // is a reload, not a recent open, and must not + // masquerade as a new open and silently reorder the recent list. the compare folds + // ascii case like the mru itself. + if ((recent_policy) || (_viv_icompare_filename(full_path_and_filename,_viv_current_fd->cFileName) != 0)) + { + _viv_recent_file_push(full_path_and_filename); + } + + _viv_open(&fd,0); + } + } + else + { + h = FindFirstFile(full_path_and_filename,&fd); + if (h != INVALID_HANDLE_VALUE) + { + wchar_t path[STRING_SIZE]; + + ret = TRUE; + + string_get_path_part(path,full_path_and_filename); + + for(;;) + { + string_path_combine(full_path_and_filename,path,fd.cFileName); + + if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + _viv_playlist_add_path(full_path_and_filename); + } + else + { + string_copy_with_bufsize(fd.cFileName,MAX_PATH,full_path_and_filename); + _viv_playlist_add(&fd); + } + + if (!FindNextFile(h,&fd)) + { + break; + } + } + + _viv_home(0,0); + + FindClose(h); + } + } + + return ret; +} +// _viv_load_image_thread will be NULL if is_preload is 1. +void _viv_open(WIN32_FIND_DATA *fd,int is_preload) +{ +debug_printf("open: %S last %S frame %S is_preload %d\n",fd->cFileName,_viv_last_fd->cFileName,_viv_frame_fd->cFileName,is_preload); + +if ((_viv_load_image_thread) && (_viv_load_image_filename)) +{ +debug_printf("CURRENTLY LOADING %S preload %d\n",_viv_load_image_filename,_viv_load_is_preload); + +} + + if (!is_preload) + { + if (_viv_file_not_found) + { + _viv_file_not_found = 0; + + _viv_status_update(); + } + + if (_viv_load_failed) + { + _viv_load_failed = 0; + + _viv_status_update(); + } + } + + if ((is_preload) && (_viv_last_frames) && (string_compare(_viv_last_fd->cFileName,fd->cFileName) == 0)) + { + // don't preload if its the same as last cache. + // this can occur if you have a playlist or folder with only 2 items. + return; + } + else + if ((!is_preload) && (_viv_last_frames) && (string_compare(_viv_last_fd->cFileName,fd->cFileName) == 0)) + { + // activate last cache + // don't activate preload. + _viv_should_activate_preload_on_load = 0; + + // stop loading + debug_printf("SET TERMINATE (LAST)\n"); + _viv_load_image_allow_draw = 0; + _viv_load_image_terminate = 1; + + if (_viv_load_image_next_fd) + { + mem_free(_viv_load_image_next_fd); + + _viv_load_image_next_fd = NULL; + } + + _viv_preload_fd->cFileName[0] = 0; + + _viv_status_update(); + + _viv_activate_last(); + + _viv_preload_next(); + + return; + } + else + if ((!is_preload) && (_viv_load_is_preload) && (*_viv_preload_fd->cFileName) && (string_compare(_viv_preload_fd->cFileName,fd->cFileName) == 0)) + { + _viv_open_preload(); + + return; + } + else + if ((!is_preload) && (_viv_load_image_thread) && (_viv_load_image_filename) && (string_compare(_viv_load_image_filename,fd->cFileName) == 0)) + { + debug_printf("already loading...\n"); + // already loading this one.. + return; + } + + // clear any existing preload and start a fresh one. + _viv_clear_preload(); + + if (_viv_load_image_thread) + { + // already loading a different image. + // add it to the queue and cancel this one. + debug_printf("SET TERMINATE (next)\n"); + _viv_load_image_terminate = 1; + + if (_viv_load_image_next_fd) + { + mem_free(_viv_load_image_next_fd); + } + + _viv_load_image_next_fd = (WIN32_FIND_DATA *)mem_alloc(sizeof(WIN32_FIND_DATA)); + os_copy_memory(_viv_load_image_next_fd,fd,sizeof(WIN32_FIND_DATA)); + _viv_load_image_next_is_preload = is_preload; + + _viv_status_update(); + } + else + { + DWORD thread_id; +// int rw; +// int rh; + RECT rect; + + GetClientRect(_viv_hwnd,&rect); + +// _viv_get_render_size(&rw,&rh); + + _viv_load_image_allow_draw = 1; + _viv_load_image_terminate = 0; + + if (_viv_load_image_filename) + { + mem_free(_viv_load_image_filename); + } + + _viv_load_image_filename = string_alloc(fd->cFileName); + _viv_load_is_preload = is_preload; + _viv_preload_is_prev = _viv_last_is_prev; + _viv_preload_state = 0; + _viv_should_activate_preload_on_load = 0; + _viv_load_render_wide = rect.right - rect.left; + _viv_load_render_high = rect.bottom - rect.top - _viv_get_status_high() - _viv_get_view_top(); + _viv_load_frame_count = 0; + os_copy_memory(_viv_load_fd,fd,sizeof(WIN32_FIND_DATA)); + + if (is_preload) + { + os_copy_memory(_viv_preload_fd,fd,sizeof(WIN32_FIND_DATA)); + } + +debug_printf("LOAD %S is_preload %d\n",_viv_load_image_filename,is_preload); + + _viv_load_image_thread = CreateThread(NULL,0,_viv_load_image_thread_proc,0,0,&thread_id); + + _viv_status_update(); + } + + if (!is_preload) + { + os_copy_memory(_viv_current_fd,fd,sizeof(WIN32_FIND_DATA)); + + _viv_update_title(); + } +} +void _viv_set_clipboard_image(void) +{ + if (_viv_frame_count) + { + if (_viv_frames[_viv_frame_position].hbitmap) + { + HDC screen_hdc; + + screen_hdc = GetDC(0); + if (screen_hdc) + { + HDC mem1_hdc; + + mem1_hdc = CreateCompatibleDC(screen_hdc); + if (mem1_hdc) + { + HDC mem2_hdc; + + mem2_hdc = CreateCompatibleDC(screen_hdc); + if (mem2_hdc) + { + HBITMAP mem1_hbitmap; + + mem1_hbitmap = CreateCompatibleBitmap(screen_hdc,_viv_image_wide,_viv_image_high); + if (mem1_hbitmap) + { + HGDIOBJ last_mem1_hbitmap; + HGDIOBJ last_mem2_hbitmap; + + last_mem1_hbitmap = SelectObject(mem1_hdc,mem1_hbitmap); + last_mem2_hbitmap = SelectObject(mem2_hdc,_viv_frames[_viv_frame_position].hbitmap); + + BitBlt(mem1_hdc,0,0,_viv_image_wide,_viv_image_high,mem2_hdc,0,0,SRCCOPY); + + SelectObject(mem2_hdc,last_mem2_hbitmap); + SelectObject(mem1_hdc,last_mem1_hbitmap); + + // if SetClipboardData fails we keep ownership + // and must free the bitmap ourselves. + if (!SetClipboardData(CF_BITMAP,mem1_hbitmap)) + { + DeleteObject(mem1_hbitmap); + } + } + + DeleteDC(mem2_hdc); + } + + DeleteDC(mem1_hdc); + } + + ReleaseDC(0,screen_hdc); + } + } + } +} +// show a bitmap that came from the clipboard. +// pasted images have no filename: the title falls back to the application +// name and every filename based command (save as, delete, rename, copy to, +// ...) already checks for an empty filename and quietly does nothing. +static void _viv_show_clipboard_image(HBITMAP hbitmap,int wide,int high) +{ + // stop an in flight file load from clobbering the pasted image. + _viv_load_image_allow_draw = 0; + _viv_load_image_terminate = 1; + + // the current image moves to the last image slot, exactly like + // navigating to a new image does. + viv_copy_current_image_to_last_image(); + + _viv_clear(); + + _viv_image_wide = wide; + _viv_image_high = high; + _viv_frame_count = 1; + _viv_frame_loaded_count = 1; + _viv_frames = (_viv_frame_t *)mem_alloc(sizeof(_viv_frame_t)); + + _viv_frames[0].hbitmap = hbitmap; + _viv_frames[0].mipmap = 0; // built lazily on the first paint. + _viv_frames[0].delay = 0; + + // a clipboard image has no filename. + _viv_current_fd->cFileName[0] = 0; + + _viv_update_title(); + + _viv_start_first_frame(); + + _viv_process_pending_clear(); +} +// the clipboard must already be open by the caller. +// dib first: the system synthesizes a CF_DIB for nearly every image +// source. a plain bitmap handle is the fallback. +void _viv_paste_clipboard_image(void) +{ + HGLOBAL hglobal; + + hglobal = GetClipboardData(CF_DIB); + + if (hglobal) + { + BITMAPINFOHEADER *bih; + + bih = (BITMAPINFOHEADER *)GlobalLock(hglobal); + if (bih) + { + // only the classic 40 byte header with an uncompressed (or + // bitfields) layout is handled here, anything else falls through + // to the CF_BITMAP copy below. + if ((bih->biSize == sizeof(BITMAPINFOHEADER)) && (bih->biPlanes == 1) && (bih->biWidth > 0) && (bih->biHeight != 0) && ((bih->biCompression == 0 /* BI_RGB */) || (bih->biCompression == 3 /* BI_BITFIELDS */)) && ((bih->biBitCount == 1) || (bih->biBitCount == 4) || (bih->biBitCount == 8) || (bih->biBitCount == 16) || (bih->biBitCount == 24) || (bih->biBitCount == 32))) + { + HDC screen_hdc; + + screen_hdc = GetDC(0); + if (screen_hdc) + { + void *bits; + HBITMAP hbitmap; + int budget_height; + + // apply the same decode-time pixel budget as the file loaders: a + // hostile clipboard dib must not force a giant allocation. + budget_height = (bih->biHeight < 0) ? -bih->biHeight : bih->biHeight; + hbitmap = 0; + if (!_viv_pixel_budget_refused(safe_size_mul((SIZE_T)bih->biWidth,(SIZE_T)budget_height))) + { + hbitmap = CreateDIBSection(screen_hdc,(BITMAPINFO *)bih,DIB_RGB_COLORS,&bits,NULL,0); + } + if (hbitmap) + { + DWORD color_count; + int mask_size; + const char *src; + int height; + int stride; + + // the clipboard dib layout: header, bitfield masks (40 byte + // headers with BI_BITFIELDS only), palette, bits. + color_count = 0; + if (bih->biBitCount <= 8) + { + color_count = bih->biClrUsed ? bih->biClrUsed : (1 << bih->biBitCount); + } + + mask_size = ((bih->biCompression == 3 /* BI_BITFIELDS */) && ((bih->biBitCount == 16) || (bih->biBitCount == 32))) ? 12 : 0; + + src = (const char *)bih + bih->biSize + mask_size + color_count * 4; + + height = bih->biHeight; + if (height < 0) + { + height = -height; + } + + stride = (int)(((DWORD)bih->biWidth * (DWORD)bih->biBitCount + 31) / 32) * 4; + + // the clipboard global must actually contain the whole + // dib (header, masks, palette and bits): a short or hostile + // clipboard would otherwise be read past its end. + if (((SIZE_T)GlobalSize(hglobal)) >= ((SIZE_T)bih->biSize + (SIZE_T)mask_size + (SIZE_T)color_count * 4) + ((SIZE_T)stride * (SIZE_T)height)) + { + // size_t length: stride*height crosses int_max inside the 64-bit + // pixel budget (400 mp x 4 bytes per pixel). + os_copy_memory(bits,src,(SIZE_T)stride * (SIZE_T)height); + + _viv_show_clipboard_image(hbitmap,(int)bih->biWidth,height); + + ReleaseDC(0,screen_hdc); + GlobalUnlock(hglobal); + + return; + } + + DeleteObject(hbitmap); + } + + ReleaseDC(0,screen_hdc); + } + } + + GlobalUnlock(hglobal); + } + } + + // fall back to a plain bitmap handle. + { + HBITMAP hbitmap; + + hbitmap = (HBITMAP)GetClipboardData(CF_BITMAP); + + if (hbitmap) + { + HBITMAP hbitmap_copy; + BITMAP bm; + + // the clipboard owns the original: make a private dib copy. + hbitmap_copy = (HBITMAP)CopyImage(hbitmap,IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION); + + if (hbitmap_copy) + { + if ((GetObject(hbitmap_copy,sizeof(BITMAP),&bm)) && (bm.bmWidth > 0) && (bm.bmHeight > 0)) + { + _viv_show_clipboard_image(hbitmap_copy,bm.bmWidth,bm.bmHeight); + + return; + } + + DeleteObject(hbitmap_copy); + } + } + } +} +// get the save format for a filename extension. (0 = png, 1 = jpeg, 2 = bmp, -1 = unknown) +static int _viv_get_extension_format(const wchar_t *filename) +{ + int i; + int last_dot; + + last_dot = -1; + + for(i=string_get_length(filename)-1;i>=0;i--) + { + if (filename[i] == L'\\') + { + break; + } + + if (filename[i] == L'.') + { + last_dot = i; + break; + } + } + + if (last_dot == -1) + { + return -1; + } + + if (_viv_icompare_w(filename + last_dot + 1,L"png") == 0) + { + return 0; + } + + if ((_viv_icompare_w(filename + last_dot + 1,L"jpg") == 0) || (_viv_icompare_w(filename + last_dot + 1,L"jpeg") == 0)) + { + return 1; + } + + if (_viv_icompare_w(filename + last_dot + 1,L"bmp") == 0) + { + return 2; + } + + return -1; +} +// save the current image to a new file. (png, jpeg or bmp) +// re-encodes with the GDI+ built-in encoders, no new dependencies. +// the in-memory rotation is included, alpha is flattened over the window background. +void _viv_save_image_as(void) +{ + if (*_viv_current_fd->cFileName) + { + if (_viv_frame_count) + { + // do not save while the progressive preview is on screen: + // frames[0] is still the low resolution thumbnail until the + // full first frame lands. + if (_viv_image_is_low_res) + { + wchar_t message_wbuf[STRING_SIZE]; + wchar_t caption_wbuf[STRING_SIZE]; + + string_copy_utf8_string(message_wbuf,localization_get_string(LOCALIZATION_ID_STATUS_BAR_LOADING)); + string_copy_utf8_string(caption_wbuf,localization_get_string(LOCALIZATION_ID_APP_NAME)); + + viv_msgbox(_viv_hwnd,caption_wbuf,message_wbuf,MB_OK|MB_ICONINFORMATION); + + return; + } + + OPENFILENAME ofn; + wchar_t tobuf[STRING_SIZE+1]; + wchar_t filter_wbuf[STRING_SIZE]; + wchar_t title_wbuf[STRING_SIZE]; + int i; + int last_dot; + + os_zero_memory(&ofn,sizeof(OPENFILENAME)); + + // default to the current filename with a .png extension. + string_copy(tobuf,_viv_current_fd->cFileName); + + last_dot = -1; + + for(i=string_get_length(tobuf)-1;i>=0;i--) + { + if (tobuf[i] == L'\\') + { + break; + } + + if (tobuf[i] == L'.') + { + last_dot = i; + break; + } + } + + if (last_dot != -1) + { + tobuf[last_dot] = 0; + } + + string_cat(tobuf,L".png"); + + string_printf(filter_wbuf,"%s (*.png)%c*.png%c%s (*.jpg)%c*.jpg%c%s (*.bmp)%c*.bmp%c", + localization_get_string(LOCALIZATION_ID_SAVE_AS_PNG),0, + localization_get_string(LOCALIZATION_ID_SAVE_AS_JPEG),0, + localization_get_string(LOCALIZATION_ID_SAVE_AS_BMP),0,0); + + string_copy_utf8_string(title_wbuf,localization_get_string(LOCALIZATION_ID_SAVE_AS_CAPTION)); + + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = _viv_hwnd; + ofn.hInstance = os_hinstance; + ofn.lpstrFilter = filter_wbuf; + ofn.nFilterIndex = 1; + ofn.lpstrFile = tobuf; + ofn.nMaxFile = STRING_SIZE; + ofn.lpstrTitle = title_wbuf; + ofn.Flags = OFN_ENABLESIZING | OFN_OVERWRITEPROMPT | OFN_NOCHANGEDIR; + + if (GetSaveFileName(&ofn)) + { + int format; + + // use the typed extension when we recognize it, otherwise the selected filter. + format = _viv_get_extension_format(tobuf); + + if (format == -1) + { + const wchar_t *extension; + + format = (int)ofn.nFilterIndex - 1; + + if ((format < 0) || (format > 2)) + { + format = 0; + } + + extension = (format == 1) ? L".jpg" : ((format == 2) ? L".bmp" : L".png"); + + // make room for the extension: string_cat stops at the + // STRING_SIZE budget, a full buffer would silently save + // the file without its extension. + if (string_get_length(tobuf) > ((STRING_SIZE - 1) - string_get_length(extension))) + { + tobuf[(STRING_SIZE - 1) - string_get_length(extension)] = 0; + } + + string_cat(tobuf,extension); + } + + // save the frame on screen, not frame 0. + if (!os_save_hbitmap(_viv_frames[_viv_frame_position].hbitmap,tobuf,format)) + { + wchar_t message_wbuf[STRING_SIZE]; + wchar_t caption_wbuf[STRING_SIZE]; + + string_copy_utf8_string(message_wbuf,localization_get_string(LOCALIZATION_ID_SAVE_AS_FAILED)); + string_copy_utf8_string(caption_wbuf,localization_get_string(LOCALIZATION_ID_APP_NAME)); + + viv_msgbox(_viv_hwnd,caption_wbuf,message_wbuf,MB_OK|MB_ICONERROR); + } + } + } + } +} +void _viv_doing_cancel(void) +{ + if (_viv_doing) + { + int was_doing; + + was_doing = _viv_doing; + + _viv_doing = _VIV_DOING_NOTHING; + + if (was_doing == _VIV_DOING_MSCROLL) + { + ShowCursor(TRUE); + } + + if (was_doing == _VIV_DOING_1TO1SCROLL) + { +// ShowCursor(TRUE); + _viv_view_set(_viv_doing_x,_viv_doing_y,1); + InvalidateRect(_viv_hwnd,0,FALSE); + } + + ReleaseCapture(); + } +} +void _viv_blank(void) +{ + _viv_clear(); + + // the blank state has no file: the stale error flags from the last + // load attempt must not outlive it (the field report: close after a + // failed load kept "failed to load image" on the status bar with no + // image open - the flags only reset on the next _viv_open). + if (_viv_file_not_found) + { + _viv_file_not_found = 0; + } + + if (_viv_load_failed) + { + _viv_load_failed = 0; + } + + if (_viv_random) + { + mem_free(_viv_random); + + _viv_random = 0; + } + + _viv_current_fd->cFileName[0] = 0; + + _viv_update_src_pixel(1,0); + _viv_status_update(); + _viv_update_title(); + + // free all dropfiles + _viv_playlist_clearall(); + + _viv_start_first_frame(); + _viv_process_pending_clear(); +} +// 14.447 - CreateStreamOnHGlobal - this is too slow over slow networks -which doesn't matter because the gif wont show the first frame until the entire gif is loaded anyway. +// 14.520 - CreateStreamOnHGlobal +// 15.834 - SHCreateStreamOnFile +// 15.850 - SHCreateStreamOnFile +// 14.914 - _viv stream - 1MB file buffer +// 14.914 - _viv stream +static DWORD WINAPI _viv_load_image_thread_proc(void *param) +{ + _viv_reply_load_image_first_frame_t first_frame; + IStream *stream; + int ret; + DWORD tickstart; + + tickstart = GetTickCount(); + + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED|COINIT_DISABLE_OLE1DDE); + + first_frame.wide = 0; + first_frame.high = 0; + first_frame.frame_count = 0; + first_frame.frame.hbitmap = 0; + first_frame.frame.mipmap = 0; + first_frame.frame.delay = 0; + first_frame.is_low_res = 0; + + ret = 0; + stream = NULL; + + debug_printf("%s %S...\n",_viv_load_is_preload ? "PRELOAD" : "LOAD",_viv_load_image_filename); + + { + HANDLE h; + + h = CreateFile(_viv_load_image_filename,GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE|((os_major_version >= 5) ? FILE_SHARE_DELETE : 0),0,OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,0); + if (h != INVALID_HANDLE_VALUE) + { + DWORD size; + HANDLE global_handle; + + size = GetFileSize(h,0); + + global_handle = GlobalAlloc(GMEM_MOVEABLE,size); + if (global_handle) + { + char *buf; + + buf = (char *)GlobalLock(global_handle); + + if (buf) + { + DWORD numread; + DWORD totreadsize; + char *d; + + d = buf; + totreadsize = size; + + while(totreadsize) + { + DWORD readsize; + +// if (_viv_load_image_terminate) +// { +// totreadsize = 0; +// break; +// } + + readsize = 1 * 1024 * 1024; + + if (readsize > totreadsize) + { + readsize = totreadsize; + } + + if (ReadFile(h,d,readsize,&numread,0)) + { + if (!numread) + { + break; + } + + d += numread; + totreadsize -= numread; + } + else + { + break; + } + } + + GlobalUnlock(global_handle); + + if (totreadsize == 0) + { + HRESULT hresult; + + hresult = CreateStreamOnHGlobal(global_handle,TRUE,&stream); + + if (SUCCEEDED(hresult)) + { + debug_printf("got stream in %f seconds\n",(double)(GetTickCount()-tickstart) * 0.001); + + // the stream owns this handle now. + global_handle = 0; + } + else + { + debug_printf("CreateStreamOnHGlobal %x\n",hresult); + stream = 0; + } + } + } + + if (global_handle) + { + GlobalFree(global_handle); + } + } + + CloseHandle(h); + } + else + { + debug_printf("CreateFile %x\n",GetLastError()); + } + } + + +/* + // webp uses hglobals + { + IStream *my_stream; + + if (SUCCEEDED(SHCreateStreamOnFileEx(_viv_load_image_filename,STGM_READ,FILE_ATTRIBUTE_NORMAL,FALSE,NULL,&my_stream))) + { + // stream owns my_stream now. + stream = my_stream; + } + } +*/ + + if (stream) + { + int orientation; + + debug_printf("stream %d\n",stream); + + if (config_orientation) + { + orientation = os_get_orientation(_viv_load_image_filename); + + debug_printf("orientation %d\n",orientation); + } + else + { + orientation = 0; + } + +// if (!_viv_load_image_terminate) + { + void *image; + int load_ret; + + // not implemented. + load_ret = 1; + + if ((os_GdipLoadImageFromStream) && (os_GdipLoadImageFromStreamICM) && (os_GdipGetImageWidth) && (os_GdipGetImageHeight) && (os_GdipImageGetFrameDimensionsCount) && (os_GdipImageGetFrameDimensionsList) && (os_GdipImageGetFrameCount) && (os_GdipGetPropertyItemSize) && (os_GdipGetPropertyItem) && (os_GdipImageSelectActiveFrame) && (os_GdipGetImageFlags) && (os_GdipDisposeImage) && (os_GdipCreateFromHDC) && (os_GdipSetCompositingMode) && (os_GdipSetCompositingQuality) && (os_GdipSetInterpolationMode) && (os_GdipSetPixelOffsetMode) && (os_GdipSetSmoothingMode) && (os_GdipDrawImageRectI) && (os_GdipDeleteGraphics)) + { + if (config_icm) + { + load_ret = os_GdipLoadImageFromStreamICM(stream,&image); + } + else + { + load_ret = os_GdipLoadImageFromStream(stream,&image); + } + } + + debug_printf("image %p\n",image); + + if (load_ret == 0) + { +// if (!_viv_load_image_terminate) + { + if (os_GdipGetImageWidth(image,&first_frame.wide) == 0) + { + // pixel budget: a hostile or corrupted header can claim + // a canvas that decodes to gigabytes of rgba. refuse the + // load before any frame allocation happens; the dispose + // below still runs so this fails like an unloadable file. + if ((os_GdipGetImageHeight(image,&first_frame.high) == 0) && (!_viv_pixel_budget_refused(safe_size_mul((SIZE_T)first_frame.wide,(SIZE_T)first_frame.high)))) + { + UINT count; + int load_wide; + int load_high; + + load_wide = first_frame.wide; + load_high = first_frame.high; + + // apply orientation. + switch (orientation) + { + case 2: // #define PHOTO_ORIENTATION_FLIPHORIZONTAL 2u + break; + + case 5: // #define PHOTO_ORIENTATION_TRANSPOSE 5u + case 6: // #define PHOTO_ORIENTATION_ROTATE270 6u + case 7: // #define PHOTO_ORIENTATION_TRANSVERSE 7u + case 8: // #define PHOTO_ORIENTATION_ROTATE90 8u + { + int temp; + temp = first_frame.wide; + first_frame.wide = first_frame.high; + first_frame.high = temp; + } + break; + } + // progressive display: post the embedded thumbnail as a + // low resolution first frame while the full decode continues. + // cameras and phones embed a small thumbnail in the exif data; + // gdi+ returns it without decoding a single scanline of the + // full image, so a big image appears instantly (blurry) and + // sharpens when the full frame arrives. + if ((!_viv_load_is_preload) && (os_GdipGetImageThumbnail) && (((VIV_UINT64)load_wide * (VIV_UINT64)load_high) > 2000000)) + { + UINT thumb_data_size; + + // PropertyTagThumbnailData 0x501A: only take this path when an + // embedded thumbnail actually exists, otherwise gdi+ would + // decode the full image just to build one. + thumb_data_size = 0; + + if ((os_GdipGetPropertyItemSize(image,0x501A,&thumb_data_size) == 0) && (thumb_data_size > 0)) + { + void *thumb_image; + + thumb_image = NULL; + + // request at most 160x120: gdi+ serves the embedded thumbnail + // without decoding when the request fits inside it. + if (os_GdipGetImageThumbnail(image,160,120,&thumb_image,NULL,NULL) == 0) + { + UINT thumb_wide; + UINT thumb_high; + + thumb_wide = 0; + thumb_high = 0; + + if ((os_GdipGetImageWidth(thumb_image,&thumb_wide) == 0) && (os_GdipGetImageHeight(thumb_image,&thumb_high) == 0) && (thumb_wide) && (thumb_high)) + { + HDC screen_hdc; + + screen_hdc = GetDC(0); + + if (screen_hdc) + { + HDC mem_hdc; + + mem_hdc = CreateCompatibleDC(screen_hdc); + + if (mem_hdc) + { + HBITMAP hbitmap; + + hbitmap = CreateCompatibleBitmap(screen_hdc,(int)thumb_wide,(int)thumb_high); + + if (hbitmap) + { + HGDIOBJ last_hbitmap; + + last_hbitmap = SelectObject(mem_hdc,hbitmap); + + { + void *g; + + if (os_GdipCreateFromHDC(mem_hdc,&g) == 0) + { + // thumbnails carry no alpha worth preserving. + os_GdipSetCompositingMode(g,1); + + // Gdiplus::InterpolationModeNearestNeighbor: the thumbnail + // is drawn at its own size. + os_GdipSetInterpolationMode(g,5); + + if (os_GdipDrawImageRectI(g,thumb_image,0,0,(int)thumb_wide,(int)thumb_high) == 0) + { + // apply orientation: 5-8 swap the axes. + if ((orientation >= 5) && (orientation <= 8)) + { + UINT temp; + + temp = thumb_wide; + thumb_wide = thumb_high; + thumb_high = temp; + } + + if (orientation > 1) + { + HBITMAP new_hbitmap; + + new_hbitmap = _viv_orientate_hbitmap(hbitmap,orientation); + + if (new_hbitmap) + { + DeleteObject(hbitmap); + + hbitmap = new_hbitmap; + } + } + + { + _viv_reply_load_image_first_frame_t low_res_first_frame; + + low_res_first_frame.wide = thumb_wide; + low_res_first_frame.high = thumb_high; + low_res_first_frame.frame_count = 1; + low_res_first_frame.frame.hbitmap = hbitmap; + low_res_first_frame.frame.mipmap = NULL; // no mipmap: the full frame provides them + low_res_first_frame.frame.delay = 0; + low_res_first_frame.is_low_res = 1; + + _viv_reply_add(_VIV_REPLY_LOAD_IMAGE_FIRST_FRAME,sizeof(low_res_first_frame),&low_res_first_frame); + + // ownership moved to the reply. + hbitmap = 0; + } + } + + os_GdipDeleteGraphics(g); + } + } + + SelectObject(mem_hdc,last_hbitmap); + } + + if (hbitmap) + { + DeleteObject(hbitmap); + } + } + + DeleteDC(mem_hdc); + } + + ReleaseDC(0,screen_hdc); + } + } + + if (thumb_image) + { + os_GdipDisposeImage(thumb_image); + } + } + } + + + + //First of all we should get the number of frame dimensions + //Images considered by GDI+ as: + //frames[animation_frame_index][how_many_animation]; + if (os_GdipImageGetFrameDimensionsCount(image,&count) == 0) + { + os_PropertyItem_t *frame_delay; + SIZE_T frame_delay_size; + + frame_delay = NULL; + frame_delay_size = 0; + + //Now we should get the identifiers for the frame dimensions + { + GUID *DimensionIDs; + + // validate the count from gdi+ before trusting it: a zero count + // would read dimension set #0 outside a zero length allocation and + // an oversized count would wrap the size multiplication. + if ((count >= 1) && (count <= (SIZE_MAX / sizeof(GUID)))) + { + DimensionIDs = mem_alloc(sizeof(GUID) * count); + + if (os_GdipImageGetFrameDimensionsList(image,DimensionIDs,count) == 0) + { + //For gif image , we only care about animation set#0 + os_GdipImageGetFrameCount(image,&DimensionIDs[0],&first_frame.frame_count); + } + + mem_free(DimensionIDs); + } + } + + // get frame delays. + if (first_frame.frame_count > 1) + { + UINT size; + + size = 0; + + // PropertyTagFrameDelay 0x5100: gdi+ leaves *size untouched + // when the property is absent, so seed it and check the return. + if ((os_GdipGetPropertyItemSize(image,0x5100,&size) == 0) && (size >= sizeof(os_PropertyItem_t))) + { + frame_delay = (os_PropertyItem_t *)mem_alloc(size); + + if (frame_delay) + { + frame_delay_size = size; + + // PropertyTagFrameDelay 0x5100: only trust the buffer when + // gdi+ actually filled it. + if (os_GdipGetPropertyItem(image,0x5100,size,frame_delay) != 0) + { + mem_free(frame_delay); + frame_delay = 0; + frame_delay_size = 0; + } + } + } + + debug_printf("frame delay size %u\n",(unsigned int)frame_delay_size); + } + + // draw frames. + + { + HDC screen_hdc; + + screen_hdc = GetDC(0); + + if (screen_hdc) + { + HDC mem_hdc; + + mem_hdc = CreateCompatibleDC(screen_hdc); + if (mem_hdc) + { + DWORD i; + + for(i=0;i 1) + { + HBITMAP new_hbitmap; + + new_hbitmap = _viv_orientate_hbitmap(hbitmap,orientation); + if (new_hbitmap) + { + DeleteObject(hbitmap); + hbitmap = new_hbitmap; + } + } + + SelectObject(mem_hdc,last_hbitmap); + + if (i) + { + _viv_frame_t frame; + int mip_wide; + int mip_high; + UINT frame_data_value; + + frame.hbitmap = hbitmap; + frame.mipmap = NULL; + + // therube: we are accessing bad data here for some images. + // just use a value of 0 for bad data. + frame_data_value = _viv_frame_delay_at(frame_delay,frame_delay_size,i); + + frame.delay = frame_data_value * 10; + + if (!frame.delay) + { + frame.delay = 100; + } + + _viv_get_mipmap(hbitmap,first_frame.wide,first_frame.high,_viv_load_render_wide/2,_viv_load_render_high/2,&mip_wide,&mip_high,&frame.mipmap); + + _viv_reply_add(_VIV_REPLY_LOAD_IMAGE_ADDITIONAL_FRAME,sizeof(_viv_frame_t),&frame); + } + else + { + int mip_wide; + int mip_high; + UINT frame_data_value; + + first_frame.frame.hbitmap = hbitmap; + first_frame.frame.mipmap = NULL; + first_frame.frame.delay = 0; + + if (first_frame.frame_count > 1) + { + // therube: we are accessing bad data here for some images. + // just use a value of 0 for bad data. + frame_data_value = _viv_frame_delay_at(frame_delay,frame_delay_size,i); + + first_frame.frame.delay = frame_data_value * 10; + + if (!first_frame.frame.delay) + { + first_frame.frame.delay = 100; + } + } + + // preload first mipmap + _viv_get_mipmap(hbitmap,first_frame.wide,first_frame.high,_viv_load_render_wide/2,_viv_load_render_high/2,&mip_wide,&mip_high,&first_frame.frame.mipmap); + + _viv_reply_add(_VIV_REPLY_LOAD_IMAGE_FIRST_FRAME,sizeof(_viv_reply_load_image_first_frame_t),&first_frame); + + ret = 1; + } + } + } + + DeleteDC(mem_hdc); + } + + ReleaseDC(0,screen_hdc); + } + } + + if (frame_delay) + { + mem_free(frame_delay); + } + + debug_printf("image loaded\n"); + } + } + } + } + + os_GdipDisposeImage(image); + } + else + { + _viv_webp_t viv_webp; + + debug_printf("GDIPlus failed to load image %S %d\n",_viv_load_image_filename,load_ret); + + viv_webp.screen_hdc = NULL; + viv_webp.mem_hdc = NULL; + viv_webp.frame_index = 0; + viv_webp.last_delay = 0; + viv_webp.orientation = orientation; + + if (webp_load(stream,&viv_webp, + (int (*)(void *,DWORD,DWORD,DWORD,int))_viv_webp_info_proc, + (int (*)(void *,BYTE *,int))_viv_webp_frame_proc)) + { + ret = 1; + } + else + { + debug_printf("libwebp failed to load image %S\n",_viv_load_image_filename); + + // we loaded at least one frame, so treat it as complete. + if (viv_webp.frame_index > 0) + { + ret = 1; + } + } + + if (viv_webp.mem_hdc) + { + DeleteDC(viv_webp.mem_hdc); + } + + if (viv_webp.screen_hdc) + { + ReleaseDC(NULL,viv_webp.screen_hdc); + } + } + } + + stream->lpVtbl->Release(stream); + } + else + { + debug_printf("Failed to create stream from %S\n",_viv_load_image_filename); + } + + _viv_reply_add(ret ? _VIV_REPLY_LOAD_IMAGE_COMPLETE : _VIV_REPLY_LOAD_IMAGE_FAILED,0,0); + + CoUninitialize(); + + debug_printf("loaded in %f seconds\n",(double)(GetTickCount()-tickstart) * 0.001); + + return 0; +} +void _viv_reply_free(_viv_reply_t *e) +{ + switch (e->type) + { + case _VIV_REPLY_LOAD_IMAGE_FIRST_FRAME: + + if (((_viv_reply_load_image_first_frame_t *)(e+1))->frame.hbitmap) + { + DeleteObject(((_viv_reply_load_image_first_frame_t *)(e+1))->frame.hbitmap); + } + + if (((_viv_reply_load_image_first_frame_t *)(e+1))->frame.mipmap) + { + _viv_mipmap_free(((_viv_reply_load_image_first_frame_t *)(e+1))->frame.mipmap); + } + + break; + + case _VIV_REPLY_LOAD_IMAGE_ADDITIONAL_FRAME: + + if (((_viv_frame_t *)(e + 1))->hbitmap) + { + DeleteObject(((_viv_frame_t *)(e + 1))->hbitmap); + } + + if (((_viv_frame_t *)(e + 1))->mipmap) + { + _viv_mipmap_free(((_viv_frame_t *)(e + 1))->mipmap); + } + + break; + } + + mem_free(e); +} +_viv_reply_t *_viv_reply_add(DWORD type,DWORD size,void *data) +{ + _viv_reply_t *e; + int is_first; + + is_first = 0; + + e = (_viv_reply_t *)mem_alloc(safe_size_add(sizeof(_viv_reply_t),size)); + + e->type = type; + e->size = size; + + os_copy_memory(e + 1,data,size); + + EnterCriticalSection(&_viv_cs); + + if (_viv_reply_start) + { + _viv_reply_last->next = e; + } + else + { + _viv_reply_start = e; + is_first = 1; + } + + _viv_reply_last = e; + e->next = 0; + + LeaveCriticalSection(&_viv_cs); + + if (is_first) + { + PostMessage(_viv_hwnd,_VIV_WM_REPLY,0,0); + } + + return e; +} +void _viv_reply_clear_all(void) +{ + _viv_reply_t *e; + + EnterCriticalSection(&_viv_cs); + + e = _viv_reply_start; + _viv_reply_start = 0; + _viv_reply_last = 0; + + LeaveCriticalSection(&_viv_cs); + + while(e) + { + _viv_reply_t *next_e; + + next_e = e->next; + + _viv_reply_free(e); + + e = next_e; + } +} +void _viv_preload_next(void) +{ + if (config_preload_next) + { + //UpdateWindow(_viv_hwnd); + + _viv_next(_viv_last_is_prev,0,1,0); + } +} +// the preload has completed and we +// want to set it as the current image. +void _viv_activate_preload(void) +{ +debug_printf("activate preload\n"); + + _viv_clear(); + + _viv_frames = _viv_preload_frames; + _viv_preload_frames = NULL; + + _viv_frame_loaded_count = _viv_preload_frame_loaded_count; + _viv_preload_frame_loaded_count = 0; + + _viv_frame_count = _viv_preload_frame_count; + _viv_preload_frame_count = 0; + + _viv_image_wide = _viv_preload_image_wide; + _viv_preload_image_wide = 0; + + _viv_image_high = _viv_preload_image_high; + _viv_preload_image_high = 0; + + _viv_start_first_frame(); + + _viv_process_pending_clear(); + + os_copy_memory(_viv_frame_fd,_viv_preload_fd,sizeof(WIN32_FIND_DATA)); + + _viv_clear_preload_frames(); + + *_viv_preload_fd->cFileName = 0; +} +// copy the current image to the last image. +void viv_copy_current_image_to_last_image(void) +{ + if (_viv_last_frames) + { + _viv_clear_frames(_viv_last_frames,_viv_last_frame_count); + + _viv_last_frames = NULL; + _viv_last_frame_count = 0; + } + +debug_printf("*** Cache LAST : %S\n",_viv_frame_fd->cFileName); + + // only copy if the whole image was loaded. + // Otherwise we need to reload the whole image again.. + if (config_cache_last) + { + if (_viv_frame_count == _viv_frame_loaded_count) + { + os_copy_memory(_viv_last_fd,_viv_frame_fd,sizeof(WIN32_FIND_DATA)); + + _viv_last_image_wide = _viv_image_wide; // last image width + _viv_last_image_high = _viv_image_high ; // last image width + _viv_last_frame_count = _viv_frame_count; // last image frame count, 1 for static image, > 1 for animation (all frames are loaded) + _viv_last_frames = _viv_frames; + + _viv_image_wide = 0; + _viv_image_high = 0; + _viv_frame_count = 0; + _viv_frames = NULL; + _viv_frame_fd->cFileName[0] = 0; + } + } +} +static void _viv_activate_last(void) +{ + WIN32_FIND_DATA old_fd; + int old_image_wide; + int old_image_high; + int old_frame_count; + _viv_frame_t *old_frames; + +debug_printf("activate last\n"); + + old_frames = NULL; + + // save current image so we can store it in last image later. + // we can't do it now because we are setting the last image to the current image. + if (config_cache_last) + { + if (_viv_frame_count == _viv_frame_loaded_count) + { +debug_printf("*** Cache LAST2 : %S\n",_viv_frame_fd->cFileName); + + os_copy_memory(&old_fd,_viv_frame_fd,sizeof(WIN32_FIND_DATA)); + + old_image_wide = _viv_image_wide; // last image width + old_image_high = _viv_image_high ; // last image width + old_frame_count = _viv_frame_count; // last image frame count, 1 for static image, > 1 for animation (all frames are loaded) + old_frames = _viv_frames; + + _viv_image_wide = 0; + _viv_image_high = 0; + _viv_frame_count = 0; + _viv_frames = NULL; + _viv_frame_fd->cFileName[0] = 0; + } + } + + os_copy_memory(_viv_current_fd,_viv_last_fd,sizeof(WIN32_FIND_DATA)); + + _viv_update_title(); + _viv_status_update(); + + _viv_clear(); + + _viv_frames = _viv_last_frames; + os_copy_memory(_viv_frame_fd,_viv_last_fd,sizeof(WIN32_FIND_DATA)); + _viv_last_frames = NULL; + + _viv_frame_loaded_count = _viv_last_frame_count; + _viv_frame_count = _viv_last_frame_count; + _viv_last_frame_count = 0; + + _viv_image_wide = _viv_last_image_wide; + _viv_last_image_wide = 0; + + _viv_image_high = _viv_last_image_high; + _viv_last_image_high = 0; + + _viv_start_first_frame(); + + _viv_process_pending_clear(); + + if (old_frames) + { + os_copy_memory(_viv_last_fd,&old_fd,sizeof(WIN32_FIND_DATA)); + + _viv_last_image_wide = old_image_wide; + _viv_last_image_high = old_image_high; + _viv_last_frame_count = old_frame_count; + _viv_last_frames = old_frames; + } +} +void _viv_clear_last(void) +{ + if (_viv_last_frames) + { + _viv_clear_frames(_viv_last_frames,_viv_last_frame_count); + + _viv_last_frames = NULL; + _viv_last_frame_count = 0; + } +} +void _viv_refresh(void) +{ + WIN32_FIND_DATA fd; + + os_copy_memory(&fd,_viv_current_fd,sizeof(WIN32_FIND_DATA)); + + // clear last cache + _viv_clear_last(); + + // clear preload. + _viv_clear_loading_preload(); + _viv_clear_preload(); + + _viv_clear(); + _viv_start_first_frame(); + _viv_process_pending_clear(); + + // no file open: the reload below would only fail against the empty + // name and pin a load error on the blank window (the field report: + // changing the backdrop or the canvas color on the bare program showed + // a load failure at the bottom left). the blank state is the correct + // result there: reset the stale flags and keep the canvas. + if (!fd.cFileName[0]) + { + if (_viv_file_not_found) + { + _viv_file_not_found = 0; + + _viv_status_update(); + } + + if (_viv_load_failed) + { + _viv_load_failed = 0; + + _viv_status_update(); + } + + return; + } + + _viv_open(&fd,0); +} +void _viv_open_preload(void) +{ + os_copy_memory(_viv_current_fd,_viv_preload_fd,sizeof(WIN32_FIND_DATA)); + + _viv_update_title(); + + if (_viv_preload_state == 0) + { + // loading... + // do we have the first frame? + if (_viv_preload_frame_loaded_count) + { + // save current image to last image. + viv_copy_current_image_to_last_image(); + + // switch now.. + _viv_load_is_preload = 0; + _viv_activate_preload(); + _viv_status_update(); + } + else + { + // still loading... + // wait... + if (!_viv_should_activate_preload_on_load) + { + _viv_should_activate_preload_on_load = 1; + + // show loading... + _viv_status_update(); + } + + debug_printf("STILL LOADING...\n"); + } + } + else + if (_viv_preload_state == 1) + { + // save current image to last image. + viv_copy_current_image_to_last_image(); + + // loaded + // preload next below.. + _viv_load_is_preload = 0; + _viv_status_update(); + + _viv_activate_preload(); + + _viv_preload_next(); + } + else + { + // save current image to last image. + viv_copy_current_image_to_last_image(); + + // failed. + // preload next below.. + _viv_load_failed = 1; + _viv_load_is_preload = 0; + _viv_status_update(); + + _viv_clear(); + + _viv_start_first_frame(); + + _viv_process_pending_clear(); + + _viv_preload_next(); + } +} +// read the 10ms delay of frame i. returns 0 on any failure, the caller +// falls back to 100ms. the gdi+ value pointer is validated against the +// property buffer before it is used, and the delay array may hold fewer +// entries than there are frames (the gif GCE block is optional), so delays +// are reused modulo the available count. +static int _viv_pixel_budget_refused(SIZE_T pixels) +{ + if (pixels > VIV_MAX_IMAGE_PIXELS) + { + debug_printf("pixel budget: refusing a %u mp canvas (ceiling %u mp)\r\n",(unsigned int)(pixels / 1000000),(unsigned int)(VIV_MAX_IMAGE_PIXELS / 1000000)); + + return 1; + } + + return 0; +} +int _viv_safe_copy_data(const void *base,SIZE_T src_size,const void *src,void *dst,SIZE_T dst_size) +{ + const BYTE *p; + BYTE *d; + SIZE_T run; + SIZE_T end; + + if (((const BYTE *)src) < ((const BYTE *)base)) + { + return 0; + } + + end = safe_size_add(((const BYTE *)src) - ((const BYTE *)base),dst_size); + + if (end == SIZE_MAX) + { + return 0; + } + + if (end > src_size) + { + return 0; + } + + p = (const BYTE *)src; + d = (BYTE *)dst; + run = dst_size; + + while(run) + { + *d++ = *p; + p++; + run--; + } + + return 1; +} diff --git a/src/viv_load.h b/src/viv_load.h new file mode 100644 index 00000000..8f29818b --- /dev/null +++ b/src/viv_load.h @@ -0,0 +1,67 @@ +// +// Copyright 2025 voidtools / David Carpenter +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +// VoidImageViewer +// viv_load.h - image loading, decode thread, clipboard images, preload. +#ifndef VIV_LOAD_H +#define VIV_LOAD_H + +#include "viv.h" + +// exported to other domains / the viv.c core +void _viv_clear(void); +void _viv_process_pending_clear(void); +void _viv_clear_loading_preload(void); +void _viv_clear_preload_frames(void); +void _viv_clear_preload(void); +// the recent-list policy of an open-by-name, declared where the intent is +// knowable - never guessed at the push site. +// VIV_OPEN_RECENT: a user command (the open dialog, the drag-drop, the +// recent click) feeds the recent list unconditionally - +// the standard mru contract, a re-open of the displayed file re-tops it. +// VIV_OPEN_FORWARDED: an externally forwarded open (the single-instance +// forward of a second launch, the re-entry the rotate verb's refresh and +// the rotate-then-recheck double-click ride) feeds the list only when the +// file is not the one already on screen: a same-file forward is a reload, +// not a recent open. the startup command line shares this site and is +// vacuously fine - no file is on screen yet, so the first open still +// enters the list. +#define VIV_OPEN_RECENT 1 +#define VIV_OPEN_FORWARDED 0 +BOOL _viv_open_from_filename(const wchar_t *filename,int recent_policy); +void _viv_open(WIN32_FIND_DATA *fd,int is_preload); +void _viv_set_clipboard_image(void); +void _viv_paste_clipboard_image(void); +void _viv_save_image_as(void); +void _viv_doing_cancel(void); +void _viv_blank(void); +void _viv_reply_free(_viv_reply_t *e); +_viv_reply_t *_viv_reply_add(DWORD type,DWORD size,void *data); +void _viv_reply_clear_all(void); +void _viv_preload_next(void); +void _viv_activate_preload(void); +void viv_copy_current_image_to_last_image(void); +void _viv_clear_last(void); +void _viv_refresh(void); +void _viv_open_preload(void); +int _viv_safe_copy_data(const void *base,SIZE_T src_size,const void *src,void *dst,SIZE_T dst_size); + +#endif diff --git a/src/viv_menu.c b/src/viv_menu.c new file mode 100644 index 00000000..fbf2a4c5 --- /dev/null +++ b/src/viv_menu.c @@ -0,0 +1,1353 @@ +// +// Copyright 2025 voidtools / David Carpenter +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +// VoidImageViewer +// viv_menu.c - command and key tables, menus, menu localization. +// Pure physical move from viv.c (R70 split): bodies are unchanged. +#include "viv.h" +#include "viv_state.h" +#include "viv_menu.h" +#include "viv_chrome.h" +#include "viv_recent.h" +#include "viv_render.h" + +// forward declarations (order preserved from viv.c) +void _viv_check_menus(HMENU hmenu); +void _viv_get_command_name(wchar_t *wbuf,int command_index); +static void _viv_cat_command_menu_path(wchar_t *wbuf,int menu_index); +static int _viv_convert_menu_ini_name_ch(int ch); +static utf8_t *_viv_cat_command_menu_ini_name_path(utf8_t *buf,int menu_index); +static void _viv_get_menu_display_name(wchar_t *buf,const utf8_t *menu_name); +int _viv_command_index_from_command_id(int command_id); +static int _viv_vk_to_text(wchar_t *wbuf,int vk); +static void _viv_cat_key_mod(wchar_t *wbuf,int vk,const utf8_t *default_keytext); +void _viv_get_key_text(wchar_t *wbuf,DWORD keyflags); +HMENU _viv_create_menu(void); +void _viv_key_add(_viv_key_list_t *key_list,int command_index,DWORD keyflags); +static void _viv_key_clear(_viv_key_list_t *key_list,int command_index); +void _viv_key_list_copy(_viv_key_list_t *dst,const _viv_key_list_t *src); +void _viv_key_clear_all(_viv_key_list_t *list); +void _viv_key_list_init(_viv_key_list_t *list); +int _viv_get_current_key_mod_flags(void); +void _viv_key_remove(_viv_key_list_t *keylist,int command_index,DWORD keyflags); + +typedef struct _viv_menu_draw_t +{ + int type; // _VIV_MENU_DRAW_* + int command_index; // COMMAND / POPUP: index into _viv_commands + int localization_id; // LOCALIZED + int recent_index; // RECENT: index into config_recent_files + const wchar_t *text; // TEXT: the builder's label store +} _viv_menu_draw_t; + +static _viv_menu_draw_t _viv_menu_draw_pool[_VIV_COMMAND_COUNT + 16]; +static int _viv_menu_draw_count; +static _viv_menu_draw_t _viv_recent_draw_pool[CONFIG_RECENT_FILE_COUNT + 4]; +static int _viv_recent_draw_count; +static _viv_menu_draw_t _viv_context_draw_pool[_VIV_COMMAND_COUNT + 16]; +static int _viv_context_draw_count; +// rc.13: the settings dropdown rows (one popup at a time, reset per open). +static _viv_menu_draw_t _viv_settings_draw_pool[32]; +static int _viv_settings_draw_count; + +// dips at the primary monitor dpi (the menubar uses the same convention). +static int _viv_menu_dip(int d) +{ + return (d * os_logical_high) / 96; +} + +void _viv_menu_row_pool_reset(int pool) +{ + switch (pool) + { + case _VIV_MENU_POOL_RECENT: + _viv_recent_draw_count = 0; + break; + + case _VIV_MENU_POOL_CONTEXT: + _viv_context_draw_count = 0; + break; + + case _VIV_MENU_POOL_SETTINGS: + _viv_settings_draw_count = 0; + break; + + default: + _viv_menu_draw_count = 0; + break; + } +} + +void *_viv_menu_row_alloc(int pool,int type,int command_index,int localization_id,int recent_index) +{ + _viv_menu_draw_t *table; + int *count; + int cap; + _viv_menu_draw_t *row; + + table = _viv_menu_draw_pool; + count = &_viv_menu_draw_count; + cap = _VIV_COMMAND_COUNT + 16; + + switch (pool) + { + case _VIV_MENU_POOL_RECENT: + table = _viv_recent_draw_pool; + count = &_viv_recent_draw_count; + cap = CONFIG_RECENT_FILE_COUNT + 4; + break; + + case _VIV_MENU_POOL_SETTINGS: + table = _viv_settings_draw_pool; + count = &_viv_settings_draw_count; + cap = 32; + break; + + case _VIV_MENU_POOL_CONTEXT: + table = _viv_context_draw_pool; + count = &_viv_context_draw_count; + break; + } + + if (*count >= cap) + { + return 0; + } + + row = &table[*count]; + (*count)++; + + row->type = type; + row->command_index = command_index; + row->localization_id = localization_id; + row->recent_index = recent_index; + row->text = 0; + + return row; +} + +// rc.13: attach an ad hoc label to a text row. the store behind the +// pointer belongs to the builder (the settings dropdowns keep a static +// label array that the pool reset reclaims with the rows). +void _viv_menu_row_set_text(void *row,const wchar_t *text) +{ + _viv_menu_draw_t *draw; + + draw = (_viv_menu_draw_t *)row; + + if (draw) + { + draw->text = text; + } +} + + + +void _viv_check_menus(HMENU hmenu) +{ + int is_slideshow; + int fill_window; + int rw; + int rh; + int slideshow_rate_id; + UINT is_image_enabled; + + is_slideshow = 0; + + if (_viv_is_fullscreen) + { + if (_viv_is_slideshow) + { + is_slideshow = 1; + _viv_status_update(); + _viv_toolbar_update_buttons(); + _viv_update_ontop(); + } + + fill_window = config_fullscreen_fill_window; + } + else + { + fill_window = config_fill_window; + } + + _viv_get_render_size(&rw,&rh); + + is_image_enabled = ((*_viv_current_fd->cFileName) && (!_viv_file_not_found) && (!_viv_load_failed)) ? MF_ENABLED : MF_DISABLED; + + EnableMenuItem(hmenu,VIV_ID_FILE_CLOSE,is_image_enabled); + EnableMenuItem(hmenu,VIV_ID_EDIT_COPY,is_image_enabled); + EnableMenuItem(hmenu,VIV_ID_EDIT_COPY_FILENAME,is_image_enabled); + EnableMenuItem(hmenu,VIV_ID_EDIT_COPY_IMAGE,is_image_enabled); + EnableMenuItem(hmenu,VIV_ID_EDIT_COPY_TO,is_image_enabled); + EnableMenuItem(hmenu,VIV_ID_EDIT_CUT,is_image_enabled); + EnableMenuItem(hmenu,VIV_ID_FILE_DELETE,is_image_enabled); + EnableMenuItem(hmenu,VIV_ID_FILE_EDIT,is_image_enabled); + EnableMenuItem(hmenu,VIV_ID_EDIT_MOVE_TO,is_image_enabled); + EnableMenuItem(hmenu,VIV_ID_FILE_OPEN_FILE_LOCATION,is_image_enabled); + EnableMenuItem(hmenu,VIV_ID_FILE_PREVIEW,is_image_enabled); + EnableMenuItem(hmenu,VIV_ID_FILE_PRINT,is_image_enabled); + EnableMenuItem(hmenu,VIV_ID_FILE_PROPERTIES,is_image_enabled); + EnableMenuItem(hmenu,VIV_ID_FILE_SET_DESKTOP_WALLPAPER,is_image_enabled); + EnableMenuItem(hmenu,VIV_ID_FILE_SAVE_AS,is_image_enabled); + EnableMenuItem(hmenu,VIV_ID_FILE_RENAME,is_image_enabled); + + EnableMenuItem(hmenu,VIV_ID_EDIT_ROTATE_270,is_image_enabled); + EnableMenuItem(hmenu,VIV_ID_EDIT_ROTATE_90,is_image_enabled); +// EnableMenuItem(hmenu,VIV_ID_SLIDESHOW_PAUSE,is_image_enabled); + + CheckMenuItem(hmenu,VIV_ID_VIEW_CAPTION,config_show_caption ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(hmenu,VIV_ID_VIEW_THICKFRAME,config_show_thickframe ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(hmenu,VIV_ID_VIEW_MENU,config_show_menu ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(hmenu,VIV_ID_VIEW_CONTROLS,config_show_controls ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(hmenu,VIV_ID_VIEW_ZOOM_CONTROLS,config_show_zoom_controls ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(hmenu,VIV_ID_VIEW_ZOOM_AUTO_HIDE,config_zoom_auto_hide ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(hmenu,VIV_ID_VIEW_BACKDROP_FOLLOW,config_backdrop_mode == CONFIG_BACKDROP_MODE_FOLLOW ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); + CheckMenuItem(hmenu,VIV_ID_VIEW_BACKDROP_BLACK,config_backdrop_mode == CONFIG_BACKDROP_MODE_BLACK ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); + CheckMenuItem(hmenu,VIV_ID_VIEW_BACKDROP_WHITE,config_backdrop_mode == CONFIG_BACKDROP_MODE_WHITE ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); + CheckMenuItem(hmenu,VIV_ID_VIEW_BACKDROP_CUSTOM,config_backdrop_mode == CONFIG_BACKDROP_MODE_CUSTOM ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); + CheckMenuItem(hmenu,VIV_ID_VIEW_BACKDROP_CHECKERBOARD,config_backdrop_mode == CONFIG_BACKDROP_MODE_CHECKERBOARD ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); + CheckMenuItem(hmenu,VIV_ID_VIEW_STATUS,config_show_status ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(hmenu,VIV_ID_VIEW_ALLOW_SHRINKING,config_allow_shrinking ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(hmenu,VIV_ID_VIEW_KEEP_ASPECT_RATIO,config_keep_aspect_ratio ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(hmenu,VIV_ID_VIEW_FILL_WINDOW,fill_window ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(hmenu,VIV_ID_VIEW_1TO1,((rw == _viv_image_wide) && (rh == _viv_image_high)) ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(hmenu,VIV_ID_VIEW_FULLSCREEN,_viv_is_fullscreen ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(hmenu,VIV_ID_VIEW_SLIDESHOW,is_slideshow ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(hmenu,VIV_ID_VIEW_ONTOP_ALWAYS,config_ontop == 1 ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); + CheckMenuItem(hmenu,VIV_ID_VIEW_ONTOP_WHILE_PLAYING_OR_ANIMATING,config_ontop == 2 ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); + CheckMenuItem(hmenu,VIV_ID_VIEW_ONTOP_NEVER,config_ontop == 0 ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); + + CheckMenuItem(hmenu,VIV_ID_SLIDESHOW_PAUSE,_viv_is_slideshow ? MF_CHECKED : MF_UNCHECKED); + + switch(config_slideshow_rate) + { + case 250: slideshow_rate_id = VIV_ID_SLIDESHOW_RATE_250; break; + case 500: slideshow_rate_id = VIV_ID_SLIDESHOW_RATE_500; break; + case 1000: slideshow_rate_id = VIV_ID_SLIDESHOW_RATE_1000; break; + case 2000: slideshow_rate_id = VIV_ID_SLIDESHOW_RATE_2000; break; + case 3000: slideshow_rate_id = VIV_ID_SLIDESHOW_RATE_3000; break; + case 4000: slideshow_rate_id = VIV_ID_SLIDESHOW_RATE_4000; break; + case 5000: slideshow_rate_id = VIV_ID_SLIDESHOW_RATE_5000; break; + case 6000: slideshow_rate_id = VIV_ID_SLIDESHOW_RATE_6000; break; + case 7000: slideshow_rate_id = VIV_ID_SLIDESHOW_RATE_7000; break; + case 8000: slideshow_rate_id = VIV_ID_SLIDESHOW_RATE_8000; break; + case 9000: slideshow_rate_id = VIV_ID_SLIDESHOW_RATE_9000; break; + case 10000: slideshow_rate_id = VIV_ID_SLIDESHOW_RATE_10000; break; + case 20000: slideshow_rate_id = VIV_ID_SLIDESHOW_RATE_20000; break; + case 30000: slideshow_rate_id = VIV_ID_SLIDESHOW_RATE_30000; break; + case 40000: slideshow_rate_id = VIV_ID_SLIDESHOW_RATE_40000; break; + case 50000: slideshow_rate_id = VIV_ID_SLIDESHOW_RATE_50000; break; + case 60000: slideshow_rate_id = VIV_ID_SLIDESHOW_RATE_60000; break; + + default: + slideshow_rate_id = VIV_ID_SLIDESHOW_RATE_CUSTOM; + break; + } + + CheckMenuItem(hmenu,VIV_ID_SLIDESHOW_RATE_250,slideshow_rate_id == VIV_ID_SLIDESHOW_RATE_250 ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); + CheckMenuItem(hmenu,VIV_ID_SLIDESHOW_RATE_500,slideshow_rate_id == VIV_ID_SLIDESHOW_RATE_500 ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); + CheckMenuItem(hmenu,VIV_ID_SLIDESHOW_RATE_1000,slideshow_rate_id == VIV_ID_SLIDESHOW_RATE_1000 ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); + CheckMenuItem(hmenu,VIV_ID_SLIDESHOW_RATE_2000,slideshow_rate_id == VIV_ID_SLIDESHOW_RATE_2000 ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); + CheckMenuItem(hmenu,VIV_ID_SLIDESHOW_RATE_3000,slideshow_rate_id == VIV_ID_SLIDESHOW_RATE_3000 ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); + CheckMenuItem(hmenu,VIV_ID_SLIDESHOW_RATE_4000,slideshow_rate_id == VIV_ID_SLIDESHOW_RATE_4000 ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); + CheckMenuItem(hmenu,VIV_ID_SLIDESHOW_RATE_5000,slideshow_rate_id == VIV_ID_SLIDESHOW_RATE_5000 ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); + CheckMenuItem(hmenu,VIV_ID_SLIDESHOW_RATE_6000,slideshow_rate_id == VIV_ID_SLIDESHOW_RATE_6000 ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); + CheckMenuItem(hmenu,VIV_ID_SLIDESHOW_RATE_7000,slideshow_rate_id == VIV_ID_SLIDESHOW_RATE_7000 ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); + CheckMenuItem(hmenu,VIV_ID_SLIDESHOW_RATE_8000,slideshow_rate_id == VIV_ID_SLIDESHOW_RATE_8000 ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); + CheckMenuItem(hmenu,VIV_ID_SLIDESHOW_RATE_9000,slideshow_rate_id == VIV_ID_SLIDESHOW_RATE_9000 ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); + CheckMenuItem(hmenu,VIV_ID_SLIDESHOW_RATE_10000,slideshow_rate_id == VIV_ID_SLIDESHOW_RATE_10000 ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); + CheckMenuItem(hmenu,VIV_ID_SLIDESHOW_RATE_20000,slideshow_rate_id == VIV_ID_SLIDESHOW_RATE_20000 ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); + CheckMenuItem(hmenu,VIV_ID_SLIDESHOW_RATE_30000,slideshow_rate_id == VIV_ID_SLIDESHOW_RATE_30000 ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); + CheckMenuItem(hmenu,VIV_ID_SLIDESHOW_RATE_40000,slideshow_rate_id == VIV_ID_SLIDESHOW_RATE_40000 ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); + CheckMenuItem(hmenu,VIV_ID_SLIDESHOW_RATE_50000,slideshow_rate_id == VIV_ID_SLIDESHOW_RATE_50000 ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); + CheckMenuItem(hmenu,VIV_ID_SLIDESHOW_RATE_60000,slideshow_rate_id == VIV_ID_SLIDESHOW_RATE_60000 ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); + CheckMenuItem(hmenu,VIV_ID_SLIDESHOW_RATE_CUSTOM,slideshow_rate_id == VIV_ID_SLIDESHOW_RATE_CUSTOM ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); + + CheckMenuItem(hmenu,VIV_ID_ANIMATION_PLAY_PAUSE,_viv_animation_play ? MF_CHECKED : MF_UNCHECKED); + + CheckMenuItem(hmenu,VIV_ID_NAV_SHUFFLE,config_shuffle ? MF_CHECKED : MF_UNCHECKED); + + CheckMenuItem(hmenu,VIV_ID_NAV_SORT_NAME,config_nav_sort == CONFIG_NAV_SORT_NAME ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); + CheckMenuItem(hmenu,VIV_ID_NAV_SORT_FULL_PATH,config_nav_sort == CONFIG_NAV_SORT_FULL_PATH_AND_FILENAME ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); + CheckMenuItem(hmenu,VIV_ID_NAV_SORT_SIZE,config_nav_sort == CONFIG_NAV_SORT_SIZE ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); + CheckMenuItem(hmenu,VIV_ID_NAV_SORT_DATE_MODIFIED,config_nav_sort == CONFIG_NAV_SORT_DATE_MODIFIED ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); + CheckMenuItem(hmenu,VIV_ID_NAV_SORT_DATE_CREATED,config_nav_sort == CONFIG_NAV_SORT_DATE_CREATED ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); + + CheckMenuItem(hmenu,VIV_ID_NAV_SORT_ASCENDING,config_nav_sort_ascending ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); + CheckMenuItem(hmenu,VIV_ID_NAV_SORT_DESCENDING,(!config_nav_sort_ascending) ? (MF_CHECKED|MFT_RADIOCHECK) : (MF_UNCHECKED|MFT_RADIOCHECK)); + + CheckMenuItem(hmenu,VIV_ID_VIEW_1TO1,((rw == _viv_image_wide) && (rh == _viv_image_high)) ? MF_CHECKED : MF_UNCHECKED); +} +void _viv_get_command_name(wchar_t *wbuf,int command_index) +{ + wchar_t menu_wbuf[STRING_SIZE]; + + *wbuf = 0; + + _viv_cat_command_menu_path(wbuf,_viv_commands[command_index].menu_id); + + _viv_get_menu_display_name(menu_wbuf,localization_get_string(_viv_commands[command_index].localization_id)); + + string_cat(wbuf,menu_wbuf); +} +static void _viv_cat_command_menu_path(wchar_t *wbuf,int menu_index) +{ + int command_index; + + if (menu_index == _VIV_MENU_ROOT) + { + return; + } + + command_index = _viv_command_index_from_command_id(menu_index); + + if (command_index != -1) + { + wchar_t menu_wbuf[STRING_SIZE]; + + _viv_get_menu_display_name(menu_wbuf,localization_get_string(_viv_commands[command_index].localization_id)); + + _viv_cat_command_menu_path(wbuf,_viv_commands[command_index].menu_id); + + string_cat(wbuf,menu_wbuf); + string_cat_utf8(wbuf," | "); + } +} +static int _viv_convert_menu_ini_name_ch(int ch) +{ + if ((ch >= 'A') && (ch <= 'Z')) + { + return ch - 'A' + 'a'; + } + + if ((ch >= 'a') && (ch <= 'z')) + { + return ch; + } + + if ((ch >= '0') && (ch <= '9')) + { + return ch; + } + + if (ch == ' ') + { + return '_'; + } + + return 0; +} +static utf8_t *_viv_cat_command_menu_ini_name_path(utf8_t *buf,int menu_index) +{ + int command_index; + utf8_t *d; + + if (menu_index == _VIV_MENU_ROOT) + { + return buf; + } + + d = buf; + + command_index = _viv_command_index_from_command_id(menu_index); + + if (command_index != -1) + { + const utf8_t *p; + + d = _viv_cat_command_menu_ini_name_path(d,_viv_commands[command_index].menu_id); + + p = localization_get_en_us_string(_viv_commands[command_index].localization_id); + + while(*p) + { + int ch; + + ch = _viv_convert_menu_ini_name_ch(*p); + + if (ch) + { + *d++ = ch; + } + + p++; + } + + *d++ = '_'; + } + + return d; +} +// make sure this is english only. +int viv_menu_name_to_ini_name(utf8_t *buf,int command_index) +{ + if (!(_viv_commands[command_index].flags & MF_POPUP)) + { + if (!(_viv_commands[command_index].flags & MF_SEPARATOR)) + { + if (!(_viv_commands[command_index].flags & MF_DELETE)) + { + utf8_t *d; + const utf8_t *p; + + d = buf; + p = localization_get_en_us_string(_viv_commands[command_index].localization_id); + + d = _viv_cat_command_menu_ini_name_path(d,_viv_commands[command_index].menu_id); + + while(*p) + { + int ch; + + ch = _viv_convert_menu_ini_name_ch(*p); + + if (ch) + { + *d++ = ch; + } + + p++; + } + + *d++ = '_'; + *d++ = 'k'; + *d++ = 'e'; + *d++ = 'y'; + *d++ = 's'; + + *d = 0; + + return 1; + } + } + } + + return 0; +} +static void _viv_get_menu_display_name(wchar_t *buf,const utf8_t *menu_name) +{ + wchar_t *d; + const wchar_t *p; + + string_copy_utf8_string(buf,menu_name); + + d = buf; + p = buf; + + while(*p) + { + if ((*p == '&') && (p[1] == '&')) + { + *d++ = '&'; + p += 2; + continue; + } + else + if (*p == '&') + { + } + else + { + *d++ = *p; + } + + p++; + } + + *d = 0; +} +int _viv_command_index_from_command_id(int command_id) +{ + int i; + + for(i=0;i<_VIV_COMMAND_COUNT;i++) + { + if (_viv_commands[i].command_id == command_id) + { + return i; + } + } + + return -1; +} +static int _viv_vk_to_text(wchar_t *wbuf,int vk) +{ + UINT scan_code; + + scan_code = MapVirtualKeyExW(vk,0,GetKeyboardLayout(GetCurrentThreadId())); + + if (scan_code) + { + LONG lParam; + + lParam = scan_code << 16; + + switch (vk) + { + case VK_CONTROL: + case VK_SHIFT: + case VK_MENU: + case VK_LWIN: + case VK_RWIN: + // dont care + lParam |= (1 << 25); + break; + + case VK_HOME: + case VK_END: + case VK_PRIOR: + case VK_NEXT: + case VK_INSERT: + case VK_DELETE: + case VK_NUMLOCK: + case VK_UP: + case VK_DOWN: + case VK_LEFT: + case VK_RIGHT: + case VK_DIVIDE: + // extended + lParam |= (1 << 24); + break; + } + + if (GetKeyNameText(lParam,wbuf,STRING_SIZE)) + { + return 1; + } + } + + return 0; +} +static void _viv_cat_key_mod(wchar_t *wbuf,int vk,const utf8_t *default_keytext) +{ + wchar_t keytext[STRING_SIZE]; + + if (!_viv_vk_to_text(keytext,vk)) + { + string_copy_utf8_string(keytext,default_keytext); + } + + string_cat(wbuf,keytext); + string_cat_utf8(wbuf,(const utf8_t *)"+"); +} +void _viv_get_key_text(wchar_t *wbuf,DWORD keyflags) +{ + wchar_t keytext[STRING_SIZE]; + + *wbuf = 0; + + if (keyflags & CONFIG_KEYFLAG_CTRL) + { + _viv_cat_key_mod(wbuf,VK_CONTROL,"Ctrl"); + } + + if (keyflags & CONFIG_KEYFLAG_ALT) + { + _viv_cat_key_mod(wbuf,VK_MENU,"Alt"); + } + + if (keyflags & CONFIG_KEYFLAG_SHIFT) + { + _viv_cat_key_mod(wbuf,VK_SHIFT,"Shift"); + } + + if (_viv_vk_to_text(keytext,keyflags & CONFIG_KEYFLAG_VK_MASK)) + { + string_cat(wbuf,keytext); + } +} +HMENU _viv_create_menu(void) +{ + HMENU hmenu; + + hmenu = CreateMenu(); + + _viv_menu_row_pool_reset(_VIV_MENU_POOL_MAIN); + + { + int i; + HMENU menus[_VIV_MENU_COUNT]; + + for(i=1;i<_VIV_MENU_COUNT;i++) + { + menus[i] = 0; + } + menus[0] = hmenu; + + for(i=0;i<_VIV_COMMAND_COUNT;i++) + { + if (!(_viv_commands[i].flags & MF_OWNERDRAW)) + { + int flags; + void *row; + + flags = _viv_commands[i].flags & (~MF_DELETE); + + if (_viv_commands[i].flags & MF_SEPARATOR) + { + row = _viv_menu_row_alloc(_VIV_MENU_POOL_MAIN,_VIV_MENU_DRAW_SEPARATOR,0,0,0); + + if (row) + { + AppendMenu(menus[_viv_commands[i].menu_id],flags | MF_OWNERDRAW,_viv_commands[i].command_id,(LPCWSTR)row); + } + else + { + AppendMenu(menus[_viv_commands[i].menu_id],flags,_viv_commands[i].command_id,L""); + } + } + else + { + if (_viv_commands[i].flags & MF_POPUP) + { + if (!menus[_viv_commands[i].command_id]) + { + menus[_viv_commands[i].command_id] = CreatePopupMenu(); + } + + row = _viv_menu_row_alloc(_VIV_MENU_POOL_MAIN,_VIV_MENU_DRAW_POPUP,i,0,0); + + if (row) + { + AppendMenu(menus[_viv_commands[i].menu_id],flags | MF_OWNERDRAW,(UINT_PTR)menus[_viv_commands[i].command_id],(LPCWSTR)row); + } + else + { + wchar_t text_wbuf[STRING_SIZE]; + + string_copy_utf8_string(text_wbuf,localization_get_string(_viv_commands[i].localization_id)); + AppendMenu(menus[_viv_commands[i].menu_id],flags,(UINT_PTR)menus[_viv_commands[i].command_id],text_wbuf); + } + } + else + { + row = _viv_menu_row_alloc(_VIV_MENU_POOL_MAIN,_VIV_MENU_DRAW_COMMAND,i,0,0); + + if (row) + { + AppendMenu(menus[_viv_commands[i].menu_id],flags | MF_OWNERDRAW,_viv_commands[i].command_id,(LPCWSTR)row); + } + else + { + wchar_t text_wbuf[STRING_SIZE]; + + string_copy_utf8_string(text_wbuf,localization_get_string(_viv_commands[i].localization_id)); + AppendMenu(menus[_viv_commands[i].menu_id],flags,_viv_commands[i].command_id,text_wbuf); + } + } + } + } + } + + // the recent-files mru submenu is dynamic (paths from the ini), so + // it is built after the static table walk and inserted before the + // exit item of the file menu. + { + HMENU recent_menu; + wchar_t text_wbuf[STRING_SIZE]; + + recent_menu = _viv_create_recent_menu(); + + string_copy_utf8_string(text_wbuf,localization_get_string(LOCALIZATION_ID_RECENT_FILES)); + + { + MENUITEMINFOW mii; + int insert_pos; + + os_zero_memory(&mii,sizeof(mii)); + mii.cbSize = sizeof(mii); + // owner drawn like every other row: the type flag lives in fType + // (fState only takes MFS_ values; the old line was silently ignored + // and the header painted in the system look). + mii.fMask = MIIM_SUBMENU | MIIM_FTYPE | MIIM_ID | MIIM_DATA; + mii.fType = MFT_OWNERDRAW; + mii.wID = _VIV_MENU_FILE_RECENT; + mii.hSubMenu = recent_menu; + mii.dwTypeData = text_wbuf; + mii.dwItemData = (ULONG_PTR)_viv_menu_row_alloc(_VIV_MENU_POOL_MAIN,_VIV_MENU_DRAW_LOCALIZED,0,LOCALIZATION_ID_RECENT_FILES,0); + + // right before the exit item (the last row of the file menu). + insert_pos = GetMenuItemCount(menus[_VIV_MENU_FILE]) - 1; + InsertMenuItemW(menus[_VIV_MENU_FILE],insert_pos,TRUE,&mii); + } + } + } + + return hmenu; +} +void _viv_key_add(_viv_key_list_t *key_list,int command_index,DWORD keyflags) +{ + config_key_t *key; + + key = mem_alloc(sizeof(config_key_t)); + + key->key = keyflags; + + if (key_list->start[command_index]) + { + key_list->last[command_index]->next = key; + } + else + { + key_list->start[command_index] = key; + } + + key->next = 0; + key_list->last[command_index] = key; +} +static void _viv_key_clear(_viv_key_list_t *key_list,int command_index) +{ + config_key_t *key; + + key = key_list->start[command_index]; + + while(key) + { + config_key_t *next_key; + + next_key = key->next; + + mem_free(key); + + key = next_key; + } + + key_list->start[command_index] = 0; + key_list->last[command_index] = 0; +} +void _viv_key_list_copy(_viv_key_list_t *dst,const _viv_key_list_t *src) +{ + int i; + + _viv_key_clear_all(dst); + + for(i=0;i<_VIV_COMMAND_COUNT;i++) + { + config_key_t *key; + + key = src->start[i]; + + while(key) + { + _viv_key_add(dst,i,key->key); + + key = key->next; + } + } +} +void _viv_key_clear_all(_viv_key_list_t *list) +{ + // free keys + int i; + + for(i=0;i<_VIV_COMMAND_COUNT;i++) + { + _viv_key_clear(list,i); + } +} +void _viv_key_list_init(_viv_key_list_t *list) +{ + // free keys + int i; + + for(i=0;i<_VIV_COMMAND_COUNT;i++) + { + list->start[i] = 0; + list->last[i] = 0; + } +} +int _viv_get_current_key_mod_flags(void) +{ + int key_flags; + + key_flags = 0; + + if (GetKeyState(VK_CONTROL) < 0) + { + key_flags |= CONFIG_KEYFLAG_CTRL; + } + + if (GetKeyState(VK_SHIFT) < 0) + { + key_flags |= CONFIG_KEYFLAG_SHIFT; + } + + if (GetKeyState(VK_MENU) < 0) + { + key_flags |= CONFIG_KEYFLAG_ALT; + } + + return key_flags; +} +void _viv_key_remove(_viv_key_list_t *keylist,int command_index,DWORD keyflags) +{ + config_key_t *key; + + key = keylist->start[command_index]; + + keylist->start[command_index] = 0; + keylist->last[command_index] = 0; + + while(key) + { + config_key_t *next_key; + + next_key = key->next; + + if (key->key == keyflags) + { + mem_free(key); + } + else + { + if (keylist->start[command_index]) + { + keylist->last[command_index]->next = key; + } + else + { + keylist->start[command_index] = key; + } + + keylist->last[command_index] = key; + key->next = 0; + } + + key = next_key; + } +} +void viv_key_add(int command_index,DWORD keyflags) +{ + _viv_key_add(_viv_key_list,command_index,keyflags); +} +void viv_key_clear_all(int command_index) +{ + _viv_key_clear(_viv_key_list,command_index); +} +config_key_t *viv_key_get_start(int command_index) +{ + return _viv_key_list->start[command_index]; +} +int viv_get_command_count(void) +{ + return _VIV_COMMAND_COUNT; +} + +// ------------------------------------------------------------------ +// owner drawn popup rows. +// +// every visible row in every popup carries a tiny _viv_menu_draw_t: the +// painters re-derive the label at draw time from the command table, the +// localization table and the live key bindings, so a language or shortcut +// change can never show a stale row and no label text is stored anywhere. +// the frame menu tree, the live recent rebuild and the canvas context menu +// each get their own pool so none can trample another's rows. +// ------------------------------------------------------------------ + +// the label for a row. command rows carry the live shortcut after a tab; +// the slideshow pause row reads as play/pause and the rate submenu header +// reads as rate, mirroring the canvas context menu overrides. +static void _viv_menu_row_text(_viv_menu_draw_t *draw,wchar_t *wbuf) +{ + *wbuf = 0; + + switch (draw->type) + { + case _VIV_MENU_DRAW_COMMAND: + case _VIV_MENU_DRAW_POPUP: + { + int key_command_index; + + if ((draw->command_index < 0) || (draw->command_index >= _VIV_COMMAND_COUNT)) + { + break; + } + + switch (_viv_commands[draw->command_index].command_id) + { + case VIV_ID_SLIDESHOW_PAUSE: + string_copy_utf8_string(wbuf,localization_get_string(LOCALIZATION_ID_PLAY_PAUSE)); + break; + + case _VIV_MENU_SLIDESHOW_RATE: + string_copy_utf8_string(wbuf,localization_get_string(LOCALIZATION_ID_RATE)); + break; + + default: + string_copy_utf8_string(wbuf,localization_get_string(_viv_commands[draw->command_index].localization_id)); + break; + } + + if (draw->type == _VIV_MENU_DRAW_COMMAND) + { + key_command_index = draw->command_index; + + switch (_viv_commands[draw->command_index].command_id) + { + case VIV_ID_FILE_DELETE: + key_command_index = _viv_command_index_from_command_id(VIV_ID_FILE_DELETE_RECYCLE); + break; + } + + if (key_command_index >= 0) + { + if (_viv_key_list->start[key_command_index]) + { + wchar_t key_text[STRING_SIZE]; + + _viv_get_key_text(key_text,_viv_key_list->start[key_command_index]->key); + + string_cat_utf8(wbuf,(const utf8_t *)"\t"); + string_cat(wbuf,key_text); + } + } + } + break; + } + + case _VIV_MENU_DRAW_RECENT: + { + wchar_t num_wbuf[64]; + + if ((draw->recent_index < 0) || (draw->recent_index >= config_recent_file_count)) + { + break; + } + + // the mru convention: an ampersand digit prefix selects the entry + // from the keyboard while the submenu is open. + string_format_number(num_wbuf,draw->recent_index + 1); + string_copy(wbuf,L"&"); + string_cat(wbuf,num_wbuf); + string_cat(wbuf,L" "); + string_cat(wbuf,string_get_filename_part(config_recent_files[draw->recent_index])); + break; + } + + case _VIV_MENU_DRAW_LOCALIZED: + string_copy_utf8_string(wbuf,localization_get_string(draw->localization_id)); + + case _VIV_MENU_DRAW_TEXT: + // the ad hoc settings dropdown labels. + if (draw->text) + { + string_copy(wbuf,draw->text); + } + break; + } +} + +// public: resolve a menu row's live label. owner drawn rows carry no +// stored string on the item, so the menubar reads its root labels back +// through this (the item data holds the row, the text re-derives from +// the live localization and key tables at ask time). +void _viv_menu_row_item_text(void *row,wchar_t *wbuf) +{ + *wbuf = 0; + + if (row) + { + _viv_menu_row_text((_viv_menu_draw_t *)row,wbuf); + } +} + +int _viv_menu_measure_item(MEASUREITEMSTRUCT *measure_item) +{ + _viv_menu_draw_t *draw; + HDC hdc; + HFONT font; + HFONT old_font; + wchar_t text_wbuf[STRING_SIZE]; + wchar_t *tab; + SIZE size; + int wide; + int dpi; + + if ((!measure_item) || (measure_item->CtlType != ODT_MENU)) + { + return 0; + } + + draw = (_viv_menu_draw_t *)measure_item->itemData; + + if (!draw) + { + return 0; + } + + dpi = os_logical_high; + + if (draw->type == _VIV_MENU_DRAW_SEPARATOR) + { + // the menu width comes from the other rows. + measure_item->itemWidth = 0; + measure_item->itemHeight = (9 * dpi) / 96; + + return 1; + } + + hdc = GetDC(_viv_hwnd); + + if (!hdc) + { + return 0; + } + + _viv_menu_row_text(draw,text_wbuf); + + tab = wcschr(text_wbuf,L'\t'); + + if (tab) + { + *tab = 0; + } + + size.cx = 0; + size.cy = 0; + + font = _viv_menu_font(); + old_font = 0; + + if (font) + { + old_font = SelectObject(hdc,font); + } + + GetTextExtentPoint32W(hdc,text_wbuf,(int)wcslen(text_wbuf),&size); + + if (tab) + { + SIZE key_size; + + if (GetTextExtentPoint32W(hdc,tab + 1,(int)wcslen(tab + 1),&key_size)) + { + // shortcut column: gap before, text, padding after. + size.cx += key_size.cx + (28 * dpi) / 96; + } + } + else + { + if (draw->type == _VIV_MENU_DRAW_POPUP) + { + size.cx += (18 * dpi) / 96; + } + } + + if (old_font) + { + SelectObject(hdc,old_font); + } + + ReleaseDC(_viv_hwnd,hdc); + + // check gutter plus the right padding. + wide = size.cx + (24 * dpi) / 96 + (14 * dpi) / 96; + + measure_item->itemWidth = wide; + measure_item->itemHeight = size.cy + (9 * dpi) / 96; + + if (measure_item->itemHeight < (22 * dpi) / 96) + { + measure_item->itemHeight = (22 * dpi) / 96; + } + + return 1; +} + +static void _viv_menu_draw_mark(HDC hdc,const RECT *rect,int center_y) +{ + HPEN pen; + HPEN old_pen; + COLORREF accent; + + accent = viv_theme_color(VIV_TK_ACCENT); + + pen = CreatePen(PS_SOLID,_viv_menu_dip(2) < 1 ? 1 : _viv_menu_dip(2),accent); + old_pen = (HPEN)SelectObject(hdc,pen); + + MoveToEx(hdc,rect->left + _viv_menu_dip(5),center_y,0); + LineTo(hdc,rect->left + _viv_menu_dip(9),center_y + _viv_menu_dip(4)); + LineTo(hdc,rect->left + _viv_menu_dip(16),center_y - _viv_menu_dip(5)); + + SelectObject(hdc,old_pen); + DeleteObject(pen); +} + +// the radio mark: a filled accent circle centered in the check gutter. +static void _viv_menu_draw_dot(HDC hdc,const RECT *rect,int center_y) +{ + HBRUSH brush; + HBRUSH old_brush; + int radius; + int x; + + radius = _viv_menu_dip(4); + + if (radius < 2) + { + radius = 2; + } + + // the dot centers in the same gutter the checkmark occupies. + x = rect->left + _viv_menu_dip(10); + + brush = CreateSolidBrush(viv_theme_color(VIV_TK_ACCENT)); + old_brush = (HBRUSH)SelectObject(hdc,brush); + + Ellipse(hdc,x - radius,center_y - radius,x + radius + 1,center_y + radius + 1); + + SelectObject(hdc,old_brush); + DeleteObject(brush); +} + +static void _viv_menu_draw_arrow(HDC hdc,int right,int center_y) +{ + HBRUSH brush; + HBRUSH old_brush; + POINT pts[3]; + int x; + int y; + + x = right - _viv_menu_dip(11); + y = center_y; + + brush = CreateSolidBrush(viv_theme_color(VIV_TK_TEXT2)); + old_brush = (HBRUSH)SelectObject(hdc,brush); + + pts[0].x = x; pts[0].y = y - _viv_menu_dip(4); + pts[1].x = x + _viv_menu_dip(5); pts[1].y = y; + pts[2].x = x; pts[2].y = y + _viv_menu_dip(4); + + Polygon(hdc,pts,3); + + SelectObject(hdc,old_brush); + DeleteObject(brush); +} + +int _viv_menu_draw_item(DRAWITEMSTRUCT *draw_item) +{ + _viv_menu_draw_t *draw; + RECT rect; + HDC hdc; + HFONT font; + HFONT old_font; + wchar_t text_wbuf[STRING_SIZE]; + wchar_t *tab; + int selected; + int disabled; + int center_y; + + if ((!draw_item) || (draw_item->CtlType != ODT_MENU)) + { + return 0; + } + + draw = (_viv_menu_draw_t *)draw_item->itemData; + + if (!draw) + { + return 0; + } + + hdc = draw_item->hDC; + rect = draw_item->rcItem; + selected = (draw_item->itemState & (ODS_SELECTED | ODS_HOTLIGHT)) != 0; + disabled = (draw_item->itemState & (ODS_GRAYED | ODS_INACTIVE)) != 0; + center_y = rect.top + ((rect.bottom - rect.top) / 2); + + if (draw->type == _VIV_MENU_DRAW_SEPARATOR) + { + RECT line_rect; + + // hairline centered in the row, inset past the check gutter. + FillRect(hdc,&rect,viv_theme_brush(VIV_TK_FACE)); + + line_rect.left = rect.left + _viv_menu_dip(24); + line_rect.right = rect.right - _viv_menu_dip(10); + line_rect.top = center_y; + line_rect.bottom = center_y + 1; + + FillRect(hdc,&line_rect,viv_theme_brush(VIV_TK_LINE)); + + return 1; + } + + FillRect(hdc,&rect,selected ? viv_theme_brush(VIV_TK_HOVER) : viv_theme_brush(VIV_TK_FACE)); + + if (draw_item->itemState & ODS_CHECKED) + { + MENUITEMINFOW mii; + int is_radio; + + // radio groups (backdrop, on top, sort, the rate ladder) draw the + // dot instead of the checkmark; the type lives on the live item. + os_zero_memory(&mii,sizeof(mii)); + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_FTYPE; + is_radio = 0; + + if ((draw_item->hwndItem) && (GetMenuItemInfoW((HMENU)draw_item->hwndItem,draw_item->itemID,FALSE,&mii))) + { + is_radio = (mii.fType & MFT_RADIOCHECK) != 0; + } + + if (is_radio) + { + _viv_menu_draw_dot(hdc,&rect,center_y); + } + else + { + _viv_menu_draw_mark(hdc,&rect,center_y); + } + } + + font = _viv_menu_font(); + old_font = 0; + + if (font) + { + old_font = SelectObject(hdc,font); + } + + SetBkMode(hdc,TRANSPARENT); + + _viv_menu_row_text(draw,text_wbuf); + + tab = wcschr(text_wbuf,L'\t'); + + if (tab) + { + *tab = 0; + } + + SetTextColor(hdc,viv_theme_color(disabled ? VIV_TK_TEXTOFF : VIV_TK_TEXT)); + + // the label starts past the check gutter. + rect.left += _viv_menu_dip(24); + + DrawTextW(hdc,text_wbuf,-1,&rect,DT_SINGLELINE | DT_VCENTER | DT_LEFT); + + if (tab) + { + RECT key_rect; + + key_rect = rect; + key_rect.right -= _viv_menu_dip(12); + + SetTextColor(hdc,viv_theme_color(disabled ? VIV_TK_TEXTOFF : VIV_TK_TEXT2)); + + DrawTextW(hdc,tab + 1,-1,&key_rect,DT_SINGLELINE | DT_VCENTER | DT_RIGHT | DT_NOPREFIX); + } + + if (draw->type == _VIV_MENU_DRAW_POPUP) + { + _viv_menu_draw_arrow(hdc,rect.right,center_y); + } + + if (old_font) + { + SelectObject(hdc,old_font); + } + + return 1; +} + +// rc.13: the popup layer theming, extracted from the main window's +// wm_initmenupopup: the #32768 class brush paints the margins between +// the owner drawn rows, and the dwm rounds the layer and colors its +// border where the attributes exist. every popup owner runs this - the +// menu bar, the canvas context menu and the settings dropdowns. +void _viv_menu_popup_theme(void) +{ + HWND menu_hwnd; + DWORD menu_pid; + + menu_hwnd = FindWindowW(L"#32768",0); + + // the class name is shared by every menu in every process on the + // desktop: the find can return another process's open menu, and + // theming that one leaves our own popup plain (and writes into a + // stranger). own process only. + if ((menu_hwnd) && (GetWindowThreadProcessId(menu_hwnd,&menu_pid)) && (menu_pid == GetCurrentProcessId())) + { + SetClassLongPtrW(menu_hwnd,GCLP_HBRBACKGROUND,(LONG_PTR)viv_theme_brush(VIV_TK_FACE)); + + os_menu_modern_chrome(menu_hwnd,viv_theme_color(VIV_TK_LINE)); + } +} + +int _viv_menu_char_item(HMENU hmenu,wchar_t ch,int popup) +{ + int i; + int count; + + if (!hmenu) + { + return -1; + } + + count = GetMenuItemCount(hmenu); + + for(i=0;i= 0) + { + break; + } + } +} + + +static void _viv_menubar_item_rect(int itemi,RECT *rect) +{ + int x; + int i; + + x = 0; + + for(i=0;ileft = x; + rect->top = 0; + rect->right = x + _viv_menubar_item_wide[itemi]; + rect->bottom = _viv_menubar_bar_high; +} + +static int _viv_menubar_hit_test(int x,int y) +{ + int itemi; + + if ((y < 0) || (y >= _viv_menubar_bar_high)) + { + return -1; + } + + for(itemi=0;itemi<_viv_menubar_item_count;itemi++) + { + if (x < _viv_menubar_item_wide[itemi]) + { + return itemi; + } + + x -= _viv_menubar_item_wide[itemi]; + } + + return -1; +} + +static void _viv_menubar_invalidate_item(int itemi) +{ + RECT rect; + + if ((itemi >= 0) && (itemi < _viv_menubar_item_count) && (_viv_menubar_hwnd)) + { + _viv_menubar_item_rect(itemi,&rect); + + InvalidateRect(_viv_menubar_hwnd,&rect,FALSE); + } +} + +// open one root popup. the state refresh the frame menu used to get from +// wm_initmenu runs here (and again from wm_initmenupopup - both idempotent), +// the pressed item keeps its lifted face while the modal loop runs, and the +// command ids reach the same wm_command path the frame menu used. +static void _viv_menubar_open_popup(int itemi) +{ + HMENU popup; + RECT rect; + POINT pt; + + if ((itemi < 0) || (itemi >= _viv_menubar_item_count)) + { + return; + } + + popup = GetSubMenu(_viv_hmenu,itemi); + + if (!popup) + { + return; + } + + _viv_check_menus(_viv_hmenu); + + _viv_menubar_item_rect(itemi,&rect); + + pt.x = rect.left; + pt.y = rect.bottom; + + ClientToScreen(_viv_menubar_hwnd,&pt); + + // the hover follow: a move onto another root item while a popup is + // up cancels the loop and reopens at the new item (the classic bar + // followed the mouse across the roots; the synthetic arrow trick does + // not exist for trackpopupmenu, so the close plus reopen is the + // honest equivalent - same tick, no visible flash at popup scale). + // the in-popup flag covers the whole loop (the context menu site and + // the cursor hider share it): the slideshow timer's recent-file swap + // defers, and the cursor stays visible while a menu is up. + _viv_in_popup_menu = 1; + + do + { + _viv_menubar_deferred = -1; + + _viv_menubar_open = itemi; + _viv_menubar_hover = itemi; + + InvalidateRect(_viv_menubar_hwnd,0,FALSE); + UpdateWindow(_viv_menubar_hwnd); + + TrackPopupMenuEx(popup,TPM_LEFTALIGN | TPM_RIGHTBUTTON,pt.x,pt.y,_viv_hwnd,0); + + if (_viv_menubar_deferred >= 0) + { + itemi = _viv_menubar_deferred; + + _viv_menubar_item_rect(itemi,&rect); + + pt.x = rect.left; + pt.y = rect.bottom; + + ClientToScreen(_viv_menubar_hwnd,&pt); + + popup = GetSubMenu(_viv_hmenu,itemi); + + if (!popup) + { + _viv_menubar_deferred = -1; + + break; + } + + _viv_check_menus(_viv_hmenu); + + continue; + } + + break; + } while(1); + + _viv_in_popup_menu = 0; + + _viv_recent_menu_flush(); + + // the loop is gone: the release that closed the menu can land on a + // sibling item, so the hover is allowed to re-arm on the next move. + _viv_menubar_open = -1; + _viv_menubar_hover = -1; + _viv_menubar_deferred = -1; + + InvalidateRect(_viv_menubar_hwnd,0,FALSE); +} + +// re-read the root items: the labels and the widths at the current font. +// the air is a fixed constant (the classic top level air, dpi scaled), so +// the light and the dark ui lay out identically - the capture that drifted +// 5.5x wide between the themes is gone with the second measurement system. +void _viv_menubar_layout(void) +{ + MENUITEMINFOW mii; + HDC hdc; + HFONT font; + HFONT old_font; + int index; + int count; + int pad; + int high; + int min_high; + + _viv_menubar_item_count = 0; + _viv_menubar_bar_high = 0; + _viv_menubar_hover = -1; + _viv_menubar_open = -1; + + if ((!_viv_hwnd) || (!_viv_hmenu)) + { + return; + } + + hdc = GetDC(_viv_hwnd); + + if (!hdc) + { + return; + } + + count = GetMenuItemCount(_viv_hmenu); + + if (count > _VIV_MENUBAR_ITEM_MAX) + { + count = _VIV_MENUBAR_ITEM_MAX; + } + + pad = (4 * os_logical_wide) / 96; + + high = 0; + + font = _viv_menu_font(); + old_font = 0; + + if (font) + { + old_font = SelectObject(hdc,font); + } + + for(index=0;index