/* * Class that will will rewind an SkStream, and then restore it to its original position when it * goes out of scope. If the SkStream is not seekable, then the stream will not be altered at all, * and will return false from canRestore.
*/
class ScopedSkStreamRestorer { public:
ScopedSkStreamRestorer(SkStream* stream) : fStream(stream), fPosition(stream->getPosition()) { if (!fStream->rewind()) {
SkCodecPrintf("Failed to rewind decoder stream.\n");
}
}
~ScopedSkStreamRestorer() { if (!fStream->seek(fPosition)) {
SkCodecPrintf("Failed to restore decoder stream.\n");
}
}
void initSource(const uint8_t*& nextInputByte, size_t& bytesInBuffer) override {
nextInputByte = fBuffer->bytes();
bytesInBuffer = 0;
} bool fillInputBuffer(const uint8_t*& nextInputByte, size_t& bytesInBuffer) override {
size_t bytesRead = fStream->read(fBuffer->writable_data(), fBuffer->size()); if (bytesRead == 0) { // Fail if we read zero bytes (libjpeg will accept any non-zero number of bytes).
SkCodecPrintf("Hit end of file reading a buffered stream.\n"); returnfalse;
}
nextInputByte = fBuffer->bytes();
bytesInBuffer = bytesRead; returntrue;
} bool skipInputBytes(size_t bytesToSkip, const uint8_t*& nextInputByte,
size_t& bytesInBuffer) override { // Skip through the already-read (or already in memory) buffer. if (bytesToSkip <= bytesInBuffer) {
nextInputByte += bytesToSkip;
bytesInBuffer -= bytesToSkip; returntrue;
}
bytesToSkip -= bytesInBuffer;
// Fail if we skip past the end of the stream. if (fStream->skip(bytesToSkip) != bytesToSkip) {
SkCodecPrintf("Failed to skip through buffered stream.\n"); returnfalse;
}
bytesInBuffer = 0;
nextInputByte = fBuffer->bytes(); returntrue;
} #ifdef SK_CODEC_DECODES_JPEG_GAINMAPS const std::vector<SkJpegSegment>& getAllSegments() override { if (fScanner) { return fScanner->getSegments();
}
ScopedSkStreamRestorer streamRestorer(fStream);
fScanner = std::make_unique<SkJpegSegmentScanner>(kJpegMarkerEndOfImage); while (!fScanner->isDone() && !fScanner->hadError()) {
constexpr size_t kBufferSize = 1024;
uint8_t buffer[kBufferSize];
size_t bytesRead = fStream->read(buffer, kBufferSize); if (bytesRead == 0) {
SkCodecPrintf("Unexpected EOF.\n"); break;
}
fScanner->onBytes(buffer, bytesRead);
} return fScanner->getSegments();
}
sk_sp<SkData> getSubsetData(size_t offset, size_t size, bool* wasCopied) override {
ScopedSkStreamRestorer streamRestorer(fStream); if (!fStream->seek(offset)) {
SkCodecPrintf("Failed to seek to subset stream position.\n"); return nullptr;
}
sk_sp<SkData> data = SkData::MakeUninitialized(size); if (fStream->read(data->writable_data(), size) != size) {
SkCodecPrintf("Failed to read subset stream data.\n"); return nullptr;
} if (wasCopied) {
*wasCopied = true;
} return data;
}
sk_sp<SkData> getSegmentParameters(const SkJpegSegment& segment) override { // If the segment's parameter length isn't longer than the two bytes for the length, // early-out early-out. if (segment.parameterLength <= kJpegSegmentParameterLengthSize) { return nullptr;
}
// Seek to the start of the segment.
ScopedSkStreamRestorer streamRestorer(fStream); if (!fStream->seek(segment.offset)) {
SkCodecPrintf("Failed to seek to segment\n"); return nullptr;
}
// Read the marker and verify it matches `segment`.
uint8_t markerCode[kJpegMarkerCodeSize] = {0}; if (fStream->read(markerCode, kJpegMarkerCodeSize) != kJpegMarkerCodeSize) {
SkCodecPrintf("Failed to read segment marker code\n"); return nullptr;
}
SkASSERT(markerCode[0] == 0xFF);
SkASSERT(markerCode[1] == segment.marker);
// Read the parameter length and verify it matches `segment`.
uint8_t parameterLength[kJpegSegmentParameterLengthSize] = {0}; if (fStream->read(parameterLength, kJpegSegmentParameterLengthSize) !=
kJpegSegmentParameterLengthSize) {
SkCodecPrintf("Failed to read parameter length\n"); return nullptr;
}
SkASSERT(256 * parameterLength[0] + parameterLength[1] == segment.parameterLength);
// Read the remainder of the segment.
size_t sizeToRead = segment.parameterLength - kJpegSegmentParameterLengthSize; auto result = SkData::MakeUninitialized(sizeToRead); if (fStream->read(result->writable_data(), sizeToRead) != sizeToRead) { return nullptr;
}
#ifdef SK_CODEC_DECODES_JPEG_GAINMAPS /* * This class implements SkJpegSourceMgr for a stream that cannot seek or rewind. It scans the data * as it is presented to the decoder. This allows it to track the position of segments, so that it * can extract subsets at a specific offset (e.g, relative to the EndOfImage segment for JpegR or * relative to an MPF segment for MPF).
*/ class SkJpegUnseekableSourceMgr : public SkJpegSourceMgr { public:
SkJpegUnseekableSourceMgr(SkStream* stream, size_t bufferSize) : SkJpegSourceMgr(stream) {
fBuffer = SkData::MakeUninitialized(bufferSize);
fScanner = std::make_unique<SkJpegSegmentScanner>(kJpegMarkerEndOfImage);
}
~SkJpegUnseekableSourceMgr() override {}
// Read the remaining bytes to skip into fBuffer and feed them into fScanner. while (bytesToSkip > 0) { if (!readToBufferAndScan(std::min(bytesToSkip, fBuffer->size()))) {
SkCodecPrintf("Failure filling unseekable input buffer.\n"); returnfalse;
}
bytesToSkip -= fLastReadSize;
}
// Indicate to libjpeg that it it needs to call fillInputBuffer.
bytesInBuffer = 0;
nextInputByte = fBuffer->bytes(); returntrue;
} const std::vector<SkJpegSegment>& getAllSegments() override { while (!fScanner->isDone() && !fScanner->hadError()) { if (!readToBufferAndScan(fBuffer->size())) {
SkCodecPrintf("Failure finishing unseekable input buffer.\n"); break;
}
} return fScanner->getSegments();
}
sk_sp<SkData> getSubsetData(size_t offset, size_t size, bool* wasCopied) override { // If we haven't reached the EndOfImage, then we are throwing away the base image before // decoding it. This is only reasonable for tests. if (!fScanner->isDone()) {
SkCodecPrintf("getSubsetData is prematurely terminating scan.\n");
}
// If we have read past offset, we can never get that data back again. if (offset < fLastReadOffset) {
SkCodecPrintf("Requested that is gone.\n"); return nullptr;
}
// Allocate the memory to return, and indicate that the result is a copy.
sk_sp<SkData> subsetData = SkData::MakeUninitialized(size);
uint8_t* subsetDataCurrent = reinterpret_cast<uint8_t*>(subsetData->writable_data());
// Determine the relationship between the offset we're reading from and |fBuffer|.
size_t offsetIntoBuffer = offset - fLastReadOffset; if (offsetIntoBuffer >= fLastReadSize) { // We have to skip past |fBuffer| to get to |offset|.
fLastReadOffset += fLastReadSize;
fLastReadSize = 0;
// Skip any additional bytes needed to get to |offset|.
size_t bytesToSkip = offset - fLastReadOffset; while (bytesToSkip > 0) {
size_t bytesSkipped = fStream->skip(bytesToSkip); if (bytesSkipped == 0) {
SkCodecPrintf("Failed to skip bytes before subset.\n"); return nullptr;
}
bytesToSkip -= bytesSkipped;
fLastReadOffset += bytesSkipped;
}
} else { // This assert is to emphatically document the side of the branch we're on.
SkASSERT(offsetIntoBuffer < fLastReadSize);
// Some of the data we want to copy has already been read into |fBuffer|. Copy that data // to |subsetData|
size_t bytesToReadFromBuffer = std::min(fLastReadSize - offsetIntoBuffer, size);
memcpy(subsetDataCurrent, fBuffer->bytes() + offsetIntoBuffer, bytesToReadFromBuffer);
size -= bytesToReadFromBuffer;
subsetDataCurrent += bytesToReadFromBuffer;
// If all of the data that we needed was in |fBuffer|, then return early. if (size == 0) { if (wasCopied) {
*wasCopied = true;
} return subsetData;
} // We will now have to read beyond |fBuffer|, so reset it.
fLastReadOffset += fLastReadSize;
fLastReadSize = 0;
}
// Read the remaining data from |fStream|. while (size > 0) {
size_t bytesRead = fStream->read(subsetDataCurrent, size); if (bytesRead == 0) {
SkCodecPrintf("Failed to read subset stream data.\n"); return nullptr;
}
size -= bytesRead;
subsetDataCurrent += bytesRead;
fLastReadOffset += bytesRead;
}
if (wasCopied) {
*wasCopied = true;
} return subsetData;
}
sk_sp<SkData> getSegmentParameters(const SkJpegSegment& segment) override { // The only way to implement this for an unseekable stream is to record the parameters as // they are scanned. return nullptr;
}
private: // Read the specified number of bytes into fBuffer and feed them to fScanner. The number of // bytes must not be larger than fBuffer's size. bool readToBufferAndScan(size_t bytesToRead) {
SkASSERT(bytesToRead <= fBuffer->size());
fLastReadOffset += fLastReadSize;
fLastReadSize = fStream->read(fBuffer->writable_data(), bytesToRead); if (fLastReadSize == 0) {
SkCodecPrintf("Hit end of file reading an unseekable stream.\n"); returnfalse;
}
fScanner->onBytes(fBuffer->bytes(), fLastReadSize); returntrue;
}
sk_sp<SkData> fBuffer;
// The number of bytes that were most recently read into fBuffer (this can be less than the size // of fBuffer).
size_t fLastReadSize = 0;
// The offset into the stream (total number of bytes read) at the time of our most recent read // into fBuffer.
size_t fLastReadOffset = 0;
}; #endif// SK_CODEC_DECODES_JPEG_GAINMAPS
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.