Масштабирование битмапа : GDI+
От: Carc Россия https://vk.com/gosha_mazov
Дата: 13.01.17 11:32
Оценка:
Нужно отмасштабировать битмапку в памяти с заданными зумом. Вчера половину дня промаялся: пищит, мигает, известно куда не попадает.
Все масштабирует, зум на лицо, но обрезает по размеру исходого битмапа. Полный: *опа-кеды.
Уважаемый All, ткните носом, ЧЯДНТ!

HBITMAP CDlgPicResize::DoResizePlus(const LONG cx /*новая ширина для битмпап*/, const LONG cy /*новая высота*/)
{
    Gdiplus::Status st;

    TRACE(TEXT("DoResizePlus cx=%d cy=%d\n"),cx,cy);
    
    //расcчитываем Zoom-фактор 
    const float cx_factor=((float)cx/(float)m_szSRC.cx);//(m_szSRC - CSize с исходными размерами 1 в 1)
    const float cy_factor=((float)cy/(float)m_szSRC.cy);
    TRACE(TEXT("cx_factor=%f, CY_factor=%f\n"),cx_factor,cy_factor);

    const HDC hdcFrom=::GetDC(m_hwndRE);//HWND куда потом будет вставлен новый битпа
    ASSERT(hdcFrom);
    //////////////////////////////////////////////////////////////////////////
    //все эти с CAutoGDI*** - это auto-объекты, которые только освобождают ресурсы GDI на выходе
     const CAutoGDIHDC_Release release_dc_wnd(hdcFrom,m_hwndRE);
    //создаем битмап на котором будем рисовать в памяти
    HBITMAP hNew=CreateCompatibleBitmap(hdcFrom,cx,cy);
    ASSERT(hNew);

    //создаем временный GDI+ битмап и выбираем его в контекст
    Gdiplus::Bitmap bmpForDraw(cx
        ,cy
        ,PixelFormat24bppRGB) ;

    Gdiplus::Graphics g(&bmpForDraw);
    g.SetClip(Gdiplus::Rect(0,0,cx,cy)) ;

    st = g.SetInterpolationMode(Gdiplus::InterpolationModeBicubic);
    g.SetCompositingQuality(Gdiplus::CompositingQualityHighQuality);
    //устанавливаем масштабирование
    g.ScaleTransform(cx_factor, cy_factor);
    {/// рисуем исходный битмап с маштабированием и новой шириной\высотой
    Gdiplus::Bitmap bmpTemp(m_hSource,NULL);// m_hSource это HBITMAP исходный
    g.DrawImage(&bmpTemp,0,0,cx,cy);

    
    //забираем битмап
    HBITMAP h=NULL;
    st = bmpForDraw.GetHBITMAP(RGB(255,0,0),&h);
    ASSERT(Gdiplus::Ok == st);
    ASSERT(h);
    ASSERT(h != hNew);
    BITMAP bNew={0};
    GetObject(h, sizeof(BITMAP),&bNew);
    TRACE(TEXT("IN: cx=%d cy=%d\n"),bNew.bmWidth,bNew.bmHeight);
    hNew=h;//ДЛЯ кодо-копателей: да здесь идет потеря вышесозданного HBITMAP, но это издержки тестирования
//, поскольку уже 100 раз переписывалось и так и эдак, 
//изначально все корректно было, и потом, когда доводить буду -  “причешу”.
    }
    
#ifdef _DEBUG
    //всяко разно дебажные проверки (ширина\высота нового битмапа соответсвуют?
    //для просмотра кидаем в файл
    BITMAP bNew={0};
    GetObject(hNew , sizeof(BITMAP),&bNew);
    TRACE(TEXT("new cx=%d cy=%d\n"),bNew.bmWidth,bNew.bmHeight);

    {
    Gdiplus::Bitmap bmpForSave(hNew,NULL);
    CLSID bmpClsid ={0};
    
    GetCodecClsid(L"image/bmp", &bmpClsid);
    st= bmpForSave.Save(L"C:\\Test_GDI.bmp",&bmpClsid,NULL);
    ASSERT(Gdiplus::Ok == st);
    }
#endif

    
    return hNew;
}


Проблема в следующем: все масштабируется, но на выходе получаем обрезанный битмап по размеру исходного. То бишь зум видно невооруженным взглядом — все чики-поки. Но если масштаб больше 100 — тогда обрезается по размеру исходного битмапа. Если масштаб меньше 100 — то опять же, все масштабируется, результирующий битмап ессесна получается меньше исходого. Но опять же все по размеру исходного, просто с черным фоном.

