Skip to content

Commit

Permalink
Work in progress
Browse files Browse the repository at this point in the history
  • Loading branch information
rzeldent committed Feb 18, 2024
1 parent 6119020 commit 2eb7a58
Show file tree
Hide file tree
Showing 14 changed files with 585 additions and 158 deletions.
18 changes: 18 additions & 0 deletions lib/micro-jpg/include/jpg.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#include <stddef.h>

#include "jpg_section.h"

class jpg
{
public:
bool decode(const uint8_t *jpg, size_t size);

const struct jpg_section *quantization_table_0_;
const struct jpg_section *quantization_table_1_;

const uint8_t *jpeg_data_start;
const uint8_t *jpeg_data_end;

private:
static const jpg_section *find_jpg_section(const uint8_t **ptr, const uint8_t *end, jpg_section::jpg_section_flag flag);
};
103 changes: 103 additions & 0 deletions lib/micro-jpg/include/jpg_section.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
#pragma once

#include <stdint.h>

struct __attribute__((packed)) jpg_section
{
enum jpg_section_flag : uint8_t
{
DATA = 0x00,
SOF0 = 0xc0,
SOF1 = 0xc1,
SOF2 = 0xc2,
SOF3 = 0xc3,
DHT = 0xc4,
SOF5 = 0xc5,
SOF6 = 0xc6,
SOF7 = 0xc7,
JPG = 0xc8,
SOF9 = 0xc9,
SOF10 = 0xca,
SOF11 = 0xcb,
DAC = 0xcc,
SOF13 = 0xcd,
SOF14 = 0xce,
SOF15 = 0xcf,
RST0 = 0xd0,
RST1 = 0xd1,
RST2 = 0xd2,
RST3 = 0xd3,
RST4 = 0xd4,
RST5 = 0xd5,
RST6 = 0xd6,
RST7 = 0xd7,
SOI = 0xd8,
EOI = 0xd9,
SOS = 0xda,
DQT = 0xdb,
DNL = 0xdc,
DRI = 0xdd,
DHP = 0xde,
EXP = 0xdf,
APP0 = 0xe0,
APP1 = 0xe1,
APP2 = 0xe2,
APP3 = 0xe3,
APP4 = 0xe4,
APP5 = 0xe5,
APP6 = 0xe6,
APP7 = 0xe7,
APP8 = 0xe8,
APP9 = 0xe9,
APP10 = 0xea,
APP11 = 0xeb,
APP12 = 0xec,
APP13 = 0xed,
APP14 = 0xee,
APP15 = 0xef,
JPG0 = 0xf0,
JPG1 = 0xf1,
JPG2 = 0xf2,
JPG3 = 0xf3,
JPG4 = 0xf4,
JPG5 = 0xf5,
JPG6 = 0xf6,
JPG7 = 0xf7,
JPG8 = 0xf8,
JPG9 = 0xf9,
COM = 0xfe,
JPG10 = 0xfa,
JPG11 = 0xfb,
JPG12 = 0xfc,
JPG13 = 0xfd
};

const uint8_t framing; // 0xff
const jpg_section_flag flag;
const uint8_t length_msb;
const uint8_t length_lsb;
const uint8_t data[];

static bool is_valid_flag(const jpg_section_flag flag);
static const char *flag_name(const jpg_section_flag flag);
uint16_t data_length() const;
uint16_t section_length() const;
};

struct __attribute__((packed)) jpg_section_app0 // 0xffe0
{
char identifier[5] = {'J', 'F', 'I', 'F', 0}; // JFIF identifier, zero-terminated
uint8_t version_major = 1;
uint8_t version_minor = 1; // JFIF version 1.1
uint8_t density_units = 0; // no density units specified
uint16_t density_hor = 1;
uint16_t density_ver = 1; // density: 1 pixel "per pixel" horizontally and vertically
uint8_t thumbnail_hor = 0;
uint8_t thumbnail_ver = 0; // no thumbnail (size 0 x 0)
};

struct __attribute__((packed)) jpg_section_dqt // 0xffdb
{
uint8_t id; // 0= quantLuminance, 1= quantChrominance
uint8_t data[64];
};
14 changes: 14 additions & 0 deletions lib/micro-jpg/library.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "micro-jpg",
"version": "1.0.0",
"description": "JPEG library",
"keywords": "",
"repository": {
"type": "git",
"url": "https://github.com/rzeldent/"
},
"build": {
"srcDir": "src/",
"includeDir": "include/"
}
}
90 changes: 90 additions & 0 deletions lib/micro-jpg/src/jpg.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#include <esp32-hal-log.h>
#include "jpg.h"

