Skip to content

Commit 0ef87e6

Browse files
committed
ImageFileBasic: ImGui UI and CanvasUi integration
- Added ImGui interface for Open/Save/Fit operations - Integrated CanvasUi for pan/zoom - Display image metadata (format, dimensions, color model, etc.) - Error handling with visual feedback
1 parent 9205e55 commit 0ef87e6

File tree

1 file changed

+154
-26
lines changed

1 file changed

+154
-26
lines changed
Lines changed: 154 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1-
#include "cinder/app/App.h"
1+
#include "cinder/app/App.h"
22
#include "cinder/app/RendererGl.h"
33
#include "cinder/gl/gl.h"
4+
#include "cinder/gl/ConstantConversions.h"
45
#include "cinder/Log.h"
56
#include "cinder/ImageIo.h"
67
#include "cinder/gl/Texture.h"
8+
#include "cinder/CinderImGui.h"
9+
#include "cinder/CanvasUi.h"
710

811
using namespace ci;
912
using namespace ci::app;
@@ -12,61 +15,186 @@ using namespace std;
1215
class ImageFileBasicApp : public App {
1316
public:
1417
void setup() override;
15-
void keyDown( KeyEvent event ) override;
18+
void update() override;
1619
void fileDrop( FileDropEvent event ) override;
1720
void draw() override;
18-
21+
22+
void openImage( const fs::path &path );
23+
void openImageDialog();
24+
void saveImage();
25+
void drawGui();
26+
1927
gl::TextureRef mTexture;
28+
ImageSourceRef mImageSource;
29+
fs::path mImagePath;
30+
std::string mErrorMessage;
31+
bool mOpenRequested = false;
32+
bool mSaveRequested = false;
33+
CanvasUi mCanvas;
2034
};
2135

2236
void ImageFileBasicApp::setup()
37+
{
38+
ImGui::Initialize();
39+
40+
mCanvas.connect( getWindow() );
41+
}
42+
43+
void ImageFileBasicApp::update()
44+
{
45+
if( mOpenRequested ) {
46+
mOpenRequested = false;
47+
openImageDialog();
48+
}
49+
if( mSaveRequested ) {
50+
mSaveRequested = false;
51+
saveImage();
52+
}
53+
}
54+
55+
void ImageFileBasicApp::openImage( const fs::path &path )
2356
{
2457
try {
25-
fs::path path = getOpenFilePath( "", ImageIo::getLoadExtensions() );
26-
if( ! path.empty() ) {
27-
mTexture = gl::Texture::create( loadImage( path ) );
28-
}
58+
mImagePath = path;
59+
mImageSource = loadImage( path );
60+
mTexture = gl::Texture::create( mImageSource );
61+
mCanvas.setContentBounds( Rectf( mTexture->getBounds() ) );
62+
mCanvas.fitAll();
63+
mErrorMessage.clear();
2964
}
3065
catch( Exception &exc ) {
3166
CI_LOG_EXCEPTION( "failed to load image.", exc );
67+
mTexture.reset();
68+
mImageSource.reset();
69+
mImagePath.clear();
70+
mErrorMessage = exc.what();
3271
}
3372
}
3473

