From dd6c006a3482414639c153cf3c86c484b55b16cf Mon Sep 17 00:00:00 2001 From: Tanishq Dubey Date: Wed, 12 Jun 2024 18:20:35 -0400 Subject: [PATCH] image rotation --- main.cpp | 467 +++++++++++-------------------------------------------- 1 file changed, 90 insertions(+), 377 deletions(-) diff --git a/main.cpp b/main.cpp index c06d690..db2ae2b 100644 --- a/main.cpp +++ b/main.cpp @@ -1,3 +1,14 @@ +// Dear ImGui: standalone example application for SDL2 + OpenGL +// (SDL is a cross-platform general purpose library for handling windows, +// inputs, OpenGL/Vulkan/Metal graphics context creation, etc.) + +// Learn about Dear ImGui: +// - FAQ https://dearimgui.com/faq +// - Getting Started https://dearimgui.com/getting-started +// - Documentation https://dearimgui.com/docs (same as your local docs/ +// folder). +// - Introduction, links and more at the top of imgui.cpp + #include #include #include @@ -7,7 +18,6 @@ #include "lib/imgui.h" #include "lib/imgui_internal.h" #include -#include #include #include #include @@ -35,141 +45,50 @@ #include "lib/backends/tex_inspect_opengl.h" #include "lib/argparse.hpp" -#include - -#include "lib/histogram.h" - struct Args : public argparse::Args { std::string &fpath = arg("path to the image"); }; - -struct EXIFData { - std::string CameraMake; - std::string CameraModel; - std::string LensModel; - std::string ImageOrientation; - std::string ImageDimensionX; - std::string ImageDimensiony; - std::string ISO; - std::string ShutterSpeed; - std::string FNumber; - std::string FocalLength; - std::string ExposureBias; - std::string MeteringMode; - std::string Flash; - std::string Time; - std::string TimeTaken; - std::string TimeTakenOffset; - std::string GPSLat; - std::string GPSLatref; - std::string GPSLon; - std::string GPSLonref; -}; - struct Texture { ImTextureID texture; ImVec2 size; int channels; - EXIFData exif; }; static uint8_t* image = nullptr; +Texture LoadTexture(const char * path) +{ + const int channelCount = 4; + int imageFileChannelCount; + int width, height; + image = (uint8_t *)stbi_load(path, &width, &height, &imageFileChannelCount, channelCount); + if (image == NULL) + { + fprintf(stderr, "%s\nFailed to open %s\n", stbi_failure_reason(), path); -EXIFData printExifData(const std::string& imagePath) { - EXIFData d; - d.CameraMake = "NULL"; - try { - // Load the image - Exiv2::Image::UniquePtr img = Exiv2::ImageFactory::open(imagePath); - if (img.get() == 0) { - std::cerr << "Error: Could not open image file " << imagePath << std::endl; - return d; - } - img->readMetadata(); - - // Get the Exif data - Exiv2::ExifData &exifData = img->exifData(); - if (exifData.empty()) { - std::cerr << "No EXIF data found in file " << imagePath << std::endl; - return d; - } - - // Helper function to print EXIF data if available - auto printExifValue = [&exifData](const char* key, std::string *d) { - Exiv2::ExifKey exifKey(key); - Exiv2::ExifData::const_iterator pos = exifData.findKey(exifKey); - if (pos != exifData.end()) { - *d = pos->value().toString(); - } - }; - - // Print common EXIF data - printExifValue("Exif.Image.Make", &d.CameraMake); - printExifValue("Exif.Image.Model", &d.CameraModel); - printExifValue("Exif.Photo.LensModel", &d.LensModel); - - printExifValue("Exif.Image.Orientation", &d.ImageOrientation); - // - printExifValue("Exif.Photo.ExposureTime", &d.ShutterSpeed); - printExifValue("Exif.Photo.FNumber", &d.FNumber); - printExifValue("Exif.Photo.ISOSpeedRatings", &d.ISO); - printExifValue("Exif.Photo.FocalLength", &d.FocalLength); - printExifValue("Exif.Photo.ExposureBiasValue", &d.ExposureBias); - printExifValue("Exif.Photo.MeteringMode", &d.MeteringMode); - printExifValue("Exif.Photo.Flash", &d.Flash); - - printExifValue("Exif.Image.DateTime", &d.Time); - printExifValue("Exif.Photo.DateTimeOriginal", &d.TimeTaken); - printExifValue("Exif.Photo.OffsetTime", &d.TimeTakenOffset); - printExifValue("Exif.Photo.PixelXDimension", &d.ImageDimensionX); - printExifValue("Exif.Photo.PixelYDimension", &d.ImageDimensiony); - - printExifValue("Exif.GPSInfo.GPSLatitudeRef", &d.GPSLatref); - printExifValue("Exif.GPSInfo.GPSLatitude", &d.GPSLat); - printExifValue("Exif.GPSInfo.GPSLongitudeRef", &d.GPSLonref); - printExifValue("Exif.GPSInfo.GPSLongitude", &d.GPSLon); - - -/* -Exif.Image.Make 0x010f Ascii 5 SONY -Exif.Image.Model 0x0110 Ascii 10 ILCE-7RM5 - -Exif.Image.Orientation 0x0112 Short 1 8 -Exif.Photo.PixelXDimension 0xa002 Long 1 9504 -Exif.Photo.PixelYDimension 0xa003 Long 1 6336 - -Exif.Photo.ExposureTime 0x829a Rational 1 1/400 -Exif.Photo.FNumber 0x829d Rational 1 56/10 -Exif.Photo.ISOSpeedRatings 0x8827 Short 1 100 -Exif.Photo.FocalLength 0x920a Rational 1 400/10 -Exif.Photo.ExposureBiasValue 0x9204 SRational 1 -10/10 -Exif.Photo.MeteringMode 0x9207 Short 1 5 -Exif.Photo.Flash 0x9209 Short 1 16 - -Exif.Image.DateTime 0x0132 Ascii 20 2024:06:07 08:58:07 -Exif.Photo.DateTimeOriginal 0x9003 Ascii 20 2024:06:07 08:58:07 -Exif.Photo.OffsetTime 0x9010 Ascii 7 -05:00 - -Exif.GPSInfo.GPSLatitudeRef 0x0001 Ascii 2 N -Exif.GPSInfo.GPSLatitude 0x0002 Rational 3 40/1 43/1 32231/1000 -Exif.GPSInfo.GPSLongitudeRef 0x0003 Ascii 2 W -Exif.GPSInfo.GPSLongitude 0x0004 Rational 3 73/1 59/1 16688/1000 -*/ - - } catch (Exiv2::Error& e) { - std::cerr << "Error: " << e.what() << std::endl; + return {nullptr,{0,0}}; } - return d; + GLenum dataFormat = GL_RGBA; + GLuint textureHandle; + glGenTextures(1, &textureHandle); + glBindTexture(GL_TEXTURE_2D, textureHandle); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, dataFormat, GL_UNSIGNED_BYTE, image); + + Texture t; + t.texture = (void*)(uintptr_t)(textureHandle); + t.size = ImVec2((float)width,(float)height); + t.channels = channelCount; + + return t; } - - -Texture ReloadTexture(Texture tin, int width, int height) { - GLuint tid = (GLuint)(uintptr_t)tin.texture; +Texture ReloadTexture(ImTextureID id, int width, int height) { + GLuint tid = (GLuint)(uintptr_t)id; glDeleteTextures((GLsizei)1, &tid); GLenum dataFormat = GL_RGBA; @@ -183,107 +102,50 @@ Texture ReloadTexture(Texture tin, int width, int height) { Texture t; t.texture = (void*)(uintptr_t)(textureHandle); t.size = ImVec2((float)width,(float)height); - t.exif = tin.exif; - t.channels = tin.channels; return t; } +void rotate90() +{ +} + void RotateImage(Texture t) { int height = t.size.y; int width = t.size.x; int channels = t.channels; - const unsigned int sizeBuffer = width * height * channels; - unsigned char *tempBuffer = new unsigned char[sizeBuffer]; + const unsigned int sizeBuffer = width * height * channels; + unsigned char *tempBuffer = new unsigned char[sizeBuffer]; - int nidx = 0; - for (int x = 0; x < width; x++) - { - for (int y = height - 1; y >= 0; y--) + + int nidx = 0; + for (int x = 0; x < width; x++) { - int idx = (x + y * width) * channels; - for (int i = 0; i < channels; i++) - tempBuffer[nidx + i] = image[idx + i]; + for (int y = height - 1; y >= 0; y--) + { + int idx = (x + y * width) * channels; + for (int i = 0; i < channels; i++) + tempBuffer[nidx + i] = image[idx + i]; - nidx = nidx + 4; - } - } - - memcpy(image, tempBuffer, sizeBuffer); - delete[] tempBuffer; -} - -Texture LoadImage(const char * path) { - const int channelCount = 4; - int imageFileChannelCount; - int width, height; - image = (uint8_t *)stbi_load(path, &width, &height, &imageFileChannelCount, channelCount); - if (image == NULL) { - fprintf(stderr, "%s\nFailed to open %s\n", stbi_failure_reason(), path); - return {nullptr,{0,0}}; - } - auto exif = printExifData(path); - - Texture t; - t.size = ImVec2((float)width,(float)height); - t.channels = channelCount; - t.exif = exif; - return t; -} - -Texture LoadTexture(Texture tin) { - GLenum dataFormat = GL_RGBA; - GLuint textureHandle; - glGenTextures(1, &textureHandle); - glBindTexture(GL_TEXTURE_2D, textureHandle); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tin.size.x, tin.size.y, 0, dataFormat, GL_UNSIGNED_BYTE, image); - - Texture t = tin; - t.texture = (void*)(uintptr_t)(textureHandle); - - if (t.exif.ImageOrientation == "3") { - RotateImage(t); - ReloadTexture(t, t.size.x, t.size.y); - t = ReloadTexture(t, t.size.y, t.size.x); - RotateImage(t); - t = ReloadTexture(t, t.size.y, t.size.x); - } else if (t.exif.ImageOrientation == "6") { - RotateImage(t); - t = ReloadTexture(t, t.size.y, t.size.x); - } else if (t.exif.ImageOrientation == "8") { - RotateImage(t); - t = ReloadTexture(t, t.size.y, t.size.x); - RotateImage(t); - t = ReloadTexture(t, t.size.y, t.size.x); - RotateImage(t); - t = ReloadTexture(t, t.size.y, t.size.x); + nidx = nidx + 4; + } } - return t; + // Copy rotated pixels + + memcpy(image, tempBuffer, sizeBuffer); + delete[] tempBuffer; } - -const int MAX_ANNOATED_TEXELS = 10000; +static bool init = true; +static bool showHelp = false; +static int mode = 0; +const int maxAnnotatedTexels = 10000; // Main code int main(int argc, char* argv[]) { - Texture t; - - try { - auto args = argparse::parse(argc, argv, true); - t = LoadImage(args.fpath.c_str()); - if (t.texture == nullptr) { - std::cerr << "failed load image" << std::endl; - return -1; - } - } catch (const std::runtime_error &e) { - std::cerr << "failed to parse arguments: " << e.what() << std::endl; - return -1; - } // Setup SDL if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != 0) { @@ -294,10 +156,6 @@ int main(int argc, char* argv[]) { bool TOOLTIP_ENABLED = false; bool GRID_ENABLED = false; bool AA_ENABLED = true; - bool SHOW_HELP = false; - bool SHOW_EXIF = false; - bool SHOW_HISTOGRAM = false; - int MODE = 0; // Decide GL+GLSL versions #if defined(IMGUI_IMPL_OPENGL_ES2) @@ -337,17 +195,9 @@ int main(int argc, char* argv[]) { SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); - - - int wh = 800; - int ww = 1280; - if (t.size.y > t.size.x) { - ww = 500; - wh = 1280; - } SDL_Window *window = SDL_CreateWindow("tview", SDL_WINDOWPOS_CENTERED, - SDL_WINDOWPOS_CENTERED, ww, wh, window_flags); + SDL_WINDOWPOS_CENTERED, 1280, 720, window_flags); if (window == nullptr) { printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError()); return -1; @@ -359,6 +209,7 @@ int main(int argc, char* argv[]) { // Setup Dear ImGui context IMGUI_CHECKVERSION(); + ImGui::CreateContext(); ImGuiIO &io = ImGui::GetIO(); (void)io; @@ -367,22 +218,34 @@ int main(int argc, char* argv[]) { ImGuiTexInspect::ImplOpenGL3_Init(); // Or DirectX 11 equivalent (check your chosen backend header file) ImGuiTexInspect::Init(); ImGuiTexInspect::CreateContext(); + ImGui::StyleColorsDark(); + ImGuiStyle &style = ImGui::GetStyle(); + ImGui_ImplSDL2_InitForOpenGL(window, gl_context); ImGui_ImplOpenGL3_Init(glsl_version); ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); - auto flags = ImGuiTexInspect::InspectorFlags_FillVertical | ImGuiTexInspect::InspectorFlags_FillHorizontal; - t = LoadTexture(t); - Histogram histogram = Histogram(t.size.x, t.size.y, t.channels); - histogram.Load(image); + Texture t; + + if (init) { + init = false; + try { + auto args = argparse::parse(argc, argv, true); + t = LoadTexture(args.fpath.c_str()); + } catch (const std::runtime_error &e) { + std::cerr << "failed to parse arguments: " << e.what() << std::endl; + return -1; + } + } // Main loop bool done = false; while (!done) { + auto flags = ImGuiTexInspect::InspectorFlags_FillVertical | ImGuiTexInspect::InspectorFlags_FillHorizontal; // Poll and handle events (inputs, window resize, etc.) SDL_Event event; @@ -409,24 +272,18 @@ int main(int argc, char* argv[]) { AA_ENABLED = !AA_ENABLED; break; case SDL_SCANCODE_H: - SHOW_HELP = !SHOW_HELP; + showHelp = !showHelp; break; case SDL_SCANCODE_D: - MODE = (MODE + 1) % 5; + mode = (mode + 1) % 5; break; case SDL_SCANCODE_R: RotateImage(t); - t = ReloadTexture(t, t.size.y, t.size.x); + t = ReloadTexture(t.texture, t.size.y, t.size.x); break; case SDL_SCANCODE_Q: done = true; break; - case SDL_SCANCODE_E: - SHOW_EXIF = !SHOW_EXIF; - break; - case SDL_SCANCODE_C: - SHOW_HISTOGRAM = !SHOW_HISTOGRAM; - break; default: break; } @@ -454,7 +311,7 @@ int main(int argc, char* argv[]) { ImGui::SetNextWindowPos(viewport->Pos); ImGui::SetNextWindowSize(viewport->Size); ImGui::Begin("Main", NULL, - ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoBringToFrontOnFocus); + ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoResize); auto wSize = ImGui::GetContentRegionAvail(); if (t.texture != 0) { @@ -488,18 +345,18 @@ int main(int argc, char* argv[]) { CurrentInspector_SetFlags(ImGuiTexInspect::InspectorFlags_NoForceFilterNearest); } - switch(MODE) { + switch(mode) { case 1: - ImGuiTexInspect::DrawAnnotations(ImGuiTexInspect::Arrow().UsePreset(ImGuiTexInspect::Arrow::NormalMap), MAX_ANNOATED_TEXELS); + ImGuiTexInspect::DrawAnnotations(ImGuiTexInspect::Arrow().UsePreset(ImGuiTexInspect::Arrow::NormalMap), maxAnnotatedTexels); break; case 2: - ImGuiTexInspect::DrawAnnotations(ImGuiTexInspect::ValueText(ImGuiTexInspect::ValueText::Format::HexString), MAX_ANNOATED_TEXELS); + ImGuiTexInspect::DrawAnnotations(ImGuiTexInspect::ValueText(ImGuiTexInspect::ValueText::Format::HexString), maxAnnotatedTexels); break; case 3: - ImGuiTexInspect::DrawAnnotations(ImGuiTexInspect::ValueText(ImGuiTexInspect::ValueText::Format::BytesDec), MAX_ANNOATED_TEXELS); + ImGuiTexInspect::DrawAnnotations(ImGuiTexInspect::ValueText(ImGuiTexInspect::ValueText::Format::BytesDec), maxAnnotatedTexels); break; case 4: - ImGuiTexInspect::DrawAnnotations(ImGuiTexInspect::ValueText(ImGuiTexInspect::ValueText::Format::Floats), MAX_ANNOATED_TEXELS); + ImGuiTexInspect::DrawAnnotations(ImGuiTexInspect::ValueText(ImGuiTexInspect::ValueText::Format::Floats), maxAnnotatedTexels); break; default: break; @@ -512,11 +369,10 @@ int main(int argc, char* argv[]) { ImGui::PopStyleVar(); ImGui::PopStyleVar(); - if (SHOW_HELP){ + if (showHelp){ ImGui::OpenPopup("HelpPopup"); - SHOW_HELP = !SHOW_HELP; + showHelp = !showHelp; } - if (ImGui::BeginPopup("HelpPopup")) { ImGui::Text("tview Help"); ImGui::Separator(); @@ -534,156 +390,13 @@ int main(int argc, char* argv[]) { ImGui::Text("\tFloat Values"); ImGui::Separator(); ImGui::Text("h - show help popup"); - ImGui::Text("c - toggle color histogram"); - ImGui::Text("e - toggle EXIF info"); - ImGui::Separator(); ImGui::Text("q - quit"); ImGui::Separator(); ImGui::Text("click anywhere to continue"); ImGui::EndPopup(); } - if (SHOW_EXIF && t.exif.CameraMake != "NULL") { - ImGuiWindowClass topmost; - topmost.ClassId = ImHashStr("TopMost"); - topmost.ViewportFlagsOverrideSet = ImGuiViewportFlags_TopMost; - ImGui::SetNextWindowClass(&topmost); - ImGui::Begin("EXIF", NULL, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoFocusOnAppearing); - if(ImGui::BeginTable("Hardware", 2)) { - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); - ImGui::Text("Make"); - ImGui::TableSetColumnIndex(1); - ImGui::Text("%s", t.exif.CameraMake.c_str()); - - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); - ImGui::Text("Model"); - ImGui::TableSetColumnIndex(1); - ImGui::Text("%s", t.exif.CameraModel.c_str()); - - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); - ImGui::Text("Lens"); - ImGui::TableSetColumnIndex(1); - ImGui::Text("%s", t.exif.LensModel.c_str()); - - ImGui::EndTable(); - } - - ImGui::Separator(); - - if(ImGui::BeginTable("Photo", 2)) { - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); - ImGui::Text("Shutter Speed"); - ImGui::TableSetColumnIndex(1); - ImGui::Text("%s", t.exif.ShutterSpeed.c_str()); - - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); - ImGui::Text("F-Stop"); - ImGui::TableSetColumnIndex(1); - ImGui::Text("%s", t.exif.FNumber.c_str()); - - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); - ImGui::Text("ISO"); - ImGui::TableSetColumnIndex(1); - ImGui::Text("%s", t.exif.ISO.c_str()); - - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); - ImGui::Text("Focal Length"); - ImGui::TableSetColumnIndex(1); - ImGui::Text("%s", t.exif.FocalLength.c_str()); - - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); - ImGui::Text("Exposure Comp"); - ImGui::TableSetColumnIndex(1); - ImGui::Text("%s", t.exif.ExposureBias.c_str()); - - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); - ImGui::Text("Metering Mode"); - ImGui::TableSetColumnIndex(1); - ImGui::Text("%s", t.exif.MeteringMode.c_str()); - - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); - ImGui::Text("Flash"); - ImGui::TableSetColumnIndex(1); - ImGui::Text("%s", t.exif.Flash.c_str()); - - ImGui::EndTable(); - } - - ImGui::Separator(); - - if(ImGui::BeginTable("Meta", 2)) { - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); - ImGui::Text("Date"); - ImGui::TableSetColumnIndex(1); - ImGui::Text("%s %s", t.exif.TimeTaken.c_str(), t.exif.TimeTakenOffset.c_str()); - - - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); - ImGui::Text("Dimensions"); - ImGui::TableSetColumnIndex(1); - ImGui::Text("%sx%s", t.exif.ImageDimensionX.c_str(), t.exif.ImageDimensiony.c_str()); - - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); - ImGui::Text("Orientation"); - ImGui::TableSetColumnIndex(1); - ImGui::Text("%s", t.exif.ImageOrientation.c_str()); - - ImGui::EndTable(); - } - - ImGui::Separator(); - - if(ImGui::BeginTable("Location", 2)) { - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); - ImGui::Text("Latitude"); - ImGui::TableSetColumnIndex(1); - ImGui::Text("%s %s", t.exif.GPSLat.c_str(), t.exif.GPSLatref.c_str()); - - - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); - ImGui::Text("Longitude"); - ImGui::TableSetColumnIndex(1); - ImGui::Text("%s %s", t.exif.GPSLon.c_str(), t.exif.GPSLonref.c_str()); - - ImGui::EndTable(); - } - - ImGui::Separator(); - ImGui::Text("Press e to hide"); - - ImGui::End(); - } - - - if (SHOW_HISTOGRAM) { - ImGuiWindowClass topmost; - topmost.ClassId = ImHashStr("TopMost"); - topmost.ViewportFlagsOverrideSet = ImGuiViewportFlags_TopMost; - ImGui::SetNextWindowClass(&topmost); - ImGui::Begin("Histogram", NULL, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoFocusOnAppearing); - histogram.Draw(); - ImGui::Separator(); - ImGui::Text("Press c to hide"); - - ImGui::End(); - } } - // Rendering ImGui::Render(); glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y);