Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Convert *bitmap to char buffer

Credits go to Edgar Reynaldo for helping out!
This thread is locked; no one can reply to it. rss feed Print
Convert *bitmap to char buffer
Scooter
Member #16,799
January 2018

Hi all:
As the title states, I need to know how to convert Allegro *BITMAP
to char, so I can store the chars into my buffer, char name[50].
Can someone help me on how to do this? I have search the internet but
have not found how this can be done. If you need more info, let me know.
Thanks for your time.

LennyLen
Member #5,313
December 2004
avatar

I'm guessing since you reference BITMAP and not ALLEGRO_BITMAP that you mean A4.

If so, then this should hopefully help: https://www.allegro.cc/manual/4/api/direct-access-to-video-memory/

Scooter
Member #16,799
January 2018

Hi LennyLen:
No, I am using allegro5. Sorry, I did not mean to mislead anyone.
I should have stated that fact. Hear is why I think this is what I
need to do:
Right click image in file manager.
I then string copy argv[1] into my char name[100].
My image loads and displays on screen.
I am able to modify image.
I then save image to "sample.png".
Everything is fine.
Now my original char name[100] is no longer valid.
But if there was a way to update the name buffer with
the new info, I would be very happy!
Is this possible or have I completely lost my mind?

Thanks for your reply, have a great day!

DanielH
Member #934
January 2001
avatar

Your original post said to put an allegro bitmap into char buffer.
Now you just want to know how to modify a char buffer?

strcpy_s(my_buffer, size of my buffer, new name);

Scooter
Member #16,799
January 2018

Hi Daniel:
You are correct. I had a name to begin with. It was stored in argv[1].
Now I have no name. All I have now is a modified bitmap. There is no name
associated with this bitmap. If I try to associate a name I would create
a seg fault because I can't copy *bitmap into a char buffer.
Am i missing something here? Please explain.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Learn the difference between a pointer and an array. char[100] is an array. char* is a pointer. If you want to copy into a char buffer fine, declare an array of char large enough to hold + 1 for the null or allocate memory for it. Then use strncpy to copy it into your char buffer.

Scooter
Member #16,799
January 2018

Hi Edgar:
Yeah, I already know the difference. If I read you correctly, you are
saying I need to save it like I would save to a .png file except to a
buffer instead! Is this correct? If so, I already do this to a file, but
I end up saving the complete backbuffer. If I have it in the buffer, I
can save only the image. Kind of crazy I guess, but that is what I got.
Saving to a file, I can do, but saving to a buffer I will have to do some
research. Never done that before. Thanks for the tip, learn something
new every day! I will mark this closed! Thanks again!

DanielH
Member #934
January 2001
avatar

So you do want to save a bitmap to a char buffer. I am thoroughly confused.

It's not so easy.

The ALLEGRO_BITMAP pointer doesn't just point to the ALLEGRO_BITMAP struct. There are internal data pointers as well that point somewhere else.

It is doable.

Hardest part would be calculating the buffer size needed?

Take a look at the struct.

