Запись патчей обработки изображений

Кварцевая платформа Композитора определяет протоколы для получения данных изображения от входных портов и обеспечения данных изображения к выходным портам. Эти протоколы избавляют от необходимости использовать явные типы данных image такой как CIImage или CGImage объекты. Используя протоколы гарантирует, что не будет никаких несоответствий импеданса между выходным портом изображения одного патча и входным портом изображения другого.

В этой главе описываются, как реализовать QCPlugInInputImageSource и QCPlugInOutputImageProvider протоколы. Тогда это обеспечивает поэтапные инструкции для создания пользовательского изображения, обрабатывающего патч, использующий два входных порта изображения и один выходной порт изображения.

Получение изображений от входного порта

QCPlugInInputImageSource протокол преобразовывает входное изображение из любого формата, это находится в или к буферу памяти или к представлению текстуры OpenGL. Когда необходимо получить доступ к пикселям в изображении, Вы просто преобразовываете изображение в представление (текстура или буфер) использование одного из методов, определенных протоколом. Используйте представление текстуры для обработки данных изображения на GPU. Используйте буферное представление для обработки данных изображения на CPU.

Для создания входного порта изображения как свойства Objective-C 2.0 объявите его следующим образом:

@property(dynamic) id<QCPlugInInputImageSource> inputImage;

Для создания входного порта изображения динамично используйте тип QCPortTypeImage:

[self addInputPortWithType:QCPortTypeImage
                    forKey:@"inputImage"
            withAttributes:nil];

Вы преобразовываете входные изображения в текстуры только, когда Вы планируете использовать OpenGL для обработки данных, поскольку OpenGL является программным интерфейсом к GPU. Для использования входных изображений в качестве текстур, необходимо выполнить эти шаги:

  1. Заблокируйте использование представления текстуры lockTextureRepresentationWithColorSpace:forBounds:. Этот метод создает текстуру OpenGL только для чтения из подобласти входного изображения.

  2. Свяжите текстуру с модулем текстуры. Можно выполнить этот шаг полностью с командами OpenGL, но намного проще использовать удобный метод bindTextureRepresentationToCGLContext:textureUnit:normalizeCoordinates: который связывает текстуру с предоставленным модулем текстуры (GL_TEXTURE0, и т.д.). Это также загружает матрицу текстуры на штабель текстуры, масштабируясь и зеркально отражая координаты при необходимости, пока Вы передаете YES как normalizeCoordinates параметр.

  3. Использование текстура любым способом является подходящим для Вашего приложения.

  4. Когда Вы больше не нуждаетесь в текстуре, развязываете ее от ее модуля текстуры. Если бы Вы использовали обязательный удобный метод на шаге 2, то необходимо вызвать unbindTextureRepresentationFromCGLContext:textureUnit удобный метод.

  5. Выпустите представление текстуры OpenGL входного изображения путем вызова unlockTextureRepresentation метод.

В дополнение к этим шагам существуют другие задачи, которые необходимо выполнить при использовании OpenGL. Запись Потребительских Патчей обеспечивает подсказки для использования OpenGL в пользовательском патче и показывает, как связать текстуру и представить ее месту назначения.

Вы преобразовываете изображения в буферное представление, только если Ваш пользовательский патч управляет входными изображениями на CPU. Для использования входных данных изображения в буфере, необходимо выполнить эти шаги:

  1. Создайте и заблокируйте буферное представление изображения с помощью lockBufferRepresentationWithPixelFormat:colorSpace:forBounds: метод, создающий буфер постоянной памяти из подобласти входного изображения. Формат пикселя и цветовое пространство должны быть совместимыми.

  2. Используйте данные изображения. Можно получить базовый адрес буфера изображения с bufferBaseAddress метод и число байтов на строку с bufferBytesPerRow метод.

  3. Когда Вам больше не будет нужен буфер изображения, вызовите unlockBufferRepresentation выпускать его.

