/******************************************************************************* * Operations. ******************************************************************************/ ColorLevels::Statistics ColorLevels::getColorLevels( ColorLevels::Options options, std::string imagePath, Magick::Blob* blob) { Magick::Image image; try { image.read(imagePath); } catch (Magick::Exception &e) { throw std::runtime_error(e.what()); } /* For simplicity, only support sRGB */ if (image.colorSpace() != Magick::sRGBColorspace) throw std::logic_error("Unsupported colorspace"); /* Convert sRGB to Lab colorspace */ image.colorSpace(Magick::ColorspaceType::LabColorspace); ColorLevels::Statistics imageStats; imageStats.width = image.size().width(); imageStats.height = image.size().height(); imageStats.redPixels = 0; imageStats.purplePixels = 0; imageStats.backgroundPixels = 0; const Magick::PixelPacket *pixels = image.getConstPixels( 0, 0, imageStats.width, imageStats.height); /* Setup image masks */ Magick::Image maskTransparentImage, maskOriginalImage; Magick::PixelPacket *maskTransparentPixels, *maskOriginalPixels; if (options.drawMaskOverTransparent) { maskTransparentImage = Magick::Image(Magick::Geometry( imageStats.width, imageStats.height), Magick::Color("rgba(0,0,0,0)")); maskTransparentPixels = maskTransparentImage.getPixels(0, 0, imageStats.width, imageStats.height); } if (options.drawMaskOverOriginalImage) { maskOriginalImage = Magick::Image(imagePath); maskOriginalPixels = maskOriginalImage.getPixels(0, 0, imageStats.width, imageStats.height); } /* Sanity check color coordinates */ if (options.redCoordinateSet) { if (options.redCoordinate.x >= imageStats.width) throw std::runtime_error("Invalid red X value."); if (options.redCoordinate.y >= imageStats.height) throw std::runtime_error("Invalid red Y value."); } if (options.purpleCoordinateSet) { if (options.purpleCoordinate.x >= imageStats.width) throw std::runtime_error("Invalid purple X value."); if (options.purpleCoordinate.y >= imageStats.height) throw std::runtime_error("Invalid purple Y value."); } if (options.backgroundCoordinateSet) { if (options.backgroundCoordinate.x >= imageStats.width) throw std::runtime_error("Invalid background X value."); if (options.backgroundCoordinate.y >= imageStats.height) throw std::runtime_error("Invalid background Y value."); } /* Setup colors */ const ColorLevels::LAB red = options.redCoordinateSet ? ColorLevels::LABColorToLAB(static_cast<Magick::ColorRGB>( pixels[(imageStats.width * options.redCoordinate.x) + options.redCoordinate.y])) : ColorLevels::getLABValueOfRGBColor( Magick::ColorRGB(options.redColor)); if (options.redCoordinateSet && options.verbose) std::cout << "Red color: " << red << std::endl; const ColorLevels::LAB purple = options.purpleCoordinateSet ? ColorLevels::LABColorToLAB(static_cast<Magick::ColorRGB>( pixels[(imageStats.width * options.purpleCoordinate.x) + options.purpleCoordinate.y])) : ColorLevels::getLABValueOfRGBColor( Magick::ColorRGB(options.purpleColor)); if (options.purpleCoordinateSet && options.verbose) std::cout << "Purple color: " << purple << std::endl; const Magick::ColorRGB redMaskColor("#00FF00"); const Magick::ColorRGB purpleMaskColor("#0000FF"); const Magick::ColorRGB backgroundMaskColor("#000000"); /* backgroundColor() returns an sRGB value, even in LAB colorspace */ const ColorLevels::LAB backgroundColor = options.backgroundCoordinateSet ? ColorLevels::LABColorToLAB(static_cast<Magick::ColorRGB>( pixels[(imageStats.width * options.backgroundCoordinate.x) + options.backgroundCoordinate.y])) : ColorLevels::getLABValueOfRGBColor( options.backgroundColor == "" ? image.backgroundColor() : Magick::ColorRGB(options.backgroundColor)); if ((options.backgroundCoordinateSet || options.backgroundColor == "") && options.verbose) std::cout << "Background color: " << backgroundColor << std::endl; for (size_t row = 0; row < imageStats.height; row++) { for (size_t col = 0; col < imageStats.width; col++) { /* Get color of current pixel */ size_t offset = (imageStats.width * row) + col; ColorLevels::LAB currentPixelLAB = ColorLevels::LABColorToLAB( static_cast<Magick::ColorRGB>(pixels[offset])); /* Check pixel for background */ if (ColorLevels::CIEDE2000(backgroundColor, currentPixelLAB) < options.backgroundThreshold) { imageStats.backgroundPixels++; if (options.drawMaskOverTransparent) maskTransparentPixels[offset] = backgroundMaskColor; if (options.drawMaskOverOriginalImage) maskOriginalPixels[offset] = backgroundMaskColor; /* Check pixel for red */ } else if (ColorLevels::CIEDE2000(red, currentPixelLAB) < options.redThreshold) { imageStats.redPixels++; if (options.drawMaskOverTransparent) maskTransparentPixels[offset] = redMaskColor; if (options.drawMaskOverOriginalImage) maskOriginalPixels[offset] = redMaskColor; /* Check pixel for purple */ } else if (ColorLevels::CIEDE2000(purple, currentPixelLAB) < options.purpleThreshold) { imageStats.purplePixels++; if (options.drawMaskOverTransparent) maskTransparentPixels[offset] = purpleMaskColor; if (options.drawMaskOverOriginalImage) maskOriginalPixels[offset] = purpleMaskColor; } } } /* Save masks */ if (options.drawMaskOverTransparent) { maskTransparentImage.syncPixels(); maskOriginalImage.write(blob); // maskTransparentImage.write( // ColorLevels::basenameWithoutExtension(imagePath) + // "_mask_transparent.png"); } if (options.drawMaskOverOriginalImage) { maskOriginalImage.syncPixels(); maskOriginalImage.write(blob); // maskOriginalImage.write( // ColorLevels::basenameWithoutExtension(imagePath) + // "_mask_original.png"); } std::cout << "ok?" << blob->length() << "\n"; return (imageStats); }
void Magick::colorSpaceImage::operator()( Magick::Image &image_ ) const { image_.colorSpace( _colorSpace ); }