본문 바로가기

기타/소스

php 이미지 리사이즈 및 크롭

//이미지 등록 php

<?
include_once('./db_config.php');//db연결 정보
include_once('./head.sub.php');
include_once('./lib/default.lib.php');//썸네일 함수 포함
include_once('./lib/class.Images.php');//이미지 관련 라이브러리

$uploadDir = './data/upload/img/profile/';
$ori_img = $uploadDir . $m_id.'_ori.jpg';

if(!is_dir($uploadDir)){
 mkdir($uploadDir, 0777);
 exec('chmod -R 777 '.$uploadDir);
}

if($_FILES['profile_img']['name']){
 if(($_FILES['profile_img']['error'] > 0) || ($_FILES['profile_img']['size'] <= 0)){
  echo '파일 업로드에 실패하였습니다.';
 } else {
  // HTTP post로 전송된 것인지 체크합니다.
  if(!is_uploaded_file($_FILES['profile_img']['tmp_name'])) {
   echo 'HTTP로 전송된 파일이 아닙니다.';
  } else {
  // move_uploaded_file은 임시 저장되어 있는 파일을 ./uploads 디렉토리로 이동합니다.
   if (move_uploaded_file($_FILES['profile_img']['tmp_name'], $ori_img)) {
    echo '성공적으로 업로드 되었습니다.\n';

    $size = getimagesize($ori_img);
    $crop_img = $uploadDir.$m_id.'_crop.jpg';
    if($size[0]==$size[1]){//1:1 비율일 경우에 thumbnail() 가 제대로 작동하지 않아서 라이브러리로 리사이징
     $image = new Image($ori_img);
     $image->resize(200,'crop');
     $image->save($m_id.'_crop', $uploadDir);
    }else{
     thumbnail($ori_img,$crop_img,'200','200'); //thumbnail() 함수는 default.lib 에 있음
    }
    echo '<script>alert("프로필 이미지가 등록되었습니다.");opener.document.location.reload();window.close();</script>';
   } else {
    echo '파일 업로드 실패입니다.\n';
   }
  }
 }
}else{
 echo '<script>alert("이미지를 선택해주세요.");history.back();</script>';
}

?>

 

 

//default.lib.php

<?

// 원본 이미지 -> 썸네일로 만드는 함수
function thumbnail($file, $save_filename, $max_width, $max_height){
  //파일 타입 구분(gif,png,jpg,bmp)
  $size = getimagesize($file);
  switch ($size['mime']) {
   case "image/gif":
    $src_img = ImageCreateFromGIF($file);
    break;
   case "image/jpeg":
    $src_img = ImageCreateFromJPEG($file);
    break;
   case "image/png":
    $src_img = ImageCreateFromPNG($file);
    break;
   case "image/bmp":
    $src_img = ImageCreateFromBMP($file);
    break;
  }
        //$src_img = ImageCreateFromJPEG($file); //JPG파일로부터 이미지를 읽어옵니다

        $img_info = getImageSize($file);//원본이미지의 정보를 얻어옵니다
        $img_width = $img_info[0];
        $img_height = $img_info[1];


        if(($img_width/$max_width) == ($img_height/$max_height)){//원본과 썸네일의 가로세로비율이 같은경우
            $dst_width=$max_width;
            $dst_height=$max_height;
        }else if(($img_width/$max_width) < ($img_height/$max_height)){//세로에 기준을 둔경우
            $dst_width=$max_height*($img_width/$img_height);
            $dst_height=$max_height;
   $t_w = $img_width;
   $t_h = ($max_height*$img_width)/$max_width;
        }else{//가로에 기준을 둔경우
            $dst_width=$max_width;
            $dst_height=$max_width*($img_height/$img_width);
   $t_w = ($max_width*$img_height)/$max_height;
   $t_h = $img_height;
        }

        $dst_img = imagecreatetruecolor($max_width, $max_height); //타겟이미지를 생성합니다
        ImageCopyResized($dst_img, $src_img, 0, 0, 0, 0, $max_width, $max_height, $t_w, $t_h); //타겟이미지에 원하는 사이즈의 이미지를 저장합니다
        ImageInterlace($dst_img);
        ImageJPEG($dst_img,  $save_filename); //실제로 이미지파일을 생성합니다
        ImageDestroy($dst_img);
        ImageDestroy($src_img);
}

?>

 

 

 

 

//class.Images.php

<?php

/* ------------------------------------------------------------------------ */
/* class.Images.php
/* Eine Klasse, um mit Bildern rumzuhantieren
/* A class to handle and manipulate images
/* ------------------------------------------------------------------------ */
/* Manuel Reinhard, manu@sprain.ch
/* Twitter: @sprain
/* Web: www.sprain.ch
/* ------------------------------------------------------------------------ */

class Image {

    //Set variables
    protected $image = "";
    protected $imageInfo = array();
    protected $fileInfo = array();
    protected $tmpfile = array();
    protected $pathToTempFiles = "";
    protected $Watermark;
    protected $newFileType;
    protected $expires = 2592000;    // 30 days by default
    protected $lastModified = 0;
    protected $isSourceImage = true;

    /**
     * Constructor of this class
     * @param string $image (path to image)
     */
    public function __construct($image, $isSourceImage=true)
    {
        if(function_exists("sys_get_temp_dir")){
            $this->setPathToTempFiles(sys_get_temp_dir());
        }else{
            $this->setPathToTempFiles($_SERVER["DOCUMENT_ROOT"]);
        }
       
        $this->isSourceImage = (bool)$isSourceImage;

        if(file_exists($image)){
            $this->image  = $image;
            $this->readImageInfo();
        }else{
            throw new Exception("File does not exist: ".$image);
        }
    }

    /**
     * Destructor of this class
     * @param string $image (path to image)
     */
    public function __destruct()
    {
        if(file_exists($this->tmpfile)){
            unlink($this->tmpfile);
        }
    }

    /**
     * Sets response expiry header value
     * @param integer $expires (seconds)
     */
    public function setExpires($expires=0){
        $this->expires = intval($expires);
    }//function


    /**
     * Read and set some basic info about the image
     * @param string $image (path to image)
     */
    protected function readImageInfo()
    {
        $data = getimagesize($this->image);

        $this->imageInfo["width"] = $data[0];
        $this->imageInfo["height"] = $data[1];
        $this->imageInfo["imagetype"] = $data[2];
        $this->imageInfo["htmlWidthAndHeight"] = $data[3];
        $this->imageInfo["mime"] = $data["mime"];
        $this->imageInfo["channels"] = ( isset($data["channels"]) ? $data["channels"] : NULL );
        $this->imageInfo["bits"] = $data["bits"];
        if($this->isSourceImage && filemtime($this->image)!==time()){
            $this->lastModified = filemtime($this->image);
        }
        return true;
    }

    /************************************
    /* SETTERS
    /************************************

    /**
     * Sets path to temp files
     * @param string $path
     */
    public function setPathToTempFiles($path)
    {
        $path = realpath($path).DIRECTORY_SEPARATOR;
        $this->pathToTempFiles = $path;
        $this->tmpfile = tempnam($this->pathToTempFiles, "classImagePhp_");

        return true;
    }

    /**
     * Sets new image type
     * @param string $newFileType (jpeg, png, bmp, gif, vnd.wap.wbmp, xbm)
     */
    public function setNewFileType($newFileType)
    {
        $this->newFileType = strtolower( $newFileType );

        return true;
    }

    /**
     * Sets new main image
     * @param string $pathToImage
     */
    protected function setNewMainImage($pathToImage)
    {
        $this->image = $pathToImage;
        $this->readImageInfo();

        return true;
    }

    /************************************
    /* ACTIONS
    /************************************

    /**
     * Resizes an image
     * Some portions of this function as found on
     * http://www.bitrepository.com/resize-an-image-keeping-its-aspect-ratio-using-php-and-gd.html
     * @param int $max_width
     * @param int $max_height
     * @param string $method
     *               fit = Fits image into width and height while keeping original aspect ratio. Expect your image not to use the full area.
     *               crop = Crops image to fill the area while keeping original aspect ratio. Expect your image to get, well, cropped.
     *               fill = Fits image into the area without taking care of any ratios. Expect your image to get deformed.
     *
     * @param string $cropAreaLeftRight
     *               l = left
     *               c = center
     *               r = right
     *               array( x-coordinate, width)
     *
     * @param string $cropAreaBottomTop
     *               t = top
     *               c = center
     *               b = bottom
     *               array( y-coordinate, height)
     */
    public function resize($max_width, $max_height, $method="fit", $cropAreaLeftRight="c", $cropAreaBottomTop="c", $jpgQuality=75, $enlarge=false)
    {
        $width  = $this->getWidth();
        $height = $this->getHeight();

        $newImage_width  = $max_width;
        $newImage_height = $max_height;
        $srcX = 0;
        $srcY = 0;

        //Get ratio of max_width : max_height
        $ratioOfMaxSizes = $max_width / $max_height;

        //Want to fit in the area?
        if($method == "fit"){

            if($ratioOfMaxSizes >= $this->getRatioWidthToHeight()){
                $max_width = $max_height * $this->getRatioWidthToHeight();
            }else{
                $max_height = $max_width * $this->getRatioHeightToWidth();
            }

            //set image data again
            $newImage_width = $max_width;
            $newImage_height = $max_height;


        //or want to crop it?
        }elseif($method == "crop"){

            //set new max height or width
            if($ratioOfMaxSizes > $this->getRatioWidthToHeight()){
                $max_height = $max_width * $this->getRatioHeightToWidth();
            }else{
                $max_width = $max_height * $this->getRatioWidthToHeight();
            }

            //which area to crop?
            if (is_array($cropAreaLeftRight)) {
                $srcX    = $cropAreaLeftRight[0];
                if($ratioOfMaxSizes > $this->getRatioWidthToHeight()){
                    $width = $cropAreaLeftRight[1];
                }else{
                    $width = $cropAreaLeftRight[1] * $this->getRatioWidthToHeight();
                }
            } elseif ($cropAreaLeftRight == "r") {
                $srcX = $width - (($newImage_width / $max_width) * $width);
            } elseif ($cropAreaLeftRight == "c") {
                $srcX = ($width/2) - ((($newImage_width / $max_width) * $width) / 2);
            }

            if (is_array($cropAreaBottomTop)) {
                $srcY    = $cropAreaBottomTop[0];
                if ($ratioOfMaxSizes > $this->getRatioWidthToHeight()) {
                    $height = $cropAreaBottomTop[1] * $this->getRatioHeightToWidth();
                } else {
                    $height = $cropAreaBottomTop[1];
                }
            } elseif ($cropAreaBottomTop == "b") {
                $srcY = $height - (($newImage_height / $max_height) * $height);
            } elseif ($cropAreaBottomTop == "c") {
                $srcY = ($height/2) - ((($newImage_height / $max_height) * $height) / 2);
            }
        }

        if(!$enlarge && ($newImage_width>$width || $newImage_height>$height)){
                $newImage_width = $width;
                $max_width = $width;
                $newImage_height = $height;
                $max_height = $height;
        }

 //Let's get it on, create image!
        list($image_create_func, $image_save_func) = $this->getFunctionNames();

  // check if it is a jpg and if there are exif data about Orientation (e.g. on uploading an image from smartphone)
  if( $this->getMimeType() == "image/jpg" || $this->getMimeType() == "image/jpeg")
  {
   $exif = exif_read_data($this->image);
   if(!empty($exif['Orientation'])) {
    switch($exif['Orientation']) {
     case 8:
      $this->rotate(90, $jpgQuality);
     break;
     case 3:
      $this->rotate(180, $jpgQuality);
     break;
     case 6:
      $this->rotate(-90, $jpgQuality);
     break;
    }
   }
  }

        $imageC = ImageCreateTrueColor($newImage_width, $newImage_height);
        $newImage = $image_create_func($this->image);

        if($image_save_func == 'ImagePNG'){
            //http://www.akemapa.com/2008/07/10/php-gd-resize-transparent-image-png-gif/
            imagealphablending($imageC, false);
            imagesavealpha($imageC, true);
            $transparent = imagecolorallocatealpha($imageC, 255, 255, 255, 127);
            imagefilledrectangle($imageC, 0, 0, $newImage_width, $newImage_height, $transparent);
        }
        ImageCopyResampled($imageC, $newImage, 0, 0, $srcX, $srcY, $max_width, $max_height, $width, $height);

        //Set image
        if($image_save_func == "imageJPG" || $image_save_func == "ImageJPEG"){
            if(!$image_save_func($imageC, $this->tmpfile, $jpgQuality)){
                throw new Exception("Cannot save file ".$this->tmpfile);
            }
        }else{
            if(!$image_save_func($imageC, $this->tmpfile)){
                throw new Exception("Cannot save file ".$this->tmpfile);
            }
        }

        //Set new main image
        $this->setNewMainImage($this->tmpfile);

        //Free memory!
        imagedestroy($imageC);
    }

    /**
     * Adds a watermark
     */
    public function addWatermark($imageWatermark)
    {
        $this->Watermark = new self($imageWatermark, false);
        $this->Watermark->setPathToTempFiles($this->pathToTempFiles);

        return $this->Watermark;
    }


    /**
     * Writes Watermark to the File
     * @param int $oapcity
     * @param int $marginH (margin in pixel from base image horizontally)
     * @param int $marginV (margin in pixel from base image vertically)
     *
     * @param string $positionWatermarkLeftRight
     *                  l = left
     *               c = center
     *               r = right
     *
     * @param string $positionWatermarkTopBottom
     *                  t = top
     *               c = center
     *               b = bottom
     */
    public function writeWatermark($opacity=50, $marginH=0, $marginV=0, $positionWatermarkLeftRight="c", $positionWatermarkTopBottom="c")
    {
        //add Watermark
        list($image_create_func, $image_save_func) = $this->Watermark->getFunctionNames();
        $watermark = $image_create_func($this->Watermark->getImage());

        //get base image
        list($image_create_func, $image_save_func) = $this->getFunctionNames();
        $baseImage = $image_create_func($this->image);

        //Calculate margins
        if($positionWatermarkLeftRight == "r"){
            $marginH = imagesx($baseImage) - imagesx($watermark) - $marginH;
        }

        if($positionWatermarkLeftRight == "c"){
            $marginH = (imagesx($baseImage)/2) - (imagesx($watermark)/2) - $marginH;
        }

        if($positionWatermarkTopBottom == "b"){
            $marginV = imagesy($baseImage) - imagesy($watermark) - $marginV;
        }

        if($positionWatermarkTopBottom == "c"){
            $marginV = (imagesy($baseImage)/2) - (imagesy($watermark)/2) - $marginV;
        }

        //****************************
        //Add watermark and keep alpha channel of pngs.
        //The following lines are based on the code found on
        //http://ch.php.net/manual/en/function.imagecopymerge.php#92787
        //****************************

        // creating a cut resource
        $cut = imagecreatetruecolor(imagesx($watermark), imagesy($watermark));

        // copying that section of the background to the cut
        imagecopy($cut, $baseImage, 0, 0, $marginH, $marginV, imagesx($watermark), imagesy($watermark));

        // placing the watermark now
        imagecopy($cut, $watermark, 0, 0, 0, 0, imagesx($watermark), imagesy($watermark));
        imagecopymerge($baseImage, $cut, $marginH, $marginV, 0, 0, imagesx($watermark), imagesy($watermark), $opacity);

        //****************************
        //****************************

        //Set image
        if(!$image_save_func($baseImage, $this->tmpfile)){
            throw new Exception("Cannot save file ".$this->tmpfile);
        }

        //Set new main image
        $this->setNewMainImage($this->tmpfile);

        //Free memory!
        imagedestroy($baseImage);
        unset($Watermark);
    }

    /**
     * Roates an image
     */
    public function rotate($degrees, $jpgQuality=75)
    {
        list($image_create_func, $image_save_func) = $this->getFunctionNames();

        $source = $image_create_func($this->image);
        if(function_exists("imagerotate")){
            $imageRotated = imagerotate($source, $degrees, 0, true);
        }else{
            $imageRotated = $this->rotateImage($source, $degrees);
        }

        if($image_save_func == "ImageJPEG"){
            if(!$image_save_func($imageRotated, $this->tmpfile, $jpgQuality)){
                throw new Exception("Cannot save file ".$this->tmpfile);
            }
        }else{
            if(!$image_save_func($imageRotated, $this->tmpfile)){
                throw new Exception("Cannot save file ".$this->tmpfile);
            }
        }

        //Set new main image
        $this->setNewMainImage($this->tmpfile);

        return true;
    }

    /**
     * Sends image data to browser
     */
    public function display()
    {
        $mime = $this->getMimeType();
        header("Content-Type: ".$mime);
        header("Cache-Control: public");
        header("Expires: ". date("r",time() + ($this->expires)));
        if($this->lastModified>0){
            header("Last-Modified: ".gmdate("D, d M Y H:i:s", $this->lastModified)." GMT");
        }
        readfile($this->image);
    }

    /**
     * Prints html code to display image
     */
    public function displayHTML($alt=false, $title=false, $class=false, $id=false, $extras=false)
    {
        print $this->getHTML($alt, $title, $class, $id, $extras);
    }

    /**
     * Creates html code to display image
     */
    public function getHTML($alt=false, $title=false, $class=false, $id=false, $extras=false)
    {
        $path = str_replace($_SERVER["DOCUMENT_ROOT"], "", $this->image);

        $code = '<img src="/'.$path.'" width="'.$this->getWidth().'" height="'.$this->getHeight().'"';
        if($alt   ){ $code .= ' alt="'.$alt.'"';}
        if($title ){ $code .= ' title="'.$title.'"';}
        if($class ){ $code .= ' class="'.$class.'"';}
        if($id    ){ $code .= ' id="'.$id.'"';}
        if($extras){ $code .= ' '.$extras;}
        $code .= ' />';

        return $code;
    }

    /**
     * Saves image to file
     */
    public function save($filename, $path="", $extension="")
    {
        //add extension
        if($extension == ""){
            $filename .= $this->getExtension(true);
        }else{
            $filename .= ".".$extension;
        }

        //add trailing slash if necessary
        if($path != ""){
            $path = realpath($path).DIRECTORY_SEPARATOR;
        }

        //create full path
        $fullPath = $path.$filename;

        //Copy file
        if(!copy($this->image, $fullPath)){
            throw new Exception("Cannot save file ".$fullPath);
        }

        //Set new main image
        $this->setNewMainImage($fullPath);

        return true;
    }

    /************************************
    /* CHECKERS
    /************************************

    /**
     * Checks whether image is RGB
     * @return bool
     */
    public function isRGB()
    {
        if($this->imageInfo["channels"] == 3){
            return true;
        }
        return false;
    }

    /**
     * Checks whether image is RGB
     * @return bool
     */
    public function isCMYK()
    {
        if($this->imageInfo["channels"] == 4){
            return true;
        }
        return false;
    }

    /**
     * Checks ratio width:height
     * Examples:
     * Ratio must be 4:3 > checkRatio(4,3)
     * Ratio must be 4:3 or 3:4 > checkRatio(4,3, true)
     * @return bool
     */
    public function checkRatio($ratio1, $ratio2, $ignoreOrientation=false)
    {
        $actualRatioWidthToHeight = $this->getRatioWidthToHeight();
        $shouldBeRatio = $ratio1 / $ratio2;

        if($actualRatioWidthToHeight == $shouldBeRatio){
            return true;
        }

        $actualRatioHeightToWidth = $this->getRatioHeightToWidth();
        if($ignoreOrientation && $actualRatioHeightToWidth == $shouldBeRatio){
            return true;
        }

        return false;
    }

    /************************************
    /* GETTERS
    /************************************

    /**
     * Returns function names
     */
    protected function getFunctionNames()
    {
        if (null == $this->newFileType) {
            $this->setNewFileType($this->getType());
        }

        switch ($this->getType()) {
            case 'jpg':
            case 'jpeg':
                $image_create_func = 'ImageCreateFromJPEG';
                break;

            case 'png':
                $image_create_func = 'ImageCreateFromPNG';
                break;

            case 'bmp':
                $image_create_func = 'ImageCreateFromBMP';
                break;

            case 'gif':
                $image_create_func = 'ImageCreateFromGIF';
                break;

            case 'vnd.wap.wbmp':
                $image_create_func = 'ImageCreateFromWBMP';
                break;

            case 'xbm':
                $image_create_func = 'ImageCreateFromXBM';
                break;

            default:
                $image_create_func = 'ImageCreateFromJPEG';
        }

        switch ($this->newFileType) {
            case 'jpg':
            case 'jpeg':
                $image_save_func = 'ImageJPEG';
                break;

            case 'png':
                $image_save_func = 'ImagePNG';
                break;

            case 'bmp':
                $image_save_func = 'ImageBMP';
                break;

            case 'gif':
                $image_save_func = 'ImageGIF';
                break;

            case 'vnd.wap.wbmp':
                $image_save_func = 'ImageWBMP';
                break;

            case 'xbm':
                $image_save_func = 'ImageXBM';
                break;

            default:
                $image_save_func = 'ImageJPEG';
        }

        return array($image_create_func, $image_save_func);
    }

    /**
     * returns the image
     */
    protected function getImage()
    {
        return $this->image;
    }

    /**
     * return info about the image
     */
    public function getImageInfo()
    {
        return $this->imageInfo;
    }

    /**
     * return info about the file
     */
    public function getFileInfo()
    {
        return $this->fileInfo;
    }

    /**
     * Gets width of image
     * @return int
     */
    public function getWidth()
    {
        return $this->imageInfo["width"];
    }

    /**
     * Gets height of image
     * @return int
     */
    public function getHeight()
    {
        return $this->imageInfo["height"];
    }

    /**
     * Gets type of image
     * @return string
     */
    public function getExtension($withDot=false)
    {
        $extension = image_type_to_extension($this->imageInfo["imagetype"]);
        $extension = str_replace("jpeg", "jpg", $extension);
        if(!$withDot){
            $extension = substr($extension, 1);
        }

        return $extension;
    }

    /**
     * Gets mime type of image
     * @return string
     */
    public function getMimeType()
    {
        return $this->imageInfo["mime"];
    }

    /**
     * Gets mime type of image
     * @return string
     */
    public function getType()
    {
        return substr(strrchr($this->imageInfo["mime"], '/'), 1);
    }

    /**
     * Get filesize
     * @return string
     */
    public function getFileSizeInBytes()
    {
        return filesize($this->image);
    }

    /**
     * Get filesize
     * @return string
     */
    public function getFileSizeInKiloBytes()
    {
        $size = $this->getFileSizeInBytes();
        return $size/1024;
    }

    /**
     * Returns a human readable filesize
     * @author      wesman20 (php.net)
     * @author      Jonas John
     * @author      Manuel Reinhard
     * @link        http://www.jonasjohn.de/snippets/php/readable-filesize.htm
     * @link        http://www.php.net/manual/en/function.filesize.php
     */
    public function getFileSize()
    {
        $size = $this->getFileSizeInBytes();

        $mod = 1024;
        $units = explode(' ','B KB MB GB TB PB');
        for ($i = 0; $size > $mod; $i++) {
            $size /= $mod;
        }

        //round differently depending on unit to use
        if($i < 2){
            $size = round($size);
        }else{
            $size = round($size, 2);
        }

        return $size . ' ' . $units[$i];
    }

    /**
     * Gets ratio width:height
     * @return float
     */
    public function getRatioWidthToHeight()
    {
        return $this->imageInfo["width"] / $this->imageInfo["height"];
    }

    /**
     * Gets ratio height:width
     * @return float
     */
    public function getRatioHeightToWidth()
    {
        return $this->imageInfo["height"] / $this->imageInfo["width"];
    }

    /************************************
    /* OTHER STUFF
    /************************************

    /**
     * Replacement for imagerotate if it doesn't exist
     * As found on http://www.php.net/manual/de/function.imagerotate.php#93692
     */
    protected function rotateImage($img, $rotation)
    {
        $width = imagesx($img);
        $height = imagesy($img);
        switch($rotation) {
            case 90: $newimg= @imagecreatetruecolor($height , $width );break;
            case 180: $newimg= @imagecreatetruecolor($width , $height );break;
            case 270: $newimg= @imagecreatetruecolor($height , $width );break;
            case 0: return $img;break;
            case 360: return $img;break;
        }

        if($newimg) {
            for($i = 0;$i < $width ; $i++) {
                for($j = 0;$j < $height ; $j++) {
                    $reference = imagecolorat($img,$i,$j);
                    switch($rotation) {
                        case 90: if(!@imagesetpixel($newimg, ($height - 1) - $j, $i, $reference )){return false;}break;
                        case 180: if(!@imagesetpixel($newimg, $width - $i, ($height - 1) - $j, $reference )){return false;}break;
                        case 270: if(!@imagesetpixel($newimg, $j, $width - $i, $reference )){return false;}break;
                    }
                }
            }
            return $newimg;
        }
        return false;
    }
}

'기타 > 소스' 카테고리의 다른 글

구글 jquery  (0) 2016.02.25
마우스 오버 시 그림자 생성  (0) 2016.02.15
그래프 그리기  (0) 2016.01.30
php mysql 컬럼수 확인  (0) 2016.01.25
유튜브 내가 필요한 태그  (0) 2016.01.13