cur 파일은 Windows 운영체제에서 마우스 커서로 사용되는 리소스파일이다.
인터넷 변환기가 있으나, 여러개를 동시에 만드는건 돈을 내야 해서 직접 포맷을 보고 구현하였다.
아래는 cur 파일의 포맷이다.
ico은 type만 1로 바꾸어 주면 된다.
아래는 RGBA의 값을 가지는 cv::Mat
을 cur와 ico 파일 버퍼로 만드는 소스이다.
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// cv_ico
//
// Copyright (C) 2018, Kim Bomm, all rights reserved.
//
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's 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.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "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.
// 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.
//
#ifndef CVTICO_CV_ICO_H
#define CVTICO_CV_ICO_H
#include<opencv2/opencv.hpp>
namespace cv{
namespace ico{
#pragma pack(push,1)
struct ICOCUR_Entires {
unsigned char width;
unsigned char height;
unsigned char color_count;
unsigned char reserved;
union {
unsigned short x_hot_spot;
unsigned short planes;
};
union {
unsigned short y_hot_spot;
unsigned short bit_counts;
};
unsigned int size_in_bytes;
unsigned int file_offset;
};
struct ICOCUR_InfoHeader {
unsigned int size;
unsigned int width;
unsigned int height;
unsigned short planes;
unsigned short bit_count;
unsigned int compression;
unsigned int image_size;
unsigned int x_pixels_per_M;
unsigned int y_pixels_per_M;
unsigned int colors_used;
unsigned int colors_important;
};
struct ICOCUR_Header {
short reserved = 0;
short type = 2;
short count = 1;
ICOCUR_Entires entires;
ICOCUR_InfoHeader info_header;
};
#pragma pack(pop)
inline bool _imwrite_ico(const cv::String& filename,const cv::Mat& img,short type){
unsigned int W=static_cast<unsigned int>(img.cols);
unsigned int H=static_cast<unsigned int>(img.rows);
if(img.channels()==1){
cv::cvtColor(img,img,CV_GRAY2BGRA);
}
if(img.channels()==3){
cv::cvtColor(img,img,CV_BGR2BGRA);
}
ICOCUR_Header header;
header.reserved = 0;
header.type = type; //ico(1), cur(2)
header.count = 1;
header.entires.width = W;
header.entires.height = H;
header.entires.color_count = 0;
header.entires.reserved = 0;
if (type == 2) {
header.entires.x_hot_spot = W/2-1;
header.entires.y_hot_spot = H/2-1;
} else if (type == 1) {
header.entires.planes = 1;
header.entires.bit_counts = 8;
}
header.entires.size_in_bytes = 40 + 4 * (W*H) + (W*H) / 8;
header.entires.file_offset = 22;
header.info_header.size = 40;
header.info_header.width = W;
header.info_header.height = H+H;
header.info_header.planes = 1;
header.info_header.bit_count = 32;
header.info_header.compression = 0;
header.info_header.image_size = (W*H) * 4;
header.info_header.x_pixels_per_M = 0;
header.info_header.y_pixels_per_M = 0;
header.info_header.colors_used = 0;
header.info_header.colors_important = 0;
int size = sizeof(header) + (W*H) * 4 + (W*H) / 8;
uchar* buffer = (uchar*)calloc(size, sizeof(uchar));
uchar* p_header = buffer;
uchar* p_colors = buffer + sizeof(header);
unsigned int* p_monochrome = (unsigned int*)(buffer + (sizeof(header) + (W*H) * 4));
memcpy(p_header, &header, sizeof(header));
for (int y = H-1; y >= 0; y--) {
for (int x = W-1; x >= 0; x--) {
cv::Vec4b c = img.at<cv::Vec4b>(y,W-1- x);
*p_colors++ = c[0];
*p_colors++ = c[1];
*p_colors++ = c[2];
*p_colors++ = c[3];
if (c[3] == 255) {
*p_monochrome |= 1 << x;
}
}
char* cm = (char*)p_monochrome;
cm[0] ^= cm[3];
cm[3] ^= cm[0];
cm[0] ^= cm[3];
cm[1] ^= cm[2];
cm[2] ^= cm[1];
cm[1] ^= cm[2];
p_monochrome++;
}
FILE* fp = fopen(filename.c_str(), "wb");
fwrite(buffer, size, 1, fp);
fclose(fp);
return true;
}
inline bool imwrite(const cv::String &filename, const cv::Mat &img) {
std::string::size_type dot = filename.find_last_of('.') + 1;
std::string ext = filename.substr(dot, filename.length() - dot);
if(ext=="ico"){
return _imwrite_ico(filename,img,1);
}else if(ext=="cur"){
return _imwrite_ico(filename,img,2);
}
return false;
}
}
}
#endif //CVTICO_CV_ICO_H