Skip to content

Commit

Permalink
i added jpg conversion lol
Browse files Browse the repository at this point in the history
  • Loading branch information
AmeliaCute committed Jan 2, 2024
1 parent 9d03654 commit d5d71dc
Show file tree
Hide file tree
Showing 10 changed files with 308 additions and 95 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,7 @@ build/
.vscode/
.vs/
.idea/
*.femboy
*.femboy
*.jpg
*.png
*.ico
10 changes: 8 additions & 2 deletions makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
CC=gcc
CFLAGS=-Wall -Wextra -std=c11
LDFLAGS = -ljpeg -lSDL2 -lm

SRC_DIR=source
BUILD_DIR=build
Expand Down Expand Up @@ -34,14 +35,14 @@ $(COMMON_DIR)/%.o: $(SRC_DIR)/common/%.c

# Compile fembng
$(TARGET_FEMBNG): $(OBJS_COMMON) $(OBJS_FEMBNG)
$(CC) $(CFLAGS) -o $@ $^
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)

$(FEMBNG_DIR)/%.o: $(SRC_DIR)/fembng/%.c
$(CC) $(CFLAGS) -c -o $@ $<

# Compile fembngapp
$(TARGET_FEMBNGAPP): $(OBJS_COMMON) $(OBJS_FEMBNGAPP)
$(CC) $(CFLAGS) -o $@ $^ -lSDL2
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)

$(FEMBNGAPP_DIR)/%.o: $(SRC_DIR)/fembngapp/%.c
$(CC) $(CFLAGS) -c -o $@ $<
Expand All @@ -53,4 +54,9 @@ test: all
./$(TARGET_FEMBNG) -w 5000 -h 5000 -o test1
./$(TARGET_FEMBNGAPP) ./test1.femboy

check: all
valgrind ./$(TARGET_FEMBNG) -w 5000 -h 5000 -o test1
valgrind ./$(TARGET_FEMBNG) -c ./test.jpg -o testjpg
./$(TARGET_FEMBNGAPP) ./test1.femboy & ./$(TARGET_FEMBNGAPP) ./testjpg.femboy

.PHONY: all clean
29 changes: 29 additions & 0 deletions source/common/convert.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#include "convert.h"

int convertJPEGToFemboy(const char *inputFile, const char *outputFile )
{
RGB *jpegPixels;
int jpegWidth, jpegHeight;

// Read JPEG file
if (readJPEGFile(inputFile, &jpegWidth, &jpegHeight, &jpegPixels) != 0)
{
fprintf(stderr, "Failed to read JPEG file\n");
return EXIT_FAILURE;
}

char outputFileWithExt[256];
strcpy(outputFileWithExt, outputFile);
strcat(outputFileWithExt, ".femboy");

if (writeBinaryFile(outputFileWithExt, jpegWidth, jpegHeight, jpegPixels) != 0)
{
fprintf(stderr, "Failed to write output file\n");
free(jpegPixels);
return EXIT_FAILURE;
}

free(jpegPixels);

return EXIT_SUCCESS;
}
14 changes: 14 additions & 0 deletions source/common/convert.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#ifndef HEADER_CONVERTER
#define HEADER_CONVERTER

#include "datastruct.h"
#include "rdwr.h"
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <jpeglib.h>
#include <string.h>

int convertJPEGToFemboy(const char *inputFile, const char *outputFile);

#endif //! HEADER_CONVERTER
52 changes: 52 additions & 0 deletions source/common/optimisation.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#include "optimisation.h"

/**
* Applies uniform quantization to the given RGB pixel data.
* Divides each color channel (R, G, B) by the specified number of colors,
* rounds down to the nearest integer, then multiplies back.
* This reduces the number of distinct colors in the image.
*/
void applyQuantization(int width, int height, RGB *pixels, int numColors)
{
int factor = 256 / numColors;

for (int i = 0; i < width * height; ++i)
{
pixels[i].r = (pixels[i].r / factor) * factor;
pixels[i].g = (pixels[i].g / factor) * factor;
pixels[i].b = (pixels[i].b / factor) * factor;
}
}

