| /* |
| * Copyright (C) 2005, 2007, 2015 Apple Inc. All rights reserved. |
| * Copyright (C) 2005 Ben La Monica <ben.lamonica@gmail.com>. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "PlatformImage.h" |
| |
| #include <CoreGraphics/CGBitmapContext.h> |
| #include <CoreGraphics/CGImage.h> |
| #include <ImageIO/CGImageDestination.h> |
| #include <algorithm> |
| #include <stdio.h> |
| |
| #ifdef _WIN32 |
| #include <winsock2.h> |
| #include <windows.h> |
| #include <fcntl.h> |
| #include <io.h> |
| #endif |
| |
| #if __APPLE__ |
| #include <TargetConditionals.h> |
| |
| #if TARGET_OS_IPHONE |
| #include <MobileCoreServices/UTCoreTypes.h> |
| #else |
| #include <CoreServices/CoreServices.h> |
| #endif |
| |
| #endif |
| |
| #ifndef CGFLOAT_DEFINED |
| #ifdef __LP64__ |
| typedef double CGFloat; |
| #else |
| typedef float CGFloat; |
| #endif |
| #define CGFLOAT_DEFINED 1 |
| #endif |
| |
| #ifdef _WIN32 |
| #define FORMAT_SIZE_T "Iu" |
| #else |
| #define FORMAT_SIZE_T "zu" |
| #endif |
| |
| #ifdef _WIN32 |
| static const CFStringRef kUTTypePNG = CFSTR("public.png"); |
| #endif |
| |
| namespace ImageDiff { |
| |
| std::unique_ptr<PlatformImage> PlatformImage::createFromStdin(size_t imageSize) |
| { |
| unsigned char buffer[2048]; |
| CFMutableDataRef data = CFDataCreateMutable(0, imageSize); |
| |
| size_t bytesRemaining = imageSize; |
| while (bytesRemaining > 0) { |
| size_t bytesToRead = std::min<size_t>(bytesRemaining, 2048); |
| size_t bytesRead = fread(buffer, 1, bytesToRead, stdin); |
| CFDataAppendBytes(data, buffer, static_cast<CFIndex>(bytesRead)); |
| bytesRemaining -= static_cast<int>(bytesRead); |
| } |
| CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData(data); |
| CFRelease(data); |
| CGImageRef image = CGImageCreateWithPNGDataProvider(dataProvider, 0, false, kCGRenderingIntentDefault); |
| CFRelease(dataProvider); |
| |
| return std::make_unique<PlatformImage>(image); |
| } |
| |
| std::unique_ptr<PlatformImage> PlatformImage::createFromDiffData(void* data, size_t width, size_t height) |
| { |
| static CGColorSpaceRef diffColorspace = CGColorSpaceCreateDeviceGray(); |
| CGDataProviderRef provider = CGDataProviderCreateWithData(0, data, width * height, [](void*, const void* data, size_t) { |
| free(const_cast<void*>(data)); |
| }); |
| CGImageRef image = CGImageCreate(width, height, 8, 8, width, diffColorspace, 0, provider, 0, false, kCGRenderingIntentDefault); |
| CFRelease(provider); |
| |
| return std::make_unique<PlatformImage>(image); |
| } |
| |
| PlatformImage::PlatformImage(CGImageRef image) |
| : m_image(image) |
| { |
| } |
| |
| PlatformImage::~PlatformImage() |
| { |
| CFRelease(m_image); |
| free(m_buffer); |
| } |
| |
| size_t PlatformImage::width() const |
| { |
| return CGImageGetWidth(m_image); |
| } |
| |
| size_t PlatformImage::height() const |
| { |
| return CGImageGetHeight(m_image); |
| } |
| |
| size_t PlatformImage::rowBytes() const |
| { |
| return width() * 4; |
| } |
| |
| bool PlatformImage::hasAlpha() const |
| { |
| CGImageAlphaInfo info = CGImageGetAlphaInfo(m_image); |
| return (info >= kCGImageAlphaPremultipliedLast) && (info <= kCGImageAlphaFirst); |
| } |
| |
| unsigned char* PlatformImage::pixels() const |
| { |
| size_t width = this->width(); |
| size_t height = this->height(); |
| size_t rowBytes = width * 4; |
| |
| m_buffer = calloc(height, rowBytes); |
| CGContextRef context = CGBitmapContextCreate(m_buffer, width, height, 8, rowBytes, CGImageGetColorSpace(m_image), kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host); |
| CGContextDrawImage(context, CGRectMake(0, 0, width, height), m_image); |
| CFRelease(context); |
| return reinterpret_cast<unsigned char*>(m_buffer); |
| } |
| |
| void PlatformImage::writeAsPNGToStdout() |
| { |
| CFMutableDataRef imageData = CFDataCreateMutable(0, 0); |
| CGImageDestinationRef imageDest = CGImageDestinationCreateWithData(imageData, kUTTypePNG, 1, 0); |
| CGImageDestinationAddImage(imageDest, m_image, 0); |
| CGImageDestinationFinalize(imageDest); |
| printf("Content-Length: %" FORMAT_SIZE_T "\n", static_cast<size_t>(CFDataGetLength(imageData))); |
| fwrite(CFDataGetBytePtr(imageData), 1, CFDataGetLength(imageData), stdout); |
| CFRelease(imageData); |
| CFRelease(imageDest); |
| } |
| |
| } // namespace ImageDiff |