Ссылка на протокол QCPlugInInputImageSource предоставляет больше информации об этих методах, а также методах, получающих текстуру и отображающих буферную информацию — такую как границы, высота, ширина и цветовое пространство. Работа гистограммы: Изменение Раскрашивает Изображение, показывает, как преобразовать входное изображение в буфер изображения.

Обеспечение изображений для выходного порта

QCPlugInOutputImageProvider протокол определяет методы для рендеринга данных изображения к буферу изображения или к текстуре. Кварцевый Композитор вызывает методы, которые Вы реализуете только, когда необходимо выходное изображение. Этот «ленивый» подход к предоставлению выходного изображения эффективен и гарантирует лучшую возможную производительность.

Если Ваш пользовательский патч имеет выходной порт изображения, необходимо реализовать надлежащие методы для рендеринга данных изображения и предоставлять информацию о месте назначения рендеринга и границах изображения.

Для создания выходного порта изображения как свойства Objective-C 2.0 объявите его следующим образом:

@property(assign) id<QCPlugInOutputImageProvider> outputImage;

Для создания входного порта изображения динамично используют тип QCPortTypeImage:

[self addOutputPortWithType:QCPortTypeImage
                    forKey:@"outputImage"
           withAttributes:nil];

Для записи изображений в тот порт необходимо выполнить эти шаги:

  1. Создайте внутренний класс, представляющий выходное изображение.

    @interface MyOutputImageProvider : NSObject <QCPlugInOutputImageProvider>
    {
      // Declare instance variables, as appropriate
    }
  2. Реализуйте методы, предоставляющие информацию об изображении —imageBounds imageColorSpace.

  3. Реализуйте методы, предоставляющие информацию о месте назначения рендеринга. Если Ваш пользовательский патч представляет к буферу изображения, необходимо реализоватьsupportedBufferPixelFormats метод. Если это представляет к текстуре, необходимо реализоватьsupportedDrawablePixelFormats и canRenderWithCGLContext: методы.

  4. Реализуйте один из методов для рендеринга месту назначения. Если Ваш пользовательский патч представляет к буферу изображения, необходимо реализовать renderToBuffer:withBytesPerRow:pixelFormat:forBounds: метод. Если Ваш пользовательский патч представляет к текстуре, необходимо реализовать renderWithCGLContext:toDrawableWithPixelFormat:forBounds: метод.

Посмотрите Ссылку на протокол QCPlugInOutputImageProvider для дополнительных подробных данных об этих методах.

Когда Кварцевый Композитор вызывает renderToBuffer:withBytesPerRow:pixelFormat:forBounds:, это передает Ваш метод базовый адрес, число байтов строки, формат пикселя данных изображения и границы подобласти. Ваш метод тогда пишет пиксели в предоставленный буфер изображения. Работа гистограммы: Изменение Раскрашивает Изображение, обеспечивает пример того, как реализовать этот метод.

Когда Кварцевый Композитор вызывает renderWithCGLContext:toDrawableWithPixelFormat:forBounds:, это автоматически устанавливает область просмотра в размерности изображения, и проекцию и modelview матрицы к единичной матрице. До рендеринга необходимо сохранить все состояния OpenGL, которыми Вы планируете измениться кроме тех определенных GL_CURRENT_BIT. Когда Вы сделаны, представив, необходимо восстановить сохраненные состояния OpenGL.

Работа гистограммы: изменение раскрашивает изображение

Этот раздел показывает, как записать пользовательский патч, имеющий два входных порта изображения и один выходной порт изображения. Патч вычисляет гистограмму для одного из входных изображений и использует ту гистограмму для изменения цветов в другом входном изображении. Это выводит измененное цветом изображение. Этот патч немного более сложен, чем описанные в остальной части книги. Прежде, чем следовать инструкциям в этом разделе, удостоверьтесь, что Вы считали Патчи Процессора Записи и знакомы с основными задачами для установки и создания пользовательского патча.