const jpg_section *jpg::find_jpg_section(const uint8_t **ptr, const uint8_t *end, jpg_section::jpg_section_flag flag)
{
log_d("find_jpeg_section 0x%02x (%s)", flag, jpg_section::flag_name(flag));
while (*ptr < end)
{
// flag, len MSB, len LSB
auto section = reinterpret_cast<const jpg_section *>((*ptr));
if (section->framing != 0xff)
{
log_e("Expected framing 0xff but found: 0x%02x", section->framing);
break;
}

if (!jpg_section::is_valid_flag(section->flag))
{
log_d("Unknown section 0x%02x", flag);
return nullptr;
}

// Advance pointer section has a length, so not SOI (0xd8) and EOI (0xd9)
*ptr += section->section_length();
if (section->flag == flag)
{
log_d("Found section 0x%02x (%s), %d bytes", flag, jpg_section::flag_name(section->flag), section->section_length());
return section;
}

log_d("Skipping section: 0x%02x (%s), %d bytes", section->flag, jpg_section::flag_name(section->flag), section->section_length());
}

// Not found
return nullptr;
}

// See https://create.stephan-brumme.com/toojpeg/
bool jpg::decode(const uint8_t *data, size_t size)
{
log_d("decode_jpeg");
// Look for start jpeg file (0xd8)
auto ptr = data;
auto end = ptr + size;

// Check for SOI (start of image) 0xff, 0xd8
if (!find_jpg_section(&ptr, end, jpg_section::jpg_section_flag::SOI))
{
log_e("No valid start of image marker found");
return false;
}

// First quantization table (Luminance - black & white images)
if (!(quantization_table_0_ = find_jpg_section(&ptr, end, jpg_section::jpg_section_flag::DQT)))
{
log_e("No quantization table 0 section found");
return false;
}

// Second quantization table (Chrominance - color images)
if (!(quantization_table_1_ = find_jpg_section(&ptr, end, jpg_section::jpg_section_flag::DQT)))
log_w("No quantization table 1 section found");

// Start of scan
if (!find_jpg_section(&ptr, end, jpg_section::jpg_section_flag::SOS))
{
log_e("No start of scan section found");
return false;
}

// Start of the data sections
jpeg_data_start = ptr;

log_d("Skipping over data sections");
// Scan over all the sections. 0xff followed by not zero, is a new section
while (ptr < end - 1 && (ptr[0] != 0xff || ptr[1] == 0))
ptr++;

// Check if marker is an end of image marker
if (!find_jpg_section(&ptr, end, jpg_section::jpg_section_flag::EOI))
{
log_e("No end of image marker found");
return false;
}

jpeg_data_size = ptr;
log_d("Total jpeg data = %d bytes", jpeg_data_end - jpeg_data_start);

return true;
}
154 changes: 154 additions & 0 deletions lib/micro-jpg/src/jpg_section.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
#include "jpg_section.h"

uint16_t jpg_section::data_length() const
{
return (length_msb << 8) + length_lsb - sizeof(jpg_section::length_msb)- sizeof(jpg_section::length_lsb);
}

uint16_t jpg_section::section_length() const
{
return flag == SOI || flag == EOI ? sizeof(jpg_section::framing) + sizeof(jpg_section::flag) : sizeof(jpg_section::framing) + sizeof(jpg_section::flag) + (length_msb << 8) + length_lsb;
}

bool jpg_section::is_valid_flag(const jpg_section_flag flag)
{
return flag >= SOF0 && flag <= COM;
}

