Ejemplo n.º 1
0
/*
 * Read enough of the stream to initialize the SkGifCodec.
 * Returns a bool representing success or failure.
 *
 * @param codecOut
 * If it returned true, and codecOut was not nullptr,
 * codecOut will be set to a new SkGifCodec.
 *
 * @param gifOut
 * If it returned true, and codecOut was nullptr,
 * gifOut must be non-nullptr and gifOut will be set to a new
 * GifFileType pointer.
 *
 * @param stream
 * Deleted on failure.
 * codecOut will take ownership of it in the case where we created a codec.
 * Ownership is unchanged when we returned a gifOut.
 *
 */
bool SkGifCodec::ReadHeader(SkStream* stream, SkCodec** codecOut, GifFileType** gifOut) {
    SkAutoTDelete<SkStream> streamDeleter(stream);

    // Read gif header, logical screen descriptor, and global color table
    SkAutoTCallVProc<GifFileType, CloseGif> gif(open_gif(stream));

    if (nullptr == gif) {
        gif_error("DGifOpen failed.\n");
        return false;
    }

    // Read through gif extensions to get to the image data.  Set the
    // transparent index based on the extension data.
    uint32_t transIndex;
    SkCodec::Result result = ReadUpToFirstImage(gif, &transIndex);
    if (kSuccess != result){
        return false;
    }

    // Read the image descriptor
    if (GIF_ERROR == DGifGetImageDesc(gif)) {
        return false;
    }
    // If reading the image descriptor is successful, the image count will be
    // incremented.
    SkASSERT(gif->ImageCount >= 1);

    if (nullptr != codecOut) {
        SkISize size;
        SkIRect frameRect;
        if (!GetDimensions(gif, &size, &frameRect)) {
            gif_error("Invalid gif size.\n");
            return false;
        }
        bool frameIsSubset = (size != frameRect.size());

        // Determine the encoded alpha type.  The transIndex might be valid if it less
        // than 256.  We are not certain that the index is valid until we process the color
        // table, since some gifs have color tables with less than 256 colors.  If
        // there might be a valid transparent index, we must indicate that the image has
        // alpha.
        // In the case where we must support alpha, we indicate kBinary, since every
        // pixel will either be fully opaque or fully transparent.
        SkEncodedInfo::Alpha alpha = (transIndex < 256) ? SkEncodedInfo::kBinary_Alpha :
                SkEncodedInfo::kOpaque_Alpha;

        // Return the codec
        // Use kPalette since Gifs are encoded with a color table.
        // Use 8-bits per component, since this is the output we get from giflib.
        // FIXME: Gifs can actually be encoded with 4-bits per pixel.  Can we support this?
        SkEncodedInfo info = SkEncodedInfo::Make(SkEncodedInfo::kPalette_Color, alpha, 8);
        *codecOut = new SkGifCodec(size.width(), size.height(), info, streamDeleter.release(),
                gif.release(), transIndex, frameRect, frameIsSubset);
    } else {
        SkASSERT(nullptr != gifOut);
        streamDeleter.release();
        *gifOut = gif.release();
    }
    return true;
}
Ejemplo n.º 2
0
SkCodec* SkCodec::NewFromStream(SkStream* stream) {
    if (!stream) {
        return NULL;
    }

    SkAutoTDelete<SkStream> streamDeleter(stream);
    
    SkAutoTDelete<SkCodec> codec(NULL);
    for (uint32_t i = 0; i < SK_ARRAY_COUNT(gDecoderProcs); i++) {
        DecoderProc proc = gDecoderProcs[i];
        const bool correctFormat = proc.IsFormat(stream);
        if (!stream->rewind()) {
            return NULL;
        }
        if (correctFormat) {
            codec.reset(proc.NewFromStream(streamDeleter.detach()));
            break;
        }
    }

    // Set the max size at 128 megapixels (512 MB for kN32).
    // This is about 4x smaller than a test image that takes a few minutes for
    // dm to decode and draw.
    const int32_t maxSize = 1 << 27;
    if (codec && codec->getInfo().width() * codec->getInfo().height() > maxSize) {
        SkCodecPrintf("Error: Image size too large, cannot decode.\n");
        return NULL;
    } else {
        return codec.detach();
    }
}
Ejemplo n.º 3
0
SkCodec* SkHeifCodec::NewFromStream(SkStream* stream, Result* result) {
    std::unique_ptr<SkStream> streamDeleter(stream);

    std::unique_ptr<HeifDecoder> heifDecoder(createHeifDecoder());
    if (heifDecoder.get() == nullptr) {
        *result = kInternalError;
        return nullptr;
    }

    HeifFrameInfo frameInfo;
    if (!heifDecoder->init(new SkHeifStreamWrapper(streamDeleter.release()),
                           &frameInfo)) {
        *result = kInvalidInput;
        return nullptr;
    }

    SkEncodedInfo info = SkEncodedInfo::Make(
            SkEncodedInfo::kYUV_Color, SkEncodedInfo::kOpaque_Alpha, 8);

    Origin orientation = get_orientation(frameInfo);

    sk_sp<SkColorSpace> colorSpace = nullptr;
    if ((frameInfo.mIccSize > 0) && (frameInfo.mIccData != nullptr)) {
        SkColorSpace_Base::ICCTypeFlag iccType = SkColorSpace_Base::kRGB_ICCTypeFlag;
        colorSpace = SkColorSpace_Base::MakeICC(
                frameInfo.mIccData.get(), frameInfo.mIccSize, iccType);
    }
    if (!colorSpace) {
        colorSpace = SkColorSpace::MakeSRGB();
    }

    *result = kSuccess;
    return new SkHeifCodec(frameInfo.mWidth, frameInfo.mHeight,
            info, heifDecoder.release(), std::move(colorSpace), orientation);
}
Ejemplo n.º 4
0
SkCodec* SkCodec::NewFromStream(SkStream* stream,
                                SkPngChunkReader* chunkReader) {
    if (!stream) {
        return nullptr;
    }

    SkAutoTDelete<SkStream> streamDeleter(stream);

    // 14 is enough to read all of the supported types.
    const size_t bytesToRead = 14;
    SkASSERT(bytesToRead <= MinBufferedBytesNeeded());

    char buffer[bytesToRead];
    size_t bytesRead = stream->peek(buffer, bytesToRead);

    // It is also possible to have a complete image less than bytesToRead bytes
    // (e.g. a 1 x 1 wbmp), meaning peek() would return less than bytesToRead.
    // Assume that if bytesRead < bytesToRead, but > 0, the stream is shorter
    // than bytesToRead, so pass that directly to the decoder.
    // It also is possible the stream uses too small a buffer for peeking, but
    // we trust the caller to use a large enough buffer.

    if (0 == bytesRead) {
        SkCodecPrintf("Could not peek!\n");
        // It is possible the stream does not support peeking, but does support
        // rewinding.
        // Attempt to read() and pass the actual amount read to the decoder.
        bytesRead = stream->read(buffer, bytesToRead);
        if (!stream->rewind()) {
            SkCodecPrintf("Could not rewind!\n");
            return nullptr;
        }
    }

    SkAutoTDelete<SkCodec> codec(nullptr);
    // PNG is special, since we want to be able to supply an SkPngChunkReader.
    // But this code follows the same pattern as the loop.
    if (SkPngCodec::IsPng(buffer, bytesRead)) {
        codec.reset(SkPngCodec::NewFromStream(streamDeleter.detach(), chunkReader));
    } else {
        for (DecoderProc proc : gDecoderProcs) {
            if (proc.IsFormat(buffer, bytesRead)) {
                codec.reset(proc.NewFromStream(streamDeleter.detach()));
                break;
            }
        }
    }

    // Set the max size at 128 megapixels (512 MB for kN32).
    // This is about 4x smaller than a test image that takes a few minutes for
    // dm to decode and draw.
    const int32_t maxSize = 1 << 27;
    if (codec && codec->getInfo().width() * codec->getInfo().height() > maxSize) {
        SkCodecPrintf("Error: Image size too large, cannot decode.\n");
        return nullptr;
    } else {
        return codec.detach();
    }
}
Ejemplo n.º 5
0
SkCodec* SkCodec::NewFromStream(SkStream* stream,
                                SkPngChunkReader* chunkReader) {
    if (!stream) {
        return nullptr;
    }

    SkAutoTDelete<SkStream> streamDeleter(stream);

    // 14 is enough to read all of the supported types.
    const size_t bytesToRead = 14;
    SkASSERT(bytesToRead <= MinBufferedBytesNeeded());

    char buffer[bytesToRead];
    size_t bytesRead = stream->peek(buffer, bytesToRead);

    // It is also possible to have a complete image less than bytesToRead bytes
    // (e.g. a 1 x 1 wbmp), meaning peek() would return less than bytesToRead.
    // Assume that if bytesRead < bytesToRead, but > 0, the stream is shorter
    // than bytesToRead, so pass that directly to the decoder.
    // It also is possible the stream uses too small a buffer for peeking, but
    // we trust the caller to use a large enough buffer.

    if (0 == bytesRead) {
        // TODO: After implementing peek in CreateJavaOutputStreamAdaptor.cpp, this
        // printf could be useful to notice failures.
        // SkCodecPrintf("Encoded image data failed to peek!\n");

        // It is possible the stream does not support peeking, but does support
        // rewinding.
        // Attempt to read() and pass the actual amount read to the decoder.
        bytesRead = stream->read(buffer, bytesToRead);
        if (!stream->rewind()) {
            SkCodecPrintf("Encoded image data could not peek or rewind to determine format!\n");
            return nullptr;
        }
    }

    // PNG is special, since we want to be able to supply an SkPngChunkReader.
    // But this code follows the same pattern as the loop.
#ifdef SK_CODEC_DECODES_PNG
    if (SkPngCodec::IsPng(buffer, bytesRead)) {
        return SkPngCodec::NewFromStream(streamDeleter.detach(), chunkReader);
    } else
#endif
    {
        for (DecoderProc proc : gDecoderProcs) {
            if (proc.IsFormat(buffer, bytesRead)) {
                return proc.NewFromStream(streamDeleter.detach());
            }
        }

#ifdef SK_CODEC_DECODES_RAW
        // Try to treat the input as RAW if all the other checks failed.
        return SkRawCodec::NewFromStream(streamDeleter.detach());
#endif
    }

    return nullptr;
}
SkBitmapRegionDecoder* SkBitmapRegionDecoder::Create(
        SkStreamRewindable* stream, Strategy strategy) {
    SkAutoTDelete<SkStreamRewindable> streamDeleter(stream);
    switch (strategy) {
        case kCanvas_Strategy: {
            SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(streamDeleter.detach()));
            if (nullptr == codec) {
                SkCodecPrintf("Error: Failed to create decoder.\n");
                return nullptr;
            }

            SkEncodedFormat format = codec->getEncodedFormat();
            switch (format) {
                case SkEncodedFormat::kJPEG_SkEncodedFormat:
                case SkEncodedFormat::kPNG_SkEncodedFormat:
                    break;
                default:
                    // FIXME: Support webp using a special case.  Webp does not support
                    //        scanline decoding.
                    return nullptr;
            }

            // If the image is a jpeg or a png, the scanline ordering should always be
            // kTopDown or kNone.  It is relevant to check because this implementation
            // only supports these two scanline orderings.
            SkASSERT(SkCodec::kTopDown_SkScanlineOrder == codec->getScanlineOrder() ||
                    SkCodec::kNone_SkScanlineOrder == codec->getScanlineOrder());

            return new SkBitmapRegionCanvas(codec.detach());
        }
        case kAndroidCodec_Strategy: {
            SkAutoTDelete<SkAndroidCodec> codec =
                    SkAndroidCodec::NewFromStream(streamDeleter.detach());
            if (nullptr == codec) {
                SkCodecPrintf("Error: Failed to create codec.\n");
                return NULL;
            }

            SkEncodedFormat format = codec->getEncodedFormat();
            switch (format) {
                case SkEncodedFormat::kJPEG_SkEncodedFormat:
                case SkEncodedFormat::kPNG_SkEncodedFormat:
                case SkEncodedFormat::kWEBP_SkEncodedFormat:
                    break;
                default:
                    return nullptr;
            }

            return new SkBitmapRegionCodec(codec.detach());
        }
        default:
            SkASSERT(false);
            return nullptr;
    }
}
Ejemplo n.º 7
0
status_t
AVFormatReader::Sniff(int32* _streamCount)
{
	TRACE("AVFormatReader::Sniff\n");

	BPositionIO* source = dynamic_cast<BPositionIO*>(Source());
	if (source == NULL) {
		TRACE("  not a BPositionIO, but we need it to be one.\n");
		return B_NOT_SUPPORTED;
	}

	Stream* stream = new(std::nothrow) Stream(source,
		&fSourceLock);
	if (stream == NULL) {
		ERROR("AVFormatReader::Sniff() - failed to allocate Stream\n");
		return B_NO_MEMORY;
	}

	ObjectDeleter<Stream> streamDeleter(stream);

	status_t ret = stream->Open();
	if (ret != B_OK) {
		TRACE("  failed to detect stream: %s\n", strerror(ret));
		return ret;
	}

	delete[] fStreams;
	fStreams = NULL;

	int32 streamCount = stream->CountStreams();
	if (streamCount == 0) {
		TRACE("  failed to detect any streams: %s\n", strerror(ret));
		return B_ERROR;
	}

	fStreams = new(std::nothrow) Stream*[streamCount];
	if (fStreams == NULL) {
		ERROR("AVFormatReader::Sniff() - failed to allocate streams\n");
		return B_NO_MEMORY;
	}

	memset(fStreams, 0, sizeof(Stream*) * streamCount);
	fStreams[0] = stream;
	streamDeleter.Detach();

	#ifdef TRACE_AVFORMAT_READER
	dump_format(const_cast<AVFormatContext*>(stream->Context()), 0, "", 0);
	#endif

	if (_streamCount != NULL)
		*_streamCount = streamCount;

	return B_OK;
}
Ejemplo n.º 8
0
SkCodec* SkJpegCodec::NewFromStream(SkStream* stream) {
    SkAutoTDelete<SkStream> streamDeleter(stream);
    SkCodec* codec = nullptr;
    if (ReadHeader(stream,  &codec, nullptr)) {
        // Codec has taken ownership of the stream, we do not need to delete it
        SkASSERT(codec);
        streamDeleter.detach();
        return codec;
    }
    return nullptr;
}
Ejemplo n.º 9
0
/*
 * Creates a bmp decoder
 * Reads enough of the stream to determine the image format
 */
SkCodec* SkBmpCodec::NewFromStream(SkStream* stream, bool inIco) {
    SkAutoTDelete<SkStream> streamDeleter(stream);
    SkCodec* codec = nullptr;
    if (ReadHeader(stream, inIco, &codec)) {
        // codec has taken ownership of stream, so we do not need to
        // delete it.
        SkASSERT(codec);
        streamDeleter.detach();
        return codec;
    }
    return nullptr;
}
Ejemplo n.º 10
0
SkCodec* SkPngCodec::NewFromStream(SkStream* stream, SkPngChunkReader* chunkReader) {
    SkAutoTDelete<SkStream> streamDeleter(stream);

    SkCodec* outCodec = nullptr;
    if (read_header(stream, chunkReader, &outCodec, nullptr, nullptr)) {
        // Codec has taken ownership of the stream.
        SkASSERT(outCodec);
        streamDeleter.release();
        return outCodec;
    }

    return nullptr;
}
Ejemplo n.º 11
0
SkBitmapRegionDecoder* SkBitmapRegionDecoder::Create(
        SkStreamRewindable* stream, Strategy strategy) {
    SkAutoTDelete<SkStreamRewindable> streamDeleter(stream);
    switch (strategy) {
        case kCanvas_Strategy: {
            SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(streamDeleter.detach()));
            if (nullptr == codec) {
                SkCodecPrintf("Error: Failed to create decoder.\n");
                return nullptr;
            }

            if (SkEncodedFormat::kWEBP_SkEncodedFormat == codec->getEncodedFormat()) {
                // FIXME: Support webp using a special case.  Webp does not support
                //        scanline decoding.
                return nullptr;
            }

            switch (codec->getScanlineOrder()) {
                case SkCodec::kTopDown_SkScanlineOrder:
                case SkCodec::kNone_SkScanlineOrder:
                    break;
                default:
                    SkCodecPrintf("Error: Scanline ordering not supported.\n");
                    return nullptr;
            }
            return new SkBitmapRegionCanvas(codec.detach());
        }
        case kAndroidCodec_Strategy: {
            SkAutoTDelete<SkAndroidCodec> codec =
                    SkAndroidCodec::NewFromStream(streamDeleter.detach());
            if (NULL == codec) {
                SkCodecPrintf("Error: Failed to create codec.\n");
                return NULL;
            }
            return new SkBitmapRegionCodec(codec.detach());
        }
        default:
            SkASSERT(false);
            return nullptr;
    }
}
Ejemplo n.º 12
0
/*
 * Read enough of the stream to initialize the SkGifCodec.
 * Returns a bool representing success or failure.
 *
 * @param codecOut
 * If it returned true, and codecOut was not nullptr,
 * codecOut will be set to a new SkGifCodec.
 *
 * @param gifOut
 * If it returned true, and codecOut was nullptr,
 * gifOut must be non-nullptr and gifOut will be set to a new
 * GifFileType pointer.
 *
 * @param stream
 * Deleted on failure.
 * codecOut will take ownership of it in the case where we created a codec.
 * Ownership is unchanged when we returned a gifOut.
 *
 */
bool SkGifCodec::ReadHeader(SkStream* stream, SkCodec** codecOut, GifFileType** gifOut) {
    SkAutoTDelete<SkStream> streamDeleter(stream);

    // Read gif header, logical screen descriptor, and global color table
    SkAutoTCallVProc<GifFileType, CloseGif> gif(open_gif(stream));

    if (nullptr == gif) {
        gif_error("DGifOpen failed.\n");
        return false;
    }

    // Read through gif extensions to get to the image data.  Set the
    // transparent index based on the extension data.
    uint32_t transIndex;
    SkCodec::Result result = ReadUpToFirstImage(gif, &transIndex);
    if (kSuccess != result){
        return false;
    }

    // Read the image descriptor
    if (GIF_ERROR == DGifGetImageDesc(gif)) {
        return false;
    }
    // If reading the image descriptor is successful, the image count will be
    // incremented.
    SkASSERT(gif->ImageCount >= 1);

    if (nullptr != codecOut) {
        SkISize size;
        SkIRect frameRect;
        if (!GetDimensions(gif, &size, &frameRect)) {
            gif_error("Invalid gif size.\n");
            return false;
        }
        bool frameIsSubset = (size != frameRect.size());

        // Determine the recommended alpha type.  The transIndex might be valid if it less
        // than 256.  We are not certain that the index is valid until we process the color
        // table, since some gifs have color tables with less than 256 colors.  If
        // there might be a valid transparent index, we must indicate that the image has
        // alpha.
        // In the case where we must support alpha, we have the option to set the
        // suggested alpha type to kPremul or kUnpremul.  Both are valid since the alpha
        // component will always be 0xFF or the entire 32-bit pixel will be set to zero.
        // We prefer kPremul because we support kPremul, and it is more efficient to use
        // kPremul directly even when kUnpremul is supported.
        SkAlphaType alphaType = (transIndex < 256) ? kPremul_SkAlphaType : kOpaque_SkAlphaType;

        // Return the codec
        // kIndex is the most natural color type for gifs, so we set this as
        // the default.
        SkImageInfo imageInfo = SkImageInfo::Make(size.width(), size.height(), kIndex_8_SkColorType,
                alphaType);
        *codecOut = new SkGifCodec(imageInfo, streamDeleter.detach(), gif.detach(), transIndex,
                frameRect, frameIsSubset);
    } else {
        SkASSERT(nullptr != gifOut);
        streamDeleter.detach();
        *gifOut = gif.detach();
    }
    return true;
}