Pulled from: https://www.netsurf-browser.org/projects/libnsgif/
Current Status
- ✅ Library Staged: Third-party code copied to FastLED
- ✅ IDecoder Interface: Created
fl/codec/idecoder.h with base decoder interface
- ⏳ Namespace Wrapping: Needs wrapping in
fl::third_party
- ⏳ C++ Conversion:
.c files need conversion to .cpp
- ⏳ FastLED Integration: Bridge implementation needed in
fl/codec/gif.cpp
- ⏳ Decoder Implementation:
fl::third_party::SoftwareGifDecoder class in software_decoder.h
- ⏳ Factory API:
Gif::createDecoder() function to return shared_ptr<IDecoder>
- ⏳ Memory Management: Integration with FastLED's buffer management and scoped arrays
- ⏳ Pixel Format Support: RGB888, RGB565, RGBA8888 conversion implementation needed
- ⏳ Configuration Structure:
GifConfig integration required
- ⏳ Animation Support: Multi-frame streaming via IDecoder pattern
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
struct nsgif { };
namespace third_party {
struct nsgif { };
}
}
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
struct nsgif { };
nsgif* decoder_;
};
}
public:
static fl::shared_ptr<IDecoder>
createDecoder(
const GifConfig& config, fl::string* error_message =
nullptr);
};
}
static IDecoderPtr createDecoder(const GifConfig &config, fl::string *error_message=nullptr)
static bool isSupported()
nsgif_error
LibNSGIF return codes.
struct fl::third_party::nsgif_bitmap_cb_vt nsgif_bitmap_cb_vt
Bitmap callbacks function table.
nsgif_error nsgif_create(const nsgif_bitmap_cb_vt *bitmap_vt, nsgif_bitmap_fmt_t bitmap_fmt, nsgif_t **gif_out) FL_NOEXCEPT
Create the NSGIF object.
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. Libnsgif Example
The libnsgif implementation will demonstrate this pattern:
namespace third_party {
typedef struct nsgif nsgif;
typedef enum {
NSGIF_INSUFFICIENT_MEMORY,
NSGIF_DATA_ERROR,
}
}
bool looping = true;
fl::u16 maxWidth = 1920;
fl::u16 maxHeight = 1080;
};
public:
static fl::shared_ptr<IDecoder>
createDecoder(
const GifConfig& config, fl::string* error_message =
nullptr);
};
nsgif* decoder_;
};
}
}
Software GIF decoder implementation using libnsgif.
nsgif_error nsgif_data_scan(nsgif_t *gif, fl::size size, const fl::u8 *data) FL_NOEXCEPT
Scan the source image data.
nsgif_error nsgif_frame_decode(nsgif_t *gif, fl::u32 frame, nsgif_bitmap_t **bitmap) FL_NOEXCEPT
Decodes a GIF frame.
void nsgif_bitmap_t
Client bitmap type.
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 Plan
🔄 Phase 1: Library Modernization (PENDING)
- C++ Conversion
- ⏳
gif.c → gif.cpp
- ⏳
lzw.c → lzw.cpp
- ⏳ Updated includes and linkage
- Namespace Wrapping
namespace third_party {
}
}
- ⏳ All libnsgif structures and functions properly namespaced
- Dependency Cleanup
- ⏳ Platform-specific includes cleaned up
- ⏳ Integration with FastLED type system
- ⏳ ByteStream compatibility implemented
🔄 Phase 2: FastLED Integration (PENDING)
- Bridge Implementation (
src/third_party/libnsgif/software_decoder.h)
nsgif* decoder_;
bool begin(fl::ByteStreamPtr stream)
override;
bool seek(fl::u32 frameIndex)
override;
};
}
fl::u32 getFrameCount() const FL_NOEXCEPT override
fl::Frame getCurrentFrame() FL_NOEXCEPT override
fl::DecodeResult decode() FL_NOEXCEPT override
bool hasMoreFrames() const FL_NOEXCEPT override
bool seek(fl::u32 frameIndex) FL_NOEXCEPT override
bool begin(fl::filebuf_ptr stream) FL_NOEXCEPT override
- ⏳ Full
IDecoder interface implementation in third-party namespace
- Factory Class Implementation (
src/fl/codec/gif.cpp)
}
return true;
}
}
shared_ptr< T > make_shared(Args &&... args) FL_NOEXCEPT
- ⏳ Factory class following MPEG1 pattern for multi-frame formats
- Configuration Mapping
- ⏳
GifConfig::looping → GIF animation loop handling
- ⏳
GifConfig::format → pixel format conversion
- ⏳
GifConfig::maxWidth/Height → size validation
- ⏳
GifConfig::mode → SingleFrame vs Streaming animation
- ⏳
GifConfig::bufferFrames → animation frame buffering
- Memory Management
- ⏳ C memory allocation replaced with FastLED patterns
- ⏳
fl::scoped_array and buffer management implemented
- ⏳ Callback-based bitmap creation converted to frame buffer approach
🔄 Phase 3: Integration & Testing (PENDING)
- Factory Class Implementation
- ⏳
Gif::createDecoder() factory function implemented
- ⏳
Gif::isSupported() platform detection function
- ⏳ Clean public API in
fl/codec/gif.h
- ⏳ Integration with existing codec framework
- IDecoder Interface Implementation
- ⏳
begin() - Initialize with ByteStream for streaming GIF data
- ⏳
decode() - Decode next frame with proper state management
- ⏳
getCurrentFrame() - Return current decoded frame
- ⏳
hasMoreFrames() - Check for additional animation frames
- ⏳
getFrameCount() - Total frame count for animations
- ⏳
seek() - Jump to specific frame index
- Error Handling
- ⏳
nsgif_error codes mapped to FastLED DecodeResult enum
- ⏳ Comprehensive error message reporting via
hasError()
- ⏳ Graceful handling of malformed GIF data
- Advanced Features
- ⏳ Multiple pixel format support (RGB888, RGB565, RGBA8888)
- ⏳ Animation frame iteration and timing
- ⏳ Transparency and disposal method handling
- ⏳ Memory-efficient streaming decode with frame buffering
Key Challenges (TO BE ADDRESSED)
- ⏳ Callback Architecture: Transform bitmap callback system to frame buffer approach
- ⏳ Memory Model: C patterns need replacement with FastLED's
fl::scoped_array and proper buffer management
- ⏳ Animation Support: GIF animation timing and frame sequencing integration using IDecoder pattern
- ⏳ Transparency Handling: Alpha channel support and background disposal methods
- ⏳ Performance: Efficient decoding with minimal memory allocation
- ⏳ Streaming Support: ByteStream integration for progressive GIF loading
Planned API
The GIF decoder will provide comprehensive animated GIF support using the IDecoder interface:
Basic Usage
config.looping = true;
if (!decoder) {
printf(
"GIF decoder creation failed: %s\n", error.
c_str());
return;
}
auto stream = fl::ByteStream::fromSpan(gif_data_span);
if (!decoder->begin(stream)) {
printf("Failed to initialize GIF decoder\n");
return;
}
const char * c_str() const FL_NOEXCEPT
Animation Support
while (decoder->hasMoreFrames()) {
auto result = decoder->decode();
fl::Frame frame = decoder->getCurrentFrame();
displayFrame(frame);
fl::u32 currentIndex = decoder->getCurrentFrameIndex();
printf("Displaying frame %u of %u\n", currentIndex, decoder->getFrameCount());
break;
decoder->hasError(&error);
printf(
"Decode error: %s\n", error.
c_str());
break;
}
}
decoder->end();
Random Access Support
fl::u32 targetFrame = 10;
if (decoder->seek(targetFrame)) {
auto result = decoder->decode();
fl::Frame frame = decoder->getCurrentFrame();
}
}
Advanced Configuration
config.maxWidth = 800;
config.maxHeight = 600;
Platform Support
Integration with FastLED Codecs
The GIF decoder integrates seamlessly with FastLED's codec architecture:
- Implements
IDecoder interface for consistent API
- Uses
fl::PixelFormat for output format specification
- Compatible with
Frame and FramePtr types
- Follows FastLED error handling conventions with
DecodeResult
- Works with
fl::ByteStreamPtr for streaming input data
- Supports animation timing and frame sequencing through
hasMoreFrames() and seek()
Unit Test Design
Planned test framework: tests/codec_gif.cpp
Required Test Coverage
Phase 1: Basic Functionality
TEST_CASE("GIF libnsgif decoder initialization") {
}
TEST_CASE("GIF valid file decoding") {
}
Phase 2: Animation Support
TEST_CASE("GIF animation frame handling") {
}
TEST_CASE("GIF transparency and disposal") {
}
Phase 3: Format Support
TEST_CASE("GIF pixel format conversion") {
}
TEST_CASE("GIF interlaced decoding") {
}
Phase 4: Edge Cases & Performance
TEST_CASE("GIF large animation handling") {
}
TEST_CASE("GIF malformed data") {
}
TEST_CASE("GIF stress testing") {
}
Test Data Requirements
- Minimal GIF: 1x1 pixel valid GIF for basic tests
- Animation Samples: Simple 2-3 frame animations
- Transparency Tests: GIFs with transparent backgrounds
- Interlaced GIFs: Progressive rendering test cases
- Size Variants: Small (64x64) to large (800x600) animations
- Malformed Data: Corrupted headers, truncated streams
Integration with Existing Test Suite
⏳ Status: Test suite to be created
- ⏳ Create
tests/codec_gif.cpp following existing codec test patterns
- ⏳ Add libnsgif-specific test cases alongside generic codec tests
- ⏳ Integration with FastLED test runner
API Integration (PLANNED)
File Structure
API Components
Libnsgif Library Overview
Libnsgif is a decoding library for GIF image format, originally developed for the NetSurf web browser. Key features include:
Core Capabilities
- Complete GIF87a and GIF89a support - Handles all standard GIF variants
- Animation support - Full multi-frame GIF animation decoding
- Transparency handling - Proper alpha channel and background disposal
- Interlaced support - Progressive GIF rendering capability
- Memory efficient - Streaming decode with minimal memory footprint
- C API - Clean, well-documented C interface
Technical Specifications
- LZW decompression - Optimized Lempel-Ziv-Welch implementation
- Color palette - Up to 256 colors with transparency support
- Frame management - Individual frame extraction and timing information
- Error handling - Comprehensive error reporting and recovery
- Platform independent - Pure C implementation with no external dependencies
Integration Advantages
- Proven stability - Used in production NetSurf browser
- Comprehensive format support - Handles edge cases and malformed files gracefully
- Small footprint - Minimal code size and memory requirements
- Clean API - Well-designed interface suitable for wrapping
- No dependencies - Self-contained implementation
Summary
The libnsgif integration is PLANNED and represents the next step in FastLED's codec expansion. Once complete, the GIF decoder will provide:
- Full GIF format support including animations and transparency
- Clean C++ API following FastLED conventions
- Multiple pixel formats (RGB888, RGB565, RGBA8888)
- Animation frame control with timing and sequencing
- Memory-efficient operation using FastLED buffer management
- Comprehensive error handling with descriptive messages
- Full test coverage and validation
The implementation will follow the established third-party integration pattern used successfully with TJpg_Decoder, ensuring consistent architecture and maintainability across FastLED's codec ecosystem.