A Java client-server application for image processing over TCP. The client sends an image and a selected operation to the server, and the server processes the image and returns the result back to the client. Supported operations are grayscale conversion, Sobel edge detection, and box blur.
This project demonstrates a simple distributed image processing workflow using Java NIO sockets and channels. The client loads an image from the local filesystem, serializes it as PNG bytes, sends it to the server together with an operation code, and waits for the processed image. The server accepts multiple clients using a Selector-based non-blocking event loop, applies the requested image algorithm, and sends the processed PNG back to the client.
- Client-server image processing over TCP
- Non-blocking server built with Java NIO
- Grayscale conversion using luminosity weighting
- Edge detection using the Sobel operator
- Blur using a box blur algorithm
- Local file loading and saving for common image formats such as JPG, JPEG, PNG, and BMP
The client connects to localhost:1234, prompts the user for an image path and an operation, loads the image from disk, converts it to PNG bytes, and sends a 5-byte header followed by the image payload. The header contains a 4-byte image size and a 1-byte operation code. After that, the client listens for the server response, reconstructs the returned image, and saves it locally as processed-<timestamp>.png.
The server opens a non-blocking ServerSocketChannel, registers it with a Selector, and handles three event types: accept, read, and write. For each connected client, it stores per-client state including header buffers, image buffers, outgoing buffers, and the current operation. Once a full request is received, the server processes the image and switches the connection to write mode to return the result. After sending the processed image, the connection goes back to read mode.
The request header is 5 bytes long:
- 4 bytes: image size
- 1 byte: operation code
The response starts with a 4-byte image size header, followed by the processed image bytes. The operation codes are:
0- grayscale1- edges2- blur
The grayscale implementation uses the luminosity method, weighting channels approximately as 0.21 for red, 0.72 for green, and 0.07 for blue before writing the same value to all RGB channels.
Edge detection is implemented with the Sobel operator. The image is first converted to grayscale, then horizontal and vertical gradients are computed using Sobel masks, and the gradient magnitude is mapped to a grayscale output image.
Blurring is implemented as a box blur using separate horizontal and vertical passes. The default blur radius is 20, and there is also an overload that allows a custom radius in code.
src/main/java/app
├── algorithm
│ ├── ImageAlgorithm.java
│ ├── blur
│ │ └── BoxBlurAlgorithm.java
│ ├── detection
│ │ └── SobelEdgeDetection.java
│ └── grayscale
│ └── LuminosityGrayscale.java
├── client
│ └── Client.java
├── filesystem
│ └── LocalFileSystemImageManager.java
└── server
├── ClientState.java
├── HeaderParts.java
├── ImageHandler.java
└── Server.java