#SelectExpand
1struct ALLEGRO_BITMAP 2{ 3 ALLEGRO_BITMAP_INTERFACE *vt; 4 5 /* 6 * When this is a sub-bitmap, these are inherited from the parent. Don't 7 * access them directly, but use al_get_bitmap_format/flags or 8 * _al_get_bitmap_display unless you are super sure this is not a sub-bitmap 9 * (e.g. when you're creating a new bitmap). 10 */ 11 int _format; 12 int _flags; 13 int _depth; 14 int _samples; 15 ALLEGRO_DISPLAY *_display; 16 ALLEGRO_BITMAP_WRAP _wrap_u; 17 ALLEGRO_BITMAP_WRAP _wrap_v; 18 /* What format is used for the backing memory 19 * (can be different from _format, for e.g. compressed bitmaps) */ 20 int _memory_format; 21 22 int w, h; 23 /* 24 * The number of bytes between a pixel at (x,y) and (x,y+1). 25 * This is larger than w * pixel_size if there is padding between lines. 26 */ 27 int pitch; 28 /* 29 * clip left, right, top, bottom 30 * Clip anything outside of this. cr/cb are exclusive, that is (0, 0, 1, 1) 31 * is the single pixel spawning a rectangle from floating point 0/0 to 1/1 - 32 * or in other words, the single pixel 0/0. 33 * 34 * There is always confusion as to whether cr/cb are exclusive, leading to 35 * subtle bugs. The suffixes are supposed to help with that. 36 */ 37 int cl; 38 int cr_excl; 39 int ct; 40 int cb_excl; 41 /* 42 * Locking info. 43 * 44 * These values represent the actual locking dimensions, which may be different 45 * from what was passed in to al_lock_bitmap_region. This is transparent to the 46 * user, but the internal drawing functions must take this into account. To 47 * that end, use this lock_data parameter value and NOT the one in locked_region. 48 * 49 * locked - locked or not? 50 * lock_x/y - top left of the locked region 51 * lock_w/h - width and height of the locked region 52 * lock_flags - flags the region was locked with 53 * lock_data - the pointer to the real locked data (see above) 54 * locked_region - a copy of the locked rectangle 55 */ 56 bool locked; 57 int lock_x; 58 int lock_y; 59 int lock_w; 60 int lock_h; 61 void* lock_data; 62 int lock_flags; 63 ALLEGRO_LOCKED_REGION locked_region; 64 65 /* Transformation for this bitmap */ 66 ALLEGRO_TRANSFORM transform; 67 ALLEGRO_TRANSFORM inverse_transform; 68 bool inverse_transform_dirty; 69 ALLEGRO_TRANSFORM proj_transform; 70 71 /* Blender for this bitmap (if not set, use TLS) */ 72 bool use_bitmap_blender; 73 ALLEGRO_BLENDER blender; 74 75 /* Shader applied to this bitmap. Set this field with 76 * _al_set_bitmap_shader_field to maintain invariants. 77 */ 78 ALLEGRO_SHADER *shader; 79 80 /* Info for sub-bitmaps */ 81 ALLEGRO_BITMAP *parent; 82 int xofs; 83 int yofs; 84 85 /* A memory copy of the bitmap data. May be NULL for an empty bitmap. */ 86 unsigned char *memory; 87 88 /* Extra data for display bitmaps, like texture id and so on. */ 89 void *extra; 90 91 _AL_LIST_ITEM *dtor_item; 92 93 /* set_target_bitmap and lock_bitmap mark bitmaps as dirty for preservation */ 94 bool dirty; 95};

You could also look at the register save and load functions. Make your own that loads/saves to/from a char buffer.

After all that, I don't know why you would want to.

EDIT:
I'm still confused. Do you need to save the filename of the bitmap or the bitmap itself to a buffer?

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

>EDIT:
>I'm still confused. Do you need to save the filename of the bitmap or the bitmap
>itself to a buffer?

I wonder that also. Please be very clear what you want, and array of rgb stored in char, or a string name to save the file as? ???

Scooter
Member #16,799
January 2018

Edgar and Daniel:
Sorry, I guess I am going at this the wrong way. I think I can clear
this up:
I am now in my file manager, I right click on an image, image shows on screen.
Everything is fine. I take the first argument argv[1] and strcpy into my char
name[100] buffer. I then save to "sample,png" file. I then open my file manager
and I see the file ONLY. Bear with me now. Code below:

                              if(lp == true);
                                 {             // saving DEFAULT image
                                     al_set_target_bitmap(temp_image);
                                     temp_image = al_load_bitmap(name);
                                     al_save_bitmap("sample.png", temp_image);
                                     al_destroy_bitmap(temp_image);
                                 }

Notice the (name) buffer called. Everything is still fine. I am happy!!!

Now I want to modify that image. Buffer called name[] is no longer valid,

Now I save the modified image. Code below:

                              if(rt == true || mr == true || dt == true)
                                 {             // saving ROTATED OR MIRROR images
                                    temp_image = al_create_bitmap(screen_width, working_screen_height);
                                    al_set_target_bitmap(temp_image);
                                    al_draw_bitmap(al_get_backbuffer(display), 0, 0, 0);
                                    al_set_target_backbuffer(display);
                                    al_save_bitmap("sample.png", temp_image);
                                    al_destroy_bitmap(temp_image);
                                 }
Sorry, the code ran over to the next line.