Работа Гистограммы пользовательский патч, описанный в этом разделе, подобна, но не точно как, демонстрационный проект Работы Гистограммы, предоставленный Инструменты Разработчика для OS X v10.5 в:

/Developer/Examples/Quartz Composer/Plugins

Вы могли бы также хотеть смотреть на тот демонстрационный проект.

Гистограмма RGBA является количеством значений на каждом уровне яркости для каждого пиксельного компонента (красный, зеленый, синий, и альфа). Для изображения с маленькой глубиной 8 битов каждый компонент может иметь значение от 0 до 255. Рисунок 3-1 показывает гистограмму RGB для гирляндного изображения. Значения интенсивности графически изображены на оси X, и число пикселей находятся на оси y. Изображение непрозрачно, таким образом, нет никакой потребности показать альфа-компонент в этом числе.

Рисунок 3-1  гистограмма RGB для изображения гирлянды
An RGB histogram for an image of a daisy

Данные изображения для этого патча обрабатываются с помощью CPU, таким образом, Вы будете видеть, как создать буферное представление изображения и рендеринг к буферу изображения путем определения пользовательского выходного провайдера изображения. (Можно узнать, как создать представление текстуры путем чтения Пишущих Потребительских Патчей.) Вы будете также видеть, как использовать Ускорять платформу для вычислений гистограммы.

Рисунок 3-2 показывает состав, использующий Работу Гистограммы пользовательский патч. Путем рассмотрения изображений миниатюр можно понять то, как патч изменяет исходное изображение с помощью изображения гистограммы.

Рисунок 3-2  Кварцевый состав, использующий Работу Гистограммы пользовательский патч
A Quartz composition that uses the Histogram Operation custom patchA Quartz composition that uses the Histogram Operation custom patch

Ускорять платформа является высокоэффективной ускоренной вектором библиотекой подпрограмм. Это идеально для использования для пользовательских патчей, выполняющих интенсивные вычисления. Вы будете пользоваться vImage библиотекой платформы для вычислений гистограммы. Функция vImageHistogramCalculation_ARGB8888 вычисляет гистограммы для альфы, красные, зеленые, и синие каналы (см. Перечисление 3-1). Это берет буфер изображения, массив, чтобы хранить данные гистограммы и флаг, чтобы указать, выключить ли vImage внутренние подпрограммы мозаичного размещения. (См. vImage Ссылочный Набор.)

  Прототип перечисления 3-1 для vImage функции гистограммы

vImage_Error vImageHistogramCalculation_ARGB8888 (
                      const vImage_Buffer *src,
                      vImagePixelCount *histogram[4],
                      vImage_Flags flags
);

Шаги для создания Работы Гистограммы пользовательский патч находятся в этих разделах:

Создайте проект XCode

Для создания Работы Гистограммы проект XCode выполните эти шаги.:

  1. Откройте Xcode и выберите File> New Project.

  2. В окне New Project выберите Standard Apple Plug-ins> Quartz Composer Plug-in и нажмите Далее.

  3. Войти HistogramOperation в текстовом поле Project Name и нажимают Finish.

  4. Выберите Project> Add to Project, перейдите к Ускорять Платформе и нажмите Add.

    Эта платформа находится в System/Library/Frameworks.

  5. В листе, появляющемся, нажмите Add.

Создайте интерфейс

