Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions .github/workflows/push-trigger.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@ on:
- 'master'
- '1.*'
- 'release*'
- 'issue*'

jobs:
build-maven-imagedecoder:
uses: mosip/kattu/.github/workflows/maven-build.yml@master-java21
with:
SERVICE_LOCATION: imagedecoder
SERVICE_LOCATION: ./
BUILD_ARTIFACT: imagedecoder
secrets:
OSSRH_USER: ${{ secrets.OSSRH_USER }}
Expand All @@ -39,7 +40,7 @@ jobs:
needs: build-maven-imagedecoder
uses: mosip/kattu/.github/workflows/maven-publish-to-nexus.yml@master-java21
with:
SERVICE_LOCATION: imagedecoder
SERVICE_LOCATION: ./
secrets:
OSSRH_USER: ${{ secrets.OSSRH_USER }}
OSSRH_SECRET: ${{ secrets.OSSRH_SECRET }}
Expand All @@ -53,7 +54,7 @@ jobs:
if: "${{ github.event_name != 'pull_request' }}"
uses: mosip/kattu/.github/workflows/maven-sonar-analysis.yml@master-java21
with:
SERVICE_LOCATION: imagedecoder
SERVICE_LOCATION: ./
PROJECT_KEY: 'mosip_imagedecoder'
secrets:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
Expand Down
16 changes: 14 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
.idea/
.vscode/
.local/
*.iml
*/target/
/.metadata/
.sonarlint/
*/.classpath
*/.gitignore
*/.project
*/.settings/
*/.settings/
.settings/
.classpath
.project
*.log
*.class
.DS_Store
Thumbs.db
.local-build.log
125 changes: 33 additions & 92 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,95 +1,36 @@
# AGENTS.md
# imagedecoder

This file provides guidance to AI agents when working with code in this repository.
## Build Commands

All commands run from the `imagedecoder/` directory:

```bash
# Build and run tests
mvn clean install

# Skip tests
mvn clean install -DskipTests

# Run tests only
mvn test

# Run a single test class
mvn test -Dtest=OpenJpegDecoderTest
mvn test -Dtest=WsqDecoderTest

# Sonar analysis (requires secrets)
mvn verify sonar:sonar -Psonar
```

Build requires Java 21 with `--enable-preview` enabled (configured in both pom.xml files). Tests use the `maven-surefire-plugin` with several `--add-opens` JVM flags.

## Architecture

This is a pure-Java biometric image decoding library for the MOSIP identity platform. It ports two native C codec libraries to Java:

- **JPEG2000** — ported from [OpenJPEG](https://github.com/lessandro/nbis) (`openjp2`)
- **WSQ** — ported from [NBIS WSQ](https://github.com/lessandro/nbis)

### Module Layout

- **`imagedecoder/`** — the published library (`io.mosip.imagedecoder:imagedecoder`)
- **`sample/`** — standalone CLI demo app that reads image files from disk and decodes them

### Core API

The single entry point is `IImageDecoderApi`:

```java
Response<DecoderResponseInfo> decode(DecoderRequestInfo requestInfo);
stack JDK21 · Maven3.9+ · Boot 4.1.1 · MPL-2.0 · parent imagedecoder-parent
prereq ../commons/kernel → kernel-core, version = kernel.core.version in pom.xml (Logfactory lives here)
reactor
├─ imagedecoder/ published lib: JPEG2000 + WSQ
└─ sample/ CLI demo, NOT in reactor
pkg io/mosip/imagedecoder/
├─ spi/ IImageDecoderApi
├─ openjpeg/ OpenJpegDecoder + *Helper (OpenJPEG 1.x C port)
├─ wsq/ WsqDecoder + *Helper (NBIS port)
├─ model/ req/resp + openjpeg/ wsq/ C-struct mirrors
├─ util/ Base64UrlUtil, ByteStreamUtil, wsq/WsqUtil
└─ constant/ exceptions/ logger/
api Response<DecoderResponseInfo> decode(DecoderRequestInfo) → .jp2 OpenJpeg | .wsq Wsq
rules
├─ ban kernel-bom · kernel-logger-logback · Jackson3 (use spring-boot-jackson2)
├─ lib no Boot repackage
├─ cover jacoco ≥0.85 instr · Sonar = (line+branch) ≥85% · excl config/dto/entity ONLY
├─ tests write tests, never add exclusions
└─ license approved: MIT/BSD/Apache/MPL/ISC/CDDL/Zlib/0BSD · no EPL/GPL/AGPL/LGPL/CC at runtime
gotchas
├─ Cio/Bio/MQC: array+index "pointers"; byteOut PRE-increments → next byte at bpIndex+1
├─ Cio: start=bpIndex=-1, end=start+length
├─ Lombok @Data on cyclic models → @ToString.Exclude/@EqualsAndHashCode.Exclude
├─ new X[n] of models → init every element (NPE otherwise)
├─ JP2 box readers must bound length (else hang on corrupt input)
└─ corrupt-input tests log millions of lines → read only `Get-Content log -Tail`
cmds (PowerShell: quote -D args)
├─ root mvn verify "-Dgpg.skip=true" # full build + jacoco gate
├─ module mvn -q test "-Dtest=Class#method" "-Dgpg.skip=true"
├─ sonar mvn verify sonar:sonar -Psonar
├─ cov parse imagedecoder/target/site/jacoco/jacoco.xml (LINE+BRANCH counters)
└─ local imagedecoder/run-local.(bat|sh) init|test|all
```

- `DecoderRequestInfo` — takes raw image bytes (`imageData`) and a `isBufferedImage` flag
- `DecoderResponseInfo` — returns image metadata (width, height, DPI, color space, bit rate, compression ratio, lossless flag) plus the decoded pixel data as base64url-encoded bytes and optionally a `BufferedImage`
- `Response<T>` — wraps any response with `statusCode`, `statusMessage`, and `response`

Two implementations:
- `OpenJpegDecoder` — handles JPEG2000 (`.jp2`)
- `WsqDecoder` — handles WSQ (`.wsq`)

### Package Structure (`imagedecoder/src/main/java/io/mosip/imagedecoder/`)

| Package | Purpose |
|---|---|
| `spi/` | Public API interface (`IImageDecoderApi`) |
| `model/` | Request/response models; also C-struct mirrors under `model/openjpeg/` and `model/wsq/` |
| `openjpeg/` | JPEG2000 codec implementation — `OpenJpegDecoder` + many `*Helper` classes |
| `wsq/` | WSQ codec implementation — `WsqDecoder` + many `*Helper` classes |
| `constant/` | Error codes and named constants for both codecs |
| `exceptions/` | `DecoderException` |
| `util/` | `Base64UrlUtil`, `ByteStreamUtil`, `ByteSwapperUtil`, and codec-specific math/image utils |
| `logger/` | Thin wrapper around `kernel-logger-logback` |

### Key Design Details

The codec implementations (`openjpeg/` and `wsq/`) are direct Java ports of C code. The `model/openjpeg/` and `model/wsq/` packages contain Java classes that mirror C structs from the original libraries. `ByteBufferContext` is used to simulate C-style sequential byte reads.

The `*Helper` classes (e.g., `J2KHelper`, `WsqDecoderHelper`) are large stateless utility classes containing the ported algorithm logic. They are called by the `Decoder` classes.

Logging follows the MOSIP convention: `logger.info(LOGGER_SESSIONID, LOGGER_IDTYPE, LOGGER_EMPTY, message)`.

### Sample Application

The `sample/` module runs from its `target/` directory after `mvn package`:

```bash
# Decode JPEG2000 files from a folder
java -cp sample-imagedecoder-*.jar;lib\* io.mosip.imagedecoder.sample.SampleImageDecoderApplication \
"io.mosip.imagedecoder.image.type=0" "io.mosip.imagedecoder.image.folder.path=/BiometricInfo"

# Decode WSQ files from a folder
java -cp sample-imagedecoder-*.jar;lib\* io.mosip.imagedecoder.sample.SampleImageDecoderApplication \
"io.mosip.imagedecoder.image.type=1" "io.mosip.imagedecoder.image.folder.path=/BiometricInfo"
```

Image type: `0` = JP2000, `1` = WSQ.

### CI/CD

GitHub Actions (`.github/workflows/push-trigger.yml`) triggers on pushes to `master`, `develop*`, `1.*`, `release*`. It reuses shared MOSIP workflows from `mosip/kattu@master-java21` for build, Nexus publish, and Sonar analysis. Publishing to Maven Central uses the `central-publishing-maven-plugin` with `autoPublish=false`.
Loading
Loading