int ColorsCommand::run()

in imagetool/commands/colors.cpp [41:204]


int ColorsCommand::run(const char** args, unsigned int numArgs)
{
	if( numArgs < 2 ) {
		fprintf(stderr, "Usage: ImageTool colors <input> [subDivisions] [numColors] [algorithm] [output]\n");
		fprintf(stderr, "\te.g. ImageTool colors <input> 2 5 histogram\n");
		return IMAGECORE_INVALID_USAGE;
	}

	const char* inputFilePath = args[0];

	EColorsAlgorithm algorithm = kColorAlgorithm_Histogram;
	if( numArgs >= 4 ) {
		if( strcmp(args[3], "kmeans") == 0 ) {
			algorithm = kColorAlgorithm_KMeans;
		} else if( strcmp(args[3], "histogram") == 0 ) {
			algorithm = kColorAlgorithm_Histogram;
		} else {
			fprintf(stderr, "error: invalid algorithm\n");
			return IMAGECORE_INVALID_USAGE;
		}
	}

	int numColors = 1;
	if( numArgs >= 3 ) {
		numColors = atoi(args[2]);
		if( numColors < 1 || (algorithm == kColorAlgorithm_Histogram && numColors > maxNumColors) || (algorithm == kColorAlgorithm_KMeans && numColors > 10) ) {
			fprintf(stderr, "error: invalid color count\n");
			return IMAGECORE_INVALID_USAGE;
		}
	}

	int subDivisions = 1;
	if( numArgs >= 2 ) {
		subDivisions = atoi(args[1]);
		if( subDivisions <= 0 || subDivisions > 16 || (subDivisions > 1 && numColors > 1) ) {
			fprintf(stderr, "error: invalid subdivision count\n");
			return IMAGECORE_INVALID_USAGE;
		}
	}

	START_CLOCK(ReadImage);

	ImageReader::Storage* source = ImageReader::FileStorage::open(inputFilePath);
	if( source == NULL ) {
		fprintf(stderr, "error: unable to open input file for '%s'\n", inputFilePath);
		return IMAGECORE_READ_ERROR;
	}

	ImageReader* imageReader = ImageReader::create(source);
	ResizeCropOperation resizeCrop;
	resizeCrop.setImageReader(imageReader);
	resizeCrop.setResizeMode(kResizeMode_AspectFit);
	resizeCrop.setResizeQuality(kResizeQuality_Low);
	resizeCrop.setOutputSize(128, 128);

	ImageRGBA* frameImage;
	resizeCrop.performResizeCrop(frameImage);

	END_CLOCK(ReadImage);

	int chunkW = frameImage->getWidth() / subDivisions;
	int chunkH = frameImage->getHeight() / subDivisions;
	bool hasAlpha = frameImage->getColorModel() == kColorModel_RGBA;
 	RGBA* subdivisionColors = (RGBA*)malloc(subDivisions * subDivisions * sizeof(RGBA));
	if( subDivisions > 1 ) {
		ImageRGBA* chunkFrameImage = ImageRGBA::create(chunkW, chunkH, hasAlpha);
		for( int cy = 0; cy < subDivisions; cy++ ) {
			for( int cx = 0; cx < subDivisions; cx++ ) {
				int ox = cx * chunkW;
				int oy = cy * chunkH;
				frameImage->copyRect(chunkFrameImage, ox, oy, 0, 0, chunkW, chunkH);
				RGBA rgba[16];
				double pct[16];
				ColorPalette::compute(chunkFrameImage, rgba, pct, 1, kColorAlgorithm_Histogram); // only use histogram algorithm for subDivisions for now
				subdivisionColors[cy * subDivisions + cx] = rgba[0];
			}
		}
		delete chunkFrameImage;
	}

	RGBA mainColors[maxNumColors];
	double colorPct[maxNumColors];
	int numOutColors = ColorPalette::compute(frameImage, mainColors, colorPct, numColors, algorithm);

	if( numArgs >= 5 ) {
		FILE* outputFile = fopen(args[4], "wb");
		if( outputFile == NULL ) {
			return IMAGECORE_WRITE_ERROR;
		}

		ImageWriter::FileStorage* outputStorage = new ImageWriter::FileStorage(outputFile);
		ImageWriter* writer = ImageWriter::createWithFormat(ImageWriter::formatFromExtension(args[1], kImageFormat_PNG), outputStorage);

		if( subDivisions > 1 ) {
			ImageRGBA* chunkImage = ImageRGBA::create(subDivisions, subDivisions, 4, 4, hasAlpha);
			for( int cy = 0; cy < subDivisions; cy++ ) {
				for( int cx = 0; cx < subDivisions; cx++ ) {
					const RGBA& color = subdivisionColors[cy * subDivisions + cx];
					chunkImage->clearRect(cx, cy, 1, 1, color.r, color.g, color.b, color.a);
				}
			}
			// Output an upsampled preview image.
			ImageRGBA* outImage = ImageRGBA::create(128, 128, hasAlpha);
			chunkImage->resize(outImage, kResizeQuality_Medium); // Prefer smoother, not sharper interpolations.
			if( writer == NULL || !writer->writeImage(outImage) ) {
				return IMAGECORE_WRITE_ERROR;
			}
			delete outImage;
		} else {
			int outWidthPerColor = 50;
			int outHeight = 30;
			unsigned int outPitch;
			ImageRGBA* outImage = ImageRGBA::create(outWidthPerColor * numOutColors, outHeight, hasAlpha);
			uint8_t* outImageBuffer = outImage->lockRect(outWidthPerColor * numOutColors, outHeight, outPitch);
			for( int k = 0; k < numOutColors; k++ ) {
				for( int i = k * outWidthPerColor; i < (k + 1) * outWidthPerColor; i++ ) {
					*(RGBA*)(&outImageBuffer[i * 4]) = mainColors[k];
				}
			}
			for( int j = 1; j < outHeight; j++ ) {
				memcpy(&outImageBuffer[outWidthPerColor * numOutColors * 4 * j], outImageBuffer, outWidthPerColor * numOutColors * 4);
			}

			if( writer == NULL || !writer->writeImage(outImage) ) {
				return IMAGECORE_WRITE_ERROR;
			}

			delete outImage;
		}
		fclose(outputFile);
		delete outputStorage;
		delete writer;
	} else {
		// Just print out the dominant colors.
		if( numColors == 1 ) {
			printf("Dominant: ");
			printf("#%02X%02X%02X", mainColors[0].r, mainColors[0].g, mainColors[0].b);
			printf("\n");
		} else {
			SECURE_ASSERT(numColors > 1);
			printf("Dominant:\n");
			for( int i = 0; i < numOutColors; i++) {
				printf("#%02X%02X%02X: %0.2f%%\n", mainColors[i].r, mainColors[i].g, mainColors[i].b, colorPct[i] * 100);
			}
		}
		if( subDivisions > 1 ) {
			printf("Subdivisions: ");
			for( int cy = 0; cy < subDivisions; cy++ ) {
				for( int cx = 0; cx < subDivisions; cx++ ) {
					const RGBA& chunkColor = subdivisionColors[cy * subDivisions + cx];
					printf("#%02X%02X%02X ", chunkColor.r, chunkColor.g, chunkColor.b);
				}
			}
			printf("\n");
		}
	}

	free(subdivisionColors);

	delete source;
	delete imageReader;

	return IMAGECORE_SUCCESS;
}