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
17 changes: 11 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
# Compiler and compiler flags
CC = gcc
CFLAGS = -g -std=c11 -Wall -Wextra -Werror -Wshadow
LDFLAGS = -lm
CFLAGS = -g -std=c11 -Wall -Wextra -Wshadow
LDFLAGS = -lm -lpng -ljpeg

# Include paths (adjust for your system)
INCLUDES = -I/ucrt64/include
# For Linux/macOS with standard paths, comment out INCLUDES or set to empty:
# INCLUDES =

# Source files and executable name
SRCS = filter.c helpers.c
TARGET = filter
SRCS = filter.c helpers.c image_io.c bmp_io.c png_io.c jpeg_io.c
TARGET = filter.exe

# Default target
all: $(TARGET)

# Rule to link the object files into the final executable
$(TARGET): $(SRCS)
$(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS)
$(CC) $(CFLAGS) $(INCLUDES) $^ -o $@ $(LDFLAGS)

# Rule to clean up generated files
clean:
rm -f $(TARGET)
rm -f $(TARGET) *.o
78 changes: 75 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -261,9 +261,81 @@ To apply a filter via command-line:
- `B <value>`: brightness
- `o`: oilpaint


Example for glow:
filter -G input.bmp output.bmp
#### Examples:

```bash
# Grayscale a PNG image
./filter.exe -g input.png output.png
# Sepia on JPEG image
./filter.exe -s input.jpg output.jpg
# Blur a BMP image
./filter.exe -b input.bmp output.bmp
# Chain multiple filters
./filter.exe -g -b input.png output.png
# Convert format (PNG to JPEG)
./filter.exe -g input.png output.jpg
# Brightness adjustment
./filter.exe -B 40 input.jpg output.jpg
```

You can also chain multiple filters by supplying multiple tags (e.g., `./filter.exe -v -g input.bmp output.bmp` for vignette then grayscale).

## Supported Image Formats

The Image-Filtering tool supports multiple image formats:

- **BMP**: 24-bit uncompressed BMP files
- **PNG**: PNG images with RGB color space (supports various PNG formats including RGBA, grayscale, palette - automatically converted to RGB)
- **JPEG**: JPEG images with RGB color space (supports grayscale and RGB JPEGs)

### Format Auto-Detection

The tool automatically detects the input image format based on file signatures (magic bytes). The output format is determined by the file extension of the output filename. You can convert between formats by simply changing the output file extension.

### Examples with Different Formats

```bash
# Process PNG image
./filter.exe -g photo.png photo_gray.png
# Process JPEG image
./filter.exe -s photo.jpg photo_sepia.jpg
# Convert PNG to JPEG
./filter.exe -g input.png output.jpg
# Convert JPEG to BMP
./filter.exe -b input.jpg output.bmp
# Chain filters on PNG
./filter.exe -g -b input.png output.png
```

## Building and Installation

#### Windows (MSYS2)
```bash
# Install dependencies in MSYS2 UCRT64 terminal
pacman -Syu
pacman -S mingw-w64-ucrt-x86_64-gcc
pacman -S mingw-w64-ucrt-x86_64-libpng
pacman -S mingw-w64-ucrt-x86_64-libjpeg-turbo
pacman -S make
```

#### Linux (Ubuntu/Debian)
```bash
sudo apt-get update
sudo apt-get install libpng-dev libjpeg-dev build-essential
```

#### macOS
```bash
brew install libpng libjpeg
```

### Building

```bash
make clean
make
```

You can also chain multiple filters by supplying multiple tags (e.g., `./filter vg input.bmp output.bmp` for vignette then grayscale).

Expand Down
6 changes: 3 additions & 3 deletions bmp.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
#endif

// --- Bitmap File Header (14 bytes) ---
typedef struct
typedef struct bmp_file_header_struct
{
uint16_t bfType; // File type ("BM")
uint32_t bfSize; // Size of the file in bytes
Expand All @@ -24,7 +24,7 @@ typedef struct
} BITMAPFILEHEADER;

// --- Bitmap Info Header (40 bytes for BITMAPINFOHEADER) ---
typedef struct
typedef struct bmp_info_header_struct
{
uint32_t biSize; // Header size (40 bytes)
int32_t biWidth; // Image width in pixels
Expand All @@ -40,7 +40,7 @@ typedef struct
} BITMAPINFOHEADER;

// --- RGB Triple (3 bytes per pixel) ---
typedef struct
typedef struct bmp_rgb_triple_struct
{
uint8_t rgbtBlue;
uint8_t rgbtGreen;
Expand Down
107 changes: 107 additions & 0 deletions bmp_io.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
#include "image_io.h"
#include "bmp.h"
#include <stdlib.h>
#include <string.h>

// Read BMP file
int read_bmp(const char *filename, ImageData *img) {
FILE *inptr = fopen(filename, "rb");
if (inptr == NULL) {
return 1;
}
BITMAPFILEHEADER bf;
if (fread(&bf, sizeof(BITMAPFILEHEADER), 1, inptr) != 1) {
fclose(inptr);
return 1;
}
BITMAPINFOHEADER bi;
if (fread(&bi, sizeof(BITMAPINFOHEADER), 1, inptr) != 1) {
fclose(inptr);
return 1;
}
if (bf.bfType != 0x4d42 || bf.bfOffBits != 54 || bi.biSize != 40 || bi.biBitCount != 24 || bi.biCompression != 0) {
fclose(inptr);
return 1;
}
img->height = abs(bi.biHeight);
img->width = bi.biWidth;
img->format = IMAGE_FORMAT_BMP;

img->pixels = (RGBTRIPLE **)malloc(img->height * sizeof(RGBTRIPLE *));
if (img->pixels == NULL) {
fclose(inptr);
return 1;
}
RGBTRIPLE *pixel_data = (RGBTRIPLE *)calloc(img->height * img->width, sizeof(RGBTRIPLE));
if (pixel_data == NULL) {
free(img->pixels);
fclose(inptr);
return 1;
}
for (int i = 0; i < img->height; i++) {
img->pixels[i] = pixel_data + i * img->width;
}
int padding = (4 - (img->width * sizeof(RGBTRIPLE)) % 4) % 4;

// Read pixels
for (int i = 0; i < img->height; i++) {
if (fread(img->pixels[i], sizeof(RGBTRIPLE), img->width, inptr) != (size_t)img->width) {
free_image(img);
fclose(inptr);
return 1;
}
fseek(inptr, padding, SEEK_CUR);
}

fclose(inptr);
return 0;
}

// Write BMP file
int write_bmp(const char *filename, ImageData *img) {
FILE *outptr = fopen(filename, "wb");
if (outptr == NULL) {
return 1;
}
int padding = (4 - (img->width * sizeof(RGBTRIPLE)) % 4) % 4;
int row_size = img->width * sizeof(RGBTRIPLE) + padding;
int image_size = row_size * img->height;

BITMAPFILEHEADER bf;
bf.bfType = 0x4d42;
bf.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + image_size;
bf.bfReserved1 = 0;
bf.bfReserved2 = 0;
bf.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);

BITMAPINFOHEADER bi;
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = img->width;
bi.biHeight = img->height;
bi.biPlanes = 1;
bi.biBitCount = 24;
bi.biCompression = 0;
bi.biSizeImage = image_size;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;

if (fwrite(&bf, sizeof(BITMAPFILEHEADER), 1, outptr) != 1 || fwrite(&bi, sizeof(BITMAPINFOHEADER), 1, outptr) != 1) {
fclose(outptr);
return 1;
}

for (int i = 0; i < img->height; i++) {
if (fwrite(img->pixels[i], sizeof(RGBTRIPLE), img->width, outptr) != (size_t)img->width) {
fclose(outptr);
return 1;
}
for (int k = 0; k < padding; k++) {
fputc(0x00, outptr);
}
}
fclose(outptr);
return 0;
}

Binary file added ex2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading