A fork of https://github.com/crosspoint-reader/crosspoint-reader
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

refactor: replace picojpeg with JPEGDEC for cover art conversion (#1517)

## Summary

- Removes the vendored `picojpeg` library and rewrites
`JpegToBmpConverter` to use the already-present `JPEGDEC` (bitbank2)
dependency
- Eliminates the redundancy of having two JPEG decoders in the firmware
- All BMP output (headers, fixed-point scaling, Atkinson/Floyd-Steinberg
dithering) is identical to before — cached cover BMPs are unaffected

## Size impact

| | Before | After | Delta |
|---|---|---|---|
| Flash | 5,754,089 bytes (87.8%) | 5,744,777 bytes (87.7%) | **−9,312
bytes** |
| RAM | 95,212 bytes (29.1%) | 92,852 bytes (28.3%) | **−2,360 bytes** |

## Implementation notes

- `bmpDrawCallback` receives MCU-sized blocks from JPEGDEC (up to 16
rows × MCU-width), accumulates them into a pre-allocated `mcuBuf`, and
applies the same scaling + dithering logic once each MCU row is complete
- File I/O uses a file-scope static `FsFile*` (safe in single-threaded
embedded context) via JPEGDEC's open/read/seek callbacks — same pattern
as `JpegToFramebufferConverter`
- Added a 52 KB free-heap guard before allocating the JPEGDEC object
(~17 KB)
- `lib/picojpeg/` deleted (2,087 lines of C removed)

## Test plan

- [ ] Build compiles without warnings
- [ ] Cover art BMP cache regenerates correctly for EPUB books
- [ ] Home screen thumbnails (1-bit BMP path) render correctly
- [ ] Custom-size thumbnails (`jpegFileToBmpStreamWithSize`) render
correctly

🤖 Generated with [Claude Code](https://claude.com/claude-code)

authored by

jpirnay and committed by
GitHub
40e4c969 80772ff6

+298 -2530
+298 -317
lib/JpegToBmpConverter/JpegToBmpConverter.cpp
··· 2 2 3 3 #include <HalDisplay.h> 4 4 #include <HalStorage.h> 5 + #include <JPEGDEC.h> 5 6 #include <Logging.h> 6 - #include <picojpeg.h> 7 7 8 8 #include <cstdio> 9 9 #include <cstring> 10 + #include <new> 10 11 11 12 #include "BitmapHelpers.h" 12 - 13 - // Context structure for picojpeg callback 14 - struct JpegReadContext { 15 - FsFile& file; 16 - uint8_t buffer[512]; 17 - size_t bufferPos; 18 - size_t bufferFilled; 19 - }; 20 13 21 14 // ============================================================================ 22 15 // IMAGE PROCESSING OPTIONS - Toggle these to test different configurations ··· 165 158 } 166 159 } 167 160 168 - // Callback function for picojpeg to read JPEG data 169 - unsigned char JpegToBmpConverter::jpegReadCallback(unsigned char* pBuf, const unsigned char buf_size, 170 - unsigned char* pBytes_actually_read, void* pCallback_data) { 171 - auto* context = static_cast<JpegReadContext*>(pCallback_data); 161 + namespace { 162 + 163 + // Max MCU height supported by any JPEG (4:2:0 chroma = 16 rows, 4:4:4 = 8 rows) 164 + constexpr int MAX_MCU_HEIGHT = 16; 165 + constexpr size_t JPEG_DECODER_SIZE = 20 * 1024; 166 + constexpr size_t MIN_FREE_HEAP = JPEG_DECODER_SIZE + 32 * 1024; 167 + 168 + // Static file pointer for JPEGDEC open callback. 169 + // Safe in single-threaded embedded context; never accessed concurrently. 170 + static FsFile* s_jpegFile = nullptr; 171 + 172 + void* bmpJpegOpen(const char* /*filename*/, int32_t* size) { 173 + if (!s_jpegFile || !*s_jpegFile) return nullptr; 174 + s_jpegFile->seek(0); 175 + *size = static_cast<int32_t>(s_jpegFile->size()); 176 + return s_jpegFile; 177 + } 178 + 179 + void bmpJpegClose(void* /*handle*/) { 180 + // Caller owns the file — do not close it here 181 + } 182 + 183 + int32_t bmpJpegRead(JPEGFILE* pFile, uint8_t* pBuf, int32_t len) { 184 + auto* f = reinterpret_cast<FsFile*>(pFile->fHandle); 185 + if (!f) return 0; 186 + int32_t n = f->read(pBuf, len); 187 + if (n < 0) n = 0; 188 + pFile->iPos += n; 189 + return n; 190 + } 191 + 192 + int32_t bmpJpegSeek(JPEGFILE* pFile, int32_t pos) { 193 + auto* f = reinterpret_cast<FsFile*>(pFile->fHandle); 194 + if (!f || !f->seek(pos)) return -1; 195 + pFile->iPos = pos; 196 + return pos; 197 + } 198 + 199 + // Context passed to the JPEGDEC draw callback via setUserPointer() 200 + struct BmpConvertCtx { 201 + Print* bmpOut; 202 + int srcWidth; 203 + int srcHeight; 204 + int outWidth; 205 + int outHeight; 206 + bool oneBit; 207 + int bytesPerRow; 208 + bool needsScaling; 209 + uint32_t scaleX_fp; // source pixels per output pixel, 16.16 fixed-point 210 + uint32_t scaleY_fp; 211 + 212 + // Accumulates one MCU row (up to MAX_MCU_HEIGHT source rows × srcWidth pixels) 213 + // Filled column-by-column as JPEGDEC callbacks arrive for the same MCU row 214 + uint8_t* mcuBuf; 215 + 216 + // Y-axis area averaging accumulators (needsScaling only) 217 + int currentOutY; 218 + uint32_t nextOutY_srcStart; // 16.16 fixed-point boundary for the next output row 219 + uint32_t* rowAccum; 220 + uint32_t* rowCount; 221 + 222 + uint8_t* bmpRow; 223 + 224 + AtkinsonDitherer* atkinsonDitherer; 225 + FloydSteinbergDitherer* fsDitherer; 226 + Atkinson1BitDitherer* atkinson1BitDitherer; 227 + 228 + bool error; 229 + }; 230 + 231 + // Write a fully-assembled output row (grayscale bytes, length outWidth) to BMP 232 + static void writeOutputRow(BmpConvertCtx* ctx, const uint8_t* srcRow, int outY) { 233 + memset(ctx->bmpRow, 0, ctx->bytesPerRow); 172 234 173 - if (!context || !context->file) { 174 - return PJPG_STREAM_READ_ERROR; 235 + if (USE_8BIT_OUTPUT && !ctx->oneBit) { 236 + for (int x = 0; x < ctx->outWidth; x++) { 237 + ctx->bmpRow[x] = adjustPixel(srcRow[x]); 238 + } 239 + } else if (ctx->oneBit) { 240 + for (int x = 0; x < ctx->outWidth; x++) { 241 + const uint8_t bit = ctx->atkinson1BitDitherer ? ctx->atkinson1BitDitherer->processPixel(srcRow[x], x) 242 + : quantize1bit(srcRow[x], x, outY); 243 + ctx->bmpRow[x / 8] |= (bit << (7 - (x % 8))); 244 + } 245 + if (ctx->atkinson1BitDitherer) ctx->atkinson1BitDitherer->nextRow(); 246 + } else { 247 + for (int x = 0; x < ctx->outWidth; x++) { 248 + const uint8_t gray = adjustPixel(srcRow[x]); 249 + uint8_t twoBit; 250 + if (ctx->atkinsonDitherer) { 251 + twoBit = ctx->atkinsonDitherer->processPixel(gray, x); 252 + } else if (ctx->fsDitherer) { 253 + twoBit = ctx->fsDitherer->processPixel(gray, x); 254 + } else { 255 + twoBit = quantize(gray, x, outY); 256 + } 257 + ctx->bmpRow[(x * 2) / 8] |= (twoBit << (6 - ((x * 2) % 8))); 258 + } 259 + if (ctx->atkinsonDitherer) 260 + ctx->atkinsonDitherer->nextRow(); 261 + else if (ctx->fsDitherer) 262 + ctx->fsDitherer->nextRow(); 175 263 } 176 264 177 - // Check if we need to refill our context buffer 178 - if (context->bufferPos >= context->bufferFilled) { 179 - context->bufferFilled = context->file.read(context->buffer, sizeof(context->buffer)); 180 - context->bufferPos = 0; 265 + ctx->bmpOut->write(ctx->bmpRow, ctx->bytesPerRow); 266 + } 267 + 268 + // Flush one scaled output row from Y-axis accumulators and advance currentOutY 269 + static void flushScaledRow(BmpConvertCtx* ctx) { 270 + memset(ctx->bmpRow, 0, ctx->bytesPerRow); 181 271 182 - if (context->bufferFilled == 0) { 183 - // EOF or error 184 - *pBytes_actually_read = 0; 185 - return 0; // Success (EOF is normal) 272 + if (USE_8BIT_OUTPUT && !ctx->oneBit) { 273 + for (int x = 0; x < ctx->outWidth; x++) { 274 + const uint8_t gray = (ctx->rowCount[x] > 0) ? (ctx->rowAccum[x] / ctx->rowCount[x]) : 0; 275 + ctx->bmpRow[x] = adjustPixel(gray); 276 + } 277 + } else if (ctx->oneBit) { 278 + for (int x = 0; x < ctx->outWidth; x++) { 279 + const uint8_t gray = (ctx->rowCount[x] > 0) ? (ctx->rowAccum[x] / ctx->rowCount[x]) : 0; 280 + const uint8_t bit = ctx->atkinson1BitDitherer ? ctx->atkinson1BitDitherer->processPixel(gray, x) 281 + : quantize1bit(gray, x, ctx->currentOutY); 282 + ctx->bmpRow[x / 8] |= (bit << (7 - (x % 8))); 186 283 } 284 + if (ctx->atkinson1BitDitherer) ctx->atkinson1BitDitherer->nextRow(); 285 + } else { 286 + for (int x = 0; x < ctx->outWidth; x++) { 287 + const uint8_t gray = adjustPixel((ctx->rowCount[x] > 0) ? (ctx->rowAccum[x] / ctx->rowCount[x]) : 0); 288 + uint8_t twoBit; 289 + if (ctx->atkinsonDitherer) { 290 + twoBit = ctx->atkinsonDitherer->processPixel(gray, x); 291 + } else if (ctx->fsDitherer) { 292 + twoBit = ctx->fsDitherer->processPixel(gray, x); 293 + } else { 294 + twoBit = quantize(gray, x, ctx->currentOutY); 295 + } 296 + ctx->bmpRow[(x * 2) / 8] |= (twoBit << (6 - ((x * 2) % 8))); 297 + } 298 + if (ctx->atkinsonDitherer) 299 + ctx->atkinsonDitherer->nextRow(); 300 + else if (ctx->fsDitherer) 301 + ctx->fsDitherer->nextRow(); 187 302 } 188 303 189 - // Copy available bytes to picojpeg's buffer 190 - const size_t available = context->bufferFilled - context->bufferPos; 191 - const size_t toRead = available < buf_size ? available : buf_size; 304 + ctx->bmpOut->write(ctx->bmpRow, ctx->bytesPerRow); 305 + ctx->currentOutY++; 306 + } 307 + 308 + // JPEGDEC draw callback — receives one MCU-width × MCU-height block at a time, 309 + // in left-to-right, top-to-bottom order (baseline JPEG). 310 + // Accumulates columns into mcuBuf; once the last column arrives (completing the MCU 311 + // row), applies scaling + dithering and writes packed BMP rows to bmpOut. 312 + int bmpDrawCallback(JPEGDRAW* pDraw) { 313 + auto* ctx = reinterpret_cast<BmpConvertCtx*>(pDraw->pUser); 314 + if (!ctx || ctx->error) return 0; 315 + 316 + const uint8_t* pixels = reinterpret_cast<uint8_t*>(pDraw->pPixels); 317 + const int stride = pDraw->iWidth; 318 + const int validW = pDraw->iWidthUsed; 319 + const int blockH = pDraw->iHeight; 320 + const int blockX = pDraw->x; 321 + const int blockY = pDraw->y; 322 + 323 + // Copy block pixels into MCU row buffer 324 + for (int r = 0; r < blockH && r < MAX_MCU_HEIGHT; r++) { 325 + const int copyW = (blockX + validW <= ctx->srcWidth) ? validW : (ctx->srcWidth - blockX); 326 + if (copyW <= 0) continue; 327 + memcpy(ctx->mcuBuf + r * ctx->srcWidth + blockX, pixels + r * stride, copyW); 328 + } 329 + 330 + // Wait for the last MCU column before processing any rows 331 + if (blockX + validW < ctx->srcWidth) return 1; 332 + 333 + // Process each complete source row in this MCU row 334 + const int endRow = blockY + blockH; 335 + 336 + for (int y = blockY; y < endRow && y < ctx->srcHeight; y++) { 337 + const uint8_t* srcRow = ctx->mcuBuf + (y - blockY) * ctx->srcWidth; 192 338 193 - memcpy(pBuf, context->buffer + context->bufferPos, toRead); 194 - context->bufferPos += toRead; 195 - *pBytes_actually_read = static_cast<unsigned char>(toRead); 339 + if (!ctx->needsScaling) { 340 + // 1:1 — outWidth == srcWidth, write directly 341 + writeOutputRow(ctx, srcRow, y); 342 + } else { 343 + // Fixed-point area averaging on X axis 344 + for (int outX = 0; outX < ctx->outWidth; outX++) { 345 + const int srcXStart = (static_cast<uint32_t>(outX) * ctx->scaleX_fp) >> 16; 346 + const int srcXEnd = (static_cast<uint32_t>(outX + 1) * ctx->scaleX_fp) >> 16; 347 + int sum = 0; 348 + int count = 0; 349 + for (int srcX = srcXStart; srcX < srcXEnd && srcX < ctx->srcWidth; srcX++) { 350 + sum += srcRow[srcX]; 351 + count++; 352 + } 353 + if (count == 0 && srcXStart < ctx->srcWidth) { 354 + sum = srcRow[srcXStart]; 355 + count = 1; 356 + } 357 + ctx->rowAccum[outX] += sum; 358 + ctx->rowCount[outX] += count; 359 + } 196 360 197 - return 0; // Success 361 + // Flush output row(s) whose Y boundary we've crossed 362 + const uint32_t srcY_fp = static_cast<uint32_t>(y + 1) << 16; 363 + while (srcY_fp >= ctx->nextOutY_srcStart && ctx->currentOutY < ctx->outHeight) { 364 + flushScaledRow(ctx); 365 + ctx->nextOutY_srcStart = static_cast<uint32_t>(ctx->currentOutY + 1) * ctx->scaleY_fp; 366 + if (srcY_fp >= ctx->nextOutY_srcStart) continue; 367 + memset(ctx->rowAccum, 0, ctx->outWidth * sizeof(uint32_t)); 368 + memset(ctx->rowCount, 0, ctx->outWidth * sizeof(uint32_t)); 369 + } 370 + } 371 + } 372 + 373 + return ctx->error ? 0 : 1; 198 374 } 199 375 376 + } // namespace 377 + 200 378 // Internal implementation with configurable target size and bit depth 201 379 bool JpegToBmpConverter::jpegFileToBmpStreamInternal(FsFile& jpegFile, Print& bmpOut, int targetWidth, int targetHeight, 202 380 bool oneBit, bool crop) { 203 381 LOG_DBG("JPG", "Converting JPEG to %s BMP (target: %dx%d)", oneBit ? "1-bit" : "2-bit", targetWidth, targetHeight); 204 382 205 - // Setup context for picojpeg callback 206 - JpegReadContext context = {.file = jpegFile, .bufferPos = 0, .bufferFilled = 0}; 383 + if (ESP.getFreeHeap() < MIN_FREE_HEAP) { 384 + LOG_ERR("JPG", "Not enough heap for JPEG decoder (%u free, need %u)", ESP.getFreeHeap(), MIN_FREE_HEAP); 385 + return false; 386 + } 387 + 388 + s_jpegFile = &jpegFile; 389 + 390 + JPEGDEC* jpeg = new (std::nothrow) JPEGDEC(); 391 + if (!jpeg) { 392 + LOG_ERR("JPG", "Failed to allocate JPEG decoder"); 393 + return false; 394 + } 207 395 208 - // Initialize picojpeg decoder 209 - pjpeg_image_info_t imageInfo; 210 - const unsigned char status = pjpeg_decode_init(&imageInfo, jpegReadCallback, &context, 0); 211 - if (status != 0) { 212 - LOG_ERR("JPG", "JPEG decode init failed with error code: %d", status); 396 + int rc = jpeg->open("", bmpJpegOpen, bmpJpegClose, bmpJpegRead, bmpJpegSeek, bmpDrawCallback); 397 + if (rc != 1) { 398 + LOG_ERR("JPG", "JPEG open failed (err=%d)", jpeg->getLastError()); 399 + delete jpeg; 213 400 return false; 214 401 } 215 402 216 - LOG_DBG("JPG", "JPEG dimensions: %dx%d, components: %d, MCUs: %dx%d", imageInfo.m_width, imageInfo.m_height, 217 - imageInfo.m_comps, imageInfo.m_MCUSPerRow, imageInfo.m_MCUSPerCol); 403 + const int srcWidth = jpeg->getWidth(); 404 + const int srcHeight = jpeg->getHeight(); 405 + 406 + LOG_DBG("JPG", "JPEG dimensions: %dx%d", srcWidth, srcHeight); 218 407 219 - // Safety limits to prevent memory issues on ESP32 220 408 constexpr int MAX_IMAGE_WIDTH = 2048; 221 409 constexpr int MAX_IMAGE_HEIGHT = 3072; 222 - constexpr int MAX_MCU_ROW_BYTES = 65536; 223 410 224 - if (imageInfo.m_width > MAX_IMAGE_WIDTH || imageInfo.m_height > MAX_IMAGE_HEIGHT) { 225 - LOG_DBG("JPG", "Image too large (%dx%d), max supported: %dx%d", imageInfo.m_width, imageInfo.m_height, 226 - MAX_IMAGE_WIDTH, MAX_IMAGE_HEIGHT); 411 + if (srcWidth <= 0 || srcHeight <= 0 || srcWidth > MAX_IMAGE_WIDTH || srcHeight > MAX_IMAGE_HEIGHT) { 412 + LOG_DBG("JPG", "Image too large or invalid (%dx%d), max supported: %dx%d", srcWidth, srcHeight, MAX_IMAGE_WIDTH, 413 + MAX_IMAGE_HEIGHT); 414 + jpeg->close(); 415 + delete jpeg; 227 416 return false; 228 417 } 229 418 230 419 // Calculate output dimensions (pre-scale to fit display exactly) 231 - int outWidth = imageInfo.m_width; 232 - int outHeight = imageInfo.m_height; 233 - // Use fixed-point scaling (16.16) for sub-pixel accuracy 420 + int outWidth = srcWidth; 421 + int outHeight = srcHeight; 234 422 uint32_t scaleX_fp = 65536; // 1.0 in 16.16 fixed point 235 423 uint32_t scaleY_fp = 65536; 236 424 bool needsScaling = false; 237 425 238 - if (targetWidth > 0 && targetHeight > 0 && (imageInfo.m_width != targetWidth || imageInfo.m_height != targetHeight)) { 239 - // Calculate scale to fit/fill target dimensions while maintaining aspect ratio 240 - const float scaleToFitWidth = static_cast<float>(targetWidth) / imageInfo.m_width; 241 - const float scaleToFitHeight = static_cast<float>(targetHeight) / imageInfo.m_height; 242 - // We scale to the smaller dimension, so we can potentially crop later. 243 - float scale = 1.0; 244 - if (crop) { // if we will crop, scale to the smaller dimension 426 + if (targetWidth > 0 && targetHeight > 0 && (srcWidth != targetWidth || srcHeight != targetHeight)) { 427 + const float scaleToFitWidth = static_cast<float>(targetWidth) / srcWidth; 428 + const float scaleToFitHeight = static_cast<float>(targetHeight) / srcHeight; 429 + float scale = 1.0f; 430 + if (crop) { 245 431 scale = (scaleToFitWidth > scaleToFitHeight) ? scaleToFitWidth : scaleToFitHeight; 246 - } else { // else, scale to the larger dimension to fit 432 + } else { 247 433 scale = (scaleToFitWidth < scaleToFitHeight) ? scaleToFitWidth : scaleToFitHeight; 248 434 } 249 435 250 - outWidth = static_cast<int>(imageInfo.m_width * scale); 251 - outHeight = static_cast<int>(imageInfo.m_height * scale); 252 - 253 - // Ensure at least 1 pixel 436 + outWidth = static_cast<int>(srcWidth * scale); 437 + outHeight = static_cast<int>(srcHeight * scale); 254 438 if (outWidth < 1) outWidth = 1; 255 439 if (outHeight < 1) outHeight = 1; 256 440 257 - // Calculate fixed-point scale factors (source pixels per output pixel) 258 - // scaleX_fp = (srcWidth << 16) / outWidth 259 - scaleX_fp = (static_cast<uint32_t>(imageInfo.m_width) << 16) / outWidth; 260 - scaleY_fp = (static_cast<uint32_t>(imageInfo.m_height) << 16) / outHeight; 441 + scaleX_fp = (static_cast<uint32_t>(srcWidth) << 16) / outWidth; 442 + scaleY_fp = (static_cast<uint32_t>(srcHeight) << 16) / outHeight; 261 443 needsScaling = true; 262 444 263 - LOG_DBG("JPG", "Scaling %dx%d -> %dx%d (target %dx%d)", imageInfo.m_width, imageInfo.m_height, outWidth, outHeight, 264 - targetWidth, targetHeight); 445 + LOG_DBG("JPG", "Scaling %dx%d -> %dx%d (target %dx%d)", srcWidth, srcHeight, outWidth, outHeight, targetWidth, 446 + targetHeight); 265 447 } 266 448 267 449 // Write BMP header with output dimensions ··· 271 453 bytesPerRow = (outWidth + 3) / 4 * 4; 272 454 } else if (oneBit) { 273 455 writeBmpHeader1bit(bmpOut, outWidth, outHeight); 274 - bytesPerRow = (outWidth + 31) / 32 * 4; // 1 bit per pixel 456 + bytesPerRow = (outWidth + 31) / 32 * 4; 275 457 } else { 276 458 writeBmpHeader2bit(bmpOut, outWidth, outHeight); 277 459 bytesPerRow = (outWidth * 2 + 31) / 32 * 4; 278 460 } 279 461 280 - uint8_t* rowBuffer = nullptr; 281 - uint8_t* mcuRowBuffer = nullptr; 282 - AtkinsonDitherer* atkinsonDitherer = nullptr; 283 - FloydSteinbergDitherer* fsDitherer = nullptr; 284 - Atkinson1BitDitherer* atkinson1BitDitherer = nullptr; 285 - uint32_t* rowAccum = nullptr; // Accumulator for each output X (32-bit for larger sums) 286 - uint32_t* rowCount = nullptr; // Count of source pixels accumulated per output X 462 + BmpConvertCtx ctx = {}; 463 + ctx.bmpOut = &bmpOut; 464 + ctx.srcWidth = srcWidth; 465 + ctx.srcHeight = srcHeight; 466 + ctx.outWidth = outWidth; 467 + ctx.outHeight = outHeight; 468 + ctx.oneBit = oneBit; 469 + ctx.bytesPerRow = bytesPerRow; 470 + ctx.needsScaling = needsScaling; 471 + ctx.scaleX_fp = scaleX_fp; 472 + ctx.scaleY_fp = scaleY_fp; 473 + ctx.error = false; 287 474 288 - // RAII guard: frees all heap resources on any return path, including early exits. 289 - // Holds references so it always sees the latest pointer values assigned below. 475 + // RAII guard: frees all heap resources on any return path 290 476 struct Cleanup { 291 - uint8_t*& rowBuffer; 292 - uint8_t*& mcuRowBuffer; 293 - AtkinsonDitherer*& atkinsonDitherer; 294 - FloydSteinbergDitherer*& fsDitherer; 295 - Atkinson1BitDitherer*& atkinson1BitDitherer; 296 - uint32_t*& rowAccum; 297 - uint32_t*& rowCount; 477 + BmpConvertCtx& ctx; 478 + JPEGDEC* jpeg; 298 479 ~Cleanup() { 299 - delete[] rowAccum; 300 - delete[] rowCount; 301 - delete atkinsonDitherer; 302 - delete fsDitherer; 303 - delete atkinson1BitDitherer; 304 - free(mcuRowBuffer); 305 - free(rowBuffer); 480 + delete[] ctx.rowAccum; 481 + delete[] ctx.rowCount; 482 + delete ctx.atkinsonDitherer; 483 + delete ctx.fsDitherer; 484 + delete ctx.atkinson1BitDitherer; 485 + free(ctx.mcuBuf); 486 + free(ctx.bmpRow); 487 + jpeg->close(); 488 + delete jpeg; 306 489 } 307 - } cleanup{rowBuffer, mcuRowBuffer, atkinsonDitherer, fsDitherer, atkinson1BitDitherer, rowAccum, rowCount}; 490 + } cleanup{ctx, jpeg}; 308 491 309 - // Allocate row buffer 310 - rowBuffer = static_cast<uint8_t*>(malloc(bytesPerRow)); 311 - if (!rowBuffer) { 312 - LOG_ERR("JPG", "Failed to allocate row buffer"); 492 + // MCU row buffer: MAX_MCU_HEIGHT rows × srcWidth columns of grayscale 493 + ctx.mcuBuf = static_cast<uint8_t*>(malloc(MAX_MCU_HEIGHT * srcWidth)); 494 + if (!ctx.mcuBuf) { 495 + LOG_ERR("JPG", "Failed to allocate MCU buffer (%d bytes)", MAX_MCU_HEIGHT * srcWidth); 313 496 return false; 314 497 } 498 + memset(ctx.mcuBuf, 0, MAX_MCU_HEIGHT * srcWidth); 315 499 316 - // Allocate a buffer for one MCU row worth of grayscale pixels 317 - // This is the minimal memory needed for streaming conversion 318 - const int mcuPixelHeight = imageInfo.m_MCUHeight; 319 - const int mcuRowPixels = imageInfo.m_width * mcuPixelHeight; 320 - 321 - // Validate MCU row buffer size before allocation 322 - if (mcuRowPixels > MAX_MCU_ROW_BYTES) { 323 - LOG_DBG("JPG", "MCU row buffer too large (%d bytes), max: %d", mcuRowPixels, MAX_MCU_ROW_BYTES); 500 + ctx.bmpRow = static_cast<uint8_t*>(malloc(bytesPerRow)); 501 + if (!ctx.bmpRow) { 502 + LOG_ERR("JPG", "Failed to allocate BMP row buffer"); 324 503 return false; 325 504 } 326 505 327 - mcuRowBuffer = static_cast<uint8_t*>(malloc(mcuRowPixels)); 328 - if (!mcuRowBuffer) { 329 - LOG_ERR("JPG", "Failed to allocate MCU row buffer (%d bytes)", mcuRowPixels); 330 - return false; 506 + if (needsScaling) { 507 + ctx.rowAccum = new (std::nothrow) uint32_t[outWidth](); 508 + ctx.rowCount = new (std::nothrow) uint32_t[outWidth](); 509 + if (!ctx.rowAccum || !ctx.rowCount) { 510 + LOG_ERR("JPG", "Failed to allocate scaling buffers"); 511 + return false; 512 + } 513 + ctx.nextOutY_srcStart = scaleY_fp; 331 514 } 332 515 333 - // Create ditherer if enabled 334 - // Use OUTPUT dimensions for dithering (after prescaling) 335 516 if (oneBit) { 336 - // For 1-bit output, use Atkinson dithering for better quality 337 - atkinson1BitDitherer = new Atkinson1BitDitherer(outWidth); 517 + ctx.atkinson1BitDitherer = new (std::nothrow) Atkinson1BitDitherer(outWidth); 338 518 } else if (!USE_8BIT_OUTPUT) { 339 519 if (USE_ATKINSON) { 340 - atkinsonDitherer = new AtkinsonDitherer(outWidth); 520 + ctx.atkinsonDitherer = new (std::nothrow) AtkinsonDitherer(outWidth); 341 521 } else if (USE_FLOYD_STEINBERG) { 342 - fsDitherer = new FloydSteinbergDitherer(outWidth); 522 + ctx.fsDitherer = new (std::nothrow) FloydSteinbergDitherer(outWidth); 343 523 } 344 524 } 345 525 346 - // For scaling: accumulate source rows into scaled output rows 347 - // We need to track which source Y maps to which output Y 348 - // Using fixed-point: srcY_fp = outY * scaleY_fp (gives source Y in 16.16 format) 349 - int currentOutY = 0; // Current output row being accumulated 350 - uint32_t nextOutY_srcStart = 0; // Source Y where next output row starts (16.16 fixed point) 526 + jpeg->setPixelType(EIGHT_BIT_GRAYSCALE); 527 + jpeg->setUserPointer(&ctx); 351 528 352 - if (needsScaling) { 353 - rowAccum = new uint32_t[outWidth](); 354 - rowCount = new uint32_t[outWidth](); 355 - nextOutY_srcStart = scaleY_fp; // First boundary is at scaleY_fp (source Y for outY=1) 356 - } 529 + rc = jpeg->decode(0, 0, 0); 357 530 358 - // Process MCUs row-by-row and write to BMP as we go (top-down) 359 - const int mcuPixelWidth = imageInfo.m_MCUWidth; 360 - 361 - for (int mcuY = 0; mcuY < imageInfo.m_MCUSPerCol; mcuY++) { 362 - // Clear the MCU row buffer 363 - memset(mcuRowBuffer, 0, mcuRowPixels); 364 - 365 - // Decode one row of MCUs 366 - for (int mcuX = 0; mcuX < imageInfo.m_MCUSPerRow; mcuX++) { 367 - const unsigned char mcuStatus = pjpeg_decode_mcu(); 368 - if (mcuStatus != 0) { 369 - if (mcuStatus == PJPG_NO_MORE_BLOCKS) { 370 - LOG_ERR("JPG", "Unexpected end of blocks at MCU (%d, %d)", mcuX, mcuY); 371 - } else { 372 - LOG_ERR("JPG", "JPEG decode MCU failed at (%d, %d) with error code: %d", mcuX, mcuY, mcuStatus); 373 - } 374 - return false; 375 - } 376 - 377 - // picojpeg stores MCU data in 8x8 blocks 378 - // Block layout: H2V2(16x16)=0,64,128,192 H2V1(16x8)=0,64 H1V2(8x16)=0,128 379 - for (int blockY = 0; blockY < mcuPixelHeight; blockY++) { 380 - for (int blockX = 0; blockX < mcuPixelWidth; blockX++) { 381 - const int pixelX = mcuX * mcuPixelWidth + blockX; 382 - if (pixelX >= imageInfo.m_width) continue; 383 - 384 - // Calculate proper block offset for picojpeg buffer 385 - const int blockCol = blockX / 8; 386 - const int blockRow = blockY / 8; 387 - const int localX = blockX % 8; 388 - const int localY = blockY % 8; 389 - const int blocksPerRow = mcuPixelWidth / 8; 390 - const int blockIndex = blockRow * blocksPerRow + blockCol; 391 - const int pixelOffset = blockIndex * 64 + localY * 8 + localX; 392 - 393 - uint8_t gray; 394 - if (imageInfo.m_comps == 1) { 395 - gray = imageInfo.m_pMCUBufR[pixelOffset]; 396 - } else { 397 - const uint8_t r = imageInfo.m_pMCUBufR[pixelOffset]; 398 - const uint8_t g = imageInfo.m_pMCUBufG[pixelOffset]; 399 - const uint8_t b = imageInfo.m_pMCUBufB[pixelOffset]; 400 - gray = (r * 25 + g * 50 + b * 25) / 100; 401 - } 402 - 403 - mcuRowBuffer[blockY * imageInfo.m_width + pixelX] = gray; 404 - } 405 - } 406 - } 407 - 408 - // Process source rows from this MCU row 409 - const int startRow = mcuY * mcuPixelHeight; 410 - const int endRow = (mcuY + 1) * mcuPixelHeight; 411 - 412 - for (int y = startRow; y < endRow && y < imageInfo.m_height; y++) { 413 - const int bufferY = y - startRow; 414 - 415 - if (!needsScaling) { 416 - // No scaling - direct output (1:1 mapping) 417 - memset(rowBuffer, 0, bytesPerRow); 418 - 419 - if (USE_8BIT_OUTPUT && !oneBit) { 420 - for (int x = 0; x < outWidth; x++) { 421 - const uint8_t gray = mcuRowBuffer[bufferY * imageInfo.m_width + x]; 422 - rowBuffer[x] = adjustPixel(gray); 423 - } 424 - } else if (oneBit) { 425 - // 1-bit output with Atkinson dithering for better quality 426 - for (int x = 0; x < outWidth; x++) { 427 - const uint8_t gray = mcuRowBuffer[bufferY * imageInfo.m_width + x]; 428 - const uint8_t bit = 429 - atkinson1BitDitherer ? atkinson1BitDitherer->processPixel(gray, x) : quantize1bit(gray, x, y); 430 - // Pack 1-bit value: MSB first, 8 pixels per byte 431 - const int byteIndex = x / 8; 432 - const int bitOffset = 7 - (x % 8); 433 - rowBuffer[byteIndex] |= (bit << bitOffset); 434 - } 435 - if (atkinson1BitDitherer) atkinson1BitDitherer->nextRow(); 436 - } else { 437 - // 2-bit output 438 - for (int x = 0; x < outWidth; x++) { 439 - const uint8_t gray = adjustPixel(mcuRowBuffer[bufferY * imageInfo.m_width + x]); 440 - uint8_t twoBit; 441 - if (atkinsonDitherer) { 442 - twoBit = atkinsonDitherer->processPixel(gray, x); 443 - } else if (fsDitherer) { 444 - twoBit = fsDitherer->processPixel(gray, x); 445 - } else { 446 - twoBit = quantize(gray, x, y); 447 - } 448 - const int byteIndex = (x * 2) / 8; 449 - const int bitOffset = 6 - ((x * 2) % 8); 450 - rowBuffer[byteIndex] |= (twoBit << bitOffset); 451 - } 452 - if (atkinsonDitherer) 453 - atkinsonDitherer->nextRow(); 454 - else if (fsDitherer) 455 - fsDitherer->nextRow(); 456 - } 457 - bmpOut.write(rowBuffer, bytesPerRow); 458 - } else { 459 - // Fixed-point area averaging for exact fit scaling 460 - // For each output pixel X, accumulate source pixels that map to it 461 - // srcX range for outX: [outX * scaleX_fp >> 16, (outX+1) * scaleX_fp >> 16) 462 - const uint8_t* srcRow = mcuRowBuffer + bufferY * imageInfo.m_width; 463 - 464 - for (int outX = 0; outX < outWidth; outX++) { 465 - // Calculate source X range for this output pixel 466 - const int srcXStart = (static_cast<uint32_t>(outX) * scaleX_fp) >> 16; 467 - const int srcXEnd = (static_cast<uint32_t>(outX + 1) * scaleX_fp) >> 16; 468 - 469 - // Accumulate all source pixels in this range 470 - int sum = 0; 471 - int count = 0; 472 - for (int srcX = srcXStart; srcX < srcXEnd && srcX < imageInfo.m_width; srcX++) { 473 - sum += srcRow[srcX]; 474 - count++; 475 - } 476 - 477 - // Handle edge case: if no pixels in range, use nearest 478 - if (count == 0 && srcXStart < imageInfo.m_width) { 479 - sum = srcRow[srcXStart]; 480 - count = 1; 481 - } 482 - 483 - rowAccum[outX] += sum; 484 - rowCount[outX] += count; 485 - } 486 - 487 - // Check if we've crossed into the next output row(s) 488 - // Current source Y in fixed point: y << 16 489 - const uint32_t srcY_fp = static_cast<uint32_t>(y + 1) << 16; 490 - 491 - // Output all rows whose boundaries we've crossed (handles both up and downscaling) 492 - // For upscaling, one source row may produce multiple output rows 493 - while (srcY_fp >= nextOutY_srcStart && currentOutY < outHeight) { 494 - memset(rowBuffer, 0, bytesPerRow); 495 - 496 - if (USE_8BIT_OUTPUT && !oneBit) { 497 - for (int x = 0; x < outWidth; x++) { 498 - const uint8_t gray = (rowCount[x] > 0) ? (rowAccum[x] / rowCount[x]) : 0; 499 - rowBuffer[x] = adjustPixel(gray); 500 - } 501 - } else if (oneBit) { 502 - // 1-bit output with Atkinson dithering for better quality 503 - for (int x = 0; x < outWidth; x++) { 504 - const uint8_t gray = (rowCount[x] > 0) ? (rowAccum[x] / rowCount[x]) : 0; 505 - const uint8_t bit = atkinson1BitDitherer ? atkinson1BitDitherer->processPixel(gray, x) 506 - : quantize1bit(gray, x, currentOutY); 507 - // Pack 1-bit value: MSB first, 8 pixels per byte 508 - const int byteIndex = x / 8; 509 - const int bitOffset = 7 - (x % 8); 510 - rowBuffer[byteIndex] |= (bit << bitOffset); 511 - } 512 - if (atkinson1BitDitherer) atkinson1BitDitherer->nextRow(); 513 - } else { 514 - // 2-bit output 515 - for (int x = 0; x < outWidth; x++) { 516 - const uint8_t gray = adjustPixel((rowCount[x] > 0) ? (rowAccum[x] / rowCount[x]) : 0); 517 - uint8_t twoBit; 518 - if (atkinsonDitherer) { 519 - twoBit = atkinsonDitherer->processPixel(gray, x); 520 - } else if (fsDitherer) { 521 - twoBit = fsDitherer->processPixel(gray, x); 522 - } else { 523 - twoBit = quantize(gray, x, currentOutY); 524 - } 525 - const int byteIndex = (x * 2) / 8; 526 - const int bitOffset = 6 - ((x * 2) % 8); 527 - rowBuffer[byteIndex] |= (twoBit << bitOffset); 528 - } 529 - if (atkinsonDitherer) 530 - atkinsonDitherer->nextRow(); 531 - else if (fsDitherer) 532 - fsDitherer->nextRow(); 533 - } 534 - 535 - bmpOut.write(rowBuffer, bytesPerRow); 536 - currentOutY++; 537 - 538 - // Update boundary for next output row 539 - nextOutY_srcStart = static_cast<uint32_t>(currentOutY + 1) * scaleY_fp; 540 - 541 - // For upscaling: don't reset accumulators if next output row uses same source data 542 - // Only reset when we'll move to a new source row 543 - if (srcY_fp >= nextOutY_srcStart) { 544 - // More output rows to emit from same source - keep accumulator data 545 - continue; 546 - } 547 - // Moving to next source row - reset accumulators 548 - memset(rowAccum, 0, outWidth * sizeof(uint32_t)); 549 - memset(rowCount, 0, outWidth * sizeof(uint32_t)); 550 - } 551 - } 552 - } 531 + if (rc != 1 || ctx.error) { 532 + LOG_ERR("JPG", "JPEG decode failed (rc=%d, err=%d)", rc, jpeg->getLastError()); 533 + return false; 553 534 } 554 535 555 536 LOG_DBG("JPG", "Successfully converted JPEG to BMP");
-2
lib/JpegToBmpConverter/JpegToBmpConverter.h
··· 6 6 class ZipFile; 7 7 8 8 class JpegToBmpConverter { 9 - static unsigned char jpegReadCallback(unsigned char* pBuf, unsigned char buf_size, 10 - unsigned char* pBytes_actually_read, void* pCallback_data); 11 9 static bool jpegFileToBmpStreamInternal(FsFile& jpegFile, Print& bmpOut, int targetWidth, int targetHeight, 12 10 bool oneBit, bool crop = true); 13 11
-2087
lib/picojpeg/picojpeg.c
··· 1 - //------------------------------------------------------------------------------ 2 - // picojpeg.c v1.1 - Public domain, Rich Geldreich <richgel99@gmail.com> 3 - // Nov. 27, 2010 - Initial release 4 - // Feb. 9, 2013 - Added H1V2/H2V1 support, cleaned up macros, signed shift fixes 5 - // Also integrated and tested changes from Chris Phoenix <cphoenix@gmail.com>. 6 - //------------------------------------------------------------------------------ 7 - #include "picojpeg.h" 8 - //------------------------------------------------------------------------------ 9 - // Set to 1 if right shifts on signed ints are always unsigned (logical) shifts 10 - // When 1, arithmetic right shifts will be emulated by using a logical shift 11 - // with special case code to ensure the sign bit is replicated. 12 - #define PJPG_RIGHT_SHIFT_IS_ALWAYS_UNSIGNED 0 13 - 14 - // Define PJPG_INLINE to "inline" if your C compiler supports explicit inlining 15 - #define PJPG_INLINE 16 - //------------------------------------------------------------------------------ 17 - typedef unsigned char uint8; 18 - typedef unsigned short uint16; 19 - typedef signed char int8; 20 - typedef signed short int16; 21 - //------------------------------------------------------------------------------ 22 - #if PJPG_RIGHT_SHIFT_IS_ALWAYS_UNSIGNED 23 - static int16 replicateSignBit16(int8 n) { 24 - switch (n) { 25 - case 0: 26 - return 0x0000; 27 - case 1: 28 - return 0x8000; 29 - case 2: 30 - return 0xC000; 31 - case 3: 32 - return 0xE000; 33 - case 4: 34 - return 0xF000; 35 - case 5: 36 - return 0xF800; 37 - case 6: 38 - return 0xFC00; 39 - case 7: 40 - return 0xFE00; 41 - case 8: 42 - return 0xFF00; 43 - case 9: 44 - return 0xFF80; 45 - case 10: 46 - return 0xFFC0; 47 - case 11: 48 - return 0xFFE0; 49 - case 12: 50 - return 0xFFF0; 51 - case 13: 52 - return 0xFFF8; 53 - case 14: 54 - return 0xFFFC; 55 - case 15: 56 - return 0xFFFE; 57 - default: 58 - return 0xFFFF; 59 - } 60 - } 61 - static PJPG_INLINE int16 arithmeticRightShiftN16(int16 x, int8 n) { 62 - int16 r = (uint16)x >> (uint8)n; 63 - if (x < 0) r |= replicateSignBit16(n); 64 - return r; 65 - } 66 - static PJPG_INLINE long arithmeticRightShift8L(long x) { 67 - long r = (unsigned long)x >> 8U; 68 - if (x < 0) r |= ~(~(unsigned long)0U >> 8U); 69 - return r; 70 - } 71 - #define PJPG_ARITH_SHIFT_RIGHT_N_16(x, n) arithmeticRightShiftN16(x, n) 72 - #define PJPG_ARITH_SHIFT_RIGHT_8_L(x) arithmeticRightShift8L(x) 73 - #else 74 - #define PJPG_ARITH_SHIFT_RIGHT_N_16(x, n) ((x) >> (n)) 75 - #define PJPG_ARITH_SHIFT_RIGHT_8_L(x) ((x) >> 8) 76 - #endif 77 - //------------------------------------------------------------------------------ 78 - // Change as needed - the PJPG_MAX_WIDTH/PJPG_MAX_HEIGHT checks are only present 79 - // to quickly detect bogus files. 80 - #define PJPG_MAX_WIDTH 16384 81 - #define PJPG_MAX_HEIGHT 16384 82 - #define PJPG_MAXCOMPSINSCAN 3 83 - //------------------------------------------------------------------------------ 84 - typedef enum { 85 - M_SOF0 = 0xC0, 86 - M_SOF1 = 0xC1, 87 - M_SOF2 = 0xC2, 88 - M_SOF3 = 0xC3, 89 - 90 - M_SOF5 = 0xC5, 91 - M_SOF6 = 0xC6, 92 - M_SOF7 = 0xC7, 93 - 94 - M_JPG = 0xC8, 95 - M_SOF9 = 0xC9, 96 - M_SOF10 = 0xCA, 97 - M_SOF11 = 0xCB, 98 - 99 - M_SOF13 = 0xCD, 100 - M_SOF14 = 0xCE, 101 - M_SOF15 = 0xCF, 102 - 103 - M_DHT = 0xC4, 104 - 105 - M_DAC = 0xCC, 106 - 107 - M_RST0 = 0xD0, 108 - M_RST1 = 0xD1, 109 - M_RST2 = 0xD2, 110 - M_RST3 = 0xD3, 111 - M_RST4 = 0xD4, 112 - M_RST5 = 0xD5, 113 - M_RST6 = 0xD6, 114 - M_RST7 = 0xD7, 115 - 116 - M_SOI = 0xD8, 117 - M_EOI = 0xD9, 118 - M_SOS = 0xDA, 119 - M_DQT = 0xDB, 120 - M_DNL = 0xDC, 121 - M_DRI = 0xDD, 122 - M_DHP = 0xDE, 123 - M_EXP = 0xDF, 124 - 125 - M_APP0 = 0xE0, 126 - M_APP15 = 0xEF, 127 - 128 - M_JPG0 = 0xF0, 129 - M_JPG13 = 0xFD, 130 - M_COM = 0xFE, 131 - 132 - M_TEM = 0x01, 133 - 134 - M_ERROR = 0x100, 135 - 136 - RST0 = 0xD0 137 - } JPEG_MARKER; 138 - //------------------------------------------------------------------------------ 139 - static const int8 ZAG[] = { 140 - 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40, 48, 141 - 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 142 - 30, 37, 44, 51, 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63, 143 - }; 144 - //------------------------------------------------------------------------------ 145 - // 128 bytes 146 - static int16 gCoeffBuf[8 * 8]; 147 - 148 - // 8*8*4 bytes * 3 = 768 149 - static uint8 gMCUBufR[256]; 150 - static uint8 gMCUBufG[256]; 151 - static uint8 gMCUBufB[256]; 152 - 153 - // 256 bytes 154 - static int16 gQuant0[8 * 8]; 155 - static int16 gQuant1[8 * 8]; 156 - 157 - // 6 bytes 158 - static int16 gLastDC[3]; 159 - 160 - typedef struct HuffTableT { 161 - uint16 mMinCode[16]; 162 - uint16 mMaxCode[16]; 163 - uint8 mValPtr[16]; 164 - } HuffTable; 165 - 166 - // DC - 192 167 - static HuffTable gHuffTab0; 168 - 169 - static uint8 gHuffVal0[16]; 170 - 171 - static HuffTable gHuffTab1; 172 - static uint8 gHuffVal1[16]; 173 - 174 - // AC - 672 175 - static HuffTable gHuffTab2; 176 - static uint8 gHuffVal2[256]; 177 - 178 - static HuffTable gHuffTab3; 179 - static uint8 gHuffVal3[256]; 180 - 181 - static uint8 gValidHuffTables; 182 - static uint8 gValidQuantTables; 183 - 184 - static uint8 gTemFlag; 185 - #define PJPG_MAX_IN_BUF_SIZE 256 186 - static uint8 gInBuf[PJPG_MAX_IN_BUF_SIZE]; 187 - static uint8 gInBufOfs; 188 - static uint8 gInBufLeft; 189 - 190 - static uint16 gBitBuf; 191 - static uint8 gBitsLeft; 192 - //------------------------------------------------------------------------------ 193 - static uint16 gImageXSize; 194 - static uint16 gImageYSize; 195 - static uint8 gCompsInFrame; 196 - static uint8 gCompIdent[3]; 197 - static uint8 gCompHSamp[3]; 198 - static uint8 gCompVSamp[3]; 199 - static uint8 gCompQuant[3]; 200 - 201 - static uint16 gRestartInterval; 202 - static uint16 gNextRestartNum; 203 - static uint16 gRestartsLeft; 204 - 205 - static uint8 gCompsInScan; 206 - static uint8 gCompList[3]; 207 - static uint8 gCompDCTab[3]; // 0,1 208 - static uint8 gCompACTab[3]; // 0,1 209 - 210 - static pjpeg_scan_type_t gScanType; 211 - 212 - static uint8 gMaxBlocksPerMCU; 213 - static uint8 gMaxMCUXSize; 214 - static uint8 gMaxMCUYSize; 215 - static uint16 gMaxMCUSPerRow; 216 - static uint16 gMaxMCUSPerCol; 217 - 218 - static uint16 gNumMCUSRemainingX, gNumMCUSRemainingY; 219 - 220 - static uint8 gMCUOrg[6]; 221 - 222 - static pjpeg_need_bytes_callback_t g_pNeedBytesCallback; 223 - static void* g_pCallback_data; 224 - static uint8 gCallbackStatus; 225 - static uint8 gReduce; 226 - //------------------------------------------------------------------------------ 227 - static void fillInBuf(void) { 228 - unsigned char status; 229 - 230 - // Reserve a few bytes at the beginning of the buffer for putting back ("stuffing") chars. 231 - gInBufOfs = 4; 232 - gInBufLeft = 0; 233 - 234 - status = (*g_pNeedBytesCallback)(gInBuf + gInBufOfs, PJPG_MAX_IN_BUF_SIZE - gInBufOfs, &gInBufLeft, g_pCallback_data); 235 - if (status) { 236 - // The user provided need bytes callback has indicated an error, so record the error and continue trying to decode. 237 - // The highest level pjpeg entrypoints will catch the error and return the non-zero status. 238 - gCallbackStatus = status; 239 - } 240 - } 241 - //------------------------------------------------------------------------------ 242 - static PJPG_INLINE uint8 getChar(void) { 243 - if (!gInBufLeft) { 244 - fillInBuf(); 245 - if (!gInBufLeft) { 246 - gTemFlag = ~gTemFlag; 247 - return gTemFlag ? 0xFF : 0xD9; 248 - } 249 - } 250 - 251 - gInBufLeft--; 252 - return gInBuf[gInBufOfs++]; 253 - } 254 - //------------------------------------------------------------------------------ 255 - static PJPG_INLINE void stuffChar(uint8 i) { 256 - gInBufOfs--; 257 - gInBuf[gInBufOfs] = i; 258 - gInBufLeft++; 259 - } 260 - //------------------------------------------------------------------------------ 261 - static PJPG_INLINE uint8 getOctet(uint8 FFCheck) { 262 - uint8 c = getChar(); 263 - 264 - if ((FFCheck) && (c == 0xFF)) { 265 - uint8 n = getChar(); 266 - 267 - if (n) { 268 - stuffChar(n); 269 - stuffChar(0xFF); 270 - } 271 - } 272 - 273 - return c; 274 - } 275 - //------------------------------------------------------------------------------ 276 - static uint16 getBits(uint8 numBits, uint8 FFCheck) { 277 - uint8 origBits = numBits; 278 - uint16 ret = gBitBuf; 279 - 280 - if (numBits > 8) { 281 - numBits -= 8; 282 - 283 - gBitBuf <<= gBitsLeft; 284 - 285 - gBitBuf |= getOctet(FFCheck); 286 - 287 - gBitBuf <<= (8 - gBitsLeft); 288 - 289 - ret = (ret & 0xFF00) | (gBitBuf >> 8); 290 - } 291 - 292 - if (gBitsLeft < numBits) { 293 - gBitBuf <<= gBitsLeft; 294 - 295 - gBitBuf |= getOctet(FFCheck); 296 - 297 - gBitBuf <<= (numBits - gBitsLeft); 298 - 299 - gBitsLeft = 8 - (numBits - gBitsLeft); 300 - } else { 301 - gBitsLeft = (uint8)(gBitsLeft - numBits); 302 - gBitBuf <<= numBits; 303 - } 304 - 305 - return ret >> (16 - origBits); 306 - } 307 - //------------------------------------------------------------------------------ 308 - static PJPG_INLINE uint16 getBits1(uint8 numBits) { return getBits(numBits, 0); } 309 - //------------------------------------------------------------------------------ 310 - static PJPG_INLINE uint16 getBits2(uint8 numBits) { return getBits(numBits, 1); } 311 - //------------------------------------------------------------------------------ 312 - static PJPG_INLINE uint8 getBit(void) { 313 - uint8 ret = 0; 314 - if (gBitBuf & 0x8000) ret = 1; 315 - 316 - if (!gBitsLeft) { 317 - gBitBuf |= getOctet(1); 318 - 319 - gBitsLeft += 8; 320 - } 321 - 322 - gBitsLeft--; 323 - gBitBuf <<= 1; 324 - 325 - return ret; 326 - } 327 - //------------------------------------------------------------------------------ 328 - static uint16 getExtendTest(uint8 i) { 329 - switch (i) { 330 - case 0: 331 - return 0; 332 - case 1: 333 - return 0x0001; 334 - case 2: 335 - return 0x0002; 336 - case 3: 337 - return 0x0004; 338 - case 4: 339 - return 0x0008; 340 - case 5: 341 - return 0x0010; 342 - case 6: 343 - return 0x0020; 344 - case 7: 345 - return 0x0040; 346 - case 8: 347 - return 0x0080; 348 - case 9: 349 - return 0x0100; 350 - case 10: 351 - return 0x0200; 352 - case 11: 353 - return 0x0400; 354 - case 12: 355 - return 0x0800; 356 - case 13: 357 - return 0x1000; 358 - case 14: 359 - return 0x2000; 360 - case 15: 361 - return 0x4000; 362 - default: 363 - return 0; 364 - } 365 - } 366 - //------------------------------------------------------------------------------ 367 - static int16 getExtendOffset(uint8 i) { 368 - switch (i) { 369 - case 0: 370 - return 0; 371 - case 1: 372 - return ((-1) << 1) + 1; 373 - case 2: 374 - return ((-1) << 2) + 1; 375 - case 3: 376 - return ((-1) << 3) + 1; 377 - case 4: 378 - return ((-1) << 4) + 1; 379 - case 5: 380 - return ((-1) << 5) + 1; 381 - case 6: 382 - return ((-1) << 6) + 1; 383 - case 7: 384 - return ((-1) << 7) + 1; 385 - case 8: 386 - return ((-1) << 8) + 1; 387 - case 9: 388 - return ((-1) << 9) + 1; 389 - case 10: 390 - return ((-1) << 10) + 1; 391 - case 11: 392 - return ((-1) << 11) + 1; 393 - case 12: 394 - return ((-1) << 12) + 1; 395 - case 13: 396 - return ((-1) << 13) + 1; 397 - case 14: 398 - return ((-1) << 14) + 1; 399 - case 15: 400 - return ((-1) << 15) + 1; 401 - default: 402 - return 0; 403 - } 404 - }; 405 - //------------------------------------------------------------------------------ 406 - static PJPG_INLINE int16 huffExtend(uint16 x, uint8 s) { 407 - return ((x < getExtendTest(s)) ? ((int16)x + getExtendOffset(s)) : (int16)x); 408 - } 409 - //------------------------------------------------------------------------------ 410 - static PJPG_INLINE uint8 huffDecode(const HuffTable* pHuffTable, const uint8* pHuffVal) { 411 - uint8 i = 0; 412 - uint8 j; 413 - uint16 code = getBit(); 414 - 415 - // This func only reads a bit at a time, which on modern CPU's is not terribly efficient. 416 - // But on microcontrollers without strong integer shifting support this seems like a 417 - // more reasonable approach. 418 - for (;;) { 419 - uint16 maxCode; 420 - 421 - if (i == 16) return 0; 422 - 423 - maxCode = pHuffTable->mMaxCode[i]; 424 - if ((code <= maxCode) && (maxCode != 0xFFFF)) break; 425 - 426 - i++; 427 - code <<= 1; 428 - code |= getBit(); 429 - } 430 - 431 - j = pHuffTable->mValPtr[i]; 432 - j = (uint8)(j + (code - pHuffTable->mMinCode[i])); 433 - 434 - return pHuffVal[j]; 435 - } 436 - //------------------------------------------------------------------------------ 437 - static void huffCreate(const uint8* pBits, HuffTable* pHuffTable) { 438 - uint8 i = 0; 439 - uint8 j = 0; 440 - 441 - uint16 code = 0; 442 - 443 - for (;;) { 444 - uint8 num = pBits[i]; 445 - 446 - if (!num) { 447 - pHuffTable->mMinCode[i] = 0x0000; 448 - pHuffTable->mMaxCode[i] = 0xFFFF; 449 - pHuffTable->mValPtr[i] = 0; 450 - } else { 451 - pHuffTable->mMinCode[i] = code; 452 - pHuffTable->mMaxCode[i] = code + num - 1; 453 - pHuffTable->mValPtr[i] = j; 454 - 455 - j = (uint8)(j + num); 456 - 457 - code = (uint16)(code + num); 458 - } 459 - 460 - code <<= 1; 461 - 462 - i++; 463 - if (i > 15) break; 464 - } 465 - } 466 - //------------------------------------------------------------------------------ 467 - static HuffTable* getHuffTable(uint8 index) { 468 - // 0-1 = DC 469 - // 2-3 = AC 470 - switch (index) { 471 - case 0: 472 - return &gHuffTab0; 473 - case 1: 474 - return &gHuffTab1; 475 - case 2: 476 - return &gHuffTab2; 477 - case 3: 478 - return &gHuffTab3; 479 - default: 480 - return 0; 481 - } 482 - } 483 - //------------------------------------------------------------------------------ 484 - static uint8* getHuffVal(uint8 index) { 485 - // 0-1 = DC 486 - // 2-3 = AC 487 - switch (index) { 488 - case 0: 489 - return gHuffVal0; 490 - case 1: 491 - return gHuffVal1; 492 - case 2: 493 - return gHuffVal2; 494 - case 3: 495 - return gHuffVal3; 496 - default: 497 - return 0; 498 - } 499 - } 500 - //------------------------------------------------------------------------------ 501 - static uint16 getMaxHuffCodes(uint8 index) { return (index < 2) ? 12 : 255; } 502 - //------------------------------------------------------------------------------ 503 - static uint8 readDHTMarker(void) { 504 - uint8 bits[16]; 505 - uint16 left = getBits1(16); 506 - 507 - if (left < 2) return PJPG_BAD_DHT_MARKER; 508 - 509 - left -= 2; 510 - 511 - while (left) { 512 - uint8 i, tableIndex, index; 513 - uint8* pHuffVal; 514 - HuffTable* pHuffTable; 515 - uint16 count, totalRead; 516 - 517 - index = (uint8)getBits1(8); 518 - 519 - if (((index & 0xF) > 1) || ((index & 0xF0) > 0x10)) return PJPG_BAD_DHT_INDEX; 520 - 521 - tableIndex = ((index >> 3) & 2) + (index & 1); 522 - 523 - pHuffTable = getHuffTable(tableIndex); 524 - pHuffVal = getHuffVal(tableIndex); 525 - 526 - gValidHuffTables |= (1 << tableIndex); 527 - 528 - count = 0; 529 - for (i = 0; i <= 15; i++) { 530 - uint8 n = (uint8)getBits1(8); 531 - bits[i] = n; 532 - count = (uint16)(count + n); 533 - } 534 - 535 - if (count > getMaxHuffCodes(tableIndex)) return PJPG_BAD_DHT_COUNTS; 536 - 537 - for (i = 0; i < count; i++) pHuffVal[i] = (uint8)getBits1(8); 538 - 539 - totalRead = 1 + 16 + count; 540 - 541 - if (left < totalRead) return PJPG_BAD_DHT_MARKER; 542 - 543 - left = (uint16)(left - totalRead); 544 - 545 - huffCreate(bits, pHuffTable); 546 - } 547 - 548 - return 0; 549 - } 550 - //------------------------------------------------------------------------------ 551 - static void createWinogradQuant(int16* pQuant); 552 - 553 - static uint8 readDQTMarker(void) { 554 - uint16 left = getBits1(16); 555 - 556 - if (left < 2) return PJPG_BAD_DQT_MARKER; 557 - 558 - left -= 2; 559 - 560 - while (left) { 561 - uint8 i; 562 - uint8 n = (uint8)getBits1(8); 563 - uint8 prec = n >> 4; 564 - uint16 totalRead; 565 - 566 - n &= 0x0F; 567 - 568 - if (n > 1) return PJPG_BAD_DQT_TABLE; 569 - 570 - gValidQuantTables |= (n ? 2 : 1); 571 - 572 - // read quantization entries, in zag order 573 - for (i = 0; i < 64; i++) { 574 - uint16 temp = getBits1(8); 575 - 576 - if (prec) temp = (temp << 8) + getBits1(8); 577 - 578 - if (n) 579 - gQuant1[i] = (int16)temp; 580 - else 581 - gQuant0[i] = (int16)temp; 582 - } 583 - 584 - createWinogradQuant(n ? gQuant1 : gQuant0); 585 - 586 - totalRead = 64 + 1; 587 - 588 - if (prec) totalRead += 64; 589 - 590 - if (left < totalRead) return PJPG_BAD_DQT_LENGTH; 591 - 592 - left = (uint16)(left - totalRead); 593 - } 594 - 595 - return 0; 596 - } 597 - //------------------------------------------------------------------------------ 598 - static uint8 readSOFMarker(void) { 599 - uint8 i; 600 - uint16 left = getBits1(16); 601 - 602 - if (getBits1(8) != 8) return PJPG_BAD_PRECISION; 603 - 604 - gImageYSize = getBits1(16); 605 - 606 - if ((!gImageYSize) || (gImageYSize > PJPG_MAX_HEIGHT)) return PJPG_BAD_HEIGHT; 607 - 608 - gImageXSize = getBits1(16); 609 - 610 - if ((!gImageXSize) || (gImageXSize > PJPG_MAX_WIDTH)) return PJPG_BAD_WIDTH; 611 - 612 - gCompsInFrame = (uint8)getBits1(8); 613 - 614 - if (gCompsInFrame > 3) return PJPG_TOO_MANY_COMPONENTS; 615 - 616 - if (left != (gCompsInFrame + gCompsInFrame + gCompsInFrame + 8)) return PJPG_BAD_SOF_LENGTH; 617 - 618 - for (i = 0; i < gCompsInFrame; i++) { 619 - gCompIdent[i] = (uint8)getBits1(8); 620 - gCompHSamp[i] = (uint8)getBits1(4); 621 - gCompVSamp[i] = (uint8)getBits1(4); 622 - gCompQuant[i] = (uint8)getBits1(8); 623 - 624 - if (gCompQuant[i] > 1) return PJPG_UNSUPPORTED_QUANT_TABLE; 625 - } 626 - 627 - return 0; 628 - } 629 - //------------------------------------------------------------------------------ 630 - // Used to skip unrecognized markers. 631 - static uint8 skipVariableMarker(void) { 632 - uint16 left = getBits1(16); 633 - 634 - if (left < 2) return PJPG_BAD_VARIABLE_MARKER; 635 - 636 - left -= 2; 637 - 638 - while (left) { 639 - getBits1(8); 640 - left--; 641 - } 642 - 643 - return 0; 644 - } 645 - //------------------------------------------------------------------------------ 646 - // Read a define restart interval (DRI) marker. 647 - static uint8 readDRIMarker(void) { 648 - if (getBits1(16) != 4) return PJPG_BAD_DRI_LENGTH; 649 - 650 - gRestartInterval = getBits1(16); 651 - 652 - return 0; 653 - } 654 - //------------------------------------------------------------------------------ 655 - // Read a start of scan (SOS) marker. 656 - static uint8 readSOSMarker(void) { 657 - uint8 i; 658 - uint16 left = getBits1(16); 659 - uint8 spectral_start, spectral_end, successive_high, successive_low; 660 - 661 - gCompsInScan = (uint8)getBits1(8); 662 - 663 - left -= 3; 664 - 665 - if ((left != (gCompsInScan + gCompsInScan + 3)) || (gCompsInScan < 1) || (gCompsInScan > PJPG_MAXCOMPSINSCAN)) 666 - return PJPG_BAD_SOS_LENGTH; 667 - 668 - for (i = 0; i < gCompsInScan; i++) { 669 - uint8 cc = (uint8)getBits1(8); 670 - uint8 c = (uint8)getBits1(8); 671 - uint8 ci; 672 - 673 - left -= 2; 674 - 675 - for (ci = 0; ci < gCompsInFrame; ci++) 676 - if (cc == gCompIdent[ci]) break; 677 - 678 - if (ci >= gCompsInFrame) return PJPG_BAD_SOS_COMP_ID; 679 - 680 - gCompList[i] = ci; 681 - gCompDCTab[ci] = (c >> 4) & 15; 682 - gCompACTab[ci] = (c & 15); 683 - } 684 - 685 - spectral_start = (uint8)getBits1(8); 686 - spectral_end = (uint8)getBits1(8); 687 - successive_high = (uint8)getBits1(4); 688 - successive_low = (uint8)getBits1(4); 689 - 690 - left -= 3; 691 - 692 - while (left) { 693 - getBits1(8); 694 - left--; 695 - } 696 - 697 - return 0; 698 - } 699 - //------------------------------------------------------------------------------ 700 - static uint8 nextMarker(void) { 701 - uint8 c; 702 - uint8 bytes = 0; 703 - 704 - do { 705 - do { 706 - bytes++; 707 - 708 - c = (uint8)getBits1(8); 709 - 710 - } while (c != 0xFF); 711 - 712 - do { 713 - c = (uint8)getBits1(8); 714 - 715 - } while (c == 0xFF); 716 - 717 - } while (c == 0); 718 - 719 - // If bytes > 0 here, there where extra bytes before the marker (not good). 720 - 721 - return c; 722 - } 723 - //------------------------------------------------------------------------------ 724 - // Process markers. Returns when an SOFx, SOI, EOI, or SOS marker is 725 - // encountered. 726 - static uint8 processMarkers(uint8* pMarker) { 727 - for (;;) { 728 - uint8 c = nextMarker(); 729 - 730 - switch (c) { 731 - case M_SOF0: 732 - case M_SOF1: 733 - case M_SOF2: 734 - case M_SOF3: 735 - case M_SOF5: 736 - case M_SOF6: 737 - case M_SOF7: 738 - // case M_JPG: 739 - case M_SOF9: 740 - case M_SOF10: 741 - case M_SOF11: 742 - case M_SOF13: 743 - case M_SOF14: 744 - case M_SOF15: 745 - case M_SOI: 746 - case M_EOI: 747 - case M_SOS: { 748 - *pMarker = c; 749 - return 0; 750 - } 751 - case M_DHT: { 752 - readDHTMarker(); 753 - break; 754 - } 755 - // Sorry, no arithmetic support at this time. Dumb patents! 756 - case M_DAC: { 757 - return PJPG_NO_ARITHMITIC_SUPPORT; 758 - } 759 - case M_DQT: { 760 - readDQTMarker(); 761 - break; 762 - } 763 - case M_DRI: { 764 - readDRIMarker(); 765 - break; 766 - } 767 - // case M_APP0: /* no need to read the JFIF marker */ 768 - 769 - case M_JPG: 770 - case M_RST0: /* no parameters */ 771 - case M_RST1: 772 - case M_RST2: 773 - case M_RST3: 774 - case M_RST4: 775 - case M_RST5: 776 - case M_RST6: 777 - case M_RST7: 778 - case M_TEM: { 779 - return PJPG_UNEXPECTED_MARKER; 780 - } 781 - default: /* must be DNL, DHP, EXP, APPn, JPGn, COM, or RESn or APP0 */ 782 - { 783 - skipVariableMarker(); 784 - break; 785 - } 786 - } 787 - } 788 - // return 0; 789 - } 790 - //------------------------------------------------------------------------------ 791 - // Finds the start of image (SOI) marker. 792 - static uint8 locateSOIMarker(void) { 793 - uint16 bytesleft; 794 - 795 - uint8 lastchar = (uint8)getBits1(8); 796 - 797 - uint8 thischar = (uint8)getBits1(8); 798 - 799 - /* ok if it's a normal JPEG file without a special header */ 800 - 801 - if ((lastchar == 0xFF) && (thischar == M_SOI)) return 0; 802 - 803 - bytesleft = 4096; // 512; 804 - 805 - for (;;) { 806 - if (--bytesleft == 0) return PJPG_NOT_JPEG; 807 - 808 - lastchar = thischar; 809 - 810 - thischar = (uint8)getBits1(8); 811 - 812 - if (lastchar == 0xFF) { 813 - if (thischar == M_SOI) 814 - break; 815 - else if (thischar == M_EOI) // getBits1 will keep returning M_EOI if we read past the end 816 - return PJPG_NOT_JPEG; 817 - } 818 - } 819 - 820 - /* Check the next character after marker: if it's not 0xFF, it can't 821 - be the start of the next marker, so the file is bad */ 822 - 823 - thischar = (uint8)((gBitBuf >> 8) & 0xFF); 824 - 825 - if (thischar != 0xFF) return PJPG_NOT_JPEG; 826 - 827 - return 0; 828 - } 829 - //------------------------------------------------------------------------------ 830 - // Find a start of frame (SOF) marker. 831 - static uint8 locateSOFMarker(void) { 832 - uint8 c; 833 - 834 - uint8 status = locateSOIMarker(); 835 - if (status) return status; 836 - 837 - status = processMarkers(&c); 838 - if (status) return status; 839 - 840 - switch (c) { 841 - case M_SOF2: { 842 - // Progressive JPEG - not supported by picojpeg (would require too 843 - // much memory, or too many IDCT's for embedded systems). 844 - return PJPG_UNSUPPORTED_MODE; 845 - } 846 - case M_SOF0: /* baseline DCT */ 847 - { 848 - status = readSOFMarker(); 849 - if (status) return status; 850 - 851 - break; 852 - } 853 - case M_SOF9: { 854 - return PJPG_NO_ARITHMITIC_SUPPORT; 855 - } 856 - case M_SOF1: /* extended sequential DCT */ 857 - default: { 858 - return PJPG_UNSUPPORTED_MARKER; 859 - } 860 - } 861 - 862 - return 0; 863 - } 864 - //------------------------------------------------------------------------------ 865 - // Find a start of scan (SOS) marker. 866 - static uint8 locateSOSMarker(uint8* pFoundEOI) { 867 - uint8 c; 868 - uint8 status; 869 - 870 - *pFoundEOI = 0; 871 - 872 - status = processMarkers(&c); 873 - if (status) return status; 874 - 875 - if (c == M_EOI) { 876 - *pFoundEOI = 1; 877 - return 0; 878 - } else if (c != M_SOS) 879 - return PJPG_UNEXPECTED_MARKER; 880 - 881 - return readSOSMarker(); 882 - } 883 - //------------------------------------------------------------------------------ 884 - static uint8 init(void) { 885 - gImageXSize = 0; 886 - gImageYSize = 0; 887 - gCompsInFrame = 0; 888 - gRestartInterval = 0; 889 - gCompsInScan = 0; 890 - gValidHuffTables = 0; 891 - gValidQuantTables = 0; 892 - gTemFlag = 0; 893 - gInBufOfs = 0; 894 - gInBufLeft = 0; 895 - gBitBuf = 0; 896 - gBitsLeft = 8; 897 - 898 - getBits1(8); 899 - getBits1(8); 900 - 901 - return 0; 902 - } 903 - //------------------------------------------------------------------------------ 904 - // This method throws back into the stream any bytes that where read 905 - // into the bit buffer during initial marker scanning. 906 - static void fixInBuffer(void) { 907 - /* In case any 0xFF's where pulled into the buffer during marker scanning */ 908 - 909 - if (gBitsLeft > 0) stuffChar((uint8)gBitBuf); 910 - 911 - stuffChar((uint8)(gBitBuf >> 8)); 912 - 913 - gBitsLeft = 8; 914 - getBits2(8); 915 - getBits2(8); 916 - } 917 - //------------------------------------------------------------------------------ 918 - // Restart interval processing. 919 - static uint8 processRestart(void) { 920 - // Let's scan a little bit to find the marker, but not _too_ far. 921 - // 1536 is a "fudge factor" that determines how much to scan. 922 - uint16 i; 923 - uint8 c = 0; 924 - 925 - for (i = 1536; i > 0; i--) 926 - if (getChar() == 0xFF) break; 927 - 928 - if (i == 0) return PJPG_BAD_RESTART_MARKER; 929 - 930 - for (; i > 0; i--) 931 - if ((c = getChar()) != 0xFF) break; 932 - 933 - if (i == 0) return PJPG_BAD_RESTART_MARKER; 934 - 935 - // Is it the expected marker? If not, something bad happened. 936 - if (c != (gNextRestartNum + M_RST0)) return PJPG_BAD_RESTART_MARKER; 937 - 938 - // Reset each component's DC prediction values. 939 - gLastDC[0] = 0; 940 - gLastDC[1] = 0; 941 - gLastDC[2] = 0; 942 - 943 - gRestartsLeft = gRestartInterval; 944 - 945 - gNextRestartNum = (gNextRestartNum + 1) & 7; 946 - 947 - // Get the bit buffer going again 948 - 949 - gBitsLeft = 8; 950 - getBits2(8); 951 - getBits2(8); 952 - 953 - return 0; 954 - } 955 - //------------------------------------------------------------------------------ 956 - // FIXME: findEOI() is not actually called at the end of the image 957 - // (it's optional, and probably not needed on embedded devices) 958 - static uint8 findEOI(void) { 959 - uint8 c; 960 - uint8 status; 961 - 962 - // Prime the bit buffer 963 - gBitsLeft = 8; 964 - getBits1(8); 965 - getBits1(8); 966 - 967 - // The next marker _should_ be EOI 968 - status = processMarkers(&c); 969 - if (status) 970 - return status; 971 - else if (gCallbackStatus) 972 - return gCallbackStatus; 973 - 974 - // gTotalBytesRead -= in_buf_left; 975 - if (c != M_EOI) return PJPG_UNEXPECTED_MARKER; 976 - 977 - return 0; 978 - } 979 - //------------------------------------------------------------------------------ 980 - static uint8 checkHuffTables(void) { 981 - uint8 i; 982 - 983 - for (i = 0; i < gCompsInScan; i++) { 984 - uint8 compDCTab = gCompDCTab[gCompList[i]]; 985 - uint8 compACTab = gCompACTab[gCompList[i]] + 2; 986 - 987 - if (((gValidHuffTables & (1 << compDCTab)) == 0) || ((gValidHuffTables & (1 << compACTab)) == 0)) 988 - return PJPG_UNDEFINED_HUFF_TABLE; 989 - } 990 - 991 - return 0; 992 - } 993 - //------------------------------------------------------------------------------ 994 - static uint8 checkQuantTables(void) { 995 - uint8 i; 996 - 997 - for (i = 0; i < gCompsInScan; i++) { 998 - uint8 compQuantMask = gCompQuant[gCompList[i]] ? 2 : 1; 999 - 1000 - if ((gValidQuantTables & compQuantMask) == 0) return PJPG_UNDEFINED_QUANT_TABLE; 1001 - } 1002 - 1003 - return 0; 1004 - } 1005 - //------------------------------------------------------------------------------ 1006 - static uint8 initScan(void) { 1007 - uint8 foundEOI; 1008 - uint8 status = locateSOSMarker(&foundEOI); 1009 - if (status) return status; 1010 - if (foundEOI) return PJPG_UNEXPECTED_MARKER; 1011 - 1012 - status = checkHuffTables(); 1013 - if (status) return status; 1014 - 1015 - status = checkQuantTables(); 1016 - if (status) return status; 1017 - 1018 - gLastDC[0] = 0; 1019 - gLastDC[1] = 0; 1020 - gLastDC[2] = 0; 1021 - 1022 - if (gRestartInterval) { 1023 - gRestartsLeft = gRestartInterval; 1024 - gNextRestartNum = 0; 1025 - } 1026 - 1027 - fixInBuffer(); 1028 - 1029 - return 0; 1030 - } 1031 - //------------------------------------------------------------------------------ 1032 - static uint8 initFrame(void) { 1033 - if (gCompsInFrame == 1) { 1034 - if ((gCompHSamp[0] != 1) || (gCompVSamp[0] != 1)) return PJPG_UNSUPPORTED_SAMP_FACTORS; 1035 - 1036 - gScanType = PJPG_GRAYSCALE; 1037 - 1038 - gMaxBlocksPerMCU = 1; 1039 - gMCUOrg[0] = 0; 1040 - 1041 - gMaxMCUXSize = 8; 1042 - gMaxMCUYSize = 8; 1043 - } else if (gCompsInFrame == 3) { 1044 - if (((gCompHSamp[1] != 1) || (gCompVSamp[1] != 1)) || ((gCompHSamp[2] != 1) || (gCompVSamp[2] != 1))) 1045 - return PJPG_UNSUPPORTED_SAMP_FACTORS; 1046 - 1047 - if ((gCompHSamp[0] == 1) && (gCompVSamp[0] == 1)) { 1048 - gScanType = PJPG_YH1V1; 1049 - 1050 - gMaxBlocksPerMCU = 3; 1051 - gMCUOrg[0] = 0; 1052 - gMCUOrg[1] = 1; 1053 - gMCUOrg[2] = 2; 1054 - 1055 - gMaxMCUXSize = 8; 1056 - gMaxMCUYSize = 8; 1057 - } else if ((gCompHSamp[0] == 1) && (gCompVSamp[0] == 2)) { 1058 - gScanType = PJPG_YH1V2; 1059 - 1060 - gMaxBlocksPerMCU = 4; 1061 - gMCUOrg[0] = 0; 1062 - gMCUOrg[1] = 0; 1063 - gMCUOrg[2] = 1; 1064 - gMCUOrg[3] = 2; 1065 - 1066 - gMaxMCUXSize = 8; 1067 - gMaxMCUYSize = 16; 1068 - } else if ((gCompHSamp[0] == 2) && (gCompVSamp[0] == 1)) { 1069 - gScanType = PJPG_YH2V1; 1070 - 1071 - gMaxBlocksPerMCU = 4; 1072 - gMCUOrg[0] = 0; 1073 - gMCUOrg[1] = 0; 1074 - gMCUOrg[2] = 1; 1075 - gMCUOrg[3] = 2; 1076 - 1077 - gMaxMCUXSize = 16; 1078 - gMaxMCUYSize = 8; 1079 - } else if ((gCompHSamp[0] == 2) && (gCompVSamp[0] == 2)) { 1080 - gScanType = PJPG_YH2V2; 1081 - 1082 - gMaxBlocksPerMCU = 6; 1083 - gMCUOrg[0] = 0; 1084 - gMCUOrg[1] = 0; 1085 - gMCUOrg[2] = 0; 1086 - gMCUOrg[3] = 0; 1087 - gMCUOrg[4] = 1; 1088 - gMCUOrg[5] = 2; 1089 - 1090 - gMaxMCUXSize = 16; 1091 - gMaxMCUYSize = 16; 1092 - } else 1093 - return PJPG_UNSUPPORTED_SAMP_FACTORS; 1094 - } else 1095 - return PJPG_UNSUPPORTED_COLORSPACE; 1096 - 1097 - gMaxMCUSPerRow = (gImageXSize + (gMaxMCUXSize - 1)) >> ((gMaxMCUXSize == 8) ? 3 : 4); 1098 - gMaxMCUSPerCol = (gImageYSize + (gMaxMCUYSize - 1)) >> ((gMaxMCUYSize == 8) ? 3 : 4); 1099 - 1100 - // This can overflow on large JPEG's. 1101 - // gNumMCUSRemaining = gMaxMCUSPerRow * gMaxMCUSPerCol; 1102 - gNumMCUSRemainingX = gMaxMCUSPerRow; 1103 - gNumMCUSRemainingY = gMaxMCUSPerCol; 1104 - 1105 - return 0; 1106 - } 1107 - //---------------------------------------------------------------------------- 1108 - // Winograd IDCT: 5 multiplies per row/col, up to 80 muls for the 2D IDCT 1109 - 1110 - #define PJPG_DCT_SCALE_BITS 7 1111 - 1112 - #define PJPG_DCT_SCALE (1U << PJPG_DCT_SCALE_BITS) 1113 - 1114 - #define PJPG_DESCALE(x) PJPG_ARITH_SHIFT_RIGHT_N_16(((x) + (1 << (PJPG_DCT_SCALE_BITS - 1))), PJPG_DCT_SCALE_BITS) 1115 - 1116 - #define PJPG_WFIX(x) ((x) * PJPG_DCT_SCALE + 0.5f) 1117 - 1118 - #define PJPG_WINOGRAD_QUANT_SCALE_BITS 10 1119 - 1120 - const uint8 gWinogradQuant[] = { 1121 - 128, 178, 178, 167, 246, 167, 151, 232, 232, 151, 128, 209, 219, 209, 128, 101, 178, 197, 197, 178, 101, 69, 1122 - 139, 167, 177, 167, 139, 69, 35, 96, 131, 151, 151, 131, 96, 35, 49, 91, 118, 128, 118, 91, 49, 46, 1123 - 81, 101, 101, 81, 46, 42, 69, 79, 69, 42, 35, 54, 54, 35, 28, 37, 28, 19, 19, 10, 1124 - }; 1125 - 1126 - // Multiply quantization matrix by the Winograd IDCT scale factors 1127 - static void createWinogradQuant(int16* pQuant) { 1128 - uint8 i; 1129 - 1130 - for (i = 0; i < 64; i++) { 1131 - long x = pQuant[i]; 1132 - x *= gWinogradQuant[i]; 1133 - pQuant[i] = (int16)((x + (1 << (PJPG_WINOGRAD_QUANT_SCALE_BITS - PJPG_DCT_SCALE_BITS - 1))) >> 1134 - (PJPG_WINOGRAD_QUANT_SCALE_BITS - PJPG_DCT_SCALE_BITS)); 1135 - } 1136 - } 1137 - 1138 - // These multiply helper functions are the 4 types of signed multiplies needed by the Winograd IDCT. 1139 - // A smart C compiler will optimize them to use 16x8 = 24 bit muls, if not you may need to tweak 1140 - // these functions or drop to CPU specific inline assembly. 1141 - 1142 - // 1/cos(4*pi/16) 1143 - // 362, 256+106 1144 - static PJPG_INLINE int16 imul_b1_b3(int16 w) { 1145 - long x = (w * 362L); 1146 - x += 128L; 1147 - return (int16)(PJPG_ARITH_SHIFT_RIGHT_8_L(x)); 1148 - } 1149 - 1150 - // 1/cos(6*pi/16) 1151 - // 669, 256+256+157 1152 - static PJPG_INLINE int16 imul_b2(int16 w) { 1153 - long x = (w * 669L); 1154 - x += 128L; 1155 - return (int16)(PJPG_ARITH_SHIFT_RIGHT_8_L(x)); 1156 - } 1157 - 1158 - // 1/cos(2*pi/16) 1159 - // 277, 256+21 1160 - static PJPG_INLINE int16 imul_b4(int16 w) { 1161 - long x = (w * 277L); 1162 - x += 128L; 1163 - return (int16)(PJPG_ARITH_SHIFT_RIGHT_8_L(x)); 1164 - } 1165 - 1166 - // 1/(cos(2*pi/16) + cos(6*pi/16)) 1167 - // 196, 196 1168 - static PJPG_INLINE int16 imul_b5(int16 w) { 1169 - long x = (w * 196L); 1170 - x += 128L; 1171 - return (int16)(PJPG_ARITH_SHIFT_RIGHT_8_L(x)); 1172 - } 1173 - 1174 - static PJPG_INLINE uint8 clamp(int16 s) { 1175 - if ((uint16)s > 255U) { 1176 - if (s < 0) 1177 - return 0; 1178 - else if (s > 255) 1179 - return 255; 1180 - } 1181 - 1182 - return (uint8)s; 1183 - } 1184 - 1185 - static void idctRows(void) { 1186 - uint8 i; 1187 - int16* pSrc = gCoeffBuf; 1188 - 1189 - for (i = 0; i < 8; i++) { 1190 - if ((pSrc[1] | pSrc[2] | pSrc[3] | pSrc[4] | pSrc[5] | pSrc[6] | pSrc[7]) == 0) { 1191 - // Short circuit the 1D IDCT if only the DC component is non-zero 1192 - int16 src0 = *pSrc; 1193 - 1194 - *(pSrc + 1) = src0; 1195 - *(pSrc + 2) = src0; 1196 - *(pSrc + 3) = src0; 1197 - *(pSrc + 4) = src0; 1198 - *(pSrc + 5) = src0; 1199 - *(pSrc + 6) = src0; 1200 - *(pSrc + 7) = src0; 1201 - } else { 1202 - int16 src4 = *(pSrc + 5); 1203 - int16 src7 = *(pSrc + 3); 1204 - int16 x4 = src4 - src7; 1205 - int16 x7 = src4 + src7; 1206 - 1207 - int16 src5 = *(pSrc + 1); 1208 - int16 src6 = *(pSrc + 7); 1209 - int16 x5 = src5 + src6; 1210 - int16 x6 = src5 - src6; 1211 - 1212 - int16 tmp1 = imul_b5(x4 - x6); 1213 - int16 stg26 = imul_b4(x6) - tmp1; 1214 - 1215 - int16 x24 = tmp1 - imul_b2(x4); 1216 - 1217 - int16 x15 = x5 - x7; 1218 - int16 x17 = x5 + x7; 1219 - 1220 - int16 tmp2 = stg26 - x17; 1221 - int16 tmp3 = imul_b1_b3(x15) - tmp2; 1222 - int16 x44 = tmp3 + x24; 1223 - 1224 - int16 src0 = *(pSrc + 0); 1225 - int16 src1 = *(pSrc + 4); 1226 - int16 x30 = src0 + src1; 1227 - int16 x31 = src0 - src1; 1228 - 1229 - int16 src2 = *(pSrc + 2); 1230 - int16 src3 = *(pSrc + 6); 1231 - int16 x12 = src2 - src3; 1232 - int16 x13 = src2 + src3; 1233 - 1234 - int16 x32 = imul_b1_b3(x12) - x13; 1235 - 1236 - int16 x40 = x30 + x13; 1237 - int16 x43 = x30 - x13; 1238 - int16 x41 = x31 + x32; 1239 - int16 x42 = x31 - x32; 1240 - 1241 - *(pSrc + 0) = x40 + x17; 1242 - *(pSrc + 1) = x41 + tmp2; 1243 - *(pSrc + 2) = x42 + tmp3; 1244 - *(pSrc + 3) = x43 - x44; 1245 - *(pSrc + 4) = x43 + x44; 1246 - *(pSrc + 5) = x42 - tmp3; 1247 - *(pSrc + 6) = x41 - tmp2; 1248 - *(pSrc + 7) = x40 - x17; 1249 - } 1250 - 1251 - pSrc += 8; 1252 - } 1253 - } 1254 - 1255 - static void idctCols(void) { 1256 - uint8 i; 1257 - 1258 - int16* pSrc = gCoeffBuf; 1259 - 1260 - for (i = 0; i < 8; i++) { 1261 - if ((pSrc[1 * 8] | pSrc[2 * 8] | pSrc[3 * 8] | pSrc[4 * 8] | pSrc[5 * 8] | pSrc[6 * 8] | pSrc[7 * 8]) == 0) { 1262 - // Short circuit the 1D IDCT if only the DC component is non-zero 1263 - uint8 c = clamp(PJPG_DESCALE(*pSrc) + 128); 1264 - *(pSrc + 0 * 8) = c; 1265 - *(pSrc + 1 * 8) = c; 1266 - *(pSrc + 2 * 8) = c; 1267 - *(pSrc + 3 * 8) = c; 1268 - *(pSrc + 4 * 8) = c; 1269 - *(pSrc + 5 * 8) = c; 1270 - *(pSrc + 6 * 8) = c; 1271 - *(pSrc + 7 * 8) = c; 1272 - } else { 1273 - int16 src4 = *(pSrc + 5 * 8); 1274 - int16 src7 = *(pSrc + 3 * 8); 1275 - int16 x4 = src4 - src7; 1276 - int16 x7 = src4 + src7; 1277 - 1278 - int16 src5 = *(pSrc + 1 * 8); 1279 - int16 src6 = *(pSrc + 7 * 8); 1280 - int16 x5 = src5 + src6; 1281 - int16 x6 = src5 - src6; 1282 - 1283 - int16 tmp1 = imul_b5(x4 - x6); 1284 - int16 stg26 = imul_b4(x6) - tmp1; 1285 - 1286 - int16 x24 = tmp1 - imul_b2(x4); 1287 - 1288 - int16 x15 = x5 - x7; 1289 - int16 x17 = x5 + x7; 1290 - 1291 - int16 tmp2 = stg26 - x17; 1292 - int16 tmp3 = imul_b1_b3(x15) - tmp2; 1293 - int16 x44 = tmp3 + x24; 1294 - 1295 - int16 src0 = *(pSrc + 0 * 8); 1296 - int16 src1 = *(pSrc + 4 * 8); 1297 - int16 x30 = src0 + src1; 1298 - int16 x31 = src0 - src1; 1299 - 1300 - int16 src2 = *(pSrc + 2 * 8); 1301 - int16 src3 = *(pSrc + 6 * 8); 1302 - int16 x12 = src2 - src3; 1303 - int16 x13 = src2 + src3; 1304 - 1305 - int16 x32 = imul_b1_b3(x12) - x13; 1306 - 1307 - int16 x40 = x30 + x13; 1308 - int16 x43 = x30 - x13; 1309 - int16 x41 = x31 + x32; 1310 - int16 x42 = x31 - x32; 1311 - 1312 - // descale, convert to unsigned and clamp to 8-bit 1313 - *(pSrc + 0 * 8) = clamp(PJPG_DESCALE(x40 + x17) + 128); 1314 - *(pSrc + 1 * 8) = clamp(PJPG_DESCALE(x41 + tmp2) + 128); 1315 - *(pSrc + 2 * 8) = clamp(PJPG_DESCALE(x42 + tmp3) + 128); 1316 - *(pSrc + 3 * 8) = clamp(PJPG_DESCALE(x43 - x44) + 128); 1317 - *(pSrc + 4 * 8) = clamp(PJPG_DESCALE(x43 + x44) + 128); 1318 - *(pSrc + 5 * 8) = clamp(PJPG_DESCALE(x42 - tmp3) + 128); 1319 - *(pSrc + 6 * 8) = clamp(PJPG_DESCALE(x41 - tmp2) + 128); 1320 - *(pSrc + 7 * 8) = clamp(PJPG_DESCALE(x40 - x17) + 128); 1321 - } 1322 - 1323 - pSrc++; 1324 - } 1325 - } 1326 - 1327 - /*----------------------------------------------------------------------------*/ 1328 - static PJPG_INLINE uint8 addAndClamp(uint8 a, int16 b) { 1329 - b = a + b; 1330 - 1331 - if ((uint16)b > 255U) { 1332 - if (b < 0) 1333 - return 0; 1334 - else if (b > 255) 1335 - return 255; 1336 - } 1337 - 1338 - return (uint8)b; 1339 - } 1340 - /*----------------------------------------------------------------------------*/ 1341 - static PJPG_INLINE uint8 subAndClamp(uint8 a, int16 b) { 1342 - b = a - b; 1343 - 1344 - if ((uint16)b > 255U) { 1345 - if (b < 0) 1346 - return 0; 1347 - else if (b > 255) 1348 - return 255; 1349 - } 1350 - 1351 - return (uint8)b; 1352 - } 1353 - /*----------------------------------------------------------------------------*/ 1354 - // 103/256 1355 - // R = Y + 1.402 (Cr-128) 1356 - 1357 - // 88/256, 183/256 1358 - // G = Y - 0.34414 (Cb-128) - 0.71414 (Cr-128) 1359 - 1360 - // 198/256 1361 - // B = Y + 1.772 (Cb-128) 1362 - /*----------------------------------------------------------------------------*/ 1363 - // Cb upsample and accumulate, 4x4 to 8x8 1364 - static void upsampleCb(uint8 srcOfs, uint8 dstOfs) { 1365 - // Cb - affects G and B 1366 - uint8 x, y; 1367 - int16* pSrc = gCoeffBuf + srcOfs; 1368 - uint8* pDstG = gMCUBufG + dstOfs; 1369 - uint8* pDstB = gMCUBufB + dstOfs; 1370 - for (y = 0; y < 4; y++) { 1371 - for (x = 0; x < 4; x++) { 1372 - uint8 cb = (uint8)*pSrc++; 1373 - int16 cbG, cbB; 1374 - 1375 - cbG = ((cb * 88U) >> 8U) - 44U; 1376 - pDstG[0] = subAndClamp(pDstG[0], cbG); 1377 - pDstG[1] = subAndClamp(pDstG[1], cbG); 1378 - pDstG[8] = subAndClamp(pDstG[8], cbG); 1379 - pDstG[9] = subAndClamp(pDstG[9], cbG); 1380 - 1381 - cbB = (cb + ((cb * 198U) >> 8U)) - 227U; 1382 - pDstB[0] = addAndClamp(pDstB[0], cbB); 1383 - pDstB[1] = addAndClamp(pDstB[1], cbB); 1384 - pDstB[8] = addAndClamp(pDstB[8], cbB); 1385 - pDstB[9] = addAndClamp(pDstB[9], cbB); 1386 - 1387 - pDstG += 2; 1388 - pDstB += 2; 1389 - } 1390 - 1391 - pSrc = pSrc - 4 + 8; 1392 - pDstG = pDstG - 8 + 16; 1393 - pDstB = pDstB - 8 + 16; 1394 - } 1395 - } 1396 - /*----------------------------------------------------------------------------*/ 1397 - // Cb upsample and accumulate, 4x8 to 8x8 1398 - static void upsampleCbH(uint8 srcOfs, uint8 dstOfs) { 1399 - // Cb - affects G and B 1400 - uint8 x, y; 1401 - int16* pSrc = gCoeffBuf + srcOfs; 1402 - uint8* pDstG = gMCUBufG + dstOfs; 1403 - uint8* pDstB = gMCUBufB + dstOfs; 1404 - for (y = 0; y < 8; y++) { 1405 - for (x = 0; x < 4; x++) { 1406 - uint8 cb = (uint8)*pSrc++; 1407 - int16 cbG, cbB; 1408 - 1409 - cbG = ((cb * 88U) >> 8U) - 44U; 1410 - pDstG[0] = subAndClamp(pDstG[0], cbG); 1411 - pDstG[1] = subAndClamp(pDstG[1], cbG); 1412 - 1413 - cbB = (cb + ((cb * 198U) >> 8U)) - 227U; 1414 - pDstB[0] = addAndClamp(pDstB[0], cbB); 1415 - pDstB[1] = addAndClamp(pDstB[1], cbB); 1416 - 1417 - pDstG += 2; 1418 - pDstB += 2; 1419 - } 1420 - 1421 - pSrc = pSrc - 4 + 8; 1422 - } 1423 - } 1424 - /*----------------------------------------------------------------------------*/ 1425 - // Cb upsample and accumulate, 8x4 to 8x8 1426 - static void upsampleCbV(uint8 srcOfs, uint8 dstOfs) { 1427 - // Cb - affects G and B 1428 - uint8 x, y; 1429 - int16* pSrc = gCoeffBuf + srcOfs; 1430 - uint8* pDstG = gMCUBufG + dstOfs; 1431 - uint8* pDstB = gMCUBufB + dstOfs; 1432 - for (y = 0; y < 4; y++) { 1433 - for (x = 0; x < 8; x++) { 1434 - uint8 cb = (uint8)*pSrc++; 1435 - int16 cbG, cbB; 1436 - 1437 - cbG = ((cb * 88U) >> 8U) - 44U; 1438 - pDstG[0] = subAndClamp(pDstG[0], cbG); 1439 - pDstG[8] = subAndClamp(pDstG[8], cbG); 1440 - 1441 - cbB = (cb + ((cb * 198U) >> 8U)) - 227U; 1442 - pDstB[0] = addAndClamp(pDstB[0], cbB); 1443 - pDstB[8] = addAndClamp(pDstB[8], cbB); 1444 - 1445 - ++pDstG; 1446 - ++pDstB; 1447 - } 1448 - 1449 - pDstG = pDstG - 8 + 16; 1450 - pDstB = pDstB - 8 + 16; 1451 - } 1452 - } 1453 - /*----------------------------------------------------------------------------*/ 1454 - // 103/256 1455 - // R = Y + 1.402 (Cr-128) 1456 - 1457 - // 88/256, 183/256 1458 - // G = Y - 0.34414 (Cb-128) - 0.71414 (Cr-128) 1459 - 1460 - // 198/256 1461 - // B = Y + 1.772 (Cb-128) 1462 - /*----------------------------------------------------------------------------*/ 1463 - // Cr upsample and accumulate, 4x4 to 8x8 1464 - static void upsampleCr(uint8 srcOfs, uint8 dstOfs) { 1465 - // Cr - affects R and G 1466 - uint8 x, y; 1467 - int16* pSrc = gCoeffBuf + srcOfs; 1468 - uint8* pDstR = gMCUBufR + dstOfs; 1469 - uint8* pDstG = gMCUBufG + dstOfs; 1470 - for (y = 0; y < 4; y++) { 1471 - for (x = 0; x < 4; x++) { 1472 - uint8 cr = (uint8)*pSrc++; 1473 - int16 crR, crG; 1474 - 1475 - crR = (cr + ((cr * 103U) >> 8U)) - 179; 1476 - pDstR[0] = addAndClamp(pDstR[0], crR); 1477 - pDstR[1] = addAndClamp(pDstR[1], crR); 1478 - pDstR[8] = addAndClamp(pDstR[8], crR); 1479 - pDstR[9] = addAndClamp(pDstR[9], crR); 1480 - 1481 - crG = ((cr * 183U) >> 8U) - 91; 1482 - pDstG[0] = subAndClamp(pDstG[0], crG); 1483 - pDstG[1] = subAndClamp(pDstG[1], crG); 1484 - pDstG[8] = subAndClamp(pDstG[8], crG); 1485 - pDstG[9] = subAndClamp(pDstG[9], crG); 1486 - 1487 - pDstR += 2; 1488 - pDstG += 2; 1489 - } 1490 - 1491 - pSrc = pSrc - 4 + 8; 1492 - pDstR = pDstR - 8 + 16; 1493 - pDstG = pDstG - 8 + 16; 1494 - } 1495 - } 1496 - /*----------------------------------------------------------------------------*/ 1497 - // Cr upsample and accumulate, 4x8 to 8x8 1498 - static void upsampleCrH(uint8 srcOfs, uint8 dstOfs) { 1499 - // Cr - affects R and G 1500 - uint8 x, y; 1501 - int16* pSrc = gCoeffBuf + srcOfs; 1502 - uint8* pDstR = gMCUBufR + dstOfs; 1503 - uint8* pDstG = gMCUBufG + dstOfs; 1504 - for (y = 0; y < 8; y++) { 1505 - for (x = 0; x < 4; x++) { 1506 - uint8 cr = (uint8)*pSrc++; 1507 - int16 crR, crG; 1508 - 1509 - crR = (cr + ((cr * 103U) >> 8U)) - 179; 1510 - pDstR[0] = addAndClamp(pDstR[0], crR); 1511 - pDstR[1] = addAndClamp(pDstR[1], crR); 1512 - 1513 - crG = ((cr * 183U) >> 8U) - 91; 1514 - pDstG[0] = subAndClamp(pDstG[0], crG); 1515 - pDstG[1] = subAndClamp(pDstG[1], crG); 1516 - 1517 - pDstR += 2; 1518 - pDstG += 2; 1519 - } 1520 - 1521 - pSrc = pSrc - 4 + 8; 1522 - } 1523 - } 1524 - /*----------------------------------------------------------------------------*/ 1525 - // Cr upsample and accumulate, 8x4 to 8x8 1526 - static void upsampleCrV(uint8 srcOfs, uint8 dstOfs) { 1527 - // Cr - affects R and G 1528 - uint8 x, y; 1529 - int16* pSrc = gCoeffBuf + srcOfs; 1530 - uint8* pDstR = gMCUBufR + dstOfs; 1531 - uint8* pDstG = gMCUBufG + dstOfs; 1532 - for (y = 0; y < 4; y++) { 1533 - for (x = 0; x < 8; x++) { 1534 - uint8 cr = (uint8)*pSrc++; 1535 - int16 crR, crG; 1536 - 1537 - crR = (cr + ((cr * 103U) >> 8U)) - 179; 1538 - pDstR[0] = addAndClamp(pDstR[0], crR); 1539 - pDstR[8] = addAndClamp(pDstR[8], crR); 1540 - 1541 - crG = ((cr * 183U) >> 8U) - 91; 1542 - pDstG[0] = subAndClamp(pDstG[0], crG); 1543 - pDstG[8] = subAndClamp(pDstG[8], crG); 1544 - 1545 - ++pDstR; 1546 - ++pDstG; 1547 - } 1548 - 1549 - pDstR = pDstR - 8 + 16; 1550 - pDstG = pDstG - 8 + 16; 1551 - } 1552 - } 1553 - /*----------------------------------------------------------------------------*/ 1554 - // Convert Y to RGB 1555 - static void copyY(uint8 dstOfs) { 1556 - uint8 i; 1557 - uint8* pRDst = gMCUBufR + dstOfs; 1558 - uint8* pGDst = gMCUBufG + dstOfs; 1559 - uint8* pBDst = gMCUBufB + dstOfs; 1560 - int16* pSrc = gCoeffBuf; 1561 - 1562 - for (i = 64; i > 0; i--) { 1563 - uint8 c = (uint8)*pSrc++; 1564 - 1565 - *pRDst++ = c; 1566 - *pGDst++ = c; 1567 - *pBDst++ = c; 1568 - } 1569 - } 1570 - /*----------------------------------------------------------------------------*/ 1571 - // Cb convert to RGB and accumulate 1572 - static void convertCb(uint8 dstOfs) { 1573 - uint8 i; 1574 - uint8* pDstG = gMCUBufG + dstOfs; 1575 - uint8* pDstB = gMCUBufB + dstOfs; 1576 - int16* pSrc = gCoeffBuf; 1577 - 1578 - for (i = 64; i > 0; i--) { 1579 - uint8 cb = (uint8)*pSrc++; 1580 - int16 cbG, cbB; 1581 - 1582 - cbG = ((cb * 88U) >> 8U) - 44U; 1583 - *pDstG++ = subAndClamp(pDstG[0], cbG); 1584 - 1585 - cbB = (cb + ((cb * 198U) >> 8U)) - 227U; 1586 - *pDstB++ = addAndClamp(pDstB[0], cbB); 1587 - } 1588 - } 1589 - /*----------------------------------------------------------------------------*/ 1590 - // Cr convert to RGB and accumulate 1591 - static void convertCr(uint8 dstOfs) { 1592 - uint8 i; 1593 - uint8* pDstR = gMCUBufR + dstOfs; 1594 - uint8* pDstG = gMCUBufG + dstOfs; 1595 - int16* pSrc = gCoeffBuf; 1596 - 1597 - for (i = 64; i > 0; i--) { 1598 - uint8 cr = (uint8)*pSrc++; 1599 - int16 crR, crG; 1600 - 1601 - crR = (cr + ((cr * 103U) >> 8U)) - 179; 1602 - *pDstR++ = addAndClamp(pDstR[0], crR); 1603 - 1604 - crG = ((cr * 183U) >> 8U) - 91; 1605 - *pDstG++ = subAndClamp(pDstG[0], crG); 1606 - } 1607 - } 1608 - /*----------------------------------------------------------------------------*/ 1609 - static void transformBlock(uint8 mcuBlock) { 1610 - idctRows(); 1611 - idctCols(); 1612 - 1613 - switch (gScanType) { 1614 - case PJPG_GRAYSCALE: { 1615 - // MCU size: 1, 1 block per MCU 1616 - copyY(0); 1617 - break; 1618 - } 1619 - case PJPG_YH1V1: { 1620 - // MCU size: 8x8, 3 blocks per MCU 1621 - switch (mcuBlock) { 1622 - case 0: { 1623 - copyY(0); 1624 - break; 1625 - } 1626 - case 1: { 1627 - convertCb(0); 1628 - break; 1629 - } 1630 - case 2: { 1631 - convertCr(0); 1632 - break; 1633 - } 1634 - } 1635 - 1636 - break; 1637 - } 1638 - case PJPG_YH1V2: { 1639 - // MCU size: 8x16, 4 blocks per MCU 1640 - switch (mcuBlock) { 1641 - case 0: { 1642 - copyY(0); 1643 - break; 1644 - } 1645 - case 1: { 1646 - copyY(128); 1647 - break; 1648 - } 1649 - case 2: { 1650 - upsampleCbV(0, 0); 1651 - upsampleCbV(4 * 8, 128); 1652 - break; 1653 - } 1654 - case 3: { 1655 - upsampleCrV(0, 0); 1656 - upsampleCrV(4 * 8, 128); 1657 - break; 1658 - } 1659 - } 1660 - 1661 - break; 1662 - } 1663 - case PJPG_YH2V1: { 1664 - // MCU size: 16x8, 4 blocks per MCU 1665 - switch (mcuBlock) { 1666 - case 0: { 1667 - copyY(0); 1668 - break; 1669 - } 1670 - case 1: { 1671 - copyY(64); 1672 - break; 1673 - } 1674 - case 2: { 1675 - upsampleCbH(0, 0); 1676 - upsampleCbH(4, 64); 1677 - break; 1678 - } 1679 - case 3: { 1680 - upsampleCrH(0, 0); 1681 - upsampleCrH(4, 64); 1682 - break; 1683 - } 1684 - } 1685 - 1686 - break; 1687 - } 1688 - case PJPG_YH2V2: { 1689 - // MCU size: 16x16, 6 blocks per MCU 1690 - switch (mcuBlock) { 1691 - case 0: { 1692 - copyY(0); 1693 - break; 1694 - } 1695 - case 1: { 1696 - copyY(64); 1697 - break; 1698 - } 1699 - case 2: { 1700 - copyY(128); 1701 - break; 1702 - } 1703 - case 3: { 1704 - copyY(192); 1705 - break; 1706 - } 1707 - case 4: { 1708 - upsampleCb(0, 0); 1709 - upsampleCb(4, 64); 1710 - upsampleCb(4 * 8, 128); 1711 - upsampleCb(4 + 4 * 8, 192); 1712 - break; 1713 - } 1714 - case 5: { 1715 - upsampleCr(0, 0); 1716 - upsampleCr(4, 64); 1717 - upsampleCr(4 * 8, 128); 1718 - upsampleCr(4 + 4 * 8, 192); 1719 - break; 1720 - } 1721 - } 1722 - 1723 - break; 1724 - } 1725 - } 1726 - } 1727 - //------------------------------------------------------------------------------ 1728 - static void transformBlockReduce(uint8 mcuBlock) { 1729 - uint8 c = clamp(PJPG_DESCALE(gCoeffBuf[0]) + 128); 1730 - int16 cbG, cbB, crR, crG; 1731 - 1732 - switch (gScanType) { 1733 - case PJPG_GRAYSCALE: { 1734 - // MCU size: 1, 1 block per MCU 1735 - gMCUBufR[0] = c; 1736 - break; 1737 - } 1738 - case PJPG_YH1V1: { 1739 - // MCU size: 8x8, 3 blocks per MCU 1740 - switch (mcuBlock) { 1741 - case 0: { 1742 - gMCUBufR[0] = c; 1743 - gMCUBufG[0] = c; 1744 - gMCUBufB[0] = c; 1745 - break; 1746 - } 1747 - case 1: { 1748 - cbG = ((c * 88U) >> 8U) - 44U; 1749 - gMCUBufG[0] = subAndClamp(gMCUBufG[0], cbG); 1750 - 1751 - cbB = (c + ((c * 198U) >> 8U)) - 227U; 1752 - gMCUBufB[0] = addAndClamp(gMCUBufB[0], cbB); 1753 - break; 1754 - } 1755 - case 2: { 1756 - crR = (c + ((c * 103U) >> 8U)) - 179; 1757 - gMCUBufR[0] = addAndClamp(gMCUBufR[0], crR); 1758 - 1759 - crG = ((c * 183U) >> 8U) - 91; 1760 - gMCUBufG[0] = subAndClamp(gMCUBufG[0], crG); 1761 - break; 1762 - } 1763 - } 1764 - 1765 - break; 1766 - } 1767 - case PJPG_YH1V2: { 1768 - // MCU size: 8x16, 4 blocks per MCU 1769 - switch (mcuBlock) { 1770 - case 0: { 1771 - gMCUBufR[0] = c; 1772 - gMCUBufG[0] = c; 1773 - gMCUBufB[0] = c; 1774 - break; 1775 - } 1776 - case 1: { 1777 - gMCUBufR[128] = c; 1778 - gMCUBufG[128] = c; 1779 - gMCUBufB[128] = c; 1780 - break; 1781 - } 1782 - case 2: { 1783 - cbG = ((c * 88U) >> 8U) - 44U; 1784 - gMCUBufG[0] = subAndClamp(gMCUBufG[0], cbG); 1785 - gMCUBufG[128] = subAndClamp(gMCUBufG[128], cbG); 1786 - 1787 - cbB = (c + ((c * 198U) >> 8U)) - 227U; 1788 - gMCUBufB[0] = addAndClamp(gMCUBufB[0], cbB); 1789 - gMCUBufB[128] = addAndClamp(gMCUBufB[128], cbB); 1790 - 1791 - break; 1792 - } 1793 - case 3: { 1794 - crR = (c + ((c * 103U) >> 8U)) - 179; 1795 - gMCUBufR[0] = addAndClamp(gMCUBufR[0], crR); 1796 - gMCUBufR[128] = addAndClamp(gMCUBufR[128], crR); 1797 - 1798 - crG = ((c * 183U) >> 8U) - 91; 1799 - gMCUBufG[0] = subAndClamp(gMCUBufG[0], crG); 1800 - gMCUBufG[128] = subAndClamp(gMCUBufG[128], crG); 1801 - 1802 - break; 1803 - } 1804 - } 1805 - break; 1806 - } 1807 - case PJPG_YH2V1: { 1808 - // MCU size: 16x8, 4 blocks per MCU 1809 - switch (mcuBlock) { 1810 - case 0: { 1811 - gMCUBufR[0] = c; 1812 - gMCUBufG[0] = c; 1813 - gMCUBufB[0] = c; 1814 - break; 1815 - } 1816 - case 1: { 1817 - gMCUBufR[64] = c; 1818 - gMCUBufG[64] = c; 1819 - gMCUBufB[64] = c; 1820 - break; 1821 - } 1822 - case 2: { 1823 - cbG = ((c * 88U) >> 8U) - 44U; 1824 - gMCUBufG[0] = subAndClamp(gMCUBufG[0], cbG); 1825 - gMCUBufG[64] = subAndClamp(gMCUBufG[64], cbG); 1826 - 1827 - cbB = (c + ((c * 198U) >> 8U)) - 227U; 1828 - gMCUBufB[0] = addAndClamp(gMCUBufB[0], cbB); 1829 - gMCUBufB[64] = addAndClamp(gMCUBufB[64], cbB); 1830 - 1831 - break; 1832 - } 1833 - case 3: { 1834 - crR = (c + ((c * 103U) >> 8U)) - 179; 1835 - gMCUBufR[0] = addAndClamp(gMCUBufR[0], crR); 1836 - gMCUBufR[64] = addAndClamp(gMCUBufR[64], crR); 1837 - 1838 - crG = ((c * 183U) >> 8U) - 91; 1839 - gMCUBufG[0] = subAndClamp(gMCUBufG[0], crG); 1840 - gMCUBufG[64] = subAndClamp(gMCUBufG[64], crG); 1841 - 1842 - break; 1843 - } 1844 - } 1845 - break; 1846 - } 1847 - case PJPG_YH2V2: { 1848 - // MCU size: 16x16, 6 blocks per MCU 1849 - switch (mcuBlock) { 1850 - case 0: { 1851 - gMCUBufR[0] = c; 1852 - gMCUBufG[0] = c; 1853 - gMCUBufB[0] = c; 1854 - break; 1855 - } 1856 - case 1: { 1857 - gMCUBufR[64] = c; 1858 - gMCUBufG[64] = c; 1859 - gMCUBufB[64] = c; 1860 - break; 1861 - } 1862 - case 2: { 1863 - gMCUBufR[128] = c; 1864 - gMCUBufG[128] = c; 1865 - gMCUBufB[128] = c; 1866 - break; 1867 - } 1868 - case 3: { 1869 - gMCUBufR[192] = c; 1870 - gMCUBufG[192] = c; 1871 - gMCUBufB[192] = c; 1872 - break; 1873 - } 1874 - case 4: { 1875 - cbG = ((c * 88U) >> 8U) - 44U; 1876 - gMCUBufG[0] = subAndClamp(gMCUBufG[0], cbG); 1877 - gMCUBufG[64] = subAndClamp(gMCUBufG[64], cbG); 1878 - gMCUBufG[128] = subAndClamp(gMCUBufG[128], cbG); 1879 - gMCUBufG[192] = subAndClamp(gMCUBufG[192], cbG); 1880 - 1881 - cbB = (c + ((c * 198U) >> 8U)) - 227U; 1882 - gMCUBufB[0] = addAndClamp(gMCUBufB[0], cbB); 1883 - gMCUBufB[64] = addAndClamp(gMCUBufB[64], cbB); 1884 - gMCUBufB[128] = addAndClamp(gMCUBufB[128], cbB); 1885 - gMCUBufB[192] = addAndClamp(gMCUBufB[192], cbB); 1886 - 1887 - break; 1888 - } 1889 - case 5: { 1890 - crR = (c + ((c * 103U) >> 8U)) - 179; 1891 - gMCUBufR[0] = addAndClamp(gMCUBufR[0], crR); 1892 - gMCUBufR[64] = addAndClamp(gMCUBufR[64], crR); 1893 - gMCUBufR[128] = addAndClamp(gMCUBufR[128], crR); 1894 - gMCUBufR[192] = addAndClamp(gMCUBufR[192], crR); 1895 - 1896 - crG = ((c * 183U) >> 8U) - 91; 1897 - gMCUBufG[0] = subAndClamp(gMCUBufG[0], crG); 1898 - gMCUBufG[64] = subAndClamp(gMCUBufG[64], crG); 1899 - gMCUBufG[128] = subAndClamp(gMCUBufG[128], crG); 1900 - gMCUBufG[192] = subAndClamp(gMCUBufG[192], crG); 1901 - 1902 - break; 1903 - } 1904 - } 1905 - break; 1906 - } 1907 - } 1908 - } 1909 - //------------------------------------------------------------------------------ 1910 - static uint8 decodeNextMCU(void) { 1911 - uint8 status; 1912 - uint8 mcuBlock; 1913 - 1914 - if (gRestartInterval) { 1915 - if (gRestartsLeft == 0) { 1916 - status = processRestart(); 1917 - if (status) return status; 1918 - } 1919 - gRestartsLeft--; 1920 - } 1921 - 1922 - for (mcuBlock = 0; mcuBlock < gMaxBlocksPerMCU; mcuBlock++) { 1923 - uint8 componentID = gMCUOrg[mcuBlock]; 1924 - uint8 compQuant = gCompQuant[componentID]; 1925 - uint8 compDCTab = gCompDCTab[componentID]; 1926 - uint8 numExtraBits, compACTab, k; 1927 - const int16* pQ = compQuant ? gQuant1 : gQuant0; 1928 - uint16 r, dc; 1929 - 1930 - uint8 s = huffDecode(compDCTab ? &gHuffTab1 : &gHuffTab0, compDCTab ? gHuffVal1 : gHuffVal0); 1931 - 1932 - r = 0; 1933 - numExtraBits = s & 0xF; 1934 - if (numExtraBits) r = getBits2(numExtraBits); 1935 - dc = huffExtend(r, s); 1936 - 1937 - dc = dc + gLastDC[componentID]; 1938 - gLastDC[componentID] = dc; 1939 - 1940 - gCoeffBuf[0] = dc * pQ[0]; 1941 - 1942 - compACTab = gCompACTab[componentID]; 1943 - 1944 - if (gReduce) { 1945 - // Decode, but throw out the AC coefficients in reduce mode. 1946 - for (k = 1; k < 64; k++) { 1947 - s = huffDecode(compACTab ? &gHuffTab3 : &gHuffTab2, compACTab ? gHuffVal3 : gHuffVal2); 1948 - 1949 - numExtraBits = s & 0xF; 1950 - if (numExtraBits) getBits2(numExtraBits); 1951 - 1952 - r = s >> 4; 1953 - s &= 15; 1954 - 1955 - if (s) { 1956 - if (r) { 1957 - if ((k + r) > 63) return PJPG_DECODE_ERROR; 1958 - 1959 - k = (uint8)(k + r); 1960 - } 1961 - } else { 1962 - if (r == 15) { 1963 - if ((k + 16) > 64) return PJPG_DECODE_ERROR; 1964 - 1965 - k += (16 - 1); // - 1 because the loop counter is k 1966 - } else 1967 - break; 1968 - } 1969 - } 1970 - 1971 - transformBlockReduce(mcuBlock); 1972 - } else { 1973 - // Decode and dequantize AC coefficients 1974 - for (k = 1; k < 64; k++) { 1975 - uint16 extraBits; 1976 - 1977 - s = huffDecode(compACTab ? &gHuffTab3 : &gHuffTab2, compACTab ? gHuffVal3 : gHuffVal2); 1978 - 1979 - extraBits = 0; 1980 - numExtraBits = s & 0xF; 1981 - if (numExtraBits) extraBits = getBits2(numExtraBits); 1982 - 1983 - r = s >> 4; 1984 - s &= 15; 1985 - 1986 - if (s) { 1987 - int16 ac; 1988 - 1989 - if (r) { 1990 - if ((k + r) > 63) return PJPG_DECODE_ERROR; 1991 - 1992 - while (r) { 1993 - gCoeffBuf[ZAG[k++]] = 0; 1994 - r--; 1995 - } 1996 - } 1997 - 1998 - ac = huffExtend(extraBits, s); 1999 - 2000 - gCoeffBuf[ZAG[k]] = ac * pQ[k]; 2001 - } else { 2002 - if (r == 15) { 2003 - if ((k + 16) > 64) return PJPG_DECODE_ERROR; 2004 - 2005 - for (r = 16; r > 0; r--) gCoeffBuf[ZAG[k++]] = 0; 2006 - 2007 - k--; // - 1 because the loop counter is k 2008 - } else 2009 - break; 2010 - } 2011 - } 2012 - 2013 - while (k < 64) gCoeffBuf[ZAG[k++]] = 0; 2014 - 2015 - transformBlock(mcuBlock); 2016 - } 2017 - } 2018 - 2019 - return 0; 2020 - } 2021 - //------------------------------------------------------------------------------ 2022 - unsigned char pjpeg_decode_mcu(void) { 2023 - uint8 status; 2024 - 2025 - if (gCallbackStatus) return gCallbackStatus; 2026 - 2027 - if ((!gNumMCUSRemainingX) && (!gNumMCUSRemainingY)) return PJPG_NO_MORE_BLOCKS; 2028 - 2029 - status = decodeNextMCU(); 2030 - if ((status) || (gCallbackStatus)) return gCallbackStatus ? gCallbackStatus : status; 2031 - 2032 - gNumMCUSRemainingX--; 2033 - if (!gNumMCUSRemainingX) { 2034 - gNumMCUSRemainingY--; 2035 - if (gNumMCUSRemainingY > 0) gNumMCUSRemainingX = gMaxMCUSPerRow; 2036 - } 2037 - 2038 - return 0; 2039 - } 2040 - //------------------------------------------------------------------------------ 2041 - unsigned char pjpeg_decode_init(pjpeg_image_info_t* pInfo, pjpeg_need_bytes_callback_t pNeed_bytes_callback, 2042 - void* pCallback_data, unsigned char reduce) { 2043 - uint8 status; 2044 - 2045 - pInfo->m_width = 0; 2046 - pInfo->m_height = 0; 2047 - pInfo->m_comps = 0; 2048 - pInfo->m_MCUSPerRow = 0; 2049 - pInfo->m_MCUSPerCol = 0; 2050 - pInfo->m_scanType = PJPG_GRAYSCALE; 2051 - pInfo->m_MCUWidth = 0; 2052 - pInfo->m_MCUHeight = 0; 2053 - pInfo->m_pMCUBufR = (unsigned char*)0; 2054 - pInfo->m_pMCUBufG = (unsigned char*)0; 2055 - pInfo->m_pMCUBufB = (unsigned char*)0; 2056 - 2057 - g_pNeedBytesCallback = pNeed_bytes_callback; 2058 - g_pCallback_data = pCallback_data; 2059 - gCallbackStatus = 0; 2060 - gReduce = reduce; 2061 - 2062 - status = init(); 2063 - if ((status) || (gCallbackStatus)) return gCallbackStatus ? gCallbackStatus : status; 2064 - 2065 - status = locateSOFMarker(); 2066 - if ((status) || (gCallbackStatus)) return gCallbackStatus ? gCallbackStatus : status; 2067 - 2068 - status = initFrame(); 2069 - if ((status) || (gCallbackStatus)) return gCallbackStatus ? gCallbackStatus : status; 2070 - 2071 - status = initScan(); 2072 - if ((status) || (gCallbackStatus)) return gCallbackStatus ? gCallbackStatus : status; 2073 - 2074 - pInfo->m_width = gImageXSize; 2075 - pInfo->m_height = gImageYSize; 2076 - pInfo->m_comps = gCompsInFrame; 2077 - pInfo->m_scanType = gScanType; 2078 - pInfo->m_MCUSPerRow = gMaxMCUSPerRow; 2079 - pInfo->m_MCUSPerCol = gMaxMCUSPerCol; 2080 - pInfo->m_MCUWidth = gMaxMCUXSize; 2081 - pInfo->m_MCUHeight = gMaxMCUYSize; 2082 - pInfo->m_pMCUBufR = gMCUBufR; 2083 - pInfo->m_pMCUBufG = gMCUBufG; 2084 - pInfo->m_pMCUBufB = gMCUBufB; 2085 - 2086 - return 0; 2087 - }
-124
lib/picojpeg/picojpeg.h
··· 1 - //------------------------------------------------------------------------------ 2 - // picojpeg - Public domain, Rich Geldreich <richgel99@gmail.com> 3 - //------------------------------------------------------------------------------ 4 - #ifndef PICOJPEG_H 5 - #define PICOJPEG_H 6 - 7 - #ifdef __cplusplus 8 - extern "C" { 9 - #endif 10 - 11 - // Error codes 12 - enum { 13 - PJPG_NO_MORE_BLOCKS = 1, 14 - PJPG_BAD_DHT_COUNTS, 15 - PJPG_BAD_DHT_INDEX, 16 - PJPG_BAD_DHT_MARKER, 17 - PJPG_BAD_DQT_MARKER, 18 - PJPG_BAD_DQT_TABLE, 19 - PJPG_BAD_PRECISION, 20 - PJPG_BAD_HEIGHT, 21 - PJPG_BAD_WIDTH, 22 - PJPG_TOO_MANY_COMPONENTS, 23 - PJPG_BAD_SOF_LENGTH, 24 - PJPG_BAD_VARIABLE_MARKER, 25 - PJPG_BAD_DRI_LENGTH, 26 - PJPG_BAD_SOS_LENGTH, 27 - PJPG_BAD_SOS_COMP_ID, 28 - PJPG_W_EXTRA_BYTES_BEFORE_MARKER, 29 - PJPG_NO_ARITHMITIC_SUPPORT, 30 - PJPG_UNEXPECTED_MARKER, 31 - PJPG_NOT_JPEG, 32 - PJPG_UNSUPPORTED_MARKER, 33 - PJPG_BAD_DQT_LENGTH, 34 - PJPG_TOO_MANY_BLOCKS, 35 - PJPG_UNDEFINED_QUANT_TABLE, 36 - PJPG_UNDEFINED_HUFF_TABLE, 37 - PJPG_NOT_SINGLE_SCAN, 38 - PJPG_UNSUPPORTED_COLORSPACE, 39 - PJPG_UNSUPPORTED_SAMP_FACTORS, 40 - PJPG_DECODE_ERROR, 41 - PJPG_BAD_RESTART_MARKER, 42 - PJPG_ASSERTION_ERROR, 43 - PJPG_BAD_SOS_SPECTRAL, 44 - PJPG_BAD_SOS_SUCCESSIVE, 45 - PJPG_STREAM_READ_ERROR, 46 - PJPG_NOTENOUGHMEM, 47 - PJPG_UNSUPPORTED_COMP_IDENT, 48 - PJPG_UNSUPPORTED_QUANT_TABLE, 49 - PJPG_UNSUPPORTED_MODE, // picojpeg doesn't support progressive JPEG's 50 - }; 51 - 52 - // Scan types 53 - typedef enum { PJPG_GRAYSCALE, PJPG_YH1V1, PJPG_YH2V1, PJPG_YH1V2, PJPG_YH2V2 } pjpeg_scan_type_t; 54 - 55 - typedef struct { 56 - // Image resolution 57 - int m_width; 58 - int m_height; 59 - 60 - // Number of components (1 or 3) 61 - int m_comps; 62 - 63 - // Total number of minimum coded units (MCU's) per row/col. 64 - int m_MCUSPerRow; 65 - int m_MCUSPerCol; 66 - 67 - // Scan type 68 - pjpeg_scan_type_t m_scanType; 69 - 70 - // MCU width/height in pixels (each is either 8 or 16 depending on the scan type) 71 - int m_MCUWidth; 72 - int m_MCUHeight; 73 - 74 - // m_pMCUBufR, m_pMCUBufG, and m_pMCUBufB are pointers to internal MCU Y or RGB pixel component buffers. 75 - // Each time pjpegDecodeMCU() is called successfully these buffers will be filled with 8x8 pixel blocks of Y or RGB 76 - // pixels. Each MCU consists of (m_MCUWidth/8)*(m_MCUHeight/8) Y/RGB blocks: 1 for greyscale/no subsampling, 2 for 77 - // H1V2/H2V1, or 4 blocks for H2V2 sampling factors. Each block is a contiguous array of 64 (8x8) bytes of a single 78 - // component: either Y for grayscale images, or R, G or B components for color images. 79 - // 80 - // The 8x8 pixel blocks are organized in these byte arrays like this: 81 - // 82 - // PJPG_GRAYSCALE: Each MCU is decoded to a single block of 8x8 grayscale pixels. 83 - // Only the values in m_pMCUBufR are valid. Each 8 bytes is a row of pixels (raster order: left to right, top to 84 - // bottom) from the 8x8 block. 85 - // 86 - // PJPG_H1V1: Each MCU contains is decoded to a single block of 8x8 RGB pixels. 87 - // 88 - // PJPG_YH2V1: Each MCU is decoded to 2 blocks, or 16x8 pixels. 89 - // The 2 RGB blocks are at byte offsets: 0, 64 90 - // 91 - // PJPG_YH1V2: Each MCU is decoded to 2 blocks, or 8x16 pixels. 92 - // The 2 RGB blocks are at byte offsets: 0, 93 - // 128 94 - // 95 - // PJPG_YH2V2: Each MCU is decoded to 4 blocks, or 16x16 pixels. 96 - // The 2x2 block array is organized at byte offsets: 0, 64, 97 - // 128, 192 98 - // 99 - // It is up to the caller to copy or blit these pixels from these buffers into the destination bitmap. 100 - unsigned char* m_pMCUBufR; 101 - unsigned char* m_pMCUBufG; 102 - unsigned char* m_pMCUBufB; 103 - } pjpeg_image_info_t; 104 - 105 - typedef unsigned char (*pjpeg_need_bytes_callback_t)(unsigned char* pBuf, unsigned char buf_size, 106 - unsigned char* pBytes_actually_read, void* pCallback_data); 107 - 108 - // Initializes the decompressor. Returns 0 on success, or one of the above error codes on failure. 109 - // pNeed_bytes_callback will be called to fill the decompressor's internal input buffer. 110 - // If reduce is 1, only the first pixel of each block will be decoded. This mode is much faster because it skips the AC 111 - // dequantization, IDCT and chroma upsampling of every image pixel. Not thread safe. 112 - unsigned char pjpeg_decode_init(pjpeg_image_info_t* pInfo, pjpeg_need_bytes_callback_t pNeed_bytes_callback, 113 - void* pCallback_data, unsigned char reduce); 114 - 115 - // Decompresses the file's next MCU. Returns 0 on success, PJPG_NO_MORE_BLOCKS if no more blocks are available, or an 116 - // error code. Must be called a total of m_MCUSPerRow*m_MCUSPerCol times to completely decompress the image. Not thread 117 - // safe. 118 - unsigned char pjpeg_decode_mcu(void); 119 - 120 - #ifdef __cplusplus 121 - } 122 - #endif 123 - 124 - #endif // PICOJPEG_H