Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/gfx/skia/skia/src/utils/mac/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 11 kB image not shown  

Quelle  SkCreateCGImageRef.cpp   Sprache: C

 
/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */


#include "include/core/SkTypes.h"
#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)

#include "include/core/SkBitmap.h"
#include "include/core/SkColorSpace.h"
#include "include/core/SkData.h"
#include "include/encode/SkICC.h"
#include "include/private/SkColorData.h"
#include "include/private/base/SkMacros.h"
#include "include/private/base/SkTo.h"
#include "include/utils/mac/SkCGUtils.h"
#include "src/utils/mac/SkUniqueCFRef.h"

#include <climits>
#include <memory>

static CGBitmapInfo compute_cgalpha_info_rgba(SkAlphaType at) {
    CGBitmapInfo info = kCGBitmapByteOrder32Big;
    switch (at) {
        case kUnknown_SkAlphaType:                                          break;
        case kOpaque_SkAlphaType:   info |= kCGImageAlphaNoneSkipLast;      break;
        case kPremul_SkAlphaType:   info |= kCGImageAlphaPremultipliedLast; break;
        case kUnpremul_SkAlphaType: info |= kCGImageAlphaLast;              break;
    }
    return info;
}

static CGBitmapInfo compute_cgalpha_info_bgra(SkAlphaType at) {
    CGBitmapInfo info = kCGBitmapByteOrder32Little;
    switch (at) {
        case kUnknown_SkAlphaType:                                           break;
        case kOpaque_SkAlphaType:   info |= kCGImageAlphaNoneSkipFirst;      break;
        case kPremul_SkAlphaType:   info |= kCGImageAlphaPremultipliedFirst; break;
        case kUnpremul_SkAlphaType: info |= kCGImageAlphaFirst;              break;
    }
    return info;
}
static CGBitmapInfo compute_cgalpha_info_4444(SkAlphaType at) {
    CGBitmapInfo info = kCGBitmapByteOrder16Little;
    switch (at) {
        case kOpaque_SkAlphaType: info |= kCGImageAlphaNoneSkipLast;      break;
        default:                  info |= kCGImageAlphaPremultipliedLast; break;
    }
    return info;
}

static bool get_bitmap_info(SkColorType skColorType,
                            SkAlphaType skAlphaType,
                            size_t* bitsPerComponent,
                            CGBitmapInfo* info,
                            bool* upscaleTo32) {
    if (upscaleTo32) {
        *upscaleTo32 = false;
    }
    switch (skColorType) {
        case kRGB_565_SkColorType:
            if (upscaleTo32) {
                *upscaleTo32 = true;
            }
            // now treat like RGBA
            *bitsPerComponent = 8;
            *info = compute_cgalpha_info_rgba(kOpaque_SkAlphaType);
            break;
        case kRGBA_8888_SkColorType:
            *bitsPerComponent = 8;
            *info = compute_cgalpha_info_rgba(skAlphaType);
            break;
        case kBGRA_8888_SkColorType:
            *bitsPerComponent = 8;
            *info = compute_cgalpha_info_bgra(skAlphaType);
            break;
        case kARGB_4444_SkColorType:
            *bitsPerComponent = 4;
            *info = compute_cgalpha_info_4444(skAlphaType);
            break;
        default:
            return false;
    }
    return true;
}

static std::unique_ptr<SkBitmap> prepare_for_image_ref(const SkBitmap& bm,
                                                       size_t* bitsPerComponent,
                                                       CGBitmapInfo* info) {
    bool upscaleTo32;
    if (!get_bitmap_info(bm.colorType(), bm.alphaType(), bitsPerComponent, info, &upscaleTo32)) {
        return nullptr;
    }
    if (upscaleTo32) {
        std::unique_ptr<SkBitmap> copy(new SkBitmap);
        // here we make a deep copy of the pixels, since CG won't take our
        // 565 directly, so we always go to RGBA
        copy->allocPixels(bm.info().makeColorType(kRGBA_8888_SkColorType));
        bm.readPixels(copy->info(), copy->getPixels(), copy->rowBytes(), 0, 0);
        return copy;
    }
    return std::make_unique<SkBitmap>(bm);
}

CGImageRef SkCreateCGImageRefWithColorspace(const SkBitmap& bm,
                                            CGColorSpaceRef colorSpace) {
    return SkCreateCGImageRef(bm);
}

