# JGimp - A Java extension for the GIMP enabling users to write scripts
# in Java and Python/Jython
# Copyright (C) 2003  Georgia Tech Research Corp.
# Written by Michael Terry, mterry@cc.gatech.edu
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

from jgimp_core import install_plugin
from gimpenums import *

"""
Divides an image into a 4x4 grid, and copies each
cell into a new layer in a new image. It must take
the following three parameters: the gimpApp object,
the name of the plug-in being called, and a list of
parameters passed to the plug-in. The paramList contains
at least the following three variables: runInteractive,
image, and drawable, which indicate whether the plug-in
is being run interactively, and the image and drawable
on which to operate.

This version illustrates how too write the image divider
plug-in in an object-oriented, rather than procedural,
style.

This version works correctly with large images, copying
smaller chunks, rather than attempting to read everything
into memory at once.
"""
def jython_image_divider(gimpApp, plugin_name, params):

    (runInteractive, image, drawable) = params
    NUM_TILES = 4

    # Calculate the size of the new image
    newWidth = drawable.size.width / NUM_TILES
    newHeight = drawable.size.height / NUM_TILES

    # Create a new image of the same type as the image passed in
    newImage = gimpApp.createImage(newWidth, newHeight, image.type)

    # Now copy each tile into a new layer in the new image, using a 
    # function to copy the tiles in smaller chunks, rather than reading
    # each tile completely into memory
    for y_tile in range(NUM_TILES):
        for x_tile in range(NUM_TILES):
            layerNum = y_tile * NUM_TILES + x_tile
            copyTileIntoNewLayer(x_tile * newWidth, y_tile * newHeight, newWidth, newHeight, layerNum + 1, drawable, newImage)

    # Display the new image and force an update
    newImage.display()
    gimpApp.flushDisplays()
    return PDB_SUCCESS # Could also be returned as a list of data (PDB_SUCCESS,)
                       # PDB_SUCCESS is defined in gimpenums.py

def copyTileIntoNewLayer(source_x, source_y, width, height, layerNum, sourceDrawable, targetImage):
    newLayer = targetImage.appendNewLayer(width,
                                          height,
                                          sourceDrawable.hasAlpha(),
                                          "Layer number " + str(layerNum),
                                          100,         # opacity
                                          NORMAL_MODE) # normal mode is defined in gimpenums.py
    pixelBuf = None
    TILE_SIZE = 256
    for x_offset in range(0, width, TILE_SIZE):
        for y_offset in range(0, height, TILE_SIZE):
            if ((width - x_offset) < TILE_SIZE):
                thisWidth = width - x_offset
            else:
                thisWidth = TILE_SIZE
            if ((height - y_offset) < TILE_SIZE):
                thisHeight = height - y_offset
            else:
                thisHeight = TILE_SIZE
            if (pixelBuf == None):
                pixelBuf = sourceDrawable.readPixelRegionInNativeByteFormat(source_x + x_offset,
                                                                            source_y + y_offset,
                                                                            thisWidth,
                                                                            thisHeight)
            else:
                sourceDrawable.readPixelRegionInNativeByteFormat(source_x + x_offset,
                                                                 source_y + y_offset,
                                                                 thisWidth,
                                                                 thisHeight,
                                                                 pixelBuf,
                                                                 0)
            newLayer.writePixelRegionInNativeByteFormat(x_offset, y_offset, thisWidth, thisHeight, pixelBuf, 0)

# Install the plug-in in the GIMP
install_plugin("jython-image-divider",                                               # The plug-in's unique name
               "Divides image into a 4x4 grid, pastes each tile into a new image",   # Its description
               "Help goes here",                                                     # A help message
               "Michael Terry",                                                      # The author
               "Copyright 2003, GTRC and Michael Terry",                             # Copyright information
               "April 2003",                                                         # Date it was made
               "<Image>/Filters/Digital Cameras/Nikon Image Divider (Jython)",       # Where to install it in the menu
               "*",                                                                  # The image types it can work on
               [                                                                     # The parameters this plug-in takes
                   (PDB_INT32, "Interactive", "Run interactive or not?"),
                   (PDB_IMAGE, "image", "The source image"),
                   (PDB_DRAWABLE, "drawable", "The drawable to divide up")
                ],
               [],                                                                   # The return values of this plug-in
               jython_image_divider)                                                 # The function to call
