Fix PNG predictor 12, 14, and 15.

This commit is contained in:
Michael R Sweet 2021-06-01 17:48:36 -04:00
parent 2856b440d1
commit 3efb4f800b
No known key found for this signature in database
GPG Key ID: 999559A027815955
2 changed files with 57 additions and 58 deletions

View File

@ -262,11 +262,11 @@ struct _pdfio_stream_s // Stream
*bufend; // End of buffer *bufend; // End of buffer
z_stream flate; // Flate filter state z_stream flate; // Flate filter state
_pdfio_predictor_t predictor; // Predictor function, if any _pdfio_predictor_t predictor; // Predictor function, if any
int pbcurrent; // Current predictor line (0 or 1)
size_t pbpixel, // Size of a pixel in bytes size_t pbpixel, // Size of a pixel in bytes
pbsize; // Predictor buffer size, if any pbsize; // Predictor buffer size, if any
unsigned char cbuffer[4096], // Compressed data buffer unsigned char cbuffer[4096], // Compressed data buffer
*pbuffers[2]; // Predictor buffers, as needed *prbuffer, // Raw buffer (previous line), as needed
*psbuffer; // PNG filter buffer, as needed
}; };

View File

@ -119,8 +119,8 @@ pdfioStreamClose(pdfio_stream_t *st) // I - Stream
done: done:
free(st->pbuffers[0]); free(st->prbuffer);
free(st->pbuffers[1]); free(st->psbuffer);
free(st); free(st);
return (ret); return (ret);
@ -216,11 +216,11 @@ _pdfioStreamCreate(
if (predictor >= 10) if (predictor >= 10)
st->pbsize ++; // Add PNG predictor byte st->pbsize ++; // Add PNG predictor byte
if ((st->pbuffers[0] = calloc(1, st->pbsize)) == NULL || (st->pbuffers[1] = calloc(1, st->pbsize)) == NULL) if ((st->prbuffer = calloc(1, st->pbsize - 1)) == NULL || (st->psbuffer = calloc(1, st->pbsize)) == NULL)
{ {
_pdfioFileError(st->pdf, "Unable to allocate %lu bytes for Predictor buffers.", (unsigned long)st->pbsize); _pdfioFileError(st->pdf, "Unable to allocate %lu bytes for Predictor buffers.", (unsigned long)st->pbsize);
free(st->pbuffers[0]); free(st->prbuffer);
free(st->pbuffers[1]); free(st->psbuffer);
free(st); free(st);
return (NULL); return (NULL);
} }
@ -234,8 +234,8 @@ _pdfioStreamCreate(
if (deflateInit(&(st->flate), 9) != Z_OK) if (deflateInit(&(st->flate), 9) != Z_OK)
{ {
_pdfioFileError(st->pdf, "Unable to start Flate filter."); _pdfioFileError(st->pdf, "Unable to start Flate filter.");
free(st->pbuffers[0]); free(st->prbuffer);
free(st->pbuffers[1]); free(st->psbuffer);
free(st); free(st);
return (NULL); return (NULL);
} }
@ -429,11 +429,11 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
if (predictor >= 10) if (predictor >= 10)
st->pbsize ++; // Add PNG predictor byte st->pbsize ++; // Add PNG predictor byte
if ((st->pbuffers[0] = calloc(1, st->pbsize)) == NULL || (st->pbuffers[1] = calloc(1, st->pbsize)) == NULL) if ((st->prbuffer = calloc(1, st->pbsize - 1)) == NULL || (st->psbuffer = calloc(1, st->pbsize)) == NULL)
{ {
_pdfioFileError(st->pdf, "Unable to allocate %lu bytes for Predictor buffers.", (unsigned long)st->pbsize); _pdfioFileError(st->pdf, "Unable to allocate %lu bytes for Predictor buffers.", (unsigned long)st->pbsize);
free(st->pbuffers[0]); free(st->prbuffer);
free(st->pbuffers[1]); free(st->psbuffer);
free(st); free(st);
return (NULL); return (NULL);
} }
@ -447,8 +447,8 @@ _pdfioStreamOpen(pdfio_obj_t *obj, // I - Object
if (inflateInit(&(st->flate)) != Z_OK) if (inflateInit(&(st->flate)) != Z_OK)
{ {
_pdfioFileError(st->pdf, "Unable to start Flate filter."); _pdfioFileError(st->pdf, "Unable to start Flate filter.");
free(st->pbuffers[0]); free(st->prbuffer);
free(st->pbuffers[1]); free(st->psbuffer);
free(st); free(st);
return (NULL); return (NULL);
} }
@ -649,8 +649,8 @@ pdfioStreamWrite(
// First column bytes remaining // First column bytes remaining
const unsigned char *bufptr = (const unsigned char *)buffer; const unsigned char *bufptr = (const unsigned char *)buffer;
// Pointer into buffer // Pointer into buffer
unsigned char *thisptr, // Current raw buffer unsigned char *sptr, // Pointer into sbuffer
*prevptr; // Previous raw buffer *pptr; // Previous raw buffer
PDFIO_DEBUG("pdfioStreamWrite(st=%p, buffer=%p, bytes=%lu)\n", st, buffer, (unsigned long)bytes); PDFIO_DEBUG("pdfioStreamWrite(st=%p, buffer=%p, bytes=%lu)\n", st, buffer, (unsigned long)bytes);
@ -681,13 +681,13 @@ pdfioStreamWrite(
{ {
// Store the PNG predictor in the first byte of the buffer... // Store the PNG predictor in the first byte of the buffer...
if (st->predictor == _PDFIO_PREDICTOR_PNG_AUTO) if (st->predictor == _PDFIO_PREDICTOR_PNG_AUTO)
st->pbuffers[st->pbcurrent][0] = 4; // Use Paeth predictor for auto... st->psbuffer[0] = 4; // Use Paeth predictor for auto...
else else
st->pbuffers[st->pbcurrent][0] = (unsigned char)(st->predictor - 10); st->psbuffer[0] = (unsigned char)(st->predictor - 10);
// Then process the current line using the specified PNG predictor... // Then process the current line using the specified PNG predictor...
thisptr = st->pbuffers[st->pbcurrent] + 1; sptr = st->psbuffer + 1;
prevptr = st->pbuffers[!st->pbcurrent] + 1; pptr = st->prbuffer;
switch (st->predictor) switch (st->predictor)
{ {
@ -697,58 +697,58 @@ pdfioStreamWrite(
case _PDFIO_PREDICTOR_PNG_NONE : case _PDFIO_PREDICTOR_PNG_NONE :
// No PNG predictor... // No PNG predictor...
memcpy(thisptr, buffer, pbline); memcpy(sptr, buffer, pbline);
break; break;
case _PDFIO_PREDICTOR_PNG_SUB : case _PDFIO_PREDICTOR_PNG_SUB :
// Encode the difference from the previous column // Encode the difference from the previous column
for (remaining = pbline; remaining > 0; remaining --, bufptr ++, thisptr ++) for (remaining = pbline; remaining > 0; remaining --, bufptr ++, sptr ++)
{ {
if (remaining < firstcol) if (remaining < firstcol)
*thisptr = *bufptr - thisptr[-pbpixel]; *sptr = *bufptr - bufptr[-pbpixel];
else else
*thisptr = *bufptr; *sptr = *bufptr;
} }
break; break;
case _PDFIO_PREDICTOR_PNG_UP : case _PDFIO_PREDICTOR_PNG_UP :
// Encode the difference from the previous line // Encode the difference from the previous line
for (remaining = pbline; remaining > 0; remaining --, bufptr ++, thisptr ++, prevptr ++) for (remaining = pbline; remaining > 0; remaining --, bufptr ++, sptr ++, pptr ++)
{ {
*thisptr = *bufptr - *prevptr; *sptr = *bufptr - *pptr;
} }
break; break;
case _PDFIO_PREDICTOR_PNG_AVERAGE : case _PDFIO_PREDICTOR_PNG_AVERAGE :
// Encode the difference with the average of the previous column and line // Encode the difference with the average of the previous column and line
for (remaining = pbline; remaining > 0; remaining --, bufptr ++, thisptr ++, prevptr ++) for (remaining = pbline; remaining > 0; remaining --, bufptr ++, sptr ++, pptr ++)
{ {
if (remaining < firstcol) if (remaining < firstcol)
*thisptr = *bufptr - (thisptr[-pbpixel] + *prevptr) / 2; *sptr = *bufptr - (bufptr[-pbpixel] + *pptr) / 2;
else else
*thisptr = *bufptr - *prevptr / 2; *sptr = *bufptr - *pptr / 2;
} }
break; break;
case _PDFIO_PREDICTOR_PNG_PAETH : case _PDFIO_PREDICTOR_PNG_PAETH :
case _PDFIO_PREDICTOR_PNG_AUTO : case _PDFIO_PREDICTOR_PNG_AUTO :
// Encode the difference with a linear transform function // Encode the difference with a linear transform function
for (remaining = pbline; remaining > 0; remaining --, bufptr ++, thisptr ++, prevptr ++) for (remaining = pbline; remaining > 0; remaining --, bufptr ++, sptr ++, pptr ++)
{ {
if (remaining < firstcol) if (remaining < firstcol)
*thisptr = *bufptr - stream_paeth(thisptr[-pbpixel], *prevptr, prevptr[-pbpixel]); *sptr = *bufptr - stream_paeth(bufptr[-pbpixel], *pptr, pptr[-pbpixel]);
else else
*thisptr = *bufptr - stream_paeth(0, *prevptr, 0); *sptr = *bufptr - stream_paeth(0, *pptr, 0);
} }
break; break;
} }
// Write the encoded line... // Write the encoded line...
if (!stream_write(st, st->pbuffers[st->pbcurrent], st->pbsize)) if (!stream_write(st, st->psbuffer, st->pbsize))
return (false); return (false);
st->pbcurrent = !st->pbcurrent; memcpy(st->prbuffer, buffer, pbline);
bytes -= pbline; bytes -= pbline;
} }
return (true); return (true);
@ -850,9 +850,9 @@ stream_read(pdfio_stream_t *st, // I - Stream
// First column bytes remaining // First column bytes remaining
unsigned char *bufptr = (unsigned char *)buffer, unsigned char *bufptr = (unsigned char *)buffer,
// Pointer into buffer // Pointer into buffer
*thisptr = st->pbuffers[st->pbcurrent] + 1, *sptr = st->psbuffer + 1,
// Current (raw) line // Current (raw) line
*prevptr = st->pbuffers[!st->pbcurrent] + 1; *pptr = st->prbuffer;
// Previous (raw) line // Previous (raw) line
PDFIO_DEBUG("stream_read: PNG predictor.\n"); PDFIO_DEBUG("stream_read: PNG predictor.\n");
@ -864,7 +864,7 @@ stream_read(pdfio_stream_t *st, // I - Stream
return (-1); return (-1);
} }
st->flate.next_out = (Bytef *)thisptr - 1; st->flate.next_out = (Bytef *)sptr - 1;
st->flate.avail_out = (uInt)st->pbsize; st->flate.avail_out = (uInt)st->pbsize;
while (st->flate.avail_out > 0) while (st->flate.avail_out > 0)
@ -898,44 +898,43 @@ stream_read(pdfio_stream_t *st, // I - Stream
return (-1); // Early end of stream return (-1); // Early end of stream
// Apply predictor for this line // Apply predictor for this line
PDFIO_DEBUG("stream_read: Line %02X %02X %02X %02X %02X.\n", thisptr[-1], thisptr[0], thisptr[0], thisptr[2], thisptr[3]); PDFIO_DEBUG("stream_read: Line %02X %02X %02X %02X %02X.\n", sptr[-1], sptr[0], sptr[0], sptr[2], sptr[3]);
switch (thisptr[-1]) switch (sptr[-1])
{ {
case 0 : // None case 0 : // None
memcpy(buffer, thisptr, remaining); memcpy(buffer, sptr, remaining);
break; break;
case 1 : // Sub case 1 : // Sub
for (; remaining > firstcol; remaining --, thisptr ++) for (; remaining > firstcol; remaining --, sptr ++)
*bufptr++ = *thisptr; *bufptr++ = *sptr;
for (; remaining > 0; remaining --, thisptr ++) for (; remaining > 0; remaining --, sptr ++, bufptr ++)
*bufptr++ = *thisptr + thisptr[-pbpixel]; *bufptr = *sptr + bufptr[-pbpixel];
break; break;
case 2 : // Up case 2 : // Up
for (; remaining > 0; remaining --, thisptr ++, prevptr ++) for (; remaining > 0; remaining --, sptr ++, pptr ++)
*bufptr++ = *thisptr + *prevptr; *bufptr++ = *sptr + *pptr;
break; break;
case 3 : // Average case 3 : // Average
for (; remaining > firstcol; remaining --, thisptr ++, prevptr ++) for (; remaining > firstcol; remaining --, sptr ++, pptr ++)
*bufptr++ = *thisptr + *prevptr / 2; *bufptr++ = *sptr + *pptr / 2;
for (; remaining > 0; remaining --, thisptr ++, prevptr ++) for (; remaining > 0; remaining --, sptr ++, pptr ++, bufptr ++)
*bufptr++ = *thisptr + (thisptr[-pbpixel] + *prevptr) / 2; *bufptr = *sptr + (bufptr[-pbpixel] + *pptr) / 2;
break; break;
case 4 : // Paeth case 4 : // Paeth
for (; remaining > firstcol; remaining --, thisptr ++, prevptr ++) for (; remaining > firstcol; remaining --, sptr ++, pptr ++)
*bufptr++ = *thisptr + stream_paeth(0, *prevptr, 0); *bufptr++ = *sptr + stream_paeth(0, *pptr, 0);
for (; remaining > 0; remaining --, thisptr ++, prevptr ++) for (; remaining > 0; remaining --, sptr ++, pptr ++, bufptr ++)
*bufptr++ = *thisptr + stream_paeth(thisptr[-pbpixel], *prevptr, prevptr[-pbpixel]); *bufptr = *sptr + stream_paeth(bufptr[-pbpixel], *pptr, pptr[-pbpixel]);
break; break;
default : default :
_pdfioFileError(st->pdf, "Bad PNG filter %d in data stream.", thisptr[-1]); _pdfioFileError(st->pdf, "Bad PNG filter %d in data stream.", sptr[-1]);
return (-1); return (-1);
} }
// Copy the computed line and swap buffers... // Copy the computed line and swap buffers...
memcpy(st->pbuffers[st->pbcurrent] + 1, buffer, st->pbsize - 1); memcpy(st->prbuffer, buffer, st->pbsize - 1);
st->pbcurrent = !st->pbcurrent;
// Return the number of bytes we copied for this line... // Return the number of bytes we copied for this line...
return ((ssize_t)(st->pbsize - 1)); return ((ssize_t)(st->pbsize - 1));