35-
void ImageFileBasicApp::keyDown( KeyEvent event )
74+
void ImageFileBasicApp::openImageDialog()
3675
{
37-
if( event.getChar() == 'o' ) {
38-
fs::path path = getOpenFilePath( "", ImageIo::getLoadExtensions() );
39-
if( ! path.empty() )
40-
mTexture = gl::Texture::create( loadImage( path ) );
41-
}
42-
else if( event.getChar() == 's' ) {
43-
fs::path path = getSaveFilePath();
44-
if( ! path.empty() ) {
45-
Surface s8( mTexture->createSource() );
46-
writeImage( writeFile( path ), s8 );
47-
}
76+
fs::path path = getOpenFilePath( "", ImageIo::getLoadExtensions() );
77+
if( ! path.empty() ) {
78+
openImage( path );
4879
}
4980
}
5081

51-
void ImageFileBasicApp::fileDrop( FileDropEvent event )
82+
void ImageFileBasicApp::saveImage()
5283
{
5384
try {
54-
mTexture = gl::Texture::create( loadImage( loadFile( event.getFile( 0 ) ) ) );
85+
fs::path path = getSaveFilePath( "", ImageIo::getWriteExtensions() );
86+
if( ! path.empty() ) {
87+
writeImage( writeFile( path ), mTexture->createSource() );
88+
}
5589
}
5690
catch( Exception &exc ) {
57-
CI_LOG_EXCEPTION( "failed to load image: " << event.getFile( 0 ), exc );
91+
CI_LOG_EXCEPTION( "failed to save image.", exc );
5892
}
5993
}
6094

95+
void ImageFileBasicApp::fileDrop( FileDropEvent event )
96+
{
97+
openImage( event.getFile( 0 ) );
98+
}
99+
61100
void ImageFileBasicApp::draw()
62101
{
63102
gl::clear( Color( 0.5f, 0.5f, 0.5f ) );
64-
gl::enableAlphaBlending();
65-
103+
104+
// Draw image with CanvasUi transformation
66105
if( mTexture ) {
67-
Rectf destRect = Rectf( mTexture->getBounds() ).getCenteredFit( getWindowBounds(), true ).scaledCentered( 0.85f );
68-
gl::draw( mTexture, destRect );
106+
gl::ScopedModelMatrix scopedMatrix( mCanvas.getModelMatrix() );
107+
gl::enableAlphaBlending();
108+
109+
gl::draw( mTexture, mTexture->getBounds() );
69110
}
111+
112+
drawGui();
113+
}
114+
115+
void ImageFileBasicApp::drawGui()
116+
{
117+
ImGui::Begin( "Image Info" );
118+
119+
if( ImGui::Button( "Open Image" ) ) {
120+
mOpenRequested = true;
121+
}
122+
123+
ImGui::SameLine();
124+
125+
ImGui::BeginDisabled( ! mTexture );
126+
if( ImGui::Button( "Save Image" ) ) {
127+
mSaveRequested = true;
128+
}
129+
ImGui::EndDisabled();
130+
131+
ImGui::SameLine();
132+
133+
ImGui::BeginDisabled( ! mTexture );
134+
if( ImGui::Button( "Fit to Window" ) ) {
135+
mCanvas.setContentBounds( Rectf( mTexture->getBounds() ) );
136+
mCanvas.fitAll();
137+
}
138+
ImGui::EndDisabled();
139+
140+
ImGui::Separator();
141+
142+
if( mTexture && mImageSource ) {
143+
ImGui::Text( "File: %s", mImagePath.filename().string().c_str() );
144+
ImGui::Separator();
145+
ImGui::Text( "Dimensions: %d x %d", mTexture->getWidth(), mTexture->getHeight() );
146+
ImGui::Text( "Texture Format: %s", gl::constantToString( mTexture->getInternalFormat() ).c_str() );
147+
ImGui::Separator();
148+
149+
// Image source information
150+
const char* colorModelStr = "Unknown";
151+
switch( mImageSource->getColorModel() ) {
152+
case ImageIo::CM_RGB: colorModelStr = "RGB"; break;
153+
case ImageIo::CM_GRAY: colorModelStr = "Grayscale"; break;
154+
default: break;
155+
}
156+
ImGui::Text( "Color Model: %s", colorModelStr );
157+
158+
const char* dataTypeStr = "Unknown";
159+
switch( mImageSource->getDataType() ) {
160+
case ImageIo::UINT8: dataTypeStr = "UINT8"; break;
161+
case ImageIo::UINT16: dataTypeStr = "UINT16"; break;
162+
case ImageIo::FLOAT16: dataTypeStr = "FLOAT16"; break;
163+
case ImageIo::FLOAT32: dataTypeStr = "FLOAT32"; break;
164+
default: break;
165+
}
166+
ImGui::Text( "Data Type: %s", dataTypeStr );
167+
168+
const char* channelOrderStr = "Unknown";
169+
switch( mImageSource->getChannelOrder() ) {
170+
case ImageIo::Y: channelOrderStr = "Y (Grayscale)"; break;
171+
case ImageIo::YA: channelOrderStr = "YA (Grayscale + Alpha)"; break;
172+
case ImageIo::RGB: channelOrderStr = "RGB"; break;
173+
case ImageIo::RGBA: channelOrderStr = "RGBA"; break;
174+
case ImageIo::RGBX: channelOrderStr = "RGBX"; break;
175+
case ImageIo::BGR: channelOrderStr = "BGR"; break;
176+
case ImageIo::BGRA: channelOrderStr = "BGRA"; break;
177+
case ImageIo::BGRX: channelOrderStr = "BGRX"; break;
178+
default: break;
179+
}
180+
ImGui::Text( "Channel Order: %s", channelOrderStr );
181+
182+
ImGui::Text( "Has Alpha: %s", mImageSource->hasAlpha() ? "Yes" : "No" );
183+
ImGui::Text( "Premultiplied: %s", mImageSource->isPremultiplied() ? "Yes" : "No" );
184+
}
185+
else {
186+
ImGui::Text( "No image loaded" );
187+
ImGui::Text( "Click 'Open Image' or drag & drop an image file" );
188+
189+
if( ! mErrorMessage.empty() ) {
190+
ImGui::Separator();
191+
ImGui::PushStyleColor( ImGuiCol_Text, ImVec4( 1.0f, 0.3f, 0.3f, 1.0f ) );
192+
ImGui::TextWrapped( "Error: %s", mErrorMessage.c_str() );
193+
ImGui::PopStyleColor();
194+
}
195+
}
196+
197+
ImGui::End();
70198
}
71199

72200
CINDER_APP( ImageFileBasicApp, RendererGl )

0 commit comments

Comments
 (0)