// from: https://www.disktuna.com/list-of-jpeg-markers/
const char *jpg_section::flag_name(const jpg_section_flag flag)
{
switch (flag)
{
case DATA:
return "DATA"; // DATA
case SOF0:
return "SOF0"; // Start of Frame 0 Baseline DCT
case SOF1:
return "SOF1"; // Start of Frame 1 Extended Sequential DCT
case SOF2:
return "SOF2"; // Start of Frame 2 Progressive DCT
case SOF3:
return "SOF3"; // Start of Frame 3 Lossless (sequential)
case DHT:
return "DHT"; // Define Huffman Table
case SOF5:
return "SOF5"; // Start of Frame 5 Differential sequential DCT
case SOF6:
return "SOF6"; // Start of Frame 6 Differential progressive DCT
case SOF7:
return "SOF7"; // Start of Frame 7 Differential lossless (sequential)
case JPG:
return "JPG"; // JPEG Extensions
case SOF9:
return "SOF9"; // Start of Frame 9 Extended sequential DCT, Arithmetic coding
case SOF10:
return "SOF10"; // Start of Frame 10 Progressive DCT, Arithmetic coding
case SOF11:
return "SOF11"; // Start of Frame 11 Lossless (sequential), Arithmetic coding
case DAC:
return "DAC"; // Define Arithmetic Coding
case SOF13:
return "SOF13"; // Start of Frame 13 Differential sequential DCT, Arithmetic coding
case SOF14:
return "SOF14"; // Start of Frame 14 Differential progressive DCT, Arithmetic coding
case SOF15:
return "SOF15"; // Start of Frame 15 Differential lossless (sequential), Arithmetic coding
case RST0:
return "RST0"; // Restart Marker 0
case RST1:
return "RST1"; // Restart Marker 1
case RST2:
return "RST2"; // Restart Marker 2
case RST3:
return "RST3"; // Restart Marker 3
case RST4:
return "RST4"; // Restart Marker 4
case RST5:
return "RST5"; // Restart Marker 5
case RST6:
return "RST6"; // Restart Marker 6
case RST7:
return "RST7"; // Restart Marker 7
case SOI:
return "SOI"; // Start of Image
case EOI:
return "EOI"; // End of Image
case SOS:
return "SOS"; // Start of Scan
case DQT:
return "DQT"; // Define Quantization Table
case DNL:
return "DNL"; // Define Number of Lines (Not common)
case DRI:
return "DRI"; // Define Restart Interval
case DHP:
return "DHP"; // Define Hierarchical Progression (Not common)
case EXP:
return "EXP"; // Expand Reference Component (Not common)
case APP0:
return "APP0"; // Application Segment 0 JFIF – JFIF JPEG image, AVI1 – Motion JPEG (MJPG)
case APP1:
return "APP1"; // Application Segment 1 EXIF Metadata, TIFF IFD format, JPEG Thumbnail (160×120) Adobe XMP
case APP2:
return "APP2"; // Application Segment 2 ICC color profile, FlashPix
case APP3:
return "APP3"; // Application Segment 3 (Not common) JPS Tag for Stereoscopic JPEG images
case APP4:
return "APP4"; // Application Segment 4 (Not common)
case APP5:
return "APP5"; // Application Segment 5 (Not common)
case APP6:
return "APP6"; // Application Segment 6 (Not common) NITF Lossles profile
case APP7:
return "APP7"; // Application Segment 7 (Not common)
case APP8:
return "APP8"; // Application Segment 8 (Not common)
case APP9:
return "APP9"; // Application Segment 9 (Not common)
case APP10:
return "APP10"; // Application Segment 10 PhoTags (Not common) ActiveObject (multimedia messages / captions)
case APP11:
return "APP11"; // Application Segment 11 (Not common) HELIOS JPEG Resources (OPI Postscript)
case APP12:
return "APP12"; // Application Segment 12 Picture Info (older digicams), Photoshop Save for Web: Ducky
case APP13:
return "APP13"; // Application Segment 13 Photoshop Save As: IRB, 8BIM, IPTC
case APP14:
return "APP14"; // Application Segment 14 (Not common)
case APP15:
return "APP15"; // Application Segment 15 (Not common)
case JPG0:
return "JPG0"; // JPEG Extension 0
case JPG1:
return "JPG1"; // JPEG Extension 1
case JPG2:
return "JPG2"; // JPEG Extension 2
case JPG3:
return "JPG3"; // JPEG Extension 3
case JPG4:
return "JPG4"; // JPEG Extension 4
case JPG5:
return "JPG5"; // JPEG Extension 5
case JPG6:
return "JPG6"; // JPEG Extension 6
case JPG7:
return "JPG7"; // SOF48 JPEG Extension 7 JPEG-LS Lossless JPEG
case JPG8:
return "JPG8"; // LSE JPEG Extension 8 JPEG-LS Extension Lossless JPEG Extension Parameters
case JPG9:
return "JPG9"; // JPEG Extension 9 (Not common)
case JPG10:
return "JPG10"; // JPEG Extension 10 (Not common)
case JPG11:
return "JPG11"; // JPEG Extension 11 (Not common)
case JPG12:
return "JPG12"; // JPEG Extension 12 (Not common)
case JPG13:
return "JPG13"; // JPEG Extension 13 (Not common)
case COM:
return "COM"; // Comment
}

return "Unknown";
}
Loading

0 comments on commit 2eb7a58

Please sign in to comment.