Ни черта не понимаю уже. Что я не так то хоть делаю!?! Уже только что не перепробовал, не попеременял в коде. Ан фиг! Хелп, коллеги!
Aml Pages Home
Отредактировано 13.01.2017 14:59 Carc . Предыдущая версия . Еще …
Отредактировано 13.01.2017 14:59 Carc . Предыдущая версия .
Отредактировано 13.01.2017 12:25 Carc . Предыдущая версия .
Отредактировано 13.01.2017 12:23 Carc . Предыдущая версия .
Отредактировано 13.01.2017 12:20 Carc . Предыдущая версия .
Отредактировано 13.01.2017 11:35 Carc . Предыдущая версия .
Отредактировано 13.01.2017 11:34 Carc . Предыдущая версия .
Re: Масштабирование битмапа : GDI+
От: Serpuh фотомер.рф
Дата: 13.01.17 16:18
Оценка:
Попробуй через g.SetTransform которая матрицу преобразований в себя принимает, на MSDN должно быть описание этих преобразований — масштаб, сдвиг и вращение.
Тут еще статьи можешь посмотреть, там есть про двойную буферизацию чтоб не мерцало http://rsdn.org/summary/625.xml
Отредактировано 13.01.2017 16:23 Serpuh . Предыдущая версия .
Re[2]: Масштабирование битмапа : GDI+
От: Carc Россия https://vk.com/gosha_mazov
Дата: 13.01.17 19:53
Оценка:
Здравствуйте, Serpuh, Вы писали:

S>Попробуй через g.SetTransform которая матрицу преобразований в себя принимает, на MSDN должно быть описание этих преобразований — масштаб, сдвиг и вращение.

S>Тут еще статьи можешь посмотреть, там есть про двойную буферизацию чтоб не мерцало http://rsdn.org/summary/625.xml
Спасибо! Полистал… Но не то всё.

Двойная буферизация мне не нужна, ибо у меня и так все в памяти рисуется. Проблема в том, что отсекается все вне исходного битмапа после масштабирования.

Методика тщательной медитации дала следующее: Visible Rect сбивается у Graphics как только я выставляю ScaleTransform
        HBITMAP hNew=CreateCompatibleBitmap(hdcFrom,cx,cy);//создали битмап в памяти с новой шириной высотой
    ASSERT(hNew);


     Gdiplus::Bitmap bmpForDraw(cx
         ,cy
         ,PixelFormat24bppRGB) ;

    Gdiplus::Graphics* gp=Gdiplus::Graphics::FromImage(&bmpForDraw);
    Gdiplus::Graphics& g=*gp;

    //тут все ок GetVisibleClipBounds возвращает Rect с новой шириной\высотой    
    Gdiplus::Rect rClipVis;
    g.GetVisibleClipBounds(&rClipVis);
    TRACE(TEXT("visible cx=%d cy=%d\n"),rClipVis.Width,rClipVis.Height);

    st = g.SetPageUnit(Gdiplus::UnitPixel);
    st = g.SetInterpolationMode(Gdiplus::InterpolationModeHighQualityBicubic);
    g.SetCompositingQuality(Gdiplus::CompositingQualityHighQuality);
    //устанавливаем масштабирование
    
    st = g.SetClip(Gdiplus::Rect(0,0,cx,cy)) ;
    //и тут все ок GetVisibleClipBounds возвращает Rect с новой шириной\высотой
    g.GetVisibleClipBounds(&rClipVis);
    
    //ставим зум
    st = g.ScaleTransform(cx_factor, cy_factor);
    //!!!!!
    //А ВОТ тут уже GetVisibleClipBounds возвращает Rect со старой шириной\высотой
    g.GetVisibleClipBounds(&rClipVis);
        
        //ФИга с два, повторная установка ничего не устанавливает, GetVisibleClipBounds все равно возвращает
    //СТАРУЮ ширину высоту
    st = g.SetClip(Gdiplus::Rect(0,0,cx,cy)) ;
    g.GetVisibleClipBounds(&rClipVis);
    TRACE(TEXT("visible cx=%d cy=%d\n"),rClipVis.Width,rClipVis.Height);


Чего делать не пойму. Почему ScaleTransform меняет Visible Rect непонятно… Если закомментировать ScaleTransform, то масштабирования просто не происходит, что вероятно и следовало ожидать…

Чего не так… Не пойму
Aml Pages Home
Re[3]: Масштабирование битмапа : GDI+
От: kov_serg Россия  
Дата: 13.01.17 20:44
Оценка:
Здравствуйте, Carc, Вы писали:

C>
...
C>        //ФИга с два, повторная установка ничего не устанавливает, GetVisibleClipBounds все равно возвращает
C>    //СТАРУЮ ширину высоту
C>    st = g.SetClip(Gdiplus::Rect(0,0,cx,cy)) ;
C>    g.GetVisibleClipBounds(&rClipVis);
C>    TRACE(TEXT("visible cx=%d cy=%d\n"),rClipVis.Width,rClipVis.Height);
C>


C>Чего делать не пойму. Почему ScaleTransform меняет Visible Rect непонятно… Если закомментировать ScaleTransform, то масштабирования просто не происходит, что вероятно и следовало ожидать…


C>Чего не так… Не пойму


st = g.SetClip(Gdiplus::Rect(0,0,cx/cx_factor,cy/cy_factor)) ;

Так не пашет?
Re[4]: Масштабирование битмапа : GDI+
От: Carc Россия https://vk.com/gosha_mazov
Дата: 13.01.17 21:36
Оценка:
Здравствуйте, kov_serg, Вы писали:

C>>Чего делать не пойму. Почему ScaleTransform меняет Visible Rect непонятно… Если закомментировать ScaleTransform, то масштабирования просто не происходит, что вероятно и следовало ожидать…


C>>Чего не так… Не пойму


_>
_>st = g.SetClip(Gdiplus::Rect(0,0,cx/cx_factor,cy/cy_factor)) ;
_>

