-
Notifications
You must be signed in to change notification settings - Fork 127
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
14 changed files
with
585 additions
and
158 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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]; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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/" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"; | ||
} |
Oops, something went wrong.