2017/11/10

Poco Library 빌드하기 2

오래전에 "Poco Library 빌드하기" 라는 글을 썼었다.
그 후로 종종 Poco Library 새버전이 나오면 빌드를 다시 해보곤 했는데 버전업되면서 몇가지 문제가 발생하였다. 나중에 필요할 것 같아 내용을 정리 해보았다.

참고로 이전에 올렸던 글을 추가한다.
------------------------------------------------------------
Poco Library 빌드를 위한 파일은 아래와 같다.
Poco Library
 http://pocoproject.org/releases/poco-1.7.3/poco-1.7.3-all.zip

OpenSSL
 https://slproweb.com/products/Win32OpenSSL.html
 https://slproweb.com/download/Win32OpenSSL-1_0_2g.exe
 https://slproweb.com/download/Win64OpenSSL-1_0_2g.exe

MySQL
 32-bit ZIP Archive(http://dev.mysql.com/downloads/file/?id=462038)
 64-bit ZIP Archive(http://dev.mysql.com/downloads/file/?id=462039)

우선 poco-1.7.3-all.zip 파일을 특정 경로에 압축을 해제 한다. 압축 해제  후 존재하지 않는 폴더 Bin, Bin64, Lib, Lib64를 생성한다. 여기서는 D:\poco-1.7.3-all 에 압축을 해제한 것으로 간주하고 기록 하였다.
Win32OpenSSL-1_0_2g.exe 설치후 설치 경로의 bin 폴더의 libeay32.dll, ssleay32.dll파일을 Bin 폴더에 복사하고 lib 폴더의 libeay32.lib, ssleay32.lib파일을 Lib 폴더에 복사한다. 그리고 lib/VC/static 폴더의 모든파일을 Lib 폴더로 복사한다.
Win64OpenSSL-1_0_2g.exe 파일의 경우 Bin64와 Lib64 폴더로 복사를 한다. 마지막으로 include 폴더의 openssl 폴더를 D:\poco-1.7.3-all\Crypto\include 폴더에 복사한다.

MySQL에 포함되어 있는 include 폴더의 모든 파일들을 D:\poco-1.7.3-all\Data\MySQL\include 복사하고 32비트 파일에 포함되어 있는 libmysql.dll파일과 libmysqld.dll 파일을 Bin 폴더로 libmysql.lib파일과 libmysqld.lib 파일을 Lib 폴더로 복사한다. 64비트 파일에 포함되어 있는 파일들은 각각 Bin64와 Lib64로 복사한다.

마지막으로 buildwin.cmd 파일을 열어 편집 한다.
수정해야할 내용은 set OPENSSL_LIB 부분으로 32비트 버전을 빌드 할 때에는 D:\poco-1.7.3-all\Lib 로 설정하고 빌드하고 64비트로 빌드 할 때에는 D:\poco-1.7.3-all\Lib64로 설정하고 빌드 한다.

이렇게 설정하고 아래와 같이 sample과 test프로젝트를 제외하고 빌드한다.

32bit: buildwin 110 build all both Win32 nosamples notests devenv
64bit: buildwin 110 build all both x64 nosamples notests devenv


첫 번째 경험했던 문제는 PLATFORM 변수가 변경되는 문제였다. 분명 64비트로 빌드를 하였는데 32비트로 빌드되면서 빌드가 실패하였다. 일부 Visual Studio 버전에서 발생하는 것 같았는데 개발 환경 설정 후 변경되는 것 같았으나 확실한 원인은 확인하지 못 하였다. 그래서 buildwin.cmd 파일에서 두 번째 PLATFORM을 체크하기 전(184 Line)에 다시 한 번 파라메터 값을 설정하도록 추가하였다.
set PLATFORM=%5
if "%PLATFORM%"=="Win32" (set PLATFORM_SUFFIX=) else (
if "%PLATFORM%"=="x64" (set PLATFORM_SUFFIX=_x64) else (
if "%PLATFORM%"=="WinCE" (set PLATFORM_SUFFIX=_CE) else (
if "%PLATFORM%"=="WEC2013" (set PLATFORM_SUFFIX=_WEC2013))))

두 번째는 Visual Studio 2017 버전의 문제로 빌드 시도시 아래와 같이 개발 환경 설정 파일을 찾지 못하는 문제였다.
set PLATFORM=%5
Error: No Visual C++ environment found.
Please run this script from a Visual Studio Command Prompt
or run "%%VSnnCOMNTOOLS%%\vsvars32.bat" first.

확인을 해 보니 VS150COMNTOOLS 라는 변수는 정의되지 않았다. 그래서 buildwin.cmd 상단에 경로를 설정해 주었다.
set VS150COMNTOOLS=C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\Tools\
Community 버전을 사용하는 경우 경로가 다를 수 있다.

설정 후 빌드를 시도하면 시작 즈음에 Cannot open components 라는 에러가 발생하고 빌드가 멈추었다. 몇 가지 확인을 해 보니 현재 경로가 Poco 작업 경로에서 다른 경도로 변경이 되어 있었다. 그래서 빌드할 컴포넌트 찾기(316 Line)를 수행하기 전에 Poco 작업 경로로 변경을 하는 코드를 추가하였다.
cd /d %POCO_BASE%
for /f %%G in ('findstr /R "." components') do (

이렇게 해야 Visual Studio 2017 버전에서 빌드가 정상적으로 이루어졌다.

2017/10/23

Reading barcode with zxing-cpp and OpenCV Volume 2

1년전쯤 작성한 글인데 ZXing-cpp 와 OpenCV를 이용한 바코드 인식 글(https://goo.gl/kRtaYn)을 올렸었는데 관련 댓글이 달리고 다른 활용처가 있어서 다시 시도를 해 보았다.
물론 한번에 되지는 않았다.

ZXing-cpp 빌드는 문제가 없었으나 이를 사용하는경우 아래와 같은 링크 에러가 발생하였다.
error LNK2005: "public: static unsigned int const zxing::DecodeHints::CHARACTER_SET" (?CHARACTER_SET@DecodeHints@zxing@@2IB) already defined in xxx.obj

인터넷 검색을 통해 해결책(https://goo.gl/WkEEcY)을 찾았다.
문제는 Visual C++ 컴파일러만 발생한 것으로 문제가 발생한 부분을 아래와 같이 수정을 하면 해결이 되었다.

Old code:

DecodeHints.h:
static const DecodeHintType CHARACTER_SET = 1 << 30;
DecodeHints.cpp:
const DecodeHintType DecodeHints::CHARACTER_SET;

has been replaced by:

DecodeHints.h:
static const DecodeHintType CHARACTER_SET;
DecodeHints.cpp:
const DecodeHintType DecodeHints::CHARACTER_SET = 1 << 30;

그리고 이전 코드에서는 컴파일에 문제가 있어서 최신 ZXing에 포함되어 있는 opencv cli 코드(zxing-cpp-master\opencv-cli\src\main.cpp)를 이용하여 테스트 해 보았다.

컴파일및 링크는 문제가 없었으나 인식률은 그리 좋아 보이지 않았다.
물론 ZXing을 얼마나 이해하고 잘 쓰는지가 문제가 될 수 있어 좀 더 분석하고 파고들어봐야 할 것 같다.

아래 코드는 테스트에 사용한 코드 이다.
 cv::String strFile( CStringA(dlgFile.GetPathName()) );
 cv::Mat matImage = cv::imread(strFile);

 cv::Mat matGray;
 cv::cvtColor( matImage, matGray, CV_RGB2GRAY );

 Ref<LuminanceSource> source = MatSource::create(matGray);
  
 bool bHybrid = true;
 string strResult;
 try
 {
  // Create luminance  source
  Ref<LuminanceSource> source = MatSource::create(matGray);

  // Search for QR code
  Ref<Reader> reader;

  if (true)
  {
   reader.reset(new MultiFormatReader);
  }
  else
  {
   reader.reset(new QRCodeReader);
  }

  Ref<Binarizer> binarizer(new GlobalHistogramBinarizer(source));
  Ref<BinaryBitmap> bitmap(new BinaryBitmap(binarizer));
  Ref<Result> result(reader->decode(bitmap, DecodeHints(DecodeHints::DEFAULT_HINT)));

  // Get result point count
  int resultPointCount = result->getResultPoints()->size();

  for (int j = 0; j < resultPointCount; j++)
  {
   // Draw circle
   circle(matImage
    , CvPoint(result->getResultPoints()[j]->getX(), result->getResultPoints()[j]->getY())
    , 10, cv::Scalar( 110, 220, 0 ), 2);
  }

  // Draw boundary on image
  if (resultPointCount > 1)
  {
   for (int j = 0; j < resultPointCount; j++)
   {
    // Get start result point
    Ref<ResultPoint> previousResultPoint = (j > 0) ? result->getResultPoints()[j - 1] : result->getResultPoints()[resultPointCount - 1];

    // Draw line
    //line(matImage, toCvPoint(previousResultPoint), toCvPoint(result->getResultPoints()[j]), cv::Scalar( 110, 220, 0 ),  2, 8 );
    line(matImage, CvPoint(previousResultPoint->getX(), previousResultPoint->getY())
     , CvPoint(result->getResultPoints()[j]->getX(), result->getResultPoints()[j]->getY())
     , cv::Scalar( 110, 220, 0 ), 2, 8 );

    // Update previous point
    previousResultPoint = result->getResultPoints()[j];
   }
  }

  if (resultPointCount > 0)
  {
   TRACE("Found Barcode : %s\n", result->getText()->getText().c_str());
   // Draw text
   putText(matImage, result->getText()->getText()
    , CvPoint(result->getResultPoints()[0]->getX(), result->getResultPoints()[0]->getY())
    , cv::FONT_HERSHEY_PLAIN, 1, cv::Scalar( 110, 220, 0 ));
  }

  // Show captured image
  cv::namedWindow( "ZXing", cv::WINDOW_AUTOSIZE );
  cv::imshow("ZXing", matImage);
 }
 catch (const ReaderException& e) 
 {
  strResult = "zxing::ReaderException: " + string(e.what());
 }
 catch (const zxing::IllegalArgumentException& e) 
 {
  strResult = "zxing::IllegalArgumentException: " + string(e.what());
 }
 catch (const zxing::Exception& e) 
 {
  strResult = "zxing::Exception: " + string(e.what());
 }
 catch (const std::exception& e) 
 {
  strResult = "std::exception: " + string(e.what());
 }

 AfxMessageBox(CString(strResult.c_str()));

2017/08/22

[Python] 파일 보안 설정 변경(File Security)

윈도우에서 파일에대한 보안 설정을하는 코드.

"""File Security Sample"""
import os
import win32api
import win32security
import ntsecuritycon as con

FILENAME = "temp.txt"
os.remove(FILENAME)

#
#Show Cacls
#
def show_cacls(filename):
    for line in os.popen("icacls %s" % filename).read().splitlines():
        print(line)

#
# Find the SIDs for Everyone, the Admin group and the current user
#
everyone, domain, type = win32security.LookupAccountName("", "Everyone")
admins, domain, type = win32security.LookupAccountName("", "Administrators")
user, domain, type = win32security.LookupAccountName("", win32api.GetUserName())

#
# Touch the file and use CACLS to show its default permissions
# (which will probably be: Admins->Full; Owner->Full; Everyone->Read)
#
open(FILENAME, "w").close()
show_cacls(FILENAME)

#
# Find the DACL part of the Security Descriptor for the file
#
sd = win32security.GetFileSecurity(FILENAME, win32security.DACL_SECURITY_INFORMATION)

#
# Create a blank DACL and add the three ACEs we want
# We will completely replace the original DACL with
# this. Obviously you might want to alter the original
# instead.
#
dacl = win32security.ACL()
dacl.AddAccessAllowedAce(win32security.ACL_REVISION, con.FILE_GENERIC_READ, everyone)
dacl.AddAccessAllowedAce(win32security.ACL_REVISION, con.FILE_GENERIC_READ | con.FILE_GENERIC_WRITE, user)
dacl.AddAccessAllowedAce(win32security.ACL_REVISION, con.FILE_ALL_ACCESS, admins)

#
# Put our new DACL into the Security Descriptor,
# update the file with the updated SD, and use
# CACLS to show what's what.
#
sd.SetSecurityDescriptorDacl(1, dacl, 0)
win32security.SetFileSecurity(FILENAME, win32security.DACL_SECURITY_INFORMATION, sd)
show_cacls(FILENAME)

출처: http://timgolden.me.uk/python/win32_how_do_i/add-security-to-a-file.html

[Python] 특정 경로 탐색

특정 경로의 파일과 폴더를 탐색하는 코드.

import os.path

FOLDER = "C:\\MyFolder"
print('Current Folder : {0}'.format(FOLDER))

for path, dirs, files in os.walk(FOLDER):
    print('\nFoler : {0}'.format(path))

    for dname in dirs:
        print('dir: {0}'.format(dname))

    for fname in files:
        print('file: {0}'.format(os.path.join(path, fname)))

[Python] 메일 보내기

간단하게 메일 전송을 테스트하기위한 코드이다.

import smtplib

from email.mime.text import MIMEText
from email import utils

MSG = MIMEText("내용 없음")

SENDER = "<보내는 메일주소>"
RECEIVER = "<받는 메일주소>"

MSG['Subject'] = "메일 전송 테스트"
MSG['From'] = SENDER
MSG['To'] = RECEIVER

MSG['Date'] = utils.formatdate(localtime=True)

print('Begin of sending...')
SERVER = smtplib.SMTP_SSL("<메일서버 주소>", <메일서버 포트번호>)
#SERVER.ehlo()
#SERVER.starttls()
#SERVER.ehlo()
SERVER.login("<메일서버 계정>", "<메일서버 암호>")
SERVER.sendmail(SENDER, RECEIVER, MSG.as_string())
SERVER.close()

print('End of sending...')