Create HBitmap in IExtractImage - winapi

I'm developping a thumbnail creator as a shell extension.
To do that, I choosed to implement interface IExtractImage.
My dll is loaded and correctly called, but, the thumbnail is always black, instead of being red.
What am I missing?
class MyShellPreview : public IExtractImage, IPersistFile
// set by IExtractImage::GetLocation
SIZE m_size;
IFACEMETHODIMP Extract(HBITMAP *phBmpImage)
{
size_t size = m_size.cx * m_size.cy * 3;
// alloc buffer
BYTE *buffer = (BYTE*)malloc(size);
// fill buffer
for (k = i = 0; i < m_size.cx; ++i)
{
for (j = 0; j < m_size.cy; ++j, ++k)
{
buffer[k] = 128;
buffer[k+1] = 0;
buffer[k+2] = 0;
}
}
*phBmpImage = CreateBitmap(m_size.cx, m_size.cy, 3, 8, buffer);
free(buffer);
return S_OK;
}
};
I know that for performance reason, I should use CreateCompatibleBitmap and SetDIBits, but I'm not sure from where I should get an HDC.

As pointed on comments, the solution was to use:
32 bits images
1 color plane
class MyShellPreview : public IExtractImage, IPersistFile
// set by IExtractImage::GetLocation
SIZE m_size;
IFACEMETHODIMP Extract(HBITMAP *phBmpImage)
{
size_t size = m_size.cx * m_size.cy * 4;
// alloc buffer
BYTE *buffer = (BYTE*)calloc(size, 1);
// fill buffer
for (k = i = 0; i < m_size.cx; ++i)
{
for (j = 0; j < m_size.cy; ++j, k+=4)
{
buffer[k] = 128;
}
}
*phBmpImage = CreateBitmap(m_size.cx, m_size.cy, 1, 24, buffer);
free(buffer);
return S_OK;
}
};

Related

Moving from AVR to ESP32 rto control led strip using 1 pin and SPI/DMA

i'm working on an old project based on AVR, that controls a led stripe using 1 pin with SPI high frequency in DMA. (42 leds)
I'm converting the code to esp-idf, but i'm facing some problem, probably base on bus/config parameters.
These are the code:
AVR:
USART_SPI_RGB_OPTIONS.baudrate = USART_SPI_RGB_BAUDRATE;
USART_SPI_RGB_OPTIONS.spimode = USART_SPI_RGB_CHMODE;
USART_SPI_RGB_OPTIONS.data_order = USART_SPI_RGB_DATA_ORDER;
usart_init_spi(USART_SPI_RGB_PORT, &USART_SPI_RGB_OPTIONS);
void dma_init(void){
struct dma_channel_config dmach_conf;
memset(&dmach_conf, 0, sizeof(dmach_conf));
dma_channel_set_burst_length(&dmach_conf, DMA_CH_BURSTLEN_1BYTE_gc);
dma_channel_set_transfer_count(&dmach_conf, DMA_BUFFER_SIZE);
dma_channel_set_src_reload_mode(&dmach_conf, DMA_CH_SRCRELOAD_TRANSACTION_gc);
dma_channel_set_dest_reload_mode(&dmach_conf, DMA_CH_DESTRELOAD_NONE_gc);
dma_channel_set_src_dir_mode(&dmach_conf, DMA_CH_SRCDIR_INC_gc);
dma_channel_set_source_address(&dmach_conf, (uint16_t)(uintptr_t)RGBMemoryMap);
dma_channel_set_dest_dir_mode(&dmach_conf, DMA_CH_DESTDIR_FIXED_gc);
dma_channel_set_destination_address(&dmach_conf, (uint16_t)(uintptr_t)USART_SPI_RGB_PORT.DATA);
dma_channel_set_trigger_source(&dmach_conf, DMA_CH_TRIGSRC_USARTD0_DRE_gc);
dma_channel_set_single_shot(&dmach_conf);
dma_enable();
dma_channel_write_config(DMA_CHANNEL, &dmach_conf);
dma_channel_enable(DMA_CHANNEL);
}
ESP-IDF:
void initSPISettings()
{
//memset(&SPI_settings, 0, sizeof(SPI_settings));
SPI_settings.host = HSPI_HOST,
SPI_settings.dma_chan = SPI_DMA_CH2;
// buscfg
SPI_settings.buscfg.flags = 0;
SPI_settings.buscfg.miso_io_num = -1;
SPI_settings.buscfg.mosi_io_num = GPIO_NUM_32;
SPI_settings.buscfg.sclk_io_num = -1;
SPI_settings.buscfg.quadwp_io_num = -1;
SPI_settings.buscfg.quadhd_io_num = -1;
SPI_settings.buscfg.max_transfer_sz = LED_DMA_BUFFER_SIZE;
// devcfg
SPI_settings.devcfg.clock_speed_hz = DMA_SPEED;
SPI_settings.devcfg.dummy_bits = 0;
SPI_settings.devcfg.mode = 0;
SPI_settings.devcfg.flags = SPI_DEVICE_NO_DUMMY;
SPI_settings.devcfg.spics_io_num = -1;
SPI_settings.devcfg.queue_size = 1;
SPI_settings.devcfg.command_bits = 0;
SPI_settings.devcfg.address_bits = 0;
}
void initSPI()
{
esp_err_t err;
initSPISettings();
err = spi_bus_initialize(SPI_settings.host, &SPI_settings.buscfg, SPI_settings.dma_chan);
ESP_ERROR_CHECK(err);
//Attach the Accel to the SPI bus
err = spi_bus_add_device(SPI_settings.host, &SPI_settings.devcfg, &SPI_settings.spi);
ESP_ERROR_CHECK(err);
}
void updateRGB()
{
spi_transaction_t t;
esp_err_t err;
printf("Start transaction to DMA...\r\n");
// for (int i = (LED_DMA_BUFFER_SIZE - LED_RESET_COUNT); i < LED_DMA_BUFFER_SIZE; i++) {
// //Setting more bytes to 0x00 at the end of memory map to assure correct RGB init
// ledDMAbuffer[i] = 0x00;
// }
t.flags = 0;
t.length = LED_DMA_BUFFER_SIZE * 8; //length is in bits
t.tx_buffer = ledDMAbuffer;
t.rx_buffer = NULL;
t.rxlength = 0;
err = spi_device_transmit(SPI_settings.spi, &t);
ESP_ERROR_CHECK(err);
}
ledDMAbuffer = heap_caps_malloc(LED_DMA_BUFFER_SIZE, MALLOC_CAP_DMA); // Critical to be DMA memory.
Do you have any ideas what i'm missing?
I fill data in the right way (i'm sure of that). If i try to control 1 led no problem at all, while increasing the number of leds controlled i have strange behaviour (for example with 2 led blinking red/green, first one works properly while second one just red)
Thanks to all

How to refresh OnPaint() function; Window Update is not working

This is my code:
void CChildView::OnPaint()
{
CPaintDC dc(this);
CBitmap b; b.LoadBitmap(IDB_BITMAP1);
CDC memdc; memdc.CreateCompatibleDC(&dc);
auto prev = memdc.SelectObject(&b);
BITMAP bmp; b.GetBitmap(&bmp);
int bitmap_height = bmp.bmHeight;
int bitmap_width = bmp.bmWidth;
if (!painted) {
nrows = divide(bitmap_height, 8);
ncols = divide(bitmap_width, 8);
piece_height = bitmap_height / nrows;
piece_width = bitmap_width / ncols;
int number_of_tiles = nrows * ncols;
positions.resize(number_of_tiles);
std::iota(positions.begin(), positions.end(), 0);
empty = positions.size() - 1;//prazna pločica je zadnja
std::shuffle(positions.begin(), positions.end(), std::mt19937{ std::random_device{}() });
painted = true;
}
for (int i = 0; i < positions.size()-1; ++i) {
int row_dest = positions[i] / ncols;
int col_dest = positions[i] % ncols;
int row_src = i / ncols;
int col_src = i % ncols;
int x_src = col_src * piece_width;
int y_src = row_src * piece_height;
int x_dest = col_dest * piece_width;
int y_dest = row_dest * piece_height;
dc.BitBlt(x_dest, y_dest, piece_width, piece_height, &memdc, x_src, y_src, SRCCOPY);
dc.SelectObject(prev);
}
}
void CChildView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call def
CWnd::OnLButtonDown(nFlags, point);
//koordinate gdje je korisnik kliknuo
int row = point.y / piece_height;
int col = point.x / piece_width;
int empty_row = empty / ncols;
int empty_col = empty % ncols;
bool slide = false;
switch (abs(row - empty_row)) {
case 1:
if (abs(col==empty_col))
slide = true;
break;
case 0:
if (abs(col-empty_col==1))
slide = true;
break;
}
if (slide) {
int old_index = row * ncols + col;
positions[old_index] = positions[empty];
empty = old_index;
CWnd::InvalidateRect(NULL, FALSE);
CWnd::UpdateWindow();
}
}
I am trying to write a program that is called SlidingPuzzle. I managed to divide a bitmap into rectangles and shuffle them randomly. However, when I click on a rectangle there is no change. I suppose that UpdateWindow() is not working. It should refresh OnPaint() function. Can someone please help me, what am I doing wrong?

ffmpeg filter dev get_video_buffer function usage

I'm writing a mosaic ffmpeg filter.
copy code from vf_vflip.c, I register a callback function get_video_buffer
and implement it as follows:
static AVFrame *get_video_buffer(AVFilterLink *link, int w, int h)
{
MosaicContext *s = link->dst->priv;
AVFrame *frame;
int i;
int j,k;
frame = ff_get_video_buffer(link->dst->outputs[0], w, h);
if (!frame)
return NULL;
if (s->w == 0 || s->h == 0)
return frame;
for (i = 0; i < 3; i ++) {
// some trick code
}
return frame;
}
static const AVFilterPad avfilter_vf_mosaic_inputs[] = {
{
.name = "default",
.type = AVMEDIA_TYPE_VIDEO,
//.get_video_buffer = get_video_buffer,
.filter_frame = filter_frame,
.config_props = config_input,
},
{ NULL }
};
But after read some filter dev guide, I found that only a few filter implement get_video_buffer funcition.The default function is f_default_get_video_buffer()
I make some log find that ffmpeg call function like
get_video_buffer
filter_frame
get_video_buffer
filter_frame
get_video_buffer
filter_frame
...
I'm confused about get_video_buffer do what job.
Only know that some filter will hold frame cache.
Can I juse comment out the get_video_buffer hook?
I see flip job both in get_video_buffer() and filter_frame() in vf_vflip.c
Is it a waste of time?
static AVFrame *get_video_buffer(AVFilterLink *link, int w, int h)
{
FlipContext *flip = link->dst->priv;
AVFrame *frame;
int i;
frame = ff_get_video_buffer(link->dst->outputs[0], w, h);
if (!frame)
return NULL;
for (i = 0; i < 4; i ++) {
int vsub = i == 1 || i == 2 ? flip->vsub : 0;
int height = AV_CEIL_RSHIFT(h, vsub);
if (frame->data[i]) {
frame->data[i] += (height - 1) * frame->linesize[i];
frame->linesize[i] = -frame->linesize[i];
}
}
return frame;
}
static int filter_frame(AVFilterLink *link, AVFrame *frame)
{
FlipContext *flip = link->dst->priv;
int i;
for (i = 0; i < 4; i ++) {
int vsub = i == 1 || i == 2 ? flip->vsub : 0;
int height = AV_CEIL_RSHIFT(link->h, vsub);
if (frame->data[i]) {
frame->data[i] += (height - 1) * frame->linesize[i];
frame->linesize[i] = -frame->linesize[i];
}
}
return ff_filter_frame(link->dst->outputs[0], frame);
}

Image gallery assistance if you may

I created an image gallery that works great, the only problem I have is that I don't know how to set up my program so when you open it it opens with the pictures as thumbnails and if you click on the thumbnails the image expands.
int maxImages;
int imageIndex;
// Declaring an array of images.
PImage[] images;
void setup() {
size(600,400);
images = new PImage[maxImages];
maxImages = 2;
imageIndex = 0; // Initial image to be displayed is the first
for (int i = 0; i < images.length; i ++ ) {
images[i] = loadImage( "changeling" + i + ".jpg" );
}
}
void draw() {
// Displaying one image
image(images[imageIndex],0,0);
}
Here it's the idea, to show the images i'm setting them whit a width and height of 100 you can use any value or your own algorithm to get the best sizes.
Knowing the space in the sketch that every image occupies I can know when the mouse was inside one of them when an mouse click event happen. Then I proceed to expand the image by doubling the size until it reaches a good size comparing whit the screen size, Again you can use you own value or algorithm to get the best expansion ratio.
Once the mouse it's clicked again when an image is expanded it goes back to the thumbnail again.
Hope this can be useful.
int maxImages;
int imageIndex;
boolean imageExpand;
// Declaring an array of images.
PImage[] images;
void setup() {
size(600,400);
maxImages = 2;
imageIndex = 0; // Initial image to be displayed is the first
boolean imageExpand;
images = new PImage[maxImages];
imageExpand = false;
for (int i = 0; i < images.length; i ++ ) {
images[i] = loadImage( "changeling" + i + ".jpg" );
}
}
void draw() {
if(!imageExpand){
showThumbnail();
}
}
void mouseClicked(){
if(!imageExpand){
for(int i=0; i < images.length; i++){
if((images[i].X > mouseX) && (images[i].X + images[i].width < mouseX)){
if((images[i].Y > mouseY) && (images[i].Y + images[i].height < mouseY)){
expandImage(images[i]);
imageExpand = true;
}
}
}
}
else{
imageExpand = false;
showThumbnail();
}
}
void expandImage(PImage myImage){
int largeWidth, largeHeight;
while((myImage.width * 2 < 600) && (myImage.height * 2 < 400)){
largeWidth = myImage.width * 2;
largeWidth = myImage.height * 2;
}
image(myImage, 0, 0, largeWidth, largeHeight);
}
void showThumbnail(){
int posX = 0, posY = 0, lastImage = 0;
for(int i=0; i < images.length; i++){
if(posX + 100 < 600){
image(images[i], posX, posY, 100, 100);
posX = posX + 100;
}
else{
posX = 0;
posY = posY + 100;
image(images[i], posX, posY, 100, 100);
}
}
}
Regards Jose

How to release memory under following situation?

Below is some core graphics code..
CGColorRef colorRefArray[MAGIC_NUM];
for (int i = 0; i < MAGIC_NUM ; i++)
{
...
colorRefArray[i] = CreateColor(colorValueForEachColor, numberofcomp);
}
colorRefArray already has memory and CreateColor(); will again create a memory and it leads to memory leak.
How do I avoid this situation?
One possible thought I have is
CGColorRef colorRefArray[MAGIC_NUM];
for (int i = 0; i < MAGIC_NUM ; i++)
{
...
CGColorRef colorref = CreateColor(colorValueForEachColor, numberofcomp);
colorRefArray[i] = colorref;
CFRelease(colorref);
}
Is this approach correct?
No it's not. You're immediately releasing the color you created. The correct approach would be this:
CGColorRef colorRefArray[MAGIC_NUM];
for (int i = 0; i < MAGIC_NUM ; i++)
{
...
colorRefArray[i] = CreateColor(colorValueForEachColor, numberofcomp);
}
//Use your colors
//Now release them
for (int i = 0; i < MAGIC_NUM ; i++)
{
CFRelease(colorRefArray[i]);
}
No, because then colorRefArray will be filled with invalid pointers.
Try using a CFMutableArray instead of a raw C array. Then you only have to worry about the reference to the array, as it will own the colours for you:
CFArrayRef CopyColorArray(void) {
CFMutableArrayRef colorRefArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
if (colorRefArray) {
for (int i = 0; i < MAGIC_NUM ; i++) {
...
CGColorRef colorref = CreateColor(colorValueForEachColor, numberofcomp);
if (colorref) {
CFArrayAppendValue(colorRefArray, colorref);
CFRelease(colorref);
}
}
}
return colorRefArray;
}

Resources