/**
* Performs chroma subsampling on the given RGB pixel data by averaging 2x2 blocks.
* Reduces the horizontal and vertical resolution by half.
*/
void chromaSubsampling(int width, int height, RGB *pixels)
{
printf("Chroma subsampling...\n");
for (int i = 0; i < height; i += 2)
{
for (int j = 0; j < width; j += 2)
{
RGB avgColor;
avgColor.r = (pixels[i * width + j].r + pixels[i * width + j + 1].r +
pixels[(i + 1) * width + j].r + pixels[(i + 1) * width + j + 1].r) /
4;

avgColor.g = (pixels[i * width + j].g + pixels[i * width + j + 1].g +
pixels[(i + 1) * width + j].g + pixels[(i + 1) * width + j + 1].g) /
4;

avgColor.b = (pixels[i * width + j].b + pixels[i * width + j + 1].b +
pixels[(i + 1) * width + j].b + pixels[(i + 1) * width + j + 1].b) /
4;

pixels[i * width + j] = avgColor;
pixels[i * width + j + 1] = avgColor;
pixels[(i + 1) * width + j] = avgColor;
pixels[(i + 1) * width + j + 1] = avgColor;
}
}
printf("Done\n");
}
10 changes: 10 additions & 0 deletions source/common/optimisation.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#ifndef HEADER_OPTIMISATION
#define HEADER_OPTIMISATION

#include "datastruct.h"
#include <stdio.h>

void applyQuantization(int width, int height, RGB *pixels, int numColors);
void chromaSubsampling(int width, int height, RGB *pixels);

#endif //! HEADER_OPTIMISATION
81 changes: 47 additions & 34 deletions source/common/rdwr.c
Original file line number Diff line number Diff line change
@@ -1,39 +1,5 @@
#include "rdwr.h"

/**
* Performs chroma subsampling on the given RGB pixel data by averaging 2x2 blocks.
* Reduces the horizontal and vertical resolution by half.
*/
void chromaSubsampling(int width, int height, RGB *pixels)
{
printf("Chroma subsampling...\n");
for (int i = 0; i < height; i += 2)
{
for (int j = 0; j < width; j += 2)
{
RGB avgColor;
avgColor.r = (pixels[i * width + j].r + pixels[i * width + j + 1].r +
pixels[(i + 1) * width + j].r + pixels[(i + 1) * width + j + 1].r) /
4;

avgColor.g = (pixels[i * width + j].g + pixels[i * width + j + 1].g +
pixels[(i + 1) * width + j].g + pixels[(i + 1) * width + j + 1].g) /
4;

avgColor.b = (pixels[i * width + j].b + pixels[i * width + j + 1].b +
pixels[(i + 1) * width + j].b + pixels[(i + 1) * width + j + 1].b) /
4;

pixels[i * width + j] = avgColor;
pixels[i * width + j + 1] = avgColor;
pixels[(i + 1) * width + j] = avgColor;
pixels[(i + 1) * width + j + 1] = avgColor;
}
}
printf("Done\n");
}


/**
* Encodes RGB pixel data into run-length encoded format.
*
Expand Down Expand Up @@ -104,6 +70,7 @@ int writeBinaryFile(const char *filename, int width, int height, RGB *pixels)
int encodedSize;

chromaSubsampling(width, height, pixels);
applyQuantization(width, height, pixels, 64);
runLengthEncode(pixels, width * height, &encodedData, &encodedSize);

fwrite(&encodedSize, sizeof(int), 1, file);
Expand Down Expand Up @@ -178,3 +145,49 @@ int readBinaryFile(const char *filename, int *width, int *height, RGB **pixels)
fclose(file);
return 0;
}

int readJPEGFile(const char *filename, int *width, int *height, RGB **pixels)
{
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;

FILE *infile;
JSAMPARRAY buffer;
int row_stride;

if ((infile = fopen(filename, "rb")) == NULL) {
fprintf(stderr, "Can't open %s\n", filename);
exit(EXIT_FAILURE);
}

cinfo.err = jpeg_std_error(&jerr);
jpeg_create_decompress(&cinfo);

jpeg_stdio_src(&cinfo, infile);
(void)jpeg_read_header(&cinfo, TRUE);
(void)jpeg_start_decompress(&cinfo);

*width = cinfo.output_width;
*height = cinfo.output_height;

row_stride = cinfo.output_width * cinfo.output_components;
buffer = (*cinfo.mem->alloc_sarray)
((j_common_ptr)&cinfo, JPOOL_IMAGE, row_stride, 1);

*pixels = (RGB *)malloc((*width) * (*height) * sizeof(RGB));

while (cinfo.output_scanline < cinfo.output_height) {
(void)jpeg_read_scanlines(&cinfo, buffer, 1);
for (int i = 0; i < cinfo.output_width; ++i) {
(*pixels)[(cinfo.output_scanline - 1) * (*width) + i].r = buffer[0][i * cinfo.output_components];
(*pixels)[(cinfo.output_scanline - 1) * (*width) + i].g = buffer[0][i * cinfo.output_components + 1];
(*pixels)[(cinfo.output_scanline - 1) * (*width) + i].b = buffer[0][i * cinfo.output_components + 2];
}
}

(void)jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);

fclose(infile);
return 0;
}
7 changes: 5 additions & 2 deletions source/common/rdwr.h
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
#ifndef READER_WRITER_HEADER
#define READER_WRITER_HEADER

#include "datastruct.h"
#include "convert.h"
#include "optimisation.h"
#include <stdio.h>
#include <stdlib.h>
#include "datastruct.h"
#include <string.h>

void chromaSubsampling(int width, int height, RGB *pixels);
void runLengthEncode(RGB *pixels, int size, RLE **encodedData, int *encodedSize);
int writeBinaryFile(const char *filename, int width, int height, RGB *pixels);
int readBinaryFile(const char *filename, int *width, int *height, RGB **pixels);
int readJPEGFile(const char *filename, int *width, int *height, RGB **pixels);

#endif // !READER_WRITER_HEADER
71 changes: 41 additions & 30 deletions source/fembng/fembng.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "../common/rdwr.h"
#include "../common/datastruct.h"
#include "../common/convert.h"


/**
Expand Down Expand Up @@ -54,26 +55,19 @@ void setAllPixelsToColor(int width, int height, RGB *pixels, RGB color)
}
}

/**
* The main function parses command line arguments, allocates memory for pixels,
* generates a rainbow gradient, writes the pixel data to a file, and cleans up.
*
* It takes the width, height and output file name as command line arguments,
* validates them, allocates memory for the pixels, generates a rainbow gradient
* into the pixels array using the width and height, writes the pixel data to
* a file named {outputFileName}.femboy, frees the memory, and returns EXIT_SUCCESS
* or EXIT_FAILURE based on whether the operations succeeded.
*/