При создании пользовательских патчей в записи Патчей Процессора большинство шагов в этом разделе должно быть знакомо Вам.

  1. Откройтесь HistogramOperationPlugin.h файл.

  2. Добавьте оператор для импорта Ускорять платформы.

    #import <Accelerate/Accelerate.h>
  3. Объявите два свойства для входных портов изображения — один для исходного изображения, которое пользовательский патч изменяет и другой для изображения, используемого для гистограммы. Объявите свойство для выходного порта изображения. Ваш код должен посмотреть следующим образом:

    #import <Quartz/Quartz.h>
    #import <Accelerate/Accelerate.h>
     
    @interface HistogramOperationPlugIn : QCPlugIn
    {
     
    }
    @property(assign) id<QCPlugInInputImageSource> inputSourceImage;
    @property(assign) id<QCPlugInInputImageSource> inputHistogramImage;
    @property(assign) id<QCPlugInOutputImageProvider> outputResultImage;
    @end
  4. Добавьте интерфейс для класса, вычисляющего гистограмму RGBA из изображения.

    Histogram объект содержит источник изображения, из которого Вы вычислите гистограмму. В дополнение к переменной экземпляра источника изображения необходимо создать четыре переменные экземпляра для хранения количества компонента цвета и альфа-значений — красный, зеленый, синий, и альфа.

    Необходимо записать метод, инициализирующий переменную экземпляра изображения. Вам будет нужен другой метод для вычислений значений гистограммы. Объявите эти методы теперь; Вы запишете им позже.

    Ваш код должен выглядеть подобным следующему:

    @interface Histogram : NSObject
    {
        id<QCPlugInInputImageSource>    _image;
     
        vImagePixelCount                _histogramA[256];
        vImagePixelCount                _histogramR[256];
        vImagePixelCount                _histogramG[256];
        vImagePixelCount                _histogramB[256];
        CGColorSpaceRef                 _colorSpace;
    }
    - (id) initWithImageSource:(id<QCPlugInInputImageSource>)image colorSpace:(CGColorSpaceRef)colorSpace;
    - (BOOL) getRGBAHistograms:(vImagePixelCount**)histograms;
    @end
  5. В интерфейсе для HistogramOperationPlugIn класс, добавляет переменная экземпляра для a Histogram объект. Вы будете использовать это для кэширования гистограммы изображения.

    Интерфейс должен быть похожим на это:

    @interface HistogramOperationPlugIn : QCPlugIn
    {
        Histogram*                        _cachedHistogram;
    }

    Обратите внимание на то, что интерфейс для Histogram класс должен или быть указан перед HistogramOperationPlugIn класс или класс должны быть объявлены с помощью:

    @class Histogram;

  6. Добавьте интерфейс для внутреннего класса для провайдера изображения, для представления выходного изображения, произведенного пользовательским патчем.

    Этот класс имеет две переменные экземпляра — входное изображение раньше создавало гистограмму, и Histogram возразите, что Вы будете использовать для изменения исходного изображения. Также необходимо объявить, что метод инициализирует переменную экземпляра изображения. Вы запишете initWithImageSource:histogram: метод позже. Когда сделано, Ваш код должен быть похожим на это:

    @interface HistogramImageProvider : NSObject <QCPlugInOutputImageProvider>
    {
        id<QCPlugInInputImageSource>    _image;
        Histogram*                      _histogram;
    }
    - (id) initWithImageSource:(id<QCPlugInInputImageSource>)image
                     histogram:(Histogram*)histogram;
    @end
  7. Закройтесь HistogramOperationPlugIn.h файл.

Измените методы для класса PlugIn

Затем Вы измените методы, должен был реализовать HistogramOperationPlugIn класс.

  1. Откройтесь HistogramOperationPlugIn.m файл.

  2. Сразу после оператора реализации для HistogramOperationPlugin, объявите свойства ввода и вывода как динамичные. Кварцевый Композитор обработает их реализацию.

    @dynamic inputSourceImage, inputHistogramImage, outputResultImage;
  3. Измените описание и имя для пользовательского патча.

    #define    kQCPlugIn_Name  @"Histogram Operation"
    #define kQCPlugIn_Description @"Alters a source image according to the histogram of another image."
  4. Вы не должны изменять значение по умолчанию attributes метод предоставил в шаблоне, который должен посмотреть следующим образом:

    + (NSDictionary*) attributes
    {
        return [NSDictionary dictionaryWithObjectsAndKeys:
                    kQCPlugIn_Name,QCPlugInAttributeNameKey,
                    kQCPlugIn_Description,QCPlugInAttributeDescriptionKey,
                    nil];
    }
  5. Измените attributesForPropertyPortWithKey: так, чтобы это возвратило словарь для каждого параметра ввода и вывода.

    + (NSDictionary*) attributesForPropertyPortWithKey:(NSString*)key
    {
     
      if([key isEqualToString:@"inputSourceImage"])
        return [NSDictionary dictionaryWithObjectsAndKeys:@"Source Image",
                             QCPortAttributeNameKey, nil];
      if([key isEqualToString:@"inputHistogramImage"])
        return [NSDictionary dictionaryWithObjectsAndKeys:@"Histogram Image",
                              QCPortAttributeNameKey, nil];
      if([key isEqualToString:@"outputResultImage"])
        return [NSDictionary dictionaryWithObjectsAndKeys:@"Result Image",
                              QCPortAttributeNameKey, nil];
      return nil;
    }
  6. Удостоверьтесь executionMode возвраты метода kQCPlugInExecutionModeProcessor.

    + (QCPlugInExecutionMode) executionMode
    {
        return kQCPlugInExecutionModeProcessor;
    }
  7. Удостоверьтесь timeMode возвраты метода kQCPlugInTimeModeNone.

    + (QCPlugInTimeMode) timeMode
    {
        return kQCPlugInTimeModeNone;
    }

Реализуйте методы для объекта гистограммы

Перед реализацией методов выполнения для HistogramOperationPlugIn, Вы реализуете методы, необходимые для Histogram класс — один для инициализации объекта с изображением, метод для выпуска изображения, когда это больше не необходимо, и другой метод, создающий буфер изображения из входного изображения и использующий vImage для вычислений гистограммы.

Необходимо добавить код в этом разделе между этими операторами:

@implementation Histogram
@end
  1. Запишите инициализировать метод, сохраняющий изображение, используемое для вычисления гистограммы.

    - (id) initWithImageSource:(id<QCPlugInInputImageSource>)image colorSpace:(CGColorSpaceRef)colorSpace
    {
       // Make sure there is an image.
      if(!image) {
            [self release];
            return nil;
        }
     
        // Keep the image and the processing color space around.
        self = [super init];
        if (self) {
           _image = [(id)image retain];
           _colorSpace = CGColorSpaceRetain(colorSpace);
         }
        return self;
    }
  2. Запишите метод, выпускающий изображение гистограммы, когда оно больше не необходимо.

    - (void) dealloc
    {
        [(id)_image release];
        CGColorSpaceRelease(_colorSpace);
     
        [super dealloc];
    }
  3. Запишите метод, получающий и хранящий данные гистограммы для каждого пиксельного компонента.

    В этом методе необходимо получить буферное представление изображения на входном порту изображения гистограммы.

    - (BOOL) getRGBAHistograms:(vImagePixelCount**)histograms
    {
        vImage_Buffer                    buffer;
        vImage_Error                    error;
     
        if(_image) {
            // Get a buffer representation from the image
            if(![_image  lockBufferRepresentationWithPixelFormat:QCPlugInPixelFormatARGB8
                         colorSpace:[_image imageColorSpace]
                         forBounds:[_image imageBounds]])
                return NO;
     
            // Set up the vImage buffer
            buffer.data = (void*)[_image bufferBaseAddress];
            buffer.rowBytes = [_image bufferBytesPerRow];
            buffer.width = [_image bufferPixelsWide];
            buffer.height = [_image bufferPixelsHigh];
            // Set up the vImage histogram array
            histograms[0] = _histogramA;
            histograms[1] = _histogramR;
            histograms[2] = _histogramG;
            histograms[3] = _histogramB;
            // Call the vImage function to compute the histograms for the image data
            error = vImageHistogramCalculation_ARGB8888(&buffer, histograms, 0);
     
            // Now that you have the histogram, you can release the buffer
            [_image unlockBufferRepresentation];
            // Handle errors, if there are any
            if(error != kvImageNoError)
                return NO;
     
            // You no longer need the histogram image, so release it
            [(id)_image release];
            _image = nil;
        }
     
        // Reverse the histogram data
        histograms[0] = _histogramR;
        histograms[1] = _histogramG;
        histograms[2] = _histogramB;
        histograms[3] = _histogramA;
     
        return YES;
    }

