Skip to content

[INJICERT-1226] Add image-compressor utility for mosipid plugin#132

Merged
swatigoel merged 4 commits intoinji:developfrom
Infosys:mosipid-image-compressor
Jan 21, 2026
Merged

[INJICERT-1226] Add image-compressor utility for mosipid plugin#132
swatigoel merged 4 commits intoinji:developfrom
Infosys:mosipid-image-compressor

Conversation

@Piyush7034
Copy link
Contributor

@Piyush7034 Piyush7034 commented Jan 21, 2026

Summary by CodeRabbit

  • New Features

    • Automatic image compression for profile photos with intelligent PNG/JPEG selection, iterative size reduction, and data-URI handling.
    • Identity responses now include a compressed image field alongside the original when a picture is present.
  • Chores

    • Updated project dependencies to enable native imaging and compression support.

✏️ Tip: You can customize this high-level summary in your review settings.

Signed-off-by: Piyush7034 <piyushshukla2100@gmail.com>
@coderabbitai
Copy link

coderabbitai bot commented Jan 21, 2026

Walkthrough

Adds image-compression support: new Maven dependencies, an ImageCompression service and utility, OpenCV native loading, and integration into the data provider to post-process JWT "picture" claims into an added compressed image field.

Changes

Cohort / File(s) Summary
Dependency Management
mosip-identity-certify-plugin/pom.xml
Added dependencies: io.mosip.image.compressor:image-compressor:0.1.0 (with exclusions), io.mosip.kernel:kernel-biometrics-api:1.3.0 (provided), org.json:json:20241224, and org.bytedeco:opencv-platform:4.9.0-1.5.10.
Image Compression Service
mosip-identity-certify-plugin/src/main/java/io/mosip/certify/mosipid/integration/service/ImageCompressorServiceImpl.java
New Spring component extending ImageCompressionService; constructor accepts Environment; exposes doResizeAndCompress(byte[]) delegating to superclass resize/compress.
Image Compression Utility
mosip-identity-certify-plugin/src/main/java/io/mosip/certify/mosipid/integration/helper/ImageCompressorUtil.java
New Spring component that parses/validates data URIs, base64-decodes payloads, iteratively compresses via service until size target or max attempts, converts JP2 -> PNG/JPEG, re-encodes as data URI, and maps parse/IO/compression errors to DataProviderExchangeException.
Data Provider Integration
mosip-identity-certify-plugin/src/main/java/io/mosip/certify/mosipid/integration/service/IdaDataProviderPluginImpl.java
Injected ImageCompressorUtil; added OpenCV native loader and Jasper IO enablement; updated fetchData to detect picture claim, compress it, and add a compressedPicture field to returned JSON.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Ida as IdaDataProviderPluginImpl
    participant Util as ImageCompressorUtil
    participant Service as ImageCompressorServiceImpl
    participant OpenCV as OpenCV_Native_Library

    Client->>Ida: fetchData(token)
    Ida->>Ida: parse JWT claims
    alt picture present
        Ida->>Util: extractAndCompressImage(dataURI)
        Util->>Util: validate & parse data URI
        Util->>Util: base64 decode -> image bytes
        loop attempts (up to configured max)
            Util->>Service: doResizeAndCompress(imageBytes)
            Service->>OpenCV: native resize/compress
            OpenCV-->>Service: compressed bytes (JP2)
            Service-->>Util: compressed bytes
            Util->>Util: check size threshold
        end
        Util->>Util: convert JP2 -> PNG/JPEG, base64 encode -> dataURI
        Util-->>Ida: compressed dataURI
        Ida->>Ida: add "picture" and "compressedPicture" to JSON
    end
    Ida-->>Client: return JSON claims
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • ckm007

Poem