I go back to the file manager. I see the "sample.png" file but I also see the
complete backbuffer. I am NOT happy!!! The first thing you are going to say
is 'That is what you ask for'. Right, because if I had ask for image_width and
image_height, I would have gotten pure garbage. Now, if I had the name buffer
updated I could have used the first code I posted and I would be happy again!
Either the name[] buffer needs to be updated or my second code needs to change.

I hope it is clear now. Thanks again for your time.

DanielH
Member #934
January 2001
avatar

You modify the image, name hasn't changed since you set it to argv[1]
What do you want name to be if image is modified?

First code
1. set temporary_bitmap to target. Why this line and what is temp_image at this point?
2. load temporary with filename from name buffer
3. save temporary_as 'sample.png'
4. delete temporary

Second code
1. create a temporary bitmap size of display
2. set temporary as target
3. draw display back buffer to temporary
4. save temporary as 'sample.png'
5. destroy temporary

So, what's the problem? Why do you say name[] is invalid if image is modified.

also, use a bitmap to keep your bitmap in and don't use the display's back buffer. Do you need to save the entire display? OR just the bitmap you modified?

Maybe if you explain a bit what your app does.

Scooter
Member #16,799
January 2018

Hi Daniel:
I want you to do me a favor. Go back and read the very first line of your
last post. That is exactly my problem. If I bring up image representing argv[1]
and I modify that image, argv[1] does NOT exist any longer at this sitting. So,
what I want is name[] buffer updated to reflect the changes to argv[1]. Then
and only then can I use the first code to save the image and get only the image
without the complete backbuffer. If I try to save argv[1] after the modification
I will receive the original argv[1], NOT what I want. I hope this helps.

DanielH
Member #934
January 2001
avatar

You said you had a char buffer called name.

At the start of your program, copy argv[1] to name. No need to ever use argv after that.
If you modify your image, modify name.

Here's and app that loads a bitmap from argv[1], modifies it, and save
Left mouse down: puts a black dot
F2: saves image to sample.png
Escape: exits

#SelectExpand
1#include <allegro5/allegro.h> 2#include <allegro5/allegro_image.h> 3#include <string> 4 5const int display_width = 1366; 6const int display_height = 768; 7ALLEGRO_DISPLAY* display = nullptr; 8ALLEGRO_EVENT_QUEUE* queue = nullptr; 9ALLEGRO_TIMER* timer = nullptr; 10int32_t logic_counter = 0; 11bool kill = false; 12bool dirty = true; 13const char name[] = "My App Name"; 14ALLEGRO_BITMAP* bitmap = nullptr; 15char bitmap_filename[256] = ""; 16bool bitmap_is_modified = false; 17bool mouse_button_was_pressed = false; 18int bitmap_x = 100; 19int bitmap_y = 100; 20int mouse_x = 0; 21int mouse_y = 0; 22 23int init(int argc, char** argv); 24void shutdown(); 25int32_t do_loop(); 26void draw_display(); 27void process_logic(); 28void process_input(); 29void display_set_title(); 30 31int main(int argc, char** argv) 32{ 33 if (init(argc, argv) == 0) 34 { 35 do_loop(); 36 } 37 38 shutdown(); 39 40 return 0; 41} 42 43int init(int argc, char** argv) 44{ 45 if (argc == 2) 46 { 47 strcpy_s(bitmap_filename, 256, argv[1]); 48 } 49 50 if (!al_init()) 51 { 52 return -1; 53 } 54 55 if (!al_install_mouse()) 56 { 57 return -1; 58 } 59 60 if (!al_install_keyboard()) 61 { 62 return -1; 63 } 64 65 if (!al_init_image_addon()) 66 { 67 return -1; 68 } 69 70 al_set_new_display_option(ALLEGRO_SAMPLE_BUFFERS, 1, ALLEGRO_SUGGEST); 71 al_set_new_display_option(ALLEGRO_SAMPLES, 8, ALLEGRO_SUGGEST); 72 al_set_new_display_flags(ALLEGRO_WINDOWED | ALLEGRO_RESIZABLE); 73 display = al_create_display(display_width, display_height); 74 if (!display) 75 { 76 return -1; 77 } 78 display_set_title(); 79 80 queue = al_create_event_queue(); 81 if (!queue) 82 { 83 return -1; 84 } 85 86 timer = al_create_timer(1.0 / 60.0); 87 if (!timer) 88 { 89 return -1; 90 } 91 92 if (argc == 2) 93 { 94 if (bitmap) 95 { 96 al_destroy_bitmap(bitmap); 97 } 98 bitmap = al_load_bitmap(bitmap_filename); 99 100 if (!bitmap) 101 { 102 return -1; 103 } 104 } 105 106 al_register_event_source(queue, al_get_display_event_source(display)); 107 al_register_event_source(queue, al_get_timer_event_source(timer)); 108 al_register_event_source(queue, al_get_keyboard_event_source()); 109 al_register_event_source(queue, al_get_mouse_event_source()); 110 111 al_start_timer(timer); 112 113 return 0; 114} 115 116void shutdown() 117{ 118 if (bitmap) 119 { 120 al_destroy_bitmap(bitmap); 121 bitmap = nullptr; 122 } 123 124 if (timer) 125 { 126 al_stop_timer(timer); 127 al_destroy_timer(timer); 128 timer = nullptr; 129 } 130 131 if (queue) 132 { 133 al_destroy_event_queue(queue); 134 queue = nullptr; 135 } 136 137 if (display) 138 { 139 al_destroy_display(display); 140 display = nullptr; 141 } 142} 143 144int32_t do_loop() 145{ 146 while (!kill) 147 { 148 process_input(); 149 150 while (logic_counter > 0) 151 { 152 process_logic(); 153 --logic_counter; 154 } 155 156 if (dirty) 157 { 158 draw_display(); 159 dirty = false; 160 } 161 162 al_rest(0.01); 163 } 164 165 return 0; 166} 167 168void draw_display() 169{ 170 al_set_target_bitmap(al_get_backbuffer(display)); 171 al_clear_to_color(al_map_rgb(255, 255, 255)); 172 173 if (bitmap) 174 { 175 al_draw_bitmap(bitmap, bitmap_x, bitmpa_y, 0); 176 } 177 178 al_flip_display(); 179} 180 181void process_logic() 182{ 183 if (mouse_button_was_pressed) 184 { 185 if (bitmap) 186 { 187 ALLEGRO_LOCKED_REGION* region = al_lock_bitmap(bitmap, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_WRITEONLY); 188 ALLEGRO_BITMAP* target = al_get_target_bitmap(); 189 al_set_target_bitmap(bitmap); 190 al_put_pixel(mouse_x - bitmap_x, mouse_y - bitmap_y, al_map_rgb(0, 0, 0)); 191 al_set_target_bitmap(target); 192 al_unlock_bitmap(bitmap); 193 bitmap_is_modified = true; 194 display_set_title(); 195 dirty = true; 196 } 197 } 198} 199 200void process_input() 201{ 202 static ALLEGRO_EVENT event; 203 204 while (!al_event_queue_is_empty(queue)) 205 { 206 al_get_next_event(queue, &event); 207 208 switch (event.type) 209 { 210 case ALLEGRO_EVENT_TIMER: 211 { 212 ++logic_counter; 213 } break; 214 215 case ALLEGRO_EVENT_DISPLAY_CLOSE: 216 { 217 kill = true; 218 } break; 219 220 case ALLEGRO_EVENT_MOUSE_AXES: 221 { 222 mouse_x = event.mouse.x; 223 mouse_y = event.mouse.y; 224 225 } break; 226 227 case ALLEGRO_EVENT_MOUSE_BUTTON_UP: 228 { 229 if (event.mouse.button == 1) 230 { 231 mouse_button_was_pressed = false; 232 } 233 } break; 234 235 case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN: 236 { 237 if (event.mouse.button == 1) 238 { 239 mouse_button_was_pressed = true; 240 } 241 } break; 242 243 case ALLEGRO_EVENT_KEY_UP: 244 { 245 if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) 246 { 247 kill = true; 248 } 249 250 if (event.keyboard.keycode == ALLEGRO_KEY_F2) 251 { 252 if (bitmap) 253 { 254 al_save_bitmap("sample.png", bitmap); 255 bitmap_is_modified = false; 256 display_set_title(); 257 } 258 } 259 } break; 260 } 261 } 262} 263 264void display_set_title() 265{ 266 char title[256] = ""; 267 268 strcat_s(title, 256, name); 269 270 if (bitmap_filename[0] != 0) 271 { 272 strcat_s(title, 256, " - "); 273 strcat_s(title, 256, bitmap_filename); 274 275 if (bitmap_is_modified) 276 { 277 strcat_s(title, 256, "*"); 278 } 279 } 280 281 al_set_window_title(display, title); 282}

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