Запишите методы выполнения для сменного класса

Для создания кода более читаемым поместите код в этот раздел между этими операторами:

@implementation HistogramOperationPlugIn (Execution)
@end
  1. Запишите выполнить метод для сменного класса.

    Этот метод вызывается Кварцевым Композитором каждый раз, когда изменяется любой из входных портов. Метод обновляет изображение гистограммы, если это изменило и создает a HistogramImageProvider объект из исходного изображения и кэшируемой гистограммы.

    - (BOOL) execute:(id<QCPlugInContext>)context atTime:(NSTimeInterval)time withArguments:(NSDictionary*)arguments
    {
        id<QCPlugInInputImageSource>    image;
        HistogramImageProvider*         provider;
        CGColorSpaceRef                 colorSpace;
     
        // If the histogram input image changes, update the cached histogram.
        if([self didValueForInputKeyChange:@"inputHistogramImage"]) {
            [_cachedHistogram release];
            if(image = self.inputHistogramImage) {
               colorSpace = (CGColorSpaceGetModel([image imageColorSpace]) == kCGColorSpaceModelRGB ?
                   [image imageColorSpace] : [context colorSpace]);
               _cachedHistogram = [[Histogram alloc]
                        initWithImageSource:self.inputHistogramImage
                        colorSpace:colorSpace];
            }
            else
                _cachedHistogram = nil;
        }
     
        // Check for a histogram and a source image, if they both exist,
        // create the provider and initialize it with the source image and histogram
        if(_cachedHistogram && (image = self.inputSourceImage)) {
            provider = [[HistogramImageProvider alloc]
                            initWithImageSource:sourceImage
                            histogram:_cachedHistogram];
            // Bail out if the provider doesn't exist
            if(provider == nil)
              return NO;
            // Otherwise, set the output image to the provider
            self.outputResultImage = provider;
            // Release the provider
            [provider release];
        }
        else
           // If the histogram and source image don't both exist,
           // set the output image to nil
           self.outputResultImage = nil;
     
        return YES;
    }
  2. Реализуйте метод выполнения остановки.

    Этот метод является дополнительным. Когда пользовательский патч прекращает выполняться, но для этого пользовательского патча необходимо выпустить кэшируемую гистограмму. Таким образом, необходимо реализовать его.

    - (void) stopExecution:(id<QCPlugInContext>)context
    {
        [_cachedHistogram release];
        _cachedHistogram = nil;
    }

Методы записи для выходного провайдера изображения

Весь код в этом разделе должен быть добавлен между этими операторами:

@implementation HistogramImageProvider
@end

