Frost Moon Project

Src/Thumbnail.cpp-Ashley Ver.1.30- - Frost Moon Project アクセスランキング

Home > ソフトウェア > Ashley > Ashley130.zip/Ashley130.exe > Src > Thumbnail.cpp

//Thumbnail.cpp
//書庫ファイル内の画像のサムネイルをHBITMAPで取得

/*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#
    Ashley Ver.1.30
    Coded by x@rgs

    This code is released under NYSL Version 0.9982
    See NYSL_withfaq.TXT for further details.

    Ashleyは、アップローダからダウンロードしたZIPやRAR等のファイル名を元に戻すソフトです。
#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*/


#include"Pch.h"
#include"Thumbnail.h"
#include"UnZipFile.h"
#include"UnRarFile.h"
#include"ArcDll.h"
#include"Path.h"
#include"Function.h"
#include"resources/resource.h"
#include<olectl.h>
#include<shlwapi.h>
#include<gdiplus.h>

//サムネイル最大バッファ(32MB)
#define THUMBNAIL_MAX_BUFFERSIZE 33554432

using namespace std;

//対応している画像の拡張子かどうか
bool IsSupportedImage(const TCHAR* pszPath){
    TCHAR szExtension[_MAX_EXT]={0};

    _tcscpy(szExtension,PathFindExtension(pszPath));
    if(_tcsicmp(szExtension,_T(".bmp"))==0)return true;
    if(_tcsicmp(szExtension,_T(".gif"))==0)return true;
    if(_tcsicmp(szExtension,_T(".ico"))==0)return true;
    if(_tcsicmp(szExtension,_T(".jpe"))==0)return true;
    if(_tcsicmp(szExtension,_T(".jpeg"))==0)return true;
    if(_tcsicmp(szExtension,_T(".jpg"))==0)return true;
    if(_tcsicmp(szExtension,_T(".jif"))==0)return true;
    if(_tcsicmp(szExtension,_T(".jfi"))==0)return true;
    if(_tcsicmp(szExtension,_T(".jfif"))==0)return true;
    if(_tcsicmp(szExtension,_T(".png"))==0)return true;
    if(_tcsicmp(szExtension,_T(".tif"))==0)return true;
    if(_tcsicmp(szExtension,_T(".tiff"))==0)return true;
    return false;
}

//16x16のダミーアイコンを描写したHBITMAPを作成
HBITMAP CreateDummyBitmap(int iWidth,int iHeight){
    HICON hIcon=NULL;

    hIcon=static_cast<HICON>(LoadImage(g_hInstance,MAKEINTRESOURCE(IDI_ICON_DUMMY),IMAGE_ICON,0,0,0));
    HDC hDC=GetDC(NULL);
    HDC hWorkDC=CreateCompatibleDC(hDC);

    HBITMAP hBitmap=CreateCompatibleBitmap(hDC,iWidth,iHeight);
    HBITMAP hOldBitmap=(HBITMAP)SelectObject(hWorkDC,hBitmap);
    DrawIcon(hWorkDC,0,0,hIcon);
    SelectObject(hWorkDC,hOldBitmap);
    DeleteDC(hWorkDC);
    DestroyIcon(hIcon);
    ReleaseDC(NULL,hDC);
    return hBitmap;
}

//16x16のダミーアイコンを描写したHBITMAPを作成
HBITMAP CreateDummyBitmap2(HDC hdc, int iWidth,int iHeight){
    HICON hIcon=NULL;

    hIcon=static_cast<HICON>(LoadImage(g_hInstance,MAKEINTRESOURCE(IDI_ICON_DUMMY),IMAGE_ICON,0,0,0));
    HDC hWorkDC=CreateCompatibleDC(hdc);

    HBITMAP hBitmap=CreateCompatibleBitmap(hdc,iWidth,iHeight);
    HBITMAP hOldBitmap=(HBITMAP)SelectObject(hWorkDC,hBitmap);
    DrawIcon(hWorkDC,0,0,hIcon);
    SelectObject(hWorkDC,hOldBitmap);
    DeleteDC(hWorkDC);
    DestroyIcon(hIcon);
    return hBitmap;
}

//ファイルパスからアイコンを取得しBitmapに変換
HBITMAP CreateBitmapFromPath(LPCTSTR lpszPath,int iWidth,int iHeight){
    SHFILEINFO shFileInfo;
    HICON hIcon=NULL;
    HIMAGELIST hImageList=NULL;

    hImageList=(HIMAGELIST)SHGetFileInfo(lpszPath,0,&shFileInfo,sizeof(shFileInfo),SHGFI_ICON|SHGFI_LARGEICON|SHGFI_USEFILEATTRIBUTES|SHGFI_SYSICONINDEX);
    hIcon=ImageList_GetIcon(hImageList,shFileInfo.iIcon,ILD_NORMAL);//ILD_IMAGE
    ICONINFO IconInfo;
    IconInfo.fIcon=true;//アイコンである
    GetIconInfo(hIcon,&IconInfo);
    BITMAP Bitmap;
    GetObject(IconInfo.hbmColor,sizeof(Bitmap),&Bitmap);
    HDC hDC=GetDC(NULL);
    HDC hWorkDC=CreateCompatibleDC(hDC);
    SetStretchBltMode(hWorkDC,HALFTONE);
    //After setting the HALFTONE stretching mode, an application must call the SetBrushOrgEx function to set the brush origin. If it fails to do so, brush misalignment occurs.
    //(http://msdn.microsoft.com/en-us/library/dd145089(v=vs.85).aspx)
    SetBrushOrgEx(hWorkDC,0,0,NULL);
    HBITMAP hBitmap=CreateCompatibleBitmap(hDC,iWidth,iHeight);
    HBITMAP hOldBitmap=(HBITMAP)SelectObject(hWorkDC,hBitmap);
    POINT pt={(iWidth-Bitmap.bmWidth)>>1,(iHeight-Bitmap.bmHeight)>>1};//中央表示座標
    DrawIcon(hWorkDC,pt.x,pt.y,hIcon);
    SelectObject(hWorkDC,hOldBitmap);
    DeleteDC(hWorkDC);
    DestroyIcon(shFileInfo.hIcon);
    DestroyIcon(hIcon);
    ReleaseDC(NULL,hDC);
    return hBitmap;
}

//IStreamからHBITMAPを取得
HBITMAP CreateBitmapFromIStream(IStream* pIStream,const LPSIZE psizeThumbnail){
    Gdiplus::Bitmap* pBitmap=Gdiplus::Bitmap::FromStream(pIStream);
    if(pBitmap==NULL)return NULL;
    if(pBitmap->GetLastStatus()!=Gdiplus::Ok)return NULL;
    if(pBitmap->GetWidth()<=0||pBitmap->GetHeight()<=0)return NULL;

    int iSrcWidth=0,iSrcHeight=0;
    int iDestWidth=0,iDestHeight=0;
    iSrcWidth=pBitmap->GetWidth();
    iSrcHeight=pBitmap->GetHeight();

    if(psizeThumbnail->cx<iSrcWidth||psizeThumbnail->cy<iSrcHeight){
        //サムネイルのキャンバスサイズより大きい
        float rX=(float)psizeThumbnail->cx/iSrcWidth;
        float rY=(float)psizeThumbnail->cy/iSrcHeight;
        iDestWidth=(int)(min(rX,rY)*iSrcWidth);//縮小後のサイズ
        iDestHeight=(int)(min(rX,rY)*iSrcHeight);
    }else{
        //サムネイルのキャンバスサイズより小さい
        iDestWidth=iSrcWidth;
        iDestHeight=iSrcHeight;
    }

    HDC hdcScreen=GetDC(NULL);
    HBITMAP hbmpResult=CreateCompatibleBitmap(hdcScreen,psizeThumbnail->cx,psizeThumbnail->cy);
    HDC hdcMemory=CreateCompatibleDC(hdcScreen);
    SetBkMode(hdcMemory,TRANSPARENT);
    ReleaseDC(NULL,hdcScreen);
    HGDIOBJ hobjOld=SelectObject(hdcMemory,hbmpResult);

    const POINT ptDest={(psizeThumbnail->cx-iDestWidth)>>1,(psizeThumbnail->cy-iDestHeight)>>1};//中央表示座標

#if 1

    Gdiplus::Graphics* pGraphics=Gdiplus::Graphics::FromHDC(hdcMemory);

//    pGraphics->SetInterpolationMode(Gdiplus::InterpolationModeInvalid);

    pGraphics->DrawImage(pBitmap,ptDest.x,ptDest.y,iDestWidth,iDestHeight);

    delete pGraphics;

#else

    //TODO:7環境でCOLORONCOLORであれば必要なし
    //HALFTONEの場合、有効にすると真っ白け
/*    HICON hIcon=static_cast<HICON>(LoadImage(g_hInstance,MAKEINTRESOURCE(IDI_ICON_DUMMY),IMAGE_ICON,0,0,LR_SHARED));
    DrawIcon(hdcMemory,0,0,hIcon);
    DestroyIcon(hIcon);
*/
    SetStretchBltMode(hdcMemory,HALFTONE);//COLORONCOLOR);

    Gdiplus::BitmapData bitmapData;
    pBitmap->LockBits(NULL,Gdiplus::ImageLockModeRead,PixelFormat32bppARGB,&bitmapData);

    BITMAPINFOHEADER BitmapInfoHeader;
    memset(&BitmapInfoHeader,0,sizeof(BITMAPINFOHEADER));
    BitmapInfoHeader.biSize=sizeof(BITMAPINFOHEADER);
    BitmapInfoHeader.biWidth=bitmapData.Width;
    BitmapInfoHeader.biHeight=bitmapData.Height;
    BitmapInfoHeader.biPlanes=1;
    BitmapInfoHeader.biBitCount=32;
    BitmapInfoHeader.biCompression=BI_RGB;
    BitmapInfoHeader.biClrUsed=0;
    BitmapInfoHeader.biClrImportant=0;

    StretchDIBits(hdcMemory,
                  ptDest.x,ptDest.y+iDestHeight,iDestWidth,-iDestHeight,
                  0, 0,BitmapInfoHeader.biWidth,BitmapInfoHeader.biHeight,
                  bitmapData.Scan0,(BITMAPINFO*)&BitmapInfoHeader,
                  DIB_RGB_COLORS,SRCCOPY);

    pBitmap->UnlockBits(&bitmapData);

#endif

    SelectObject(hdcMemory,hobjOld);
    DeleteDC(hdcMemory);
    return hbmpResult;
}

HBITMAP CreateBitmapFromMemory(LPCVOID lpcBuffer,const ULONG ulBufferSize,const LPSIZE psizeThumbnail){
    HBITMAP hRetBitmap=NULL;
    HANDLE hBuffer=NULL;
    LPVOID lpBuffer=NULL;
    IStream* pIStream=NULL;

    //lpBuffer=(LPVOID)GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT,ulBufferSize);
    hBuffer=GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT,ulBufferSize);
    if(hBuffer){
        lpBuffer=GlobalLock(hBuffer);
        if(lpBuffer){
            CopyMemory(lpBuffer,lpcBuffer,ulBufferSize);
            if(CreateStreamOnHGlobal(hBuffer,false,&pIStream)==S_OK){
                hRetBitmap=CreateBitmapFromIStream(pIStream,psizeThumbnail);//IStreamからHBITMAP取得
                pIStream->Release();
            }
        }
    }
    GlobalUnlock(hBuffer);
    GlobalFree(hBuffer);//解放
    hBuffer=NULL;
    return hRetBitmap;
}

//zipファイル内の画像のサムネイルをHBITMAPで取得
HBITMAP GetThumbnailBitmapFromZipFile(const TCHAR* pszFilePath,const int iWidth,const int iHeight){
    bool bSuccess=false;
    int iCount=0;//格納ファイル数
    int iThumbIndex=-1;//サムネイルとして利用する画像のIndex
    HBITMAP hRetBitmap=NULL;
    LPBYTE lpBuffer=NULL;
    SIZE sizeThumbnail;
    CUnZip UnZip;

    if(!UnZip.OpenFile(pszFilePath))return NULL;//書庫ファイルを開くことが出来ない
    iCount=UnZip.GetFileCount();
    if(iCount==0)return NULL;//書庫内にファイルがない
    tstring strFileName;
    for(int i=0;i<iCount;i++){
        if(!UnZip.GetFileInfo(i))break;//書庫ファイル内の情報を取得出来ない
        if(UnZip.IsDirectory())continue;//ディレクトリである
        if(UnZip.GetUncompressedSize()>THUMBNAIL_MAX_BUFFERSIZE)continue;//サムネイル最大バッファより大きい
        if(UnZip.GetCompressedSize()==0||UnZip.GetUncompressedSize()==0)continue;//ファイルサイズが0
        if(IsSupportedImage(UnZip.GetFileName())){//対応している画像ファイルである
            if(iThumbIndex<0)iThumbIndex=i;
            if(strFileName.empty())strFileName=UnZip.GetFileName();
            if(_StrCmpLogicalW(UnZip.GetFileName(),(PCWSTR)strFileName.c_str())==-1){//GetZipFileItemName()<strFileName
                iThumbIndex=i;
                strFileName=UnZip.GetFileName();
            }
        }
    }
    if(iThumbIndex<0)return NULL;
    if(!UnZip.GetFileInfo(iThumbIndex))return NULL;//書庫ファイル内の情報を取得出来ない
    lpBuffer=(LPBYTE)HeapAlloc(GetProcessHeap(),0,UnZip.GetUncompressedSize()*sizeof(BYTE));//ファイルのバッファ確保
    if(lpBuffer){
        ZeroMemory(lpBuffer,UnZip.GetUncompressedSize()*sizeof(BYTE));
        if(!UnZip.ExtractMem(iThumbIndex,lpBuffer,UnZip.GetUncompressedSize()))return NULL;
        //サムネイルサイズ設定
        sizeThumbnail.cx=iWidth;
        sizeThumbnail.cy=iHeight;
        //HBITMAP取得
        hRetBitmap=CreateBitmapFromMemory(lpBuffer,UnZip.GetUncompressedSize(),&sizeThumbnail);
        if(hRetBitmap!=NULL)bSuccess=true;
        else bSuccess=false;
        HeapFree(GetProcessHeap(),0,lpBuffer);
        lpBuffer=NULL;
    }
    return (bSuccess)?hRetBitmap:NULL;
}

//サムネイルとして利用する画像のIndexを取得
__int64 GetThumbnailIndexRAR(LPCTSTR lpszFilePath){
    CUnRar UnRar;

    if(!UnRar.CheckReady())return -1;//DLLは使用可能な状況ではない
    if(!UnRar.OpenFile(lpszFilePath))return -1;//書庫ファイルを開くことが出来ない
    //ソリッド、マルチボリューム、ヘッダ暗号化書庫は無視する
    if(UnRar.IsArchiveSolid()||UnRar.IsArchiveVolume()||UnRar.IsArchiveEncryptedHeaders())return -1;
    UINT64 iPackedSize,iUnpackedSize;
    __int64 i=-1,iThumbIndex=-1;
    tstring strFileName;
    while(UnRar.ReadFileInfo()){
        i+=1;
        iPackedSize=UnRar.GetFilePackedSize64();
        iUnpackedSize=UnRar.GetFileUnpackedSize64();
        if(UnRar.IsDirectory()||iUnpackedSize>THUMBNAIL_MAX_BUFFERSIZE||iPackedSize==0||iUnpackedSize==0){
            UnRar.SkipFile();
            continue;
        }
        if(IsSupportedImage(UnRar.GetFileName())){
            if(iThumbIndex<0)iThumbIndex=i;
            if(strFileName.empty())strFileName=UnRar.GetFileName();
            if(_StrCmpLogicalW(UnRar.GetFileName(),(PCWSTR)strFileName.c_str())==-1){//GetFileName()<strFileName
                iThumbIndex=i;
                strFileName=UnRar.GetFileName();
            }
        }
        UnRar.SkipFile();
    }
    return iThumbIndex;
}

//rarファイル内の画像のサムネイルをHBITMAPで取得
HBITMAP GetThumbnailBitmapFromRarFile(const TCHAR* pszFilePath,const int iWidth,const int iHeight){
    __int64 iThumbIndex=-1;//サムネイルとして利用する画像のIndex
    HBITMAP hRetBitmap=NULL;
    SIZE sizeThumbnail;
    IStream* pIStream=NULL;
    CUnRar UnRar;

    if(!UnRar.CheckReady())return NULL;//DLLは使用可能な状況ではない
    iThumbIndex=GetThumbnailIndexRAR(pszFilePath);
    if(iThumbIndex<0)return NULL;
    if(!UnRar.OpenFile(pszFilePath,false))return NULL;///書庫ファイルを開くことが出来ない
    if(!UnRar.SkipFiles(iThumbIndex))return NULL;
    //ファイルの情報を読み込む
    if(!UnRar.ReadFileInfo())return NULL;
    //サムネイルサイズ設定
    sizeThumbnail.cx=iWidth;
    sizeThumbnail.cy=iHeight;
    HGLOBAL hGlobal=GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT,(SIZE_T)UnRar.GetFileUnpackedSize64());
    if(hGlobal){
        if(CreateStreamOnHGlobal(hGlobal,TRUE,(LPSTREAM*)&pIStream)==S_OK){
            UnRar.SetIStream(pIStream);
            //HBITMAP取得
            if(UnRar.ProcessFile())hRetBitmap=CreateBitmapFromIStream(pIStream,&sizeThumbnail);
        }
    }
    GlobalFree(hGlobal);
    pIStream->Release();
    return (hRetBitmap!=NULL)?hRetBitmap:NULL;
}

//lzhファイル内の画像のサムネイルをHBITMAPで取得
HBITMAP GetThumbnailBitmapFromLHAFile(const TCHAR* pszFilePath,const int iWidth,const int iHeight){
    bool bSuccess=false;
    bool bSuccessBitmap=false;
    int iCmdLineLength=0;
    LONGLONG llOriginalSize=0,llCompressedSize=0,llTargetOriginalSize=0;
    LPSTR lpszRetPath=NULL;//GetFileName()の引数
    LPWSTR lpszRetPathW=NULL;
    HBITMAP hRetBitmap=NULL;
    TCHAR pszCmdLine[MAX_PATH*2]={0};//LPWSTR pszCmdLine=NULL;//DLLに渡すコマンド
    LPBYTE lpBuffer=NULL;
    SIZE sizeThumbnail;
    CArcDll ArcDll;

    if(!ArcDll.LoadDll(_T("UNLHA32.DLL"),_T("Unlha")))return NULL;//DLLを読み込むことが出来ない
    ArcDll.SetCursorMode(false);//DLL独自のカーソルを表示しない
    do{//ダミーループ
        do{//ダミーループ
            if(ArcDll.CheckArchiveW(pszFilePath,1)==false)break;//正しい書庫ファイルではない
            if(ArcDll.GetRunning())break;//DLLは動作中である
            if(ArcDll.OpenArchiveW(NULL,pszFilePath,0)==NULL)break;//書庫ファイルを開くことが出来ない
            bSuccess=true;
        }while(0);
        if(!bSuccess)return NULL;
        bSuccess=false;
        if(ArcDll.FindFirstA("*.*",NULL)==-1)break;//書庫ファイル内の情報を取得出来ない
        lpszRetPath=(LPSTR)malloc(MAX_PATH);//HeapAlloc(GetProcessHeap(),0,MAX_PATH);
        lpszRetPathW=(LPWSTR)malloc(MAX_PATH);
        tstring strFileName;
        do{
            //GetFileNameW()だと失敗してしまう?
            //GetUserDefaultLangID()
            if(ArcDll.GetFileNameA(lpszRetPath,MAX_PATH)){
                continue;//書庫ファイル内のファイル名を取得出来ない
            }else{
                if(!MultiByteToWideChar(CP_ACP,0,lpszRetPath,-1,lpszRetPathW,MAX_PATH))continue;//変換失敗
            }
            if(ArcDll.IsDirectory())continue;//ディレクトリである
            ArcDll.GetOriginalSizeEx(&llOriginalSize);
            ArcDll.GetCompressedSizeEx(&llCompressedSize);
            if(llOriginalSize>THUMBNAIL_MAX_BUFFERSIZE)continue;//サムネイル最大バッファより大きい
            if(llOriginalSize==0||llCompressedSize==0)continue;//ファイルサイズが0
            if(IsSupportedImage(lpszRetPathW)){//対応している画像ファイルである
                if(strFileName.empty()){
                    strFileName=lpszRetPathW;
                    llTargetOriginalSize=llOriginalSize;
                }
                if(_StrCmpLogicalW(lpszRetPathW,(PCWSTR)strFileName.c_str())==-1){//GetZipFileItemName()<strFileName
                    strFileName=lpszRetPathW;
                    llTargetOriginalSize=llOriginalSize;
                }
                bSuccess=true;
                break;
            }
        }while(ArcDll.FindNext(NULL)!=-1);//検索終了まで回す
        if(!bSuccess)break;//対応している画像が格納されていなかった
        bSuccess=false;
        ArcDll.CloseArchive();
        iCmdLineLength=lstrlen(pszFilePath)+strFileName.size()+24;
        //pszCmdLine=(LPWSTR)malloc(iCmdLineLength);//HeapAlloc(GetProcessHeap(),0,iCmdLineLength);
        //if(pszCmdLine){
            //n(展開状況ダイアログ表示の抑止)
            //gm(エラーメッセージ表示の抑止)
            wsprintf(pszCmdLine,_T("-n -gm \"%s\" \"%s\""),pszFilePath,strFileName.c_str());
                lpBuffer=(LPBYTE)malloc(llTargetOriginalSize*sizeof(BYTE));//HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,llTargetOriginalSize*sizeof(BYTE));//ファイルのバッファ確保
                if(lpBuffer){
                    if(ArcDll.ExtractMemW(NULL,pszCmdLine,lpBuffer,llTargetOriginalSize,NULL,NULL,NULL)==0){
                        //サムネイルサイズ設定
                        sizeThumbnail.cx=iWidth;
                        sizeThumbnail.cy=iHeight;
                        //HBITMAP取得
                        hRetBitmap=CreateBitmapFromMemory(lpBuffer,llOriginalSize,&sizeThumbnail);
                        if(hRetBitmap!=NULL)bSuccessBitmap=true;
                        else bSuccessBitmap=false;
                    }
                    free(lpBuffer);//HeapFree(GetProcessHeap(),0,lpBuffer);
                    lpBuffer=NULL;
            //}
            //free(pszCmdLine);//HeapFree(GetProcessHeap(),0,pszCmdLine);
            //pszCmdLine=NULL;
        }
        bSuccess=true;
    }while(0);
    if(!bSuccess)ArcDll.CloseArchive();
    free(lpszRetPath);//HeapFree(GetProcessHeap(),0,lpszRetPath);
    free(lpszRetPathW);
    return (bSuccess)?hRetBitmap:NULL;
}

HBITMAP GetThumbnailBitmapFromArchiveFile(const TCHAR* pszFilePath,const int iWidth,const int iHeight){
    LPTSTR lpszExtension=NULL;
    HBITMAP hBitmap=NULL;

    lpszExtension=PathFindExtension(pszFilePath);
    if(_tcsicmp(lpszExtension,_T(".zip"))==0){
        hBitmap=GetThumbnailBitmapFromZipFile(pszFilePath,iWidth,iHeight);
    }else if(_tcsicmp(lpszExtension,_T(".rar"))==0){
        hBitmap=GetThumbnailBitmapFromRarFile(pszFilePath,iWidth,iHeight);
    }else if(_tcsicmp(lpszExtension,_T(".lzh"))==0){
        hBitmap=GetThumbnailBitmapFromLHAFile(pszFilePath,iWidth,iHeight);
    }
    return hBitmap;
}

Home > ソフトウェア > Ashley > Ashley130.zip/Ashley130.exe > Src > Thumbnail.cpp