CGImageRef SkCreateCGImageRef(const SkBitmap& bm) {
    if (bm.drawsNothing()) {
        return nullptr;
    }
    size_t bitsPerComponent SK_INIT_TO_AVOID_WARNING;
    CGBitmapInfo info       SK_INIT_TO_AVOID_WARNING;

    std::unique_ptr<SkBitmap> bitmap = prepare_for_image_ref(bm, &bitsPerComponent, &info);
    if (nullptr == bitmap) {
        return nullptr;
    }

    SkPixmap pm = bitmap->pixmap();  // Copy bitmap info before releasing it.
    const size_t s = bitmap->computeByteSize();
    void* pixels = bitmap->getPixels();

    // our provider "owns" the bitmap*, and will take care of deleting it
    SkUniqueCFRef<CGDataProviderRef> dataRef(CGDataProviderCreateWithData(
            bitmap.release(), pixels, s,
            [](void* p, const void*, size_t) { delete reinterpret_cast<SkBitmap*>(p); }));

    SkUniqueCFRef<CGColorSpaceRef> colorSpace(SkCreateCGColorSpace(bm.colorSpace()));
    return CGImageCreate(pm.width(),
                         pm.height(),
                         bitsPerComponent,
                         pm.info().bytesPerPixel() * CHAR_BIT,
                         pm.rowBytes(),
                         colorSpace.get(),
                         info,
                         dataRef.get(),
                         nullptr,
                         false,
                         kCGRenderingIntentDefault);
}

void SkCGDrawBitmap(CGContextRef cg, const SkBitmap& bm, float x, float y) {
    SkUniqueCFRef<CGImageRef> img(SkCreateCGImageRef(bm));

    if (img) {
        CGRect r = CGRectMake(0, 0, bm.width(), bm.height());

        CGContextSaveGState(cg);
        CGContextTranslateCTM(cg, x, r.size.height + y);
        CGContextScaleCTM(cg, 1, -1);

        CGContextDrawImage(cg, r, img.get());

        CGContextRestoreGState(cg);
    }
}

///////////////////////////////////////////////////////////////////////////////////////////////////

CGContextRef SkCreateCGContext(const SkPixmap& pmap) {
    CGBitmapInfo cg_bitmap_info = 0;
    size_t bitsPerComponent = 0;
    switch (pmap.colorType()) {
        case kRGBA_8888_SkColorType:
            bitsPerComponent = 8;
            cg_bitmap_info = compute_cgalpha_info_rgba(pmap.alphaType());
            break;
        case kBGRA_8888_SkColorType:
            bitsPerComponent = 8;
            cg_bitmap_info = compute_cgalpha_info_bgra(pmap.alphaType());
            break;
        default:
            return nullptr;   // no other colortypes are supported (for now)
    }

    size_t rb = pmap.addr() ? pmap.rowBytes() : 0;
    SkUniqueCFRef<CGColorSpaceRef> cs(SkCreateCGColorSpace(pmap.colorSpace()));
    CGContextRef cg = CGBitmapContextCreate(pmap.writable_addr(), pmap.width(), pmap.height(),
                                            bitsPerComponent, rb, cs.get(), cg_bitmap_info);
    return cg;
}

bool SkCopyPixelsFromCGImage(const SkImageInfo& info, size_t rowBytes, void* pixels,
                             CGImageRef image) {
    CGBitmapInfo cg_bitmap_info = 0;
    size_t bitsPerComponent = 0;
    switch (info.colorType()) {
        case kRGBA_8888_SkColorType:
            bitsPerComponent = 8;
            cg_bitmap_info = compute_cgalpha_info_rgba(info.alphaType());
            break;
        case kBGRA_8888_SkColorType:
            bitsPerComponent = 8;
            cg_bitmap_info = compute_cgalpha_info_bgra(info.alphaType());
            break;
        default:
            return false;   // no other colortypes are supported (for now)
    }

    SkUniqueCFRef<CGColorSpaceRef> cs(SkCreateCGColorSpace(info.colorSpace()));
    SkUniqueCFRef<CGContextRef> cg(CGBitmapContextCreate(
                pixels, info.width(), info.height(), bitsPerComponent,
                rowBytes, cs.get(), cg_bitmap_info));
    if (!cg) {
        return false;
    }

    // use this blend mode, to avoid having to erase the pixels first, and to avoid CG performing
    // any blending (which could introduce errors and be slower).
    CGContextSetBlendMode(cg.get(), kCGBlendModeCopy);

    CGContextDrawImage(cg.get(), CGRectMake(0, 0, info.width(), info.height()), image);
    return true;
}

bool SkCreateBitmapFromCGImage(SkBitmap* dst, CGImageRef image) {
    const int width = SkToInt(CGImageGetWidth(image));
    const int height = SkToInt(CGImageGetHeight(image));
    sk_sp<SkColorSpace> colorSpace(SkMakeColorSpaceFromCGColorSpace(CGImageGetColorSpace(image)));
    SkImageInfo info = SkImageInfo::MakeN32Premul(width, height, colorSpace);

    SkBitmap tmp;
    if (!tmp.tryAllocPixels(info)) {
        return false;
    }

    if (!SkCopyPixelsFromCGImage(tmp.info(), tmp.rowBytes(), tmp.getPixels(), image)) {
        return false;
    }

    CGImageAlphaInfo cgInfo = CGImageGetAlphaInfo(image);
    switch (cgInfo) {
        case kCGImageAlphaNone:
        case kCGImageAlphaNoneSkipLast:
        case kCGImageAlphaNoneSkipFirst:
            SkASSERT(SkBitmap::ComputeIsOpaque(tmp));
            tmp.setAlphaType(kOpaque_SkAlphaType);
            break;
        default:
            // we don't know if we're opaque or not, so compute it.
            if (SkBitmap::ComputeIsOpaque(tmp)) {
                tmp.setAlphaType(kOpaque_SkAlphaType);
            }
    }

    *dst = tmp;
    return true;
}

sk_sp<SkImage> SkMakeImageFromCGImage(CGImageRef src) {
    SkBitmap bm;
    if (!SkCreateBitmapFromCGImage(&bm, src)) {
        return nullptr;
    }

    bm.setImmutable();
    return bm.asImage();
}

CGDataProviderRef SkCreateCGDataProvider(sk_sp<SkData> data) {
    if (!data) {
        return nullptr;
    }

    CGDataProviderRef result = CGDataProviderCreateWithData(
            data.get(), data->data(), data->size(), [](void* info, const void*, size_t) {
                reinterpret_cast<SkData*>(info)->unref();
            });
    if (!result) {
        return nullptr;
    }

    // Retain `data` for the release that will come when `result` is freed.
    data->ref();
    return result;
}

sk_sp<SkColorSpace> SkMakeColorSpaceFromCGColorSpace(CGColorSpaceRef cgColorSpace) {
    if (!cgColorSpace) {
        return nullptr;
    }

    // Attempt to convert by name.
    SkUniqueCFRef<CFStringRef> name(CGColorSpaceCopyName(cgColorSpace));
    if (name && CFStringCompare(name.get(), kCGColorSpaceSRGB, 0) == kCFCompareEqualTo) {
        return SkColorSpace::MakeSRGB();
    }

    // Attempt to convert by parsing the ICC profile.
    SkUniqueCFRef<CFDataRef> iccData(CGColorSpaceCopyICCData(cgColorSpace));
    if (!iccData) {
        return nullptr;
    }
    skcms_ICCProfile iccProfile;
    if (!skcms_Parse(
                CFDataGetBytePtr(iccData.get()), CFDataGetLength(iccData.get()), &iccProfile)) {
        return nullptr;
    }
    return SkColorSpace::Make(iccProfile);
}

CGColorSpaceRef SkCreateCGColorSpace(const SkColorSpace* space) {
    // Initialize result to sRGB. We will use this as the fallback on failure.
    CGColorSpaceRef cgSRGB = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);

    // Early-out of this is sRGB (or nullptr defaulting to sRGB).
    if (!space || space->isSRGB()) {
        return cgSRGB;
    }

    // Create an SkData with the ICC profile.
    skcms_TransferFunction fn;
    skcms_Matrix3x3 to_xyzd50;
    space->transferFn(&fn);
    space->toXYZD50(&to_xyzd50);
    sk_sp<SkData> iccData = SkWriteICCProfile(fn, to_xyzd50);
    if (!iccData) {
        return cgSRGB;
    }

    // Create a CGColorSpaceRef from that ICC data.
    const size_t kNumComponents = 3;
    const CGFloat kComponentRanges[6] = {0, 1, 0, 1, 0, 1};
    SkUniqueCFRef<CGDataProviderRef> iccDataProvider(SkCreateCGDataProvider(iccData));
    CGColorSpaceRef result = CGColorSpaceCreateICCBased(
            kNumComponents, kComponentRanges, iccDataProvider.get(), cgSRGB);
    if (!result) {
        return cgSRGB;
    }

    // We will not be returning |cgSRGB|, so free it now.
    CFRelease(cgSRGB);
    cgSRGB = nullptr;

    return result;
}

#endif//defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)

Messung V0.5
C=94 H=95 G=94

¤ Dauer der Verarbeitung: 0.0 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

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.