🐰 I nibble bytes in moonlit code,
I squeeze each face down soft and neat.
From data URI to slimmer load,
A tiny picture, light and sweet.
Hop—compress, encode, and tweet! 📸✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title accurately and clearly describes the main change: adding an image-compressor utility for the mosipid plugin.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In
`@mosip-identity-certify-plugin/src/main/java/io/mosip/certify/mosipid/integration/helper/ImageCompressorUtil.java`:
- Around line 100-108: The catch-all in ImageCompressorUtil is currently
catching and re-wrapping DataProviderExchangeException thrown earlier (e.g.,
when max attempts exceeded), losing the original code and message; fix this by
adding a specific catch for DataProviderExchangeException (or checking
instanceof in the generic catch) before the catch(Exception e) to rethrow the
original DataProviderExchangeException unchanged (preserve its error code and
message), and keep the existing IllegalArgumentException and general Exception
handlers (which should still log via log.error and wrap other exceptions into
ERROR_COMPRESSING_IMAGE).

In
`@mosip-identity-certify-plugin/src/main/java/io/mosip/certify/mosipid/integration/service/IdaDataProviderPluginImpl.java`:
- Around line 47-61: The static initializer sets the OPENCV IO flag via
System.setProperty("OPENCV_IO_ENABLE_JASPER","1") but logs
System.getenv("OPENCV_IO_ENABLE_JASPER"), causing a mismatch; change the logging
to read the same source you set (System.getProperty) or set the environment
before class load so both match, and avoid using log.info in the static block by
either switching to System.out.println for this static init message or moving
the logging to a `@PostConstruct` (or initialization method) where the logging
framework is guaranteed initialized; update references to
System.setProperty/System.getProperty and replace log.info(...) in the static
block accordingly.
🧹 Nitpick comments (1)
mosip-identity-certify-plugin/src/main/java/io/mosip/certify/mosipid/integration/helper/ImageCompressorUtil.java (1)

61-83: Recompression strategy may not be effective and could degrade quality.

Recompressing an already-compressed JP2 image (line 82: inputBytes = jp2Bytes) is unlikely to achieve significant size reduction since the compression is already applied. Each recompression iteration may degrade image quality without proportional size benefits.

Consider alternative approaches:

  • Adjusting compression quality parameters on the initial pass
  • Resizing/downscaling the image dimensions before compression

Additionally, the targetSize constant (4096 bytes) is hardcoded. Consider making it configurable via application properties for flexibility.

Signed-off-by: Piyush7034 <piyushshukla2100@gmail.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In
`@mosip-identity-certify-plugin/src/main/java/io/mosip/certify/mosipid/integration/helper/ImageCompressorUtil.java`:
- Around line 76-78: The size check currently validates jp2Bytes against
maxAllowedImageSize before converting to the final image format; change the
logic to perform the size validation after format conversion using the final
output byte array (e.g., finalBytes) so the constraint applies to the actual
PNG/JPEG produced. Locate the block that produces jp2Bytes and the subsequent
conversion branches (the code that writes/creates PNG or JPEG from jp2Bytes) and
move or add the check to compare finalBytes.length to maxAllowedImageSize;
ensure both conversion paths (PNG and JPEG) perform this post-conversion check
and handle the oversized case the same way the original check did.
♻️ Duplicate comments (1)
mosip-identity-certify-plugin/src/main/java/io/mosip/certify/mosipid/integration/helper/ImageCompressorUtil.java (1)

105-114: Exception handling swallows DataProviderExchangeException thrown from compression loop.

The DataProviderExchangeException thrown at lines 80-83 (with code FACE_IMAGE_TOO_LARGE) will be caught by the generic catch (Exception e) and re-wrapped with ERROR_COMPRESSING_IMAGE, losing the original error code.

🐛 Proposed fix to preserve DataProviderExchangeException
         } catch (IllegalArgumentException iae) {
             log.error("ERROR_PARSING_IMAGE_DATA", iae);
             throw new DataProviderExchangeException("ERROR_PARSING_IMAGE_DATA", iae.getMessage());
+        } catch (DataProviderExchangeException dpe) {
+            throw dpe;
         } catch (Exception e) {
             log.error("Image compression failed", e);
             throw new DataProviderExchangeException(
                     "ERROR_COMPRESSING_IMAGE",
                     "Failed to compress image data. Check the image format and other properties."
             );
         }