DanielH
Member #934
January 2001
avatar

You could also add a function to load a different bitmap and modify name. If you had some sort of fileloader dialog or whatever.

#SelectExpand
1bool bitmap_load(const char* filename) 2{ 3 if (!filename) 4 { 5 return false; 6 } 7 8 if (bitmap) 9 { 10 al_destroy_bitmap(bitmap); 11 } 12 13 bitmap = al_load_bitmap(filename); 14 if (!bitmap) 15 { 16 return false; 17 } 18 19 strcpy_s(name, 256, filename); 20 bitmap_is_modified = false; 21 22 return true; 23}

Scooter
Member #16,799
January 2018

Hi Daniel and Edgar:
Well it looks like I am stuck with what I have. Any changes I make I get
kick right back to codeblocks. I ran your program Daniel and it ran fine with
some minor changes. I also investigated what Edgar posted. I am a little concerned about what happened. He talked like the argv[1] would be alive for the
complete sitting. I found that not to be the case. I rotated the bitmap
and all went well except when I tried to copy argv[1] to another buffer. Back
to codeblocks I went in a flash. I hope Edgar is not upset with what I said. I
would not question him at all. Both of you know more about this than I do. I
am just saying what I found on my machine. My program runs fine I already have
it in my Linux system. I click on an image and the image is on the screen. I might look into what you just posted about loading a new file from the disk.
Thanks to both of you for your help!

DanielH
Member #934
January 2001
avatar

Are you changing argv in your code? While it is not constant, if you don't modify it, then it will always point to the same array of constant strings. Also, it will persist throughout runtime, You shouldn't have any program accessing it at any point (inside of scope). If outside of scope, then make a buffer.

char name[256] = ""; // valid throughout source file

int main(int argc, char** argv) // valid only inside main.
{
}

Unless your modifying it.

Also, can post code?

Scooter
Member #16,799
January 2018

Hi Daniel:
I am sure the problem in losing argv[1] is because I leave main(). The best I
can do to get what I want is a complete rewrite of the program. It was a very
expensive lesson to learn. I go back and forth out of main() all the time. The
main problem is having to save the complete backbuffer after changing argv[1].
It is too big of a problem to try to change what I have now! I hate to give it up
because it is the only image viewer I have. I will start Monday to rewrite what
I have now keeping in mind saving argv[1] all through the program.

AceBlkwell
Member #13,038
July 2011
avatar

This is probably a stupid suggestion and not applicable, but is there any way to declare argv[1] static? I know when you want to keep a value in a variable for when you re-enter a function, you can make it static and value does not reinitialize.

static int count = 0;

Just thinking out loud.

Or maybe write the name to global variable or file? Again, just shooting in the dark.

DanielH
Member #934
January 2001
avatar

Once again, why and huh?

Reenter function?

They are already static because they will only ever be alive while your program is running. Which is the entire time. Just because you jump to other code and back doesn't change that.

Scooter
Member #16,799
January 2018

Hi Daniel:
Hey, I lied to you! I didn't wait till next week, I rewrote enough to test
out the life of argv[1]. OK, I am inside of main the whole time. I know what
you and Edgar said about staying within main and I did. The name buffer is
still not updating. In fact, the program is worse than before the rewrite. I
don't doubt what you are saying. I would never do that. It is not what I see
on my end. The only time I am able to save ONLY the image is when I bring up
the image and save without any changes. I guess I have completed this project.
Three months is enough time to spend on it. It works and works fine and I am
happy I got this far. Time to move on to something else. Thanks for the help!

DanielH
Member #934
January 2001
avatar

Don't give up.

Scooter said:

The name buffer is still not updating

Are you not updating the name buffer? It won't magically change unless you change it.

Did you create a name buffer or are you only using argv[1]?

I'm still confused on what you are doing or not doing or what you are trying to accomplish.

Go to: