libheif
libheif copied to clipboard
Read .HEIC from iPhone and rewrite to .heic got 0 width and height and Image has Black boarder
Hi, thanks for sharing this awesome lib. I have some problems when I test to read from iPhone's .HEIC file and want to rewrite to .heic.
First I try to use your simple encoding API but not work, after that I use the code from example/heif_enc.cc but still have this problem.
Here is my code
int main(int argc, char** argv) {
const char* file_path = "Path/to/IMG_6894.HEIC";
const char* output_path = "Path/to/vs_output.heic";
vector<string> raw_params = {
"x265:crf=20.5",
"x265:colorprim=smpte170m",
"x265:rdoq-level=1",
"x265:aq-strength=1.2",
"x265:deblock=-2:-2" };
int master_alpha = 1;
int two_colr_boxes = 0;
int thumb_alpha = 1;
int list_encoders = 0;
const char* encoderId = nullptr;
int nclx_matrix_coefficients = 6;
int nclx_colour_primaries = 2;
int nclx_transfer_characteristic = 2;
int nclx_full_range = true;
bool lossless = false;
int logging_level = 0;
int thumbnail_bbox_size = 0;
bool enc_av1f = false;
bool crop_to_even_size = false;
heif_context* ctx = heif_context_alloc();
if (!ctx) {
std::cerr << "Could not create context object\n";
return 1;
}
// get the default encoder
heif_encoder* encoder = nullptr;
heif_context_get_encoder_for_format(ctx, heif_compression_HEVC, &encoder);
#define MAX_ENCODERS 5
const heif_encoder_descriptor* encoder_descriptors[MAX_ENCODERS];
int count = heif_context_get_encoder_descriptors(ctx,
enc_av1f ? heif_compression_AV1 : heif_compression_HEVC,
nullptr,
encoder_descriptors, MAX_ENCODERS);
if (list_encoders) {
show_list_of_encoders(encoder_descriptors, count);
return 0;
}
if (count > 0) {
int idx = 0;
if (encoderId != nullptr) {
for (int i = 0; i <= count; i++) {
if (i == count) {
std::cerr << "Unknown encoder ID. Choose one from the list below.\n";
show_list_of_encoders(encoder_descriptors, count);
return 5;
}
if (strcmp(encoderId, heif_encoder_descriptor_get_id_name(encoder_descriptors[i])) == 0) {
idx = i;
break;
}
}
}
heif_error error = heif_context_get_encoder(ctx, encoder_descriptors[idx], &encoder);
if (error.code) {
std::cerr << error.message << "\n";
return 5;
}
}
else {
std::cerr << "No " << (enc_av1f ? "AV1" : "HEVC") << " encoder available.\n";
return 5;
}
tuple<uint8_t*, int, int, int, int, heif_image*> datas = read_heif_data(file_path);
uint8_t* data = get<0>(datas);
int stride = get<1>(datas);
int width = get<2>(datas);
int height = get<3>(datas);
int has_alpha = get<4>(datas);
int channels = has_alpha ? 4 : 3;
struct heif_image* image = get<5>(datas);
struct heif_error err;
err = heif_image_create((int)width, (int)height,
heif_colorspace_RGB,
has_alpha ? heif_chroma_interleaved_RGBA : heif_chroma_interleaved_RGB,
&image);
(void)err;
heif_image_add_plane(image, heif_channel_interleaved, (int)width, (int)height,
has_alpha ? 32 : 24);
int img_stride;
uint8_t* p = (uint8_t*)heif_image_get_plane(image, heif_channel_interleaved, &img_stride);
cout << "Read Width: " << width << endl
<< "Read Height: " << height << endl
<< "Read Stride: " << stride << endl
<< "Write Width: " << width << endl
<< "Write Height: " << height << endl
<< "Write Stride: " << img_stride << endl
;
for (uint32_t y = 0; y < height; y++) {
uint32_t prow = y * img_stride;
uint32_t irow = y * stride;
uint32_t row_len = width * channels;
memcpy(p + prow, data + irow, row_len);
}
struct heif_error error;
// encode the image
heif_color_profile_nclx nclx;
nclx.matrix_coefficients = (heif_matrix_coefficients)nclx_matrix_coefficients;
nclx.transfer_characteristics = (heif_transfer_characteristics)nclx_transfer_characteristic;
nclx.color_primaries = (heif_color_primaries)nclx_colour_primaries;
nclx.full_range_flag = (uint8_t)nclx_full_range;
heif_image_set_nclx_color_profile(image, &nclx);
//// set the encoder parameters
heif_encoder_set_lossy_quality(encoder, 50);
heif_encoder_set_lossless(encoder, lossless);
heif_encoder_set_logging_level(encoder, logging_level);
set_params(encoder, raw_params);
heif_encoding_options* opts = heif_encoding_options_alloc();
opts->save_alpha_channel = (uint8_t)master_alpha;
opts->save_two_colr_boxes_when_ICC_and_nclx_available = (uint8_t)two_colr_boxes;
if (crop_to_even_size) {
if (heif_image_get_primary_width(image) == 1 ||
heif_image_get_primary_height(image) == 1) {
std::cerr << "Image only has a size of 1 pixel width or height. Cannot crop to even size.\n";
return 1;
}
std::cerr << "Warning: option --even-size/-E is deprecated as it is not needed anymore.\n";
int right = heif_image_get_primary_width(image) % 2;
int bottom = heif_image_get_primary_height(image) % 2;
error = heif_image_crop(image, 0, right, 0, bottom);
if (error.code != 0) {
heif_encoding_options_free(opts);
std::cerr << "Could not crop image: " << error.message << "\n";
return 1;
}
}
heif_image_handle* handle;
error = heif_context_encode_image(ctx, image, encoder, opts, &handle);
if (error.code != 0) {
heif_encoding_options_free(opts);
std::cerr << "Could not encode HEIF/AVIF file: " << error.message << "\n";
return 1;
}
if (thumbnail_bbox_size > 0) {
// encode thumbnail
struct heif_image_handle* thumbnail_handle;
opts->save_alpha_channel = master_alpha && thumb_alpha;
error = heif_context_encode_thumbnail(ctx,
image,
handle,
encoder,
opts,
thumbnail_bbox_size,
&thumbnail_handle);
if (error.code) {
heif_encoding_options_free(opts);
std::cerr << "Could not generate thumbnail: " << error.message << "\n";
return 5;
}
if (thumbnail_handle) {
heif_image_handle_release(thumbnail_handle);
}
}
heif_image_handle_release(handle);
heif_encoding_options_free(opts);
heif_encoder_release(encoder);
error = heif_context_write_to_file(ctx, output_path);
if (error.code) {
std::cerr << error.message << "\n";
return NULL;
}
//write_heif_data(image, 50, output_path);
datas = read_heif_data(output_path);
data = get<0>(datas);
stride = get<1>(datas);
width = get<2>(datas);
height = get<3>(datas);
cout << "Read Width: " << width << endl
<< "Read Height: " << height << endl
<< "Read Stride: " << stride << endl
;
return 0;
}
My read_heif_data function is following:
tuple<uint8_t*,int,int,int,int, heif_image*> read_heif_data(const char* input_filename) {
heif_context* ctx = heif_context_alloc();
heif_context_read_from_file(ctx, input_filename, nullptr);
int num_images = heif_context_get_number_of_top_level_images(ctx);
// get a handle to the primary image
heif_image_handle* handle;
heif_context_get_primary_image_handle(ctx, &handle);
int img_width = heif_image_handle_get_width(handle);
int img_height = heif_image_handle_get_height(handle);
int has_alpha = heif_image_handle_has_alpha_channel(handle);
struct heif_image* img;
struct heif_error err;
int stride; // bytes per line
uint8_t* data;
// decode the image and convert colorspace to RGB, saved as 24bit interleaved
err = heif_decode_image(handle, &img, heif_colorspace_RGB, has_alpha ? heif_chroma_interleaved_RGBA : heif_chroma_interleaved_RGB, nullptr);
if (err.code) {
heif_image_handle_release(handle);
std::cerr << "Could not decode image: " << ": "
<< err.message << "\n";
return { data, stride, img_width, img_height, has_alpha, img };
}
data = heif_image_get_plane(img, heif_channel_interleaved, &stride);
//err = heif_image_get_nclx_color_profile(img, &nclx);
return { data, stride, img_width, img_height, has_alpha, img };
}
Here is the output I got.
Read Width: 2268
Read Height: 4032
Read Stride: 6816
Write Width: 2268
Write Height: 4032
Write Stride: 6816
Read Width: 0
Read Height: 0
Read Stride: 6816
My Original Input Image like this
and my output .heic file got this
You can see the black border there.
Is there something I need to know? I'm a newbie in C++.
thanks for the reply. 😄
My OS env is
Windows 10 21H2
Microsoft Visual Studio Community 2019 16.10.3
Install libheif by Vcpkg