_>Так не пашет?
Не-а. Все то же самое — масштабирует, это видно. Но обрезает(или дополняет черным фоном, если результирующий меньше) по исходному битмапу
Aml Pages Home
Re: Масштабирование битмапа : GDI+
От: MTimur  
Дата: 14.01.17 08:19
Оценка: 1 (1)
Здравствуйте, Carc, Вы писали:
  Скрытый текст
C>Нужно отмасштабировать битмапку в памяти с заданными зумом. Вчера половину дня промаялся: пищит, мигает, известно куда не попадает.
C>Все масштабирует, зум на лицо, но обрезает по размеру исходого битмапа. Полный: *опа-кеды.
C>Уважаемый All, ткните носом, ЧЯДНТ!

C>
C>HBITMAP CDlgPicResize::DoResizePlus(const LONG cx /*новая ширина для битмпап*/, const LONG cy /*новая высота*/)
C>{
C>    Gdiplus::Status st;

C>    TRACE(TEXT("DoResizePlus cx=%d cy=%d\n"),cx,cy);
    
C>    //расcчитываем Zoom-фактор 
C>    const float cx_factor=((float)cx/(float)m_szSRC.cx);//(m_szSRC - CSize с исходными размерами 1 в 1)
C>    const float cy_factor=((float)cy/(float)m_szSRC.cy);
C>    TRACE(TEXT("cx_factor=%f, CY_factor=%f\n"),cx_factor,cy_factor);

C>    const HDC hdcFrom=::GetDC(m_hwndRE);//HWND куда потом будет вставлен новый битпа
C>    ASSERT(hdcFrom);
C>    //////////////////////////////////////////////////////////////////////////
C>    //все эти с CAutoGDI*** - это auto-объекты, которые только освобождают ресурсы GDI на выходе
C>     const CAutoGDIHDC_Release release_dc_wnd(hdcFrom,m_hwndRE);
C>    //создаем битмап на котором будем рисовать в памяти
C>    HBITMAP hNew=CreateCompatibleBitmap(hdcFrom,cx,cy);
C>    ASSERT(hNew);

C>    //создаем временный GDI+ битмап и выбираем его в контекст
C>    Gdiplus::Bitmap bmpForDraw(cx
C>        ,cy
C>        ,PixelFormat24bppRGB) ;

C>    Gdiplus::Graphics g(&bmpForDraw);
C>    g.SetClip(Gdiplus::Rect(0,0,cx,cy)) ;

C>    st = g.SetInterpolationMode(Gdiplus::InterpolationModeBicubic);
C>    g.SetCompositingQuality(Gdiplus::CompositingQualityHighQuality);
C>    //устанавливаем масштабирование
C>    g.ScaleTransform(cx_factor, cy_factor);
C>    {/// рисуем исходный битмап с маштабированием и новой шириной\высотой
C>    Gdiplus::Bitmap bmpTemp(m_hSource,NULL);// m_hSource это HBITMAP исходный
C>    g.DrawImage(&bmpTemp,0,0,cx,cy);

    
C>    //забираем битмап
C>    HBITMAP h=NULL;
C>    st = bmpForDraw.GetHBITMAP(RGB(255,0,0),&h);
C>    ASSERT(Gdiplus::Ok == st);
C>    ASSERT(h);
C>    ASSERT(h != hNew);
C>    BITMAP bNew={0};
C>    GetObject(h, sizeof(BITMAP),&bNew);
C>    TRACE(TEXT("IN: cx=%d cy=%d\n"),bNew.bmWidth,bNew.bmHeight);
C>    hNew=h;//ДЛЯ кодо-копателей: да здесь идет потеря вышесозданного HBITMAP, но это издержки тестирования
C>//, поскольку уже 100 раз переписывалось и так и эдак, 
C>//изначально все корректно было, и потом, когда доводить буду -  “причешу”.
C>    }
    
C>#ifdef _DEBUG
C>    //всяко разно дебажные проверки (ширина\высота нового битмапа соответсвуют?
C>    //для просмотра кидаем в файл
C>    BITMAP bNew={0};
C>    GetObject(hNew , sizeof(BITMAP),&bNew);
C>    TRACE(TEXT("new cx=%d cy=%d\n"),bNew.bmWidth,bNew.bmHeight);

C>    {
C>    Gdiplus::Bitmap bmpForSave(hNew,NULL);
C>    CLSID bmpClsid ={0};
    
C>    GetCodecClsid(L"image/bmp", &bmpClsid);
C>    st= bmpForSave.Save(L"C:\\Test_GDI.bmp",&bmpClsid,NULL);
C>    ASSERT(Gdiplus::Ok == st);
C>    }
C>#endif

    
C>    return hNew;
C>}
C>


C>Проблема в следующем: все масштабируется, но на выходе получаем обрезанный битмап по размеру исходного. То бишь зум видно невооруженным взглядом — все чики-поки. Но если масштаб больше 100 — тогда обрезается по размеру исходного битмапа. Если масштаб меньше 100 — то опять же, все масштабируется, результирующий битмап ессесна получается меньше исходого. Но опять же все по размеру исходного, просто с черным фоном.

C>Ни черта не понимаю уже. Что я не так то хоть делаю!?! Уже только что не перепробовал, не попеременял в коде. Ан фиг! Хелп, коллеги!

А если так?
    g.SetClip(Gdiplus::Rect(0,0,cx,cy)) ; // не нужен
    ...
    ...
    g.DrawImage(&bmpTemp,0,0);
Отредактировано 14.01.2017 8:22 MTimur . Предыдущая версия .
Re[2]: Масштабирование битмапа : GDI+
От: Carc Россия https://vk.com/gosha_mazov
Дата: 14.01.17 08:40
Оценка:
MT>А если так?
MT>
MT>    g.SetClip(Gdiplus::Rect(0,0,cx,cy)) ; // не нужен
MT>    ...
MT>    ...
MT>    g.DrawImage(&bmpTemp,0,0);
MT>

Пробовал. Вообще не масштабирует это раз (я имею ввиду зум радостно пропадает), ну или в каких-то ранних пробах, все равно режется.

Факт на лицо:
1) до вызова ScaleTransform — GetVisibleClipBounds выдает корректный RECT — новый (ну например больше на нужное число пикселов)

2) после вызова ScaleTransform (т.е. сразу проверяем, следующей строкой) — GetVisibleClipBounds выдает уже старый RECT. Именно что по размеру исходого битмапа. Такое ощущение, что вызов ScaleTransform заставляет GDI+ что-то перерасчитать… Ну и результат налицо: масштаб есть, это просто видно глазами, но выдает он только часть, которая влезла в старый (меньший) RECT

3) Пробовал закомментировать ScaleTransform. Тогда нет зума. Рисуется 1 в 1. Мысли вроде такой: мол всякие преобразования я тебе задал (SetInterpolation, Quality и.тд.), а потом сказал рисуй с новой шириной\высотой (большЕго RECT), а GDI+ мол сама все натянет\растянет. Дык фиг! Опять же рисует в масштабе 1 к 1.
Aml Pages Home
Re[3]: Масштабирование битмапа : GDI+
От: MTimur  
Дата: 14.01.17 08:55
Оценка:
Здравствуйте, Carc, Вы писали:

  Скрытый текст
MT>>А если так?
MT>>
MT>>    g.SetClip(Gdiplus::Rect(0,0,cx,cy)) ; // не нужен
MT>>    ...
MT>>    ...
MT>>    g.DrawImage(&bmpTemp,0,0);
MT>>

C>Пробовал. Вообще не масштабирует это раз (я имею ввиду зум радостно пропадает), ну или в каких-то ранних пробах, все равно режется.

C>Факт на лицо:

C>1) до вызова ScaleTransform — GetVisibleClipBounds выдает корректный RECT — новый (ну например больше на нужное число пикселов)

C>2) после вызова ScaleTransform (т.е. сразу проверяем, следующей строкой) — GetVisibleClipBounds выдает уже старый RECT. Именно что по размеру исходого битмапа. Такое ощущение, что вызов ScaleTransform заставляет GDI+ что-то перерасчитать… Ну и результат налицо: масштаб есть, это просто видно глазами, но выдает он только часть, которая влезла в старый (меньший) RECT


C>3) Пробовал закомментировать ScaleTransform. Тогда нет зума. Рисуется 1 в 1. Мысли вроде такой: мол всякие преобразования я тебе задал (SetInterpolation, Quality и.тд.), а потом сказал рисуй с новой шириной\высотой (большЕго RECT), а GDI+ мол сама все натянет\растянет. Дык фиг! Опять же рисует в масштабе 1 к 1.

Посмотреть бы результат (исходная картинка, scale, результирующая)
ScaleTransform создает матрицу преобразования для всей сцены. Вероятно, масштабирование происходит вокруг центра битмапа, соответственно левый верхний угол смещается. Если так, то нужно юзать TranslateTransform.
Re[4]: Масштабирование битмапа : GDI+
От: Carc Россия https://vk.com/gosha_mazov
Дата: 14.01.17 09:45
Оценка:
Здравствуйте, MTimur, Вы писали:


MT>[/cut]

MT>Посмотреть бы результат (исходная картинка, scale, результирующая)
MT>ScaleTransform создает матрицу преобразования для всей сцены. Вероятно, масштабирование происходит вокруг центра битмапа, соответственно левый верхний угол смещается. Если так, то нужно юзать TranslateTransform.
Тут бинарник http://www.amlpages.com/Source/richedit_test.zip

При старте сразу вставляет битмапку в CRichEditView, и стартует диалог ресайза. Там можно поиграться. Изменяем ширину, софтина перерассчитывает длину и пытается создать новый битмап на основе старого отмасштабированного по новой длине и ширине. Ну и изменяет высоту, тогда все наоборот — вычисляет ширину на основе новой высоты и.т.д…
Aml Pages Home
Re[5]: Масштабирование битмапа : GDI+
От: MTimur  
Дата: 14.01.17 09:51
Оценка:
Здравствуйте, Carc, Вы писали:

C>Здравствуйте, MTimur, Вы писали:



MT>>[/cut]

MT>>Посмотреть бы результат (исходная картинка, scale, результирующая)
MT>>ScaleTransform создает матрицу преобразования для всей сцены. Вероятно, масштабирование происходит вокруг центра битмапа, соответственно левый верхний угол смещается. Если так, то нужно юзать TranslateTransform.
C>Тут бинарник http://www.amlpages.com/Source/richedit_test.zip

C>При старте сразу вставляет битмапку в CRichEditView, и стартует диалог ресайза. Там можно поиграться. Изменяем ширину, софтина перерассчитывает длину и пытается создать новый битмап на основе старого отмасштабированного по новой длине и ширине. Ну и изменяет высоту, тогда все наоборот — вычисляет ширину на основе новой высоты и.т.д…


Так это элементарный случай, можно проще:
   g.DrawImage(&im, rcDest);

Без всяких матриц преобразований.

ps как то так

pps И да, судя по результату, я бы смотрел код, который копирует отмасштабированный битмап на окно, а не код ресайза.
Отредактировано 14.01.2017 9:56 MTimur . Предыдущая версия . Еще …
Отредактировано 14.01.2017 9:52 MTimur . Предыдущая версия .
Re[6]: Масштабирование битмапа : GDI+
От: Carc Россия https://vk.com/gosha_mazov
Дата: 14.01.17 10:47
Оценка:
MT>Так это элементарный случай, можно проще:
MT>
MT>   g.DrawImage(&im, rcDest);
MT>

MT>Без всяких матриц преобразований.
Дык в том то и дело, что такие варианты с rect или c (x,y,cx,cy) я попробовал сразу. Благо они во всех интернетах мелькают. Но не получается

MT>ps как то так


MT>pps И да, судя по результату, я бы смотрел код, который копирует отмасштабированный битмап на окно, а не код ресайза.


Дык вроде нету там копирования. Там CStatic и ему делается CStatic::SetBitmap, суть простые обертки над WinAPI.

Код: http://www.amlpages.com/Source/richedit_test.rar, MFC, VS6.

Ресайз идет в CDlgResize (это тот диалог, который она запускает при старте, он же и меню Pictures\Resize, но нужно чтобы в CRichEditView был выделен обьект).
Aml Pages Home
Re[7]: Масштабирование битмапа : GDI+
От: MTimur  
Дата: 14.01.17 11:40
Оценка: 6 (1)
Здравствуйте, Carc, Вы писали:

C>Дык в том то и дело, что такие варианты с rect или c (x,y,cx,cy) я попробовал сразу. Благо они во всех интернетах мелькают. Но не получается

Он работает, это точно.

C>Дык вроде нету там копирования. Там CStatic и ему делается CStatic::SetBitmap, суть простые обертки над WinAPI.

Ну ок. Не ты копируешь, а CStatic, суть одна.. Размер твоего CStatic cx*cy. Тогда:
1. Размер картинки 0.5(cx*cy). CStatic благополучно отрисовывает ее на своем DC, а все остальное оставляет как есть (черный BG).
2. Размер картинки 2*(cx*cy). CStatic отрисовывает ее на своем DC только то, что помещается в его окно. Результат — обрезан правый и нижний край.
Копируй картинку сам на DC контрола. Я бы прям на диалоге рисовал и обрамлял бы прямоугольником.

C>Код: http://www.amlpages.com/Source/richedit_test.rar, MFC, VS6.

C>Ресайз идет в CDlgResize (это тот диалог, который она запускает при старте, он же и меню Pictures\Resize, но нужно чтобы в CRichEditView был выделен обьект).

Не совсем так как я думал выше, но около того:
void CDlgPicResize::SetPicBitmap(const HBITMAP hBitmap)
{
    ASSERT(hBitmap);
    BITMAP bmp={0};
    GetObject(m_hSource,sizeof(BITMAP),&bmp);

    const HBITMAP hCopy=(HBITMAP)CopyImage(hBitmap,IMAGE_BITMAP, bmp.bmWidth, bmp.bmHeight, LR_CREATEDIBSECTION);
    const HBITMAP hCopy=(HBITMAP)CopyImage(hBitmap,IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION); // fixed!
    ASSERT(hCopy);
    ...


Но теперь при масштабе > 1, черные полосы справа и снизу. Потому что при ресайзе ты устанавливаешь clipping по размеру исходного изображения. Зачем?

Кусок кода рабочего. Просто выпилил все эти g.SetClip.
HBITMAP CDlgPicResize::DoResizePlus(const LONG cx, const LONG cy)
{
...
    HBITMAP hNew=CreateCompatibleBitmap(hdcFrom,2*cx,2*cy); // зачем х2???  
    HBITMAP hNew=CreateCompatibleBitmap(hdcFrom,cx,cy);
...
     Gdiplus::Bitmap bmpForDraw(cx
         ,cy
         ,PixelFormat24bppRGB) ;
    const int sdfsd=bmpForDraw.GetWidth();

    Gdiplus::Graphics* gp=Gdiplus::Graphics::FromImage(&bmpForDraw);
    //Gdiplus::Graphics& g=*gp;
    Gdiplus::Graphics g(hdcComp);
    {/// рисуем исходный битмап с маштабирование и новой шириной\высотой
    Gdiplus::Bitmap bmpTemp(m_hSource,NULL);
    Gdiplus::RectF rDst(0,0,cx,cy);
    Gdiplus::Pen pen(RGB(255,0,0));
    g.DrawRectangle(&pen,rDst);
    g.DrawImage(&bmpTemp,rDst);
    HBITMAP h=NULL;
    st = bmpForDraw.GetHBITMAP(RGB(255,0,0),&h);
    ASSERT(Gdiplus::Ok == st);
    ASSERT(h);
    ASSERT(h != hNew);
    BITMAP bNew={0};
    GetObject(h, sizeof(BITMAP),&bNew);
    TRACE(TEXT("IN: cx=%d cy=%d\n"),bNew.bmWidth,bNew.bmHeight);
    //hNew=h;
    }
 ...
}


В результате, у меня все заработало. Весь файл после изменений DlgPicResize.cpp

зы А вообще трэш какой-то. Это же не продакшн, да?
Отредактировано 14.01.2017 12:01 MTimur . Предыдущая версия . Еще …
Отредактировано 14.01.2017 11:41 MTimur . Предыдущая версия .
Re: Масштабирование битмапа : GDI
От: CEMb  
Дата: 16.01.17 03:01
Оценка:
Здравствуйте, Carc, Вы писали:

C>Нужно отмасштабировать битмапку в памяти с заданными зумом.


если ещё актуально, могу дать свой код масштабирования картинки в памяти любого размера в любой размер с линейным выравниванием
Re[8]: Масштабирование битмапа : GDI+
От: Carc Россия https://vk.com/gosha_mazov
Дата: 16.01.17 07:09
Оценка:
Здравствуйте, MTimur, Вы писали:


MT>В результате, у меня все заработало. Весь файл после изменений DlgPicResize.cpp

СПАСИБО!
Заработало… Правда, я так и не понял, что ты нашаманил, чего я не шаманил. CopyImage + LR_CREATEDIBSECTION без ширины, высоты? А что оно дает?
Дело в том, что остальное (GDI+ варианты Draw с разными параметрами) я вроде как пробовал. Тем более что по всей сети были примеры как раз безо всяких ScaleTransform.
Но в том то, все и дело, что у меня то по любому не получалось.

MT>зы А вообще трэш какой-то. Это же не продакшн, да?

Ну конечно же нет. Тест. И соответственно говорящее название RichEdit_Test. Простенький проект, на котором гоняются только отдельные модули\классы, с конкретным функционалом и только!
Aml Pages Home
Re[2]: Масштабирование битмапа : GDI
От: Carc Россия https://vk.com/gosha_mazov
Дата: 16.01.17 07:10
Оценка:
Здравствуйте, CEMb, Вы писали:

CEM>Здравствуйте, Carc, Вы писали:


C>>Нужно отмасштабировать битмапку в памяти с заданными зумом.


CEM>если ещё актуально, могу дать свой код масштабирования картинки в памяти любого размера в любой размер с линейным выравниванием

Дафай! Все равно хочу досконально разобраться…
Aml Pages Home
Re[3]: Масштабирование битмапа : GDI
От: CEMb  
Дата: 16.01.17 13:02
Оценка:
Здравствуйте, Carc, Вы писали:

C>Дафай! Все равно хочу досконально разобраться…


  Код
LPBYTE m_lpByte;// байтовые данные
SIZE m_size; //
// 1. только 32-битные картинки
// 2. делается растяжка сначала в одну сторону, потом в другую, поэтому красивого радиального выравнивания нету
// 3. используются кривые Безье 1-го порядка :)

void CBmp::Expand(int iW, int iH)
{
    if(!m_lpByte)
        return;

    int w = m_size.cx;
    int w4 = w*4;

    int j;

    LPBYTE lpByte = (LPBYTE)GlobalAlloc(GMEM_FIXED, w4*iH);
    memset(lpByte, 0, w4*iH);

    //    VERTICAL

    int h1 = iH-1;

    register LPBYTE lpb, lpb2, lpbd;
    lpbd = lpByte;

    if(iH > m_size.cy)
    {
        int is = 0;    //    index of src y
        int cy1 = m_size.cy-1;
        int a0, a1;
        for(j=0; j<iH; j++)
        {
            is = j*cy1/h1;
            lpb = m_lpByte + (is)*w4;
            lpb2 = m_lpByte + (is+1)*w4;
            a1 = (j*cy1*255/h1)%255;
            a0 = 255-a1;

            if(a1 == 0)
            {
                for(int i=0; i<w; i++)
                {
                    *lpbd++ = (*lpb++);
                    *lpbd++ = (*lpb++);
                    *lpbd++ = (*lpb++);
                    *lpbd++ = (*lpb++);
                }
            }
            else if(a0 == 0)
            {
                for(int i=0; i<w; i++)
                {
                    *lpbd++ = (*lpb2++);
                    *lpbd++ = (*lpb2++);
                    *lpbd++ = (*lpb2++);
                    *lpbd++ = (*lpb2++);
                }
            }
            else
            {
                for(int i=0; i<w; i++)
                {
                    *lpbd++ = (a0* *lpb++ + a1* *lpb2++)/255;
                    *lpbd++ = (a0* *lpb++ + a1* *lpb2++)/255;
                    *lpbd++ = (a0* *lpb++ + a1* *lpb2++)/255;
                    *lpbd++ = (a0* *lpb++ + a1* *lpb2++)/255;
                }
            }
        }
    }
    else
    {
        int id = 0;    //    index of dst y
        int cy = m_size.cy;
        int iStep = w4;

        int a0;

        int idx1;

        for(j=0; j<cy; j++)
        {
            id = j*iH/cy;
            idx1 = (j+1)*iH/cy;

            lpb = m_lpByte + (j)*iStep;
            lpbd = lpByte + iStep*id;

            if(id == idx1)
            {
                for(int i=0; i<w; i++)
                {
                    *lpbd++ += *lpb++ * iH / cy;
                    *lpbd++ += *lpb++ * iH / cy;
                    *lpbd++ += *lpb++ * iH / cy;
                    *lpbd++ += *lpb++ * iH / cy;
                }
            }
            else if(id != idx1)
            {
                a0 = ((idx1*cy)-(j)*iH);
                if(a0)
                {
                    for(int i=0; i<w; i++)
                    {
                        *lpbd++ += *lpb++ * a0 / cy;
                        *lpbd++ += *lpb++ * a0 / cy;
                        *lpbd++ += *lpb++ * a0 / cy;
                        *lpbd++ += *lpb++ * a0 / cy;
                    }
                }
                lpb = m_lpByte + (j)*iStep;
                lpbd = lpByte + iStep*idx1;
                a0 = ((j+1)*iH - ((idx1)*cy));
                if(a0)
                {
                    for(int i=0; i<w; i++)
                    {
                        *lpbd++ += *lpb++ * a0 / cy;
                        *lpbd++ += *lpb++ * a0 / cy;
                        *lpbd++ += *lpb++ * a0 / cy;
                        *lpbd++ += *lpb++ * a0 / cy;
                    }
                }
            }
        }
    }

    //    HORIZONTAL
    w = iW;
    w4 = w*4;
    LPBYTE lpByteOut = (LPBYTE)GlobalAlloc(GMEM_FIXED, iW*iH*4);
    memset(lpByteOut, 0x0, iW*iH*4);

    if(iW > m_size.cx)
    {
        int w1 = iW-1;
        lpbd = lpByteOut;
        int is = 0;    //    index of src x
        int cx1 = m_size.cx-1;
        int iStepS = m_size.cx*4;
        int iStepD = w4;
        int a0, a1;
        for(int i=0; i<iW; i++)
        {
            is = i*cx1/w1;
            lpb = lpByte + (is)*4;
            lpb2 = lpByte + (is+1)*4;
            lpbd = lpByteOut + (i+0)*4;
            a1 = (i*cx1*255/w1)%255;
            a0 = 255-a1;
            if(a1 == 0)
            {
                for(j=0; j<iH; j++)
                {
                    *lpbd = *lpb;
                    lpb++; lpb2++; lpbd++;
                    *lpbd = *lpb;
                    lpb++; lpb2++; lpbd++;
                    *lpbd = *lpb;
                    lpb++; lpb2++; lpbd++;
                    *lpbd = *lpb;
                    lpbd+=iStepD-3, lpb+=iStepS-3,    lpb2+=iStepS-3;
                }
            }
            else if(a0 == 0)
            {
                for(j=0; j<iH; j++)
                {
                    *lpbd = a1;
                    lpb++; lpb2++; lpbd++;
                    *lpbd = a1;
                    lpb++; lpb2++; lpbd++;
                    *lpbd = a1;
                    lpb++; lpb2++; lpbd++;
                    *lpbd = a1;
                    lpbd+=iStepD-3, lpb+=iStepS-3,    lpb2+=iStepS-3;
                }
            }
            else
            {
                for(j=0; j<iH; j++)
                {
                    *lpbd = (a0* *lpb + a1* *lpb2)/255;
                    lpb++; lpb2++; lpbd++;
                    *lpbd = (a0* *lpb + a1* *lpb2)/255;
                    lpb++; lpb2++; lpbd++;
                    *lpbd = (a0* *lpb + a1* *lpb2)/255;
                    lpb++; lpb2++; lpbd++;
                    *lpbd = (a0* *lpb + a1* *lpb2)/255;
                    lpbd+=iStepD-3, lpb+=iStepS-3,    lpb2+=iStepS-3;
                }
            }
        }
    }
    else
    {
        int w1 = iW-1;
        int id = 0;    //    index of dst x

        int cx = m_size.cx;

        int iStepS = m_size.cx*4;
        int iStepD = w4;

        for(int i=0; i<cx; i++)
        {
            id = i*iW/cx;
            int idx1 = (i+1)*iW/cx;
            int a0 = 0;

            lpb = lpByte + i*4;
            lpbd = lpByteOut + (id+0)*4;

            if(id == idx1)
            {
                for(int j=0; j<iH; j++)
                {
                    *lpbd++ += *lpb++ * iW / cx;
                    *lpbd++ += *lpb++ * iW / cx;
                    *lpbd++ += *lpb++ * iW / cx;
                    *lpbd++ += *lpb++ * iW / cx;
                    lpbd+=iStepD-4, lpb+=iStepS-4;
                }
            }
            if(id != idx1)
            {
                a0 = ((idx1*cx)-i*iW);
                if(a0)
                {
                    for(int j=0; j<iH; j++)
                    {
                        *lpbd++ += *lpb++ * a0 / cx;
                        *lpbd++ += *lpb++ * a0 / cx;
                        *lpbd++ += *lpb++ * a0 / cx;
                        *lpbd++ += *lpb++ * a0 / cx;
                        lpbd+=iStepD-4, lpb+=iStepS-4;
                    }
                }
                lpb = lpByte + i*4;
                lpbd = lpByteOut + (id+1)*4;// + iStepD;
                a0 = ((i+1)*iW - ((idx1)*cx));
                if(a0)
                {
                    for(j=0; j<iH; j++)
                    {
                        *lpbd++ += *lpb++ * a0 / cx;
                        *lpbd++ += *lpb++ * a0 / cx;
                        *lpbd++ += *lpb++ * a0 / cx;
                        *lpbd++ += *lpb++ * a0 / cx;
                        lpbd+=iStepD-4, lpb+=iStepS-4;
                    }
                }
            }
        }
    }

    m_size.cx = iW;
    m_size.cy = iH;
    m_iLength = iW*iH*4;
    GlobalFree(m_lpByte);
    m_lpByte = lpByteOut;

    GlobalFree(lpByte);
}


критика и улучшения приветствуются
если ещё какие трансформации нужны, тоже могу дать
Re[9]: Масштабирование битмапа : GDI+
От: MTimur  
Дата: 16.01.17 15:45
Оценка:
Здравствуйте, Carc, Вы писали:

C>Заработало… Правда, я так и не понял, что ты нашаманил, чего я не шаманил.

Посмотри diff, проанализируй. Я вроде бы все изменения описал.

C>CopyImage + LR_CREATEDIBSECTION без ширины, высоты? А что оно дает?

bmp.bmWidth, bmp.bmHeight — это размер исходного битмапа, а копируемый битмап у тебя либо больше, либо меньше. Что получится в результате должно быть понятно.
Re[10]: Масштабирование битмапа : GDI+
От: Carc Россия https://vk.com/gosha_mazov
Дата: 16.01.17 16:08
Оценка:
Здравствуйте, MTimur, Вы писали:

MT>Здравствуйте, Carc, Вы писали:


C>>Заработало… Правда, я так и не понял, что ты нашаманил, чего я не шаманил.

MT>Посмотри diff, проанализируй. Я вроде бы все изменения описал.
На кой дифф? Глаза же есть… Я в том смысле, что не уловил твоей мысли…

C>>CopyImage + LR_CREATEDIBSECTION без ширины, высоты? А что оно дает?

MT>bmp.bmWidth, bmp.bmHeight — это размер исходного битмапа, а копируемый битмап у тебя либо больше, либо меньше. Что получится в результате должно быть понятно.
Дык вроде там CopyImage юзался для копирования исходного битмапа, который потом отрисовывается GDI+ со всякими вывертами (я пытался через ScaleTransfofm, в твоем коде уже просто DrawImage с заданной шириной\высотой).

Дык тут и непонятка: какая разница что я указываю при CopyImage исходного битмапа? Все равно что есть в исходном, то и скопируется — что задавай я ширину, высоту, что нет. Разве я не прав?

PS: я исходный копировал исключительно из-за стремных мыслей, что GDI+::Bitmap в деструкторе удалит HBITMAP полученный в конструкторе. А мне этот исходный Bitmap вроде как нужен был потом… На да эти стремки лишнее, HBITMAP деструктор не трогает.
Aml Pages Home
Re[11]: Масштабирование битмапа : GDI+
От: MTimur  
Дата: 16.01.17 16:15
Оценка:
Здравствуйте, Carc, Вы писали:

C>Дык вроде там CopyImage юзался для копирования исходного битмапа, который потом отрисовывается GDI+ со всякими вывертами (я пытался через ScaleTransfofm, в твоем коде уже просто DrawImage с заданной шириной\высотой).


CopyImage

cxDesired [in]
Type: int
The desired width, in pixels, of the image. If this is zero, then the returned image will have the same width as the original hImage.
cyDesired [in]
Type: int
The desired height, in pixels, of the image. If this is zero, then the returned image will have the same height as the original hImage.


Т.е. ты уменьшил/увеличил картинку, а потом отрисовал ее с исходным размером.
Отредактировано 16.01.2017 16:18 MTimur . Предыдущая версия .
Re[12]: Масштабирование битмапа : GDI+
От: Carc Россия https://vk.com/gosha_mazov
Дата: 16.01.17 16:22
Оценка:
Здравствуйте, MTimur, Вы писали:

MT>Здравствуйте, Carc, Вы писали:


C>>Дык вроде там CopyImage юзался для копирования исходного битмапа, который потом отрисовывается GDI+ со всякими вывертами (я пытался через ScaleTransfofm, в твоем коде уже просто DrawImage с заданной шириной\высотой).


MT>Допустим исходный битмап имеет размер 100*100.

MT>1. Из увеличенного битмапа размером 200*200 точек копируем область размером 100*100. Что получится?
MT>2. Из уменьшенного битмапа размером 50*50 точек копируем область размером 100*100. Результат?
Ну ты не уловил… У меня там как было примерно…

1) Копирую исходный битмап ДО рисования. (сейчас я это убрал — ибо лишнее)
2) Создаю битмап в памяти, чтобы отрисоваться на нем. И выбираю его в Graphics в конструкторе.
3) Рисую исходный со новой шириной\высотой (как ты подсказал), или (как не работало) со ScaleTransform…

Т.е. улови, я не копирую результирующий битмап. Я копировал только исходный, и то это оказалось лишним, и сейчас я это убрал.
Aml Pages Home
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.