Пример #1
0
// cf. http://stackoverflow.com/questions/4598872/creating-hbitmap-from-memory-buffer/4616394#4616394
Bitmap *BitmapFromData(const char *data, size_t len)
{
    ImgFormat format = GfxFormatFromData(data, len);
    if (Img_TGA == format)
        return tga::ImageFromData(data, len);
    if (Img_WebP == format)
        return webp::ImageFromData(data, len);
    if (Img_JP2 == format)
        return fitz::ImageFromData(data, len);
    if (Img_JPEG == format && JpegUsesArithmeticCoding(data, len))
        return fitz::ImageFromData(data, len);

    ScopedComPtr<IStream> stream(CreateStreamFromData(data, len));
    if (!stream)
        return NULL;
    if (Img_JXR == format)
        return WICDecodeImageFromStream(stream);

    Bitmap *bmp = Bitmap::FromStream(stream);
    if (bmp && bmp->GetLastStatus() != Ok) {
        delete bmp;
        bmp = NULL;
    }
    // GDI+ under Windows XP sometimes fails to extract JPEG image dimensions
    if (bmp && Img_JPEG == format && (0 == bmp->GetWidth() || 0 == bmp->GetHeight())) {
        delete bmp;
        bmp = fitz::ImageFromData(data, len);
    }
    return bmp;
}
Пример #2
0
bool IsGdiPlusNativeFormat(const char *data, size_t len)
{
    ImgFormat fmt = GfxFormatFromData(data, len);
    return Img_BMP == fmt || Img_GIF == fmt ||
           (Img_JPEG == fmt && !JpegUsesArithmeticCoding(data, len)) ||
           Img_PNG == fmt || Img_TIFF == fmt;
}
Пример #3
0
// Windows' JPEG codec doesn't support arithmetic coding
static bool JpegUsesArithmeticCoding(const char* data, size_t len) {
    CrashIf(GfxFormatFromData(data, len) != Img_JPEG);

    ByteReader r(data, len);
    for (size_t ix = 2; ix + 9 < len && r.Byte(ix) == 0xFF; ix += r.WordBE(ix + 2) + 2) {
        if (0xC9 <= r.Byte(ix + 1) && r.Byte(ix + 1) <= 0xCB) {
            // found the start of a frame using arithmetic coding
            return true;
        }
    }
    return false;
}
Пример #4
0
// Windows' PNG codec fails to handle an edge case, resulting in
// an infinite loop (cf. http://cxsecurity.com/issue/WLB-2014080021 )
static bool PngRequiresPresetDict(const char* data, size_t len) {
    CrashIf(GfxFormatFromData(data, len) != Img_PNG);

    ByteReader r(data, len);
    for (size_t ix = 8; ix + 12 < len && r.DWordBE(ix) < len - ix - 12; ix += r.DWordBE(ix) + 12) {
        if (r.DWordBE(ix + 4) == 0x49444154 /* IDAT */) {
            // check the zlib header's FDICT flag
            // (even if this image claims not to be zlib compressed!)
            return (r.Byte(ix + 9) & (1 << 5)) != 0;
        }
    }

    return false;
}
Пример #5
0
const WCHAR *GfxFileExtFromData(const char *data, size_t len)
{
    switch (GfxFormatFromData(data, len)) {
    case Img_BMP:  return L".bmp";
    case Img_GIF:  return L".gif";
    case Img_JPEG: return L".jpg";
    case Img_JXR:  return L".jxr";
    case Img_PNG:  return L".png";
    case Img_TGA:  return L".tga";
    case Img_TIFF: return L".tif";
    case Img_WebP: return L".webp";
    case Img_JP2:  return L".jp2";
    default:       return NULL;
    }
}
Пример #6
0
// adapted from http://cpansearch.perl.org/src/RJRAY/Image-Size-3.230/lib/Image/Size.pm
Size BitmapSizeFromData(const char *data, size_t len)
{
    Size result;
    ByteReader r(data, len);
    switch (GfxFormatFromData(data, len)) {
    case Img_BMP:
        if (len >= sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)) {
            BITMAPINFOHEADER bmi;
            bool ok = r.UnpackLE(&bmi, sizeof(bmi), "3d2w6d", sizeof(BITMAPFILEHEADER));
            CrashIf(!ok);
            result.Width = bmi.biWidth;
            result.Height = bmi.biHeight;
        }
        break;
    case Img_GIF:
        if (len >= 13) {
            // find the first image's actual size instead of using the
            // "logical screen" size which is sometimes too large
            size_t ix = 13;
            // skip the global color table
            if ((r.Byte(10) & 0x80))
                ix += 3 * (1 << ((r.Byte(10) & 0x07) + 1));
            while (ix + 8 < len) {
                if (r.Byte(ix) == 0x2C) {
                    result.Width = r.WordLE(ix + 5);
                    result.Height = r.WordLE(ix + 7);
                    break;
                }
                else if (r.Byte(ix) == 0x21 && r.Byte(ix + 1) == 0xF9)
                    ix += 8;
                else if (r.Byte(ix) == 0x21 && r.Byte(ix + 1) == 0xFE) {
                    const char *commentEnd = r.Find(ix + 2, 0x00);
                    ix = commentEnd ? commentEnd - data + 1 : len;
                }
                else if (r.Byte(ix) == 0x21 && r.Byte(ix + 1) == 0x01 && ix + 15 < len) {
                    const char *textDataEnd = r.Find(ix + 15, 0x00);
                    ix = textDataEnd ? textDataEnd - data + 1 : len;
                }
                else if (r.Byte(ix) == 0x21 && r.Byte(ix + 1) == 0xFF && ix + 14 < len) {
                    const char *applicationDataEnd = r.Find(ix + 14, 0x00);
                    ix = applicationDataEnd ? applicationDataEnd - data + 1 : len;
                }
                else
                    break;
            }
        }
        break;
    case Img_JPEG:
        // find the last start of frame marker for non-differential Huffman/arithmetic coding
        for (size_t ix = 2; ix + 9 < len && r.Byte(ix) == 0xFF; ) {
            if (0xC0 <= r.Byte(ix + 1) && r.Byte(ix + 1) <= 0xC3 ||
                0xC9 <= r.Byte(ix + 1) && r.Byte(ix + 1) <= 0xCB) {
                result.Width = r.WordBE(ix + 7);
                result.Height = r.WordBE(ix + 5);
            }
            ix += r.WordBE(ix + 2) + 2;
        }
        break;
    case Img_JXR:
    case Img_TIFF:
        if (len >= 10) {
            bool isBE = r.Byte(0) == 'M', isJXR = r.Byte(2) == 0xBC;
            CrashIf(!isBE && r.Byte(0) != 'I' || isJXR && isBE);
            const WORD WIDTH = isJXR ? 0xBC80 : 0x0100, HEIGHT = isJXR ? 0xBC81 : 0x0101;
            size_t idx = r.DWord(4, isBE);
            WORD count = idx <= len - 2 ? r.Word(idx, isBE) : 0;
            for (idx += 2; count > 0 && idx <= len - 12; count--, idx += 12) {
                WORD tag = r.Word(idx, isBE), type = r.Word(idx + 2, isBE);
                if (r.DWord(idx + 4, isBE) != 1)
                    continue;
                else if (WIDTH == tag && 4 == type)
                    result.Width = r.DWord(idx + 8, isBE);
                else if (WIDTH == tag && 3 == type)
                    result.Width = r.Word(idx + 8, isBE);
                else if (WIDTH == tag && 1 == type)
                    result.Width = r.Byte(idx + 8);
                else if (HEIGHT == tag && 4 == type)
                    result.Height = r.DWord(idx + 8, isBE);
                else if (HEIGHT == tag && 3 == type)
                    result.Height = r.Word(idx + 8, isBE);
                else if (HEIGHT == tag && 1 == type)
                    result.Height = r.Byte(idx + 8);
            }
        }
        break;
    case Img_PNG:
        if (len >= 24 && str::StartsWith(data + 12, "IHDR")) {
            result.Width = r.DWordBE(16);
            result.Height = r.DWordBE(20);
        }
        break;
    case Img_TGA:
        if (len >= 16) {
            result.Width = r.WordLE(12);
            result.Height = r.WordLE(14);
        }
        break;
    case Img_WebP:
        if (len >= 30 && str::StartsWith(data + 12, "VP8 ")) {
            result.Width = r.WordLE(26) & 0x3fff;
            result.Height = r.WordLE(28) & 0x3fff;
        }
        else {
            result = webp::SizeFromData(data, len);
        }
        break;
    case Img_JP2:
        if (len >= 32) {
            size_t ix = 0;
            while (ix < len - 32) {
                uint32_t lbox = r.DWordBE(ix);
                uint32_t tbox = r.DWordBE(ix + 4);
                if (0x6A703268 /* jp2h */ == tbox) {
                    ix += 8;
                    if (r.DWordBE(ix) == 24 && r.DWordBE(ix + 4) == 0x69686472 /* ihdr */) {
                        result.Width = r.DWordBE(ix + 16);
                        result.Height = r.DWordBE(ix + 12);
                    }
                    break;
                }
                else if (lbox != 0 && ix < UINT32_MAX - lbox) {
                    ix += lbox;
                }
                else {
                    break;
                }
            }
        }
        break;
    }

    if (result.Empty()) {
        // let GDI+ extract the image size if we've failed
        // (currently happens for animated GIF)
        Bitmap *bmp = BitmapFromData(data, len);
        if (bmp)
            result = Size(bmp->GetWidth(), bmp->GetHeight());
        delete bmp;
    }

    return result;
}