int main(int argc, char *argv[])
{
if (argc != 7)
if (argc < 5)
{
fprintf(stderr, "Usage: %s -w <width> -h <height> -o <output_file>\n", argv[0]);
fprintf(stderr, "Usage: %s -w <width> -h <height> -o <output_file> [-q number_colors] [-c <input_file>]\n", argv[0]);
return EXIT_FAILURE;
}

int width, height;
char *outputFileName;
int width = 8, height = 8;
unsigned char *quantization;
char *outputFileName = "test";
char *inputFileName = NULL;

for (int i = 1; i < argc; i += 2)
{
Expand All @@ -89,34 +83,51 @@ int main(int argc, char *argv[])
{
outputFileName = argv[i + 1];
}
else if (strcmp(argv[i], "-c") == 0)
{
inputFileName = argv[i + 1];
}
else if (strcmp(argv[i], "-q") == 0)
{
quantization = argv[i + 1];
} // TODO: Implement quantization option
else
{
fprintf(stderr, "Unknown option: %s\n", argv[i]);
return EXIT_FAILURE;
}
}

RGB *pixels = (RGB *)malloc(width * height * sizeof(RGB));
if (!pixels)
{
fprintf(stderr, "Memory allocation failed\n");
return EXIT_FAILURE;
}
if (inputFileName) {
if (convertJPEGToFemboy(inputFileName, outputFileName) != 0)
{
fprintf(stderr, "Failed to convert JPEG to femboy\n");
return EXIT_FAILURE;
}
} else {
// Generate rainbow gradient
RGB *pixels = (RGB *)malloc(width * height * sizeof(RGB));
if (!pixels)
{
fprintf(stderr, "Memory allocation failed\n");
return EXIT_FAILURE;
}

generateRainbowGradient(width, height, pixels);
generateRainbowGradient(width, height, pixels);

char outputFileNameWithExt[256];
strcpy(outputFileNameWithExt, outputFileName);
strcat(outputFileNameWithExt, ".femboy");
char outputFileNameWithExt[256];
strcpy(outputFileNameWithExt, outputFileName);
strcat(outputFileNameWithExt, ".femboy");

if (writeBinaryFile(outputFileNameWithExt, width, height, pixels) != 0)
{
fprintf(stderr, "Failed to write output file\n");
free(pixels);
return EXIT_FAILURE;
}

if (writeBinaryFile(outputFileNameWithExt, width, height, pixels) != 0)
{
fprintf(stderr, "Failed to write output file\n");
free(pixels);
return EXIT_FAILURE;
}

free(pixels);

return EXIT_SUCCESS;
}
Loading

0 comments on commit d5d71dc

Please sign in to comment.