Выходной провайдер изображения выполняет всю работу для рендеринга изображения. Вспомните, что Кварцевый Композитор вызывает Ваш метод рендеринга только, когда выходное изображение необходимо, таким образом избегая ненужных вычислений.

  1. Запишите метод, инициализирующий провайдера изображения с исходным изображением ранее вычисленная гистограмма.

    - (id) initWithImageSource:(id<QCPlugInInputImageSource>)image histogram:(Histogram*)histogram
    {
        // Check to make sure  an image and a histogram exists.
        if(!image || !histogram) {
            [self release];
            return nil;
        }
     
        // Keep the image and histogram around.
        self = [super init];
        if (self) {
            _image = [(id)image retain];
            _histogram = [histogram retain];
        }
     
        return self;
    }
  2. Реализация a dealloc метод, выпускающий изображение и гистограмму.

     
    - (void) dealloc
    {
        [(id)_image release];
        [_histogram release];
     
        [super dealloc];
    }
  3. Реализуйте метод для информирования Кварцевого Композитора границ изображения.

    - (NSRect) imageBounds
    {
        // This image has the same bounds as the source image.
        return [_image imageBounds];
    }
  4. Реализуйте метод для информирования Кварцевого Композитора цветового пространства, использованного изображением.

    - (CGColorSpaceRef) imageColorSpace
    {
        // Preserve the original image color space.
        return [_image imageColorSpace];
    }
  5. Реализуйте метод для информирования Кварцевого Композитора поддерживаемых форматов пикселя.

    Необходимо поддерживать ARGB8, BGRA8 и RGBAf. Используйте константы, предоставленные в Кварцевой платформе Композитора.

    - (NSArray*) supportedBufferPixelFormats
    {
        /* Support for only ARGB8, BGRA8 and RGBAf */
        return [NSArray arrayWithObjects:QCPlugInPixelFormatARGB8,
                                          QCPlugInPixelFormatBGRA8,
                                          QCPlugInPixelFormatRGBAf,
                                          nil];
    }
  6. Реализуйте рендеринг для буферизации метода.

    Кварцевый Композитор вызывает этот метод каждый раз, когда Ваш пользовательский патч должен произвести выходное изображение. Это происходит, когда выходной порт изображения подключен к входному порту изображения и когда один из ввода отображает изменение.

    - (BOOL) renderToBuffer:(void*)baseAddress
            withBytesPerRow:(NSUInteger)rowBytes
                pixelFormat:(NSString*)format
                  forBounds:(NSRect)bounds
    {
        vImage_Buffer        inBuffer,
                             outBuffer;
        vImage_Error         error;
        const vImagePixelCount*     histograms[4];
        const vImagePixelCount*     temp;
     
        // Retrieve histogram data. This triggers computation of the
        // histogram if necessary.
        if(![_histogram getRGBAHistograms:(vImagePixelCount**)histograms])
             return NO;
     
        // Get a buffer representation for the source image.
        if(![_image lockBufferRepresentationWithPixelFormat:format
                                                 colorSpace:[_image imageColorSpace]
                                                  forBounds:bounds])
             // Bail out if the buffer representation fails
             return NO;
     
        // Apply the previously computed histogram to the source image and
        // render the result to the output buffer
        inBuffer.data = (void*)[_image bufferBaseAddress];
        inBuffer.rowBytes = [_image bufferBytesPerRow];
        inBuffer.width = [_image bufferPixelsWide];
        inBuffer.height = [_image bufferPixelsHigh];
        outBuffer.data = baseAddress;
        outBuffer.rowBytes = rowBytes;
        outBuffer.width = [_image bufferPixelsWide];
        outBuffer.height = [_image bufferPixelsHigh];
        // Call the vImage histogram function that's appropriate
        // for the pixel format.
        if([format isEqualToString:QCPlugInPixelFormatRGBAf])
            error = vImageHistogramSpecification_ARGBFFFF(&inBuffer, &outBuffer,
                                                            NULL, histograms,
                                                            256, 0.0, 1.0, 0);
        else if([format isEqualToString:QCPlugInPixelFormatARGB8]) {
            // You need to convert the histogram from RGBA to ARGB
            temp = histograms[3];
            histograms[3] = histograms[2];
            histograms[2] = histograms[1];
            histograms[1] = histograms[0];
            histograms[0] = temp;
            error = vImageHistogramSpecification_ARGB8888(&inBuffer, &outBuffer,
                                                          histograms, 0);
        }
        else if([format isEqualToString:QCPlugInPixelFormatBGRA8]) {
            // You need to convert the histogram from RGBA to BGRA
            temp = histograms[0];
            histograms[0] = histograms[2];
            histograms[2] = temp;
            error = vImageHistogramSpecification_ARGB8888(&inBuffer, &outBuffer,
                                                          histograms, 0);
        }
        else
            // This should never happen.
            error = -1;
     
        // Release the buffer representation.
        [_image unlockBufferRepresentation];
        // Check for vImage errors.
        if(error != kvImageNoError)
              return NO;
        // Success!
        return YES;
    }