Pulled from: https://github.com/Bodmer/TJpg_Decoder/commit/71bfc2607b6963ee3334ff6f601345c5d2b7a8da
Current Status
- ✅ Library Staged: Third-party code copied to FastLED
- ✅ Namespace Wrapping: Successfully wrapped in
fl::third_party
- ✅ C++ Conversion:
tjpgd.c converted to tjpgd.cpp
- ✅ FastLED Integration: Complete bridge implementation in
fl/codec/jpeg.cpp
- ✅ Decoder Implementation:
TJpgDecoder class implements IDecoder interface
- ✅ Static API:
Jpeg class provides convenient static decode methods
- ✅ Memory Management: Uses FastLED's buffer management and scoped arrays
- ✅ Pixel Format Support: RGB888, RGB565, RGBA8888 conversion implemented
- ✅ Configuration Mapping:
JpegDecoderConfig fully integrated
FastLED Third-Party Namespace Architecture
FastLED mandates that all third-party libraries be wrapped in the fl::third_party namespace to:
1. Prevent Global Namespace Pollution
class TJpg_Decoder { };
namespace third_party {
class TJpg_Decoder { };
}
}
Base definition for an LED controller.
2. Clear Ownership and Licensing Boundaries
The fl::third_party namespace makes it immediately clear:
- What code is external: Everything in
fl::third_party comes from external sources
- Licensing considerations: Third-party code may have different licenses
- Maintenance responsibility: External libraries have their own update cycles
- API stability: Third-party APIs may change independently of FastLED
3. Controlled Integration Points
class TJpg_Decoder { };
}
class Jpeg {
static bool decode(
const JpegDecoderConfig& config, );
private:
};
}
static bool decode(const JpegConfig &config, fl::span< const fl::u8 > data, Frame *frame, fl::string *error_message=nullptr)
4. Implementation Benefits
Namespace Isolation
- No symbol conflicts with user code or other libraries
- Clear separation between FastLED native code and external dependencies
- Enables multiple versions of similar libraries if needed
API Transformation
- Third-party libraries keep their original APIs intact
- FastLED provides idiomatic C++ wrappers that follow project conventions
- Users interact with clean FastLED APIs, not raw third-party interfaces
Maintenance Advantages
- Updates to third-party libraries are contained within their namespace
- FastLED can provide compatibility layers when third-party APIs change
- Clear responsibility boundaries for bug fixes and feature development
5. TJpg_Decoder Example
The TJpg_Decoder implementation demonstrates this pattern perfectly:
namespace third_party {
class TJpg_Decoder {
};
}
}
static bool decode(
const JpegDecoderConfig& config,
fl::span<const fl::u8> data,
Frame* frame,
fl::string* error_message = nullptr);
};
}
fl::third_party::TJpg_Decoder decoder_;
};
}
JRESULT drawJpg(int32_t x, int32_t y, const uint8_t array[], size_t array_size) FL_NOEXCEPT
6. Guidelines for Third-Party Integration
When adding new third-party libraries to FastLED:
- Always use
fl::third_party namespace - Non-negotiable requirement
- Preserve original APIs - Don't modify third-party code unnecessarily
- Create FastLED wrappers - Provide clean C++ APIs following project conventions
- Document boundaries clearly - Make it obvious what's third-party vs. FastLED native
- Handle type conversions - Bridge between third-party types and FastLED types
- Manage memory correctly - Use FastLED memory management patterns in wrappers
This architecture ensures FastLED remains maintainable, extensible, and free from the complexities often introduced by direct third-party library integration.
Implementation Summary
✅ Phase 1: Library Modernization (COMPLETED)
- C++ Conversion
- ✅
tjpgd.c → tjpgd.cpp
- ✅ Updated includes and linkage
- Namespace Wrapping
namespace third_party {
}
}
- ✅ All TJpg_Decoder classes properly namespaced
- Dependency Cleanup
- ✅ Arduino-specific includes cleaned up
- ✅ Integration with FastLED type system
- ✅ ByteStream compatibility implemented
✅ Phase 2: FastLED Integration (COMPLETED)
- Bridge Implementation (
src/fl/codec/jpeg.cpp) class TJpgDecoder : public IDecoder {
};
- ✅ Full
IDecoder interface implementation
- Configuration Mapping
- ✅
JpegDecoderConfig::Quality → TJpg scaling factor
- ✅
JpegDecoderConfig::format → pixel format conversion
- ✅
JpegDecoderConfig::maxWidth/Height → size validation
- Memory Management
- ✅ Arduino memory allocation replaced with FastLED patterns
- ✅
fl::scoped_array and buffer management implemented
- ✅ Callback-based output converted to frame buffer approach
✅ Phase 3: Integration & Testing (COMPLETED)
- Static API Implementation
- ✅
Jpeg::decode() static methods implemented
- ✅
Jpeg::isSupported() platform detection
- ✅ Clean public API in
fl/codec/jpeg.h
- Error Handling
- ✅
JRESULT codes mapped to FastLED error system
- ✅ Comprehensive error message reporting
- Advanced Features
- ✅ Multiple pixel format support (RGB888, RGB565, RGBA8888)
- ✅ Quality/scaling configuration
- ✅ Memory-efficient streaming decode
Key Challenges (RESOLVED)
- ✅ Callback Architecture: Successfully transformed coordinate-based drawing to frame buffer approach using
outputCallback() static method
- ✅ Memory Model: Arduino patterns replaced with FastLED's
fl::scoped_array and proper buffer management
- ✅ Platform Dependencies: ESP32/Arduino-specific filesystem code removed, using FastLED's
ByteStream abstraction
- ✅ Performance: Efficient decoding maintained through direct memory copying and optimized pixel format conversion
Current Working API
The JPEG decoder is now fully functional and integrated into FastLED. Here's how to use it:
Basic Usage
fl::JpegDecoderConfig config;
config.quality = fl::JpegDecoderConfig::Medium;
if (!frame) {
printf(
"JPEG decode failed: %s\n", error.
c_str());
}
const char * c_str() const FL_NOEXCEPT
Advanced Configuration
fl::JpegDecoderConfig config;
config.quality = fl::JpegDecoderConfig::High;
config.maxWidth = 1920;
config.maxHeight = 1080;
Platform Support
} else {
}
static bool isSupported()
Integration with FastLED Codecs
The JPEG decoder integrates seamlessly with FastLED's codec architecture:
- Uses
fl::PixelFormat for output format specification
- Compatible with
Frame and FramePtr types
- Follows FastLED error handling conventions
- Works with
fl::span<const fl::u8> for input data
Unit Test Design
Existing test framework: tests/codec_jpeg.cpp
Current Test Coverage
- ✅ Availability Testing:
Jpeg::isSupported() detection
- ✅ Factory Testing:
Jpeg::decode() static methods
- ✅ Lifecycle Testing:
begin(), end(), and state management
- ✅ Configuration Testing:
JpegConfig parameter validation
- ✅ Error Handling: Null stream and invalid input handling
Additional Tests Required for TJpg Integration
Phase 1: Basic Functionality
TEST_CASE("JPEG TJpg decoder initialization") {
}
TEST_CASE("JPEG valid file decoding") {
}
Phase 2: Format Support
TEST_CASE("JPEG pixel format conversion") {
}
TEST_CASE("JPEG scaling and quality") {
}
Phase 3: Edge Cases & Performance
TEST_CASE("JPEG large image handling") {
}
TEST_CASE("JPEG malformed data") {
}
TEST_CASE("JPEG stress testing") {
}
Test Data Requirements
- Minimal JPEG: 1x1 pixel valid JPEG for basic tests
- Format Samples: RGB/Grayscale/Progressive variants
- Size Variants: Small (64x64) to large (1920x1080) images
- Malformed Data: Corrupted headers, truncated streams
Integration with Existing Test Suite
✅ Status: Test suite updated and functional
- ✅
CHECK_FALSE(jpegSupported) replaced with CHECK(jpegSupported)
- ✅ TJpg-specific test cases added alongside generic codec tests
- ✅ Tests pass with TJpg_Decoder implementation
API Integration (COMPLETED)
Main FastLED API entry point: src/fl/codec/jpeg.h
- ✅
fl::Jpeg::decode() - Static decode methods (replaces factory pattern)
- ✅
fl::Jpeg::isSupported() - Platform detection
- ✅
JpegDecoderConfig - Configuration structure
- ✅ Full integration with FastLED
Frame and PixelFormat systems
Summary
The TJpg_Decoder integration is COMPLETE and fully functional. The JPEG decoder now provides:
- Clean C++ API following FastLED conventions
- Multiple pixel formats (RGB888, RGB565, RGBA8888)
- Quality/scaling control via configuration
- Memory-efficient operation using FastLED buffer management
- Comprehensive error handling with descriptive messages
- Full test coverage and validation
The decoder is ready for production use in FastLED applications requiring JPEG image decoding capabilities.