Signed-off-by: Piyush7034 <piyushshukla2100@gmail.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
mosip-identity-certify-plugin/src/main/java/io/mosip/certify/mosipid/integration/service/IdaDataProviderPluginImpl.java (1)

130-148: Preserve DataProviderExchangeException from image compression.

extractAndCompressImage throws DataProviderExchangeException, but the catch-all wraps it into ERROR_FETCHING_KYC_DATA, losing the original error code/message. Add a specific catch to rethrow.

🔧 Proposed fix
-        catch (JSONException | JsonProcessingException e) {
+        catch (JSONException | JsonProcessingException e) {
             log.error("Error occurred during json processing: " + e.getMessage());
             throw new DataProviderExchangeException("JSON_PARSING_FAILED", e.getMessage());
         }
+        catch (DataProviderExchangeException e) {
+            throw e;
+        }
         catch (Exception e) {
             log.error("ERROR_FETCHING_KYC_DATA. " +  e.getMessage());
             throw new DataProviderExchangeException("ERROR_FETCHING_KYC_DATA", e.getMessage());
         }
♻️ Duplicate comments (1)
mosip-identity-certify-plugin/src/main/java/io/mosip/certify/mosipid/integration/helper/ImageCompressorUtil.java (1)

72-103: Validate max size after JP2→PNG/JPEG conversion.

The limit is enforced on JP2 bytes, but the final PNG/JPEG can be larger, so the constraint may be violated. Please move the size check to apply to the final output bytes.

🔧 Proposed fix
-            if (jp2Bytes.length <= maxAllowedImageSize) {
-                break;
-            }
-            if (attempts >= maxRetryAttempts) {
-                throw new DataProviderExchangeException(
-                        "FACE_IMAGE_TOO_LARGE",
-                        "Unable to compress image with available compression. Check size or quality of the input image."
-                );
-            }
-
-            // use the last compressed output as the next input
-            inputBytes = jp2Bytes;
-        }
-
-        // Convert JP2 → desired output format
-        final byte[] outBytes;
-        final String outMime;
-        if (usePng) {
-            outBytes = CommonUtil.convertJP2ToPNGBytes(jp2Bytes);
-            outMime  = "image/png";
-        } else {
-            outBytes = CommonUtil.convertJP2ToJPEGBytes(jp2Bytes);
-            outMime  = "image/jpeg";
-        }
-
-        // Encode and return as Data URI
-        final String b64 = Base64.getEncoder().encodeToString(outBytes);
-        return "data:" + outMime + ";base64," + b64;
+            // Convert JP2 → desired output format
+            final byte[] outBytes;
+            final String outMime;
+            if (usePng) {
+                outBytes = CommonUtil.convertJP2ToPNGBytes(jp2Bytes);
+                outMime  = "image/png";
+            } else {
+                outBytes = CommonUtil.convertJP2ToJPEGBytes(jp2Bytes);
+                outMime  = "image/jpeg";
+            }
+
+            if (outBytes.length <= maxAllowedImageSize) {
+                // Encode and return as Data URI
+                final String b64 = Base64.getEncoder().encodeToString(outBytes);
+                return "data:" + outMime + ";base64," + b64;
+            }
+            if (attempts >= maxRetryAttempts) {
+                throw new DataProviderExchangeException(
+                        "FACE_IMAGE_TOO_LARGE",
+                        "Unable to compress image with available compression. Check size or quality of the input image."
+                );
+            }
+
+            // use the last compressed output as the next input
+            inputBytes = jp2Bytes;
+        }

Signed-off-by: Piyush7034 <piyushshukla2100@gmail.com>
@swatigoel swatigoel merged commit bc25e9f into inji:develop